2023 day 9
Mix.install([
{:kino, "~> 0.11.3"}
])
Section
input = Kino.Input.textarea("input")
sample_input = """
10 13 16 21 30 45
0 3 6 9 12 15
1 3 6 10 15 21
"""
input = Kino.Input.read(input)
Part 1 & Part 2
defmodule Day9 do
defmodule Part1 do
def solve(input_str) do
input_str
|> Day9.parse()
|> Enum.map(&predict_next/1)
|> Enum.sum()
end
defp predict_next(sequence) do
do_predict_next(sequence, [List.last(sequence)])
end
defp do_predict_next(cur_seq, last_values, non_zero_cnt \\ nil)
defp do_predict_next(_cur_seq, last_values, 0) do
Enum.sum(last_values)
end
defp do_predict_next(cur_seq, last_values, _non_zero_cnt) do
{_, [last | _] = next_sequence, non_zero_cnt} =
cur_seq
|> Enum.reduce({_prev = nil, _diffs = [], _non_zero_cnt = 0}, fn
num, {nil, [], 0} ->
{num, [], 0}
num, {prev, diffs, non_zero_cnt} ->
diff = num - prev
non_zero_cnt = if diff != 0, do: non_zero_cnt + 1, else: non_zero_cnt
{num, [diff | diffs], non_zero_cnt}
end)
last_values = [last | last_values]
do_predict_next(Enum.reverse(next_sequence), last_values, non_zero_cnt)
end
end
defmodule Part2 do
def solve(input_str) do
input_str
|> Day9.parse()
|> Enum.map(&predict_backward/1)
|> Enum.sum()
end
def predict_backward(sequence) do
do_predict_backward(sequence, [hd(sequence)])
end
defp do_predict_backward(cur_seq, first_values, non_zero_cnt \\ nil)
defp do_predict_backward(_cur_seq, [0 | first_values], 0) do
first_values
|> Enum.reverse()
|> Enum.map_every(2, fn x -> -x end)
|> Enum.sum()
|> then(&(-&1))
end
defp do_predict_backward(cur_seq, first_values, _non_zero_cnt) do
{_, next_sequence, non_zero_cnt} =
cur_seq
|> Enum.reduce({_prev = nil, _diffs = [], _non_zero_cnt = 0}, fn
num, {nil, [], 0} ->
{num, [], 0}
num, {prev, diffs, non_zero_cnt} ->
diff = num - prev
non_zero_cnt = if diff != 0, do: non_zero_cnt + 1, else: non_zero_cnt
{num, [diff | diffs], non_zero_cnt}
end)
[first | _] = next_sequence = Enum.reverse(next_sequence)
first_values = [first | first_values]
do_predict_backward(next_sequence, first_values, non_zero_cnt)
end
end
def parse(input_str) do
to_integer = &String.to_integer/1
input_str
|> String.split("\n", trim: true)
|> Enum.map(&(String.split(&1) |> Enum.map(to_integer)))
end
end
Day9.Part1.solve(input)
Day9.Part2.solve(input)
k1 = f1 - 0
k2 = f2 - k1 = f2 - f1
k3 = f3 - k2 = f3 - f2 + f1
k4 = f4 - f3 + f2 - f1