Advent of Code - Day 1

Sat, Dec 04 2021

Day One - Part A

The first problem was determining how many times a value was larger than the preceding value.

I know Elixir has a fantastic core library called Enum, but I like using recursion to see what is happening. The first thing was to have a look at the data. Below is a subset of a list of depths.

[ 171, 173, 174, 163, 161 ...]

I always like to start with my exit function when writing recursive functions. I know I will match on an empty list, so I start there. I also know I want the result, so I return it.

def count_increasing_depths([], count), do: count

Next is the main logic. I need to assess each record and then update the count.

def count_increasing_depths([h | t], count) do
  count = ...
  count_increasing_depths(t, count)
end

The logic is if the current value of h is larger than the last value, then add 1 to the count. To make this work, I need to pass the value of the previous call. Adjusting my function signatures, I get the following and can now implement my test.

def count_increasing_depths([], count, _last), do: count

def count_increasing_depths([h | t], count, last) do
  count = if last < h, do: count + 1, else: count
  count_increasing_depths(t, count, h)
end

To run the code, I call it with the starting values Advant.count_increasing_depths(depths(), 0, 0). This works nicely but does not give me the correct answer. After re-reading the question, I realise I need to account for the first value not being assessed. To fix this, I need another match on the function.

def count_increasing_depths([h | t], count, 0), do: count_increasing_depths(t, count, h)

def count_increasing_depths([], count, _last), do: count

def count_increasing_depths([h | t], count, last) do
  count = if last < h, do: count + 1, else: count
  count_increasing_depths(t, count, h)
end

Now when I run Advant.count_increasing_depths(depths(), 0, 0) the first match extracts the first value and starts the recursive call. The answer is correct, so Happy Days.

Day One - Part B

The second part of the problem is a little more complex, and it requires adding a sliding window of values and then making the same comparison. Since I already have a function that counts the increasing values, I decided to build a new list that can be passed into count_increasing_depths/3; I started with my exit.

def sum_sliding_window([], results), do: results

Now I needed a function to do the test. I know I needed the first three values, so I started there. I match the first three values and add them together. I then add that to an accumulator called results by adding them to the start of the list [ sum | results].

def sum_sliding_window([a, b, c | t], results) do
  sum = a + b + c
  sum_sliding_window(t, [sum | results])
end

The problem is that the t is missing two of the values I need in the next iteration. The simplest solution is to put them back.

def sum_sliding_window([], results), do: results

def sum_sliding_window([a, b, c | t], results) do
  sum = a + b + c
  tail = [b, c | t]
  sum_sliding_window(tail, [sum | results])
end

Now I can run the code Advant.sum_sliding_window(depths(), []) |> Advant.count_increasing_depths(0, 0) but no dice the answer is wrong. This took me a minute to figure out, and I had to get some smaller test data to see what I was doing wrong. In the end, it was a silly mistake; when I created the new list with [ sum | results], I was reversing the order of the values. I made a quick adjustment to my exit function, and happy days again!

def sum_sliding_window([], results), do: Enum.reverse(results)

def sum_sliding_window([a, b, c | t], results) do
  sum = a + b + c
  tail = [b, c | t]
  sum_sliding_window(tail, [sum | results])
end