Powered by AppSignal & Oban Pro

Day 1

2021/notebooks/day-01.livemd

Day 1

Setup

input = Aoc.get_input(1)
textarea = Kino.Input.textarea("Puzzle Input", default: input)
lines =
  Kino.Input.read(textarea)
  |> String.split("\n", trim: true)

Part 1

lines
|> Enum.map(&String.to_integer(&1))
|> Enum.reduce({nil, 0}, fn
  n, {prev, total} when is_integer(prev) and n > prev -> {n, total + 1}
  n, {_prev, total} -> {n, total}
end)
|> elem(1)

Part 2

lines
|> Enum.map(&String.to_integer(&1))
|> Enum.reduce({nil, nil, []}, fn
  n, {a, nil, xs} -> {n, a, xs}
  n, {a, b, xs} -> {n, a, [n + a + b | xs]}
end)
|> elem(2)
|> Enum.reverse()
|> Enum.reduce({nil, 0}, fn
  n, {prev, total} when is_integer(prev) and n > prev -> {n, total + 1}
  n, {_prev, total} -> {n, total}
end)
|> elem(1)

Part 2 revisited

Improvement over the previous solution by performing a single pass over the list.

lines
|> Enum.map(&String.to_integer(&1))
# {count, n-1, n-2, prev_sum}
|> Enum.reduce({0, nil, nil, nil}, fn
  n, {c, a, nil, prev} ->
    {c, n, a, prev}

  n, {c, a, b, nil} ->
    {c, n, a, a + b + n}

  n, {c, a, b, prev} ->
    next = a + b + n

    if next > prev do
      {c + 1, n, a, next}
    else
      {c, n, a, next}
    end
end)
|> elem(0)

Nicer to read solution.

lines
|> Enum.map(&String.to_integer/1)
|> Enum.chunk_every(3, 1, :discard)
|> Enum.map(&Enum.sum/1)
|> Enum.chunk_every(2, 1, :discard)
|> Enum.count(fn [a, b] -> a < b end)

When looking at the inputs and comparing the numbers, we have:

$a + b + c < b + c + d$

Which can be simplified to:

$a < d$

lines
|> Enum.map(&String.to_integer/1)
|> Enum.chunk_every(4, 1, :discard)
|> Enum.count(fn [a, _, _, d] -> a < d end)

Using streams, which would not need to make multiple passes.

lines
|> Stream.map(&String.to_integer/1)
|> Stream.chunk_every(4, 1, :discard)
|> Enum.count(fn [a, _, _, d] -> a < d end)