# š Christmas Coding with Elixir, Day 2

Following on from yesterday, hereās the second puzzle of Advent of Code.

# The Puzzle: Part 1

ā ā Day 2: Inventory Management System ā -

You stop falling through time, catch your breath, and check the screen on the device. āDestination reached. Current Year: 1518. Current Location: North Pole Utility Closet 83N10.ā You made it! Now, to find those anomalies.

Outside the utility closet, you hear footsteps and a voice. āā¦Iām not sure either. But now that so many people have chimneys, maybe he could sneak in that way?ā Another voice responds, āActually, weāve been working on a new kind of suit that would let him fit through tight spaces like that. But, I heard that a few days ago, they lost the prototype fabric, the design plans, everything! Nobody on the team can even seem to remember important details of the project!ā

āWouldnāt they have had enough fabric to fill several boxes in the warehouse? Theyād be stored together, so the box IDs should be similar. Too bad it would take forever to search the warehouse for two similar box IDsā¦ā They walk too far away to hear any more.

Late at night, you sneak to the warehouse ā who knows what kinds of paradoxes you could cause if you were discovered ā and use your fancy wrist device to quickly scan every box and produce a list of the likely candidates (your puzzle input).

To make sure you didnāt miss any, you scan the likely candidate boxes again, counting the number that have an ID containing exactly two of any letter and then separately counting those with exactly three of any letter. You can multiply those two counts together to get a rudimentary checksumand compare it to what your device predicts.

For example, if you see the following box IDs:

`abcdef` contains no letters that appear exactly two or three times.

`bababc` contains two `a` and three `b`, so it counts for both.

`abbcde` contains two `b`, but no letter appears exactly three times.

`abcccd` contains three `c`, but no letter appears exactly two times.

`aabcdd` contains two `a` and two `d`, but it only counts once.

`abcdee` contains two `e`.

`ababab` contains three `a` and three `b`, but it only counts once.

Of these box IDs, four of them contain a letter which appears exactly twice, and three of them contain a letter which appears exactly three times. Multiplying these together produces a checksum of `4 * 3 = 12`.

What is the checksum for your list of box IDs?

# Solving It

Hereās our input:

And hereās some code to get our answer. Letās break it down.

Thereās quite a lot going on here. `Boxes.group_by_letters/1` takes the list of box IDs and uses `Enum.group_by/2` to move them into groups (once weāve turned each string into an array of individual characters with `String.codepoints/1`). The second argument is the tiny anonymous function, `&(&1)`, which simply returns the current element. As a result, the function groups each letter with other letters that match it i.e.

`> ["a", "a", "a", "b", "b", "c"] |> Enum.group_by(&(&1))%{"a" => ["a", "a", "a"], "b" => ["b", "b"], "c" => ["c"]}`

Next, we use a nested map to convert this into an array of tuples.

`> ["aaabbc", "def"] |> Boxes.group_by_letters[[{"a", 3}, {"b", 2}, {"c", 1}], [{"d", 1}, {"e", 1}, {"f", 1}]]`

Now we have a decent structure to work with!

The `Boxes.ids_with_repeated_letters/2` function takes the above input (along with an integer) and returns all the tuples where the count value matches the given integer. We achieve this with `Enum.filter/2` and then use `Enum.reject/2` to get rid of empty arrays.

Once we have the filtered arrays for strings that occur twice and three times, we can use `Enum.count/1` to tell us how many of each there are, then multiply them to get our checksum.

`\$ cat input.txt | ./advent2.1.exs9633`

Quite a lot of steps there, but nothing too groundbreaking.

# The Puzzle: Part 2

ā ā Part Two ā -

Confident that your list of box IDs is complete, youāre ready to find the boxes full of prototype fabric.

The boxes will have IDs which differ by exactly one character at the same position in both strings. For example, given the following box IDs:

`abcdefghijklmnopqrstfguijaxcyewvxyz`

The IDs `abcde` and `axcye` are close, but they differ by two characters (the second and fourth). However, the IDs `fghij` and `fguij` differ by exactly one character, the third (`h` and `u`). Those must be the correct boxes.

What letters are common between the two correct box IDs? (In the example above, this is found by removing the differing character from either ID, producing `fgij`.)

# Solving It

Here things get a little trickier.

We need to find two strings in a list of 250 that are identical except for a single different character. Hereās the code in full, and Iāll break it down afterwards.

Letās start with `Boxes.differences/2` on line 25. This takes two strings, then uses `Enum.zip/1` to interleave the characters of each as an array of tuples e.g.

`> [["a", "a", "a"], ["b", "b", "b"]] |> Enum.zip()[{"a", "b"}, {"a", "b"}, {"a", "b"}]`

Now we can use `Enum.filter/2 `to find pairs of characters that donāt match and `Enum.count/1` to count them. If thereās only 1 character different, this function returns `1` (which weāll use in the next function).

The `Boxes.differences_of_one/1` function on line 18 takes a list of parcel ID numbers and then uses an Elixir comprehension to generate all possible combinations. In order to find the two parcels that have IDs differing by one, it makes sense to have a list of all possible pairs so the comprehension is an easy approach to build it.

Here it is in action:

`> for a <- 1..3, b <- 1..3, do: [a, b][[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]`

As you can see, it generates duplicates (`[1, 2]` is the same pair as `[2, 1]`)! To work around this, we use `Enum.sort/1` in the comprehension do-block and then `Enum.uniq/1` to filter out the unique combinations.

Now itās a simple case of `Enum.filter/2`, using our `Boxes.differences/2` function to find pairs of IDs that differ only by one.

So thatās most of the work done! The `Boxes.common_letters/1` function on line 4 takes the unique pair of IDs we discovered and then tells us the common letters between them. To do this, we use `Enum.zip/1` again to interleave them, `Enum.reject/2 `to remove any tuple with differing characters, then `Enum.map/2` and `Enum.join/1` to re-assemble the common characters into a single string again.

`\$ cat input.txt | ./advent2.2.exslujnogabetpmsydyfcovzixaw`

# Summary

The list comprehensions in Elixir are very powerful for generating data. I strongly recommend checking out the documentation and then experimenting with them.

Iāll be adding my Ruby and Elixir solutions to Github if youād like to read further: https://github.com/seanhandley/adventofcode2018

EDIT: My December turned out to be way busier than Iād expected and I bailed on this. Sorry folks ā¹ļø

--

--