Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 9

2023/09.livemd

Day 9

Mix.install([
  {:kino, "~> 0.11.3"}
])

Input

example = """
0 3 6 9 12 15
1 3 6 10 15 21
10 13 16 21 30 45
"""

input = Kino.Input.textarea("Input", default: example)

Part 1

expected = [18, 28, 68]
[18, 28, 68]
defmodule Part1 do
  def parse(input) do
    for history <- String.split(input, "\n", trim: true) do
      for n <- String.split(history) do
        String.to_integer(n)
      end
    end
  end

  def sequence(history, func, acc) do
    next =
      history
      |> Enum.chunk_every(2, 1, :discard)
      |> Enum.map(fn [a, b] -> b - a end)

    if Enum.all?(next, &amp;(&amp;1 == 0)) do
      [func.(history) | acc]
    else
      sequence(next, func, [func.(history) | acc])
    end
  end

  def run(input) do
    for history <- parse(input) do
      sequence(history, &amp;List.last/1, [])
      |> Enum.reduce(&amp;(&amp;1 + &amp;2))
    end
  end
end

Part1.run(example) == expected
true
Kino.Input.read(input)
|> Part1.run()
|> Enum.sum()
|> then(&amp;Kino.Markdown.new("Part 1: #{&amp;1}"))

Part 2

expected = [-3, 0, 5]
[-3, 0, 5]
defmodule Part2 do
  def run(input) do
    for history <- Part1.parse(input) do
      Part1.sequence(history, &amp;List.first/1, [])
      |> Enum.reduce(&amp;(&amp;1 - &amp;2))
    end
  end
end

Part2.run(example) == expected
true
Kino.Input.read(input)
|> Part2.run()
|> Enum.sum()
|> then(&amp;Kino.Markdown.new("Part 2: #{&amp;1}"))