import AOC aoc 2021, 18 do def p1 do input() |> Enum.reduce(fn x, acc -> concat(acc, x) |> reduce() end) |> to_lists() |> magnitude() end def p2 do numbers = input() |> Enum.to_list() for a <- numbers, b <- numbers, a != b do concat(a, b) |> reduce() |> to_lists() |> magnitude() end |> Enum.max() end def magnitude([a, b]) do 3 * magnitude(a) + 2 * magnitude(b) end def magnitude(n), do: n def reduce(encoded_snailfish_number) do case step(encoded_snailfish_number) do {:nop, result} -> result {_, result} -> reduce(result) end end def step([{dl, _} = left, {d, a}, {d, b}, right | rest]) when d > 4 and dl != d do {:exploded, [add(left, a), {d - 1, 0}, add(right, b) | rest]} end def step([{dl, _} = left, {d, a}, {d, _}]) when d > 4 and dl != d do {:exploded, [add(left, a), {d - 1, 0}]} end def step([{d, _}, {d, b}, right | rest]) when d > 4 do {:exploded, [{d - 1, 0}, add(right, b) | rest]} end def step([{d, n} | rest]) when n >= 10 do l = {d + 1, div(n, 2)} r = {d + 1, div(n, 2) + rem(n, 2)} {:split, [l, r | rest]} end def step([]) do {:nop, []} end def step([h | rest]) do {op, rest} = step(rest) {op, [h | rest]} end def add({d, n}, x), do: {d, n + x} def concat(xs, ys), do: deepen(xs ++ ys) def deepen(xs) do for {d, x} <- xs, do: {d + 1, x} end def to_lists(flat) do case to_lists_(flat) do {true, unflatter} -> to_lists(unflatter) {false, [{0, unflattest}]} -> unflattest end end def to_lists_([]), do: {false, []} def to_lists_([{d, a}, {d, b} | rest]) do {true, [{d - 1, [a, b]} | rest]} end def to_lists_([x | rest]) do {recurse, rest} = to_lists_(rest) {recurse, [x | rest]} end def encoded_to_string(encoded) do encoded |> to_lists() |> inspect(charlists: :as_lists) |> String.replace(" ", "") end def fst([a, _]), do: a def snd([_, b]), do: b def read_input_line(line, depth \\ 0) def read_input_line("[" <> rest, depth), do: read_input_line(rest, depth + 1) def read_input_line("]" <> rest, depth), do: read_input_line(rest, depth - 1) def read_input_line("," <> rest, depth), do: read_input_line(rest, depth) def read_input_line("", _), do: [] def read_input_line(line, depth) do {n, rest} = Integer.parse(line) [{depth, n} | read_input_line(rest, depth)] end def input() do input_stream() |> Enum.map(&read_input_line/1) end end