DEV Community

Cover image for High-Entropy Passphrases
Robert Mion
Robert Mion

Posted on

High-Entropy Passphrases

Advent of Code 2017 Day 4

Part 1

  1. Inventory Management System Redux!
  2. Writing my working algorithm

Inventory Management System Redux!

  • Remember 2018 Day 2?
  • It asked me to find exact counts of letters within strings
  • This feels similar, but easier, in my opinion
  • Because I don't need to build an object of letter counts for each string
  • I just need an Array and a Set, so I can compare length and size!

Writing my working algorithm

Split the input at each newline character into an array of strings

For each string, accumulate a tally, starting at 0
  Split the string at each space character into an array of strings
  If the length of the array is the same as the size of a Set generated from that array
    Increment the tally by 1, because there are no duplicate phrases
  Else
    Leave the tally unchanged

Return the tally
Enter fullscreen mode Exit fullscreen mode

In JavaScript, I use reduce(), split(), Array.length, Set.size and a ternary operator in a one long chained statement:

input.split('\n')
     .reduce((tally, current) => {
       return tally += current.split(' ').length 
                    == new Set(current.split(' ')).size 
                    ? 1 : 0
     }, 0)
Enter fullscreen mode Exit fullscreen mode

Part 2

  1. What a delightful twist!
  2. Three reduce()rs, that's how!
  3. Revealing my working reduce()rs

What a delightful twist!

  • Anagrams, eh? How fun!
  • And also...complicating

Hmm...how should I attempt to solve this?

Three reduce()rs, that's how!

This is going to get complex really fast, so bear with me:

  1. An outer reduce() to track the tallies of valid passphrases
  2. An inner reduce() to collect all the stringified letter tallies for each word
  3. An inner-most reduce() to generate a stringified letter tally for one word

This animation illustrates each of the reduce()rs using the last example set of passphrases:
Animation of all three reducers

Revealing my working reduce()rs

This is the JavaScript I'm proud to have written in about 15 minutes:

return input
  .split('\n')
  .reduce((passphrases, passphrase) => {
    let letterCounts = passphrase
      .split(' ')
      .reduce((list, group) => {
        let counts = group
          .split(' ')
          .reduce((tallies, letter) => {
            tallies[letter] = (tallies[letter] || 0) + 1
            return tallies
          }, {})
        list.push(
          Object.keys(counts)
            .sort()
            .map(el => el + '|' + counts[el]).join(''))
        return list
      }, [])
    return passphrases += letterCounts.length 
                       == new Set(letterCounts).size 
                       ? 1 : 0
  }, 0)
Enter fullscreen mode Exit fullscreen mode

I did it!!

  • I solved both parts!
  • I used a ton of reduce()!
  • I made a detailed GIF showing what each reduce() does!
  • I really enjoyed solving Part 2!
  • I'm now tied for my personal best star score in a given year: 40!

Top comments (0)