Advent of Code, in Erlang: Day 1

Published Sunday, December 12, 2021 by Bryan

While I'm waiting for the Day 13 puzzle to unlock, let's jump back in time and talk about Advent of Code Day 1. This one was a nice smoke test to demonstrate how the puzzle workflow goes. Get an evironment set up. Read and parse a file. Learn that the second half will use the same input, but alter the analysis in some way.

Day 1, Part 1 asked for the number of times the number on a line of the input was greater than the number on the line before it. Part 2 asked for the number of times that the sum of line N, N-1, and N-2 was greater than the sum of lines N-1, N-2, and N-3.

I wrote the code to get my answer exactly that way - keeping track of a window, comparing sums. You can check the git history for that version. The only neat trick there was recognizing that Part 1 was the same as Part 2 if you considered it as using a window of length 1. But, because the code also didn't fit my latest puzzle-solving format, I've decided to write a better version for this post.

The rewrite also takes advantage of something else I noticed: there is no reason to compute the sums of the window. Because the current window and the previous window differ only by the number being pushed out and the number being pushed in, we only need to compare those two numbers.

count_increases(WindowLength, Numbers) ->
    ComparisonStart = lists:nthtail(WindowLength, Numbers),
    element(2, lists:foldl(
                 fun(New, {[Old|Rest], Count}) when New > Old ->
                         {Rest, Count + 1};
                    (_, {[_|Rest], Count}) ->
                         {Rest, Count}
                 end,
                 {Numbers, 0},
                 ComparisonStart)).

This solution, instead of keeping track of a rolling window, just uses two separate pointers into the list of numbers: one at the New number being pushed in, and the other at the Old number being pushed out. That's how sublists work in Erlang: they're the same memory, just with different handles to the "head" of the list. So, we can fold over the numbers in the list, starting WindowLength numbers in (ComparisonStart), while comparing to the earlier point in the list, where the number is about to leave the window.

Example = [199,200,208,210,200,207,240,269,260,263].
7 = puzzle01:count_increases(1, Example).
5 = puzzle01:count_increases(3, Example).

That's what the puzzle description says I should get. Hooray! I've pushed this version to the github repo. I know some people don't like reading fold syntax, but in addition to being succinct, I think it helps explain the purpose of the iteration a little better than a "manual" function recursion in some cases. What do you think? Let me know on Github (beerriot). Good luck with Day 13!