Day 18
Setup
sample = """
[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]
[[[5,[2,8]],4],[5,[[9,9],0]]]
[6,[[[6,2],[5,6]],[[7,6],[4,7]]]]
[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]
[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]]
[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]]
[[[[5,4],[7,7]],8],[[8,3],8]]
[[9,3],[[9,9],[6,[4,9]]]]
[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]
[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]
"""
input = """
[[5,[[8,5],8]],[[9,3],[0,3]]]
[[[8,[3,6]],[0,[1,2]]],[[[4,1],4],[7,[5,8]]]]
[[[[2,0],6],[4,8]],[8,[3,0]]]
[[[[8,2],[8,3]],[[0,9],5]],3]
[[[[4,4],[2,3]],8],[[1,[3,8]],[8,4]]]
[[[2,[1,0]],[[3,2],0]],[9,2]]
[[[0,4],[[9,8],[6,6]]],3]
[[[6,[6,2]],[[4,5],3]],[0,7]]
[[[[2,8],4],[[1,2],[3,8]]],9]
[[[3,[7,6]],[9,9]],[[8,9],[[6,2],[3,4]]]]
[0,[4,[[4,1],8]]]
[[[[3,3],[8,7]],[9,7]],[[7,6],4]]
[[1,[[0,6],4]],[[5,[3,3]],6]]
[[[0,4],7],4]
[[[2,[1,7]],8],[6,[2,[8,7]]]]
[[[9,7],[[2,5],[7,9]]],[1,[4,[8,6]]]]
[[[[3,7],6],[[1,6],[5,4]]],[0,[6,2]]]
[9,5]
[[[[6,1],[4,5]],[[4,2],8]],[[5,[5,1]],[[7,3],6]]]
[9,[9,[[7,4],[6,9]]]]
[3,[[9,2],9]]
[[[[1,7],6],[3,[9,7]]],[[6,[4,3]],[[5,6],5]]]
[[[[0,6],[7,9]],[[2,8],2]],[5,[3,[4,9]]]]
[0,[[[1,8],7],[9,4]]]
[5,[0,[[4,5],6]]]
[[[[7,9],[4,9]],[7,[7,5]]],[6,[[1,6],[8,7]]]]
[[[4,[0,1]],[[9,0],[8,1]]],[[0,7],[5,[0,4]]]]
[0,1]
[[[[7,7],[0,7]],8],[[3,[4,2]],[6,6]]]
[[[[7,8],[4,3]],[7,[7,0]]],[3,[2,3]]]
[[[[6,9],[3,2]],[[4,7],2]],[[3,[7,5]],[[3,3],3]]]
[7,[[[6,7],[1,3]],9]]
[[[[2,9],[2,1]],[3,[9,9]]],[1,[[0,7],[2,4]]]]
[[7,4],[[[0,0],5],[[2,4],5]]]
[[[[2,9],8],[3,4]],[6,[[8,7],[4,3]]]]
[[[8,3],0],[4,[[6,7],5]]]
[[[6,[4,1]],[[1,1],[0,4]]],[[[6,2],[8,6]],[5,2]]]
[9,[[[5,6],0],[[7,2],3]]]
[7,[[[6,6],[1,7]],8]]
[[1,[9,[6,2]]],[[4,0],[[7,7],[4,2]]]]
[[[5,[5,9]],[0,[7,2]]],[[3,3],6]]
[[5,[3,6]],[[0,[8,4]],[6,[5,5]]]]
[[[0,5],[[8,7],[0,3]]],[[[4,1],[6,2]],[[3,2],[2,7]]]]
[[[6,9],5],[[7,3],[[5,0],[2,2]]]]
[[3,5],[[1,[3,4]],[2,[5,3]]]]
[[9,9],[4,6]]
[[[[6,4],[3,7]],[3,8]],[3,[2,[3,7]]]]
[[4,[[1,1],6]],[7,[[1,1],6]]]
[[[[6,4],3],9],2]
[[[[8,1],3],7],[4,[9,1]]]
[4,[[[7,7],6],8]]
[[[7,5],[8,1]],[[6,[6,5]],[6,7]]]
[[8,[3,[1,3]]],[2,[[6,1],[0,5]]]]
[9,[[8,6],0]]
[[8,[1,5]],[[[6,4],6],1]]
[2,[[3,[4,6]],[[2,9],[6,4]]]]
[[[[0,9],[2,0]],[[2,4],7]],[[[7,1],3],[7,9]]]
[[[3,6],[[6,6],1]],[[[0,5],[6,8]],5]]
[[[4,5],[[5,1],0]],[3,[[3,1],[2,8]]]]
[[[[9,0],[7,6]],5],[6,[[0,3],1]]]
[[[1,4],[5,7]],[[9,[3,8]],3]]
[[[7,7],1],[[[5,0],[4,0]],8]]
[[[[0,9],[0,6]],[[5,8],[7,4]]],2]
[[[[0,2],1],[[4,8],0]],[4,[[8,7],[9,1]]]]
[[[1,[2,0]],[[8,4],[0,0]]],5]
[[[9,[8,1]],[[1,1],[4,2]]],[9,[7,[6,9]]]]
[[[[0,2],[1,5]],[[9,2],[8,7]]],[[6,8],[6,0]]]
[[[3,[6,7]],[[9,8],[6,9]]],[8,[[4,6],5]]]
[[[9,[1,5]],[[4,8],9]],2]
[[[0,[1,5]],0],0]
[[[[4,1],4],[4,[7,4]]],[[[3,9],9],3]]
[[[9,7],[[8,7],[0,0]]],[[[0,0],3],3]]
[[9,[[2,0],6]],[[8,6],[5,4]]]
[2,[6,1]]
[[7,[1,[9,5]]],[[[7,8],[1,0]],[6,3]]]
[[[[2,3],1],[7,3]],[[[1,5],[2,2]],[[6,3],7]]]
[4,6]
[[[[4,0],1],2],[[[0,5],8],[8,[0,4]]]]
[[5,[7,0]],[[[4,5],[0,2]],5]]
[[[5,[3,1]],[[8,4],[4,9]]],[2,[[4,8],9]]]
[[[0,7],2],[[[2,5],8],[0,[5,3]]]]
[[[[2,2],[8,1]],[8,[1,3]]],[6,7]]
[[[9,2],[[4,8],[7,1]]],[[[5,2],7],[5,8]]]
[[[2,8],[[3,6],[8,3]]],[[0,5],6]]
[[[3,[7,6]],[4,[5,2]]],6]
[[7,[[5,2],8]],[1,[8,[8,3]]]]
[[[[8,9],7],[[1,1],0]],[[3,6],[[7,8],9]]]
[[4,[[4,2],[7,9]]],[[8,9],[8,8]]]
[[[5,5],[9,[0,7]]],[[[5,8],8],4]]
[[8,[[4,4],[0,0]]],[[2,1],[[2,5],3]]]
[[6,[[4,3],[1,6]]],0]
[[[4,[1,6]],2],[[0,7],1]]
[[[6,[9,9]],[4,8]],[[[1,1],9],[4,[1,7]]]]
[[[[2,1],6],[[3,8],[2,2]]],[9,[7,6]]]
[[0,[[1,0],9]],[8,[0,6]]]
[[[8,[3,4]],[[6,7],[9,9]]],[[7,[6,8]],[[7,7],[6,8]]]]
[4,[[[4,5],[4,4]],[5,[9,0]]]]
[[[[8,2],7],[6,5]],2]
[[9,7],[4,[[5,3],7]]]
[[[[6,5],0],1],[[[5,8],[3,9]],[[9,4],[8,3]]]]
"""
Part a
defmodule Day18 do
# SHARED
def any_true_in_tree?(bool) when is_boolean(bool), do: bool
def any_true_in_tree?(x), do: x |> List.flatten() |> Enum.any?()
def number_to_false(digit) when is_integer(digit), do: false
def number_to_false([x, y]), do: [number_to_false(x), number_to_false(y)]
# MAGNITUDE, SUM, and REDUCE
def magnitude(number) when is_integer(number), do: number
def magnitude([x, y]), do: 3 * magnitude(x) + 2 * magnitude(y)
def sum_and_reduce(a, b), do: reduce([a, b])
def reduce(number) do
# IO.puts "Reducing: #{inspect(number, charlists: :as_lists)}"
case {any_true_in_tree?(first_exploding_pair(number, 0)),
any_true_in_tree?(first_splitting_pair(number))} do
{true, _} -> reduce(explode(number))
{_, true} -> reduce(split(number))
_ -> number
end
end
# EXPLODE
def first_exploding_pair(digit, _) when is_integer(digit), do: false
def first_exploding_pair(_pair, nesting_level) when nesting_level >= 4, do: true
def first_exploding_pair([x, y], nesting_level) do
left = first_exploding_pair(x, nesting_level + 1)
if any_true_in_tree?(left) do
[left, number_to_false(y)]
else
[left, first_exploding_pair(y, nesting_level + 1)]
end
end
def explode(pair) do
# explode(pair, first_exploding_pair(pair, 0))
{new_pair, _, _} = explode(pair, first_exploding_pair(pair, 0))
new_pair
end
def explode([x, y], true), do: {0, x, y}
def explode([x, y], [s1, s2]) do
if any_true_in_tree?(s1) do
# Left branch explodes
{new_x, left, right} = explode(x, s1)
{[new_x, add_left(y, right)], left, 0}
else
# Right branch explodes
{new_y, left, right} = explode(y, s2)
{[add_right(x, left), new_y], 0, right}
end
end
def add_left(digit, add) when is_integer(digit), do: digit + add
def add_left([x, y], add), do: [add_left(x, add), y]
def add_right(digit, add) when is_integer(digit), do: digit + add
def add_right([x, y], add), do: [x, add_right(y, add)]
# SPLIT
def first_splitting_pair(digit) when is_integer(digit), do: digit >= 10
def first_splitting_pair([x, y]) do
left = first_splitting_pair(x)
if any_true_in_tree?(left) do
[left, number_to_false(y)]
else
[left, first_splitting_pair(y)]
end
end
def split(x), do: split(x, first_splitting_pair(x))
def split(x, true) when is_integer(x), do: [div(x, 2), x - div(x, 2)]
def split(x, false) when is_integer(x), do: x
def split([x, y], [s1, s2]), do: [split(x, s1), split(y, s2)]
end
# EXPLODE SAMPLES
if false do
IO.puts(inspect(Day18.explode([[[[[9, 8], 1], 2], 3], 4])))
IO.puts(Day18.explode([[[[[9, 8], 1], 2], 3], 4]) == [[[[0, 9], 2], 3], 4])
IO.puts(inspect(Day18.explode([7, [6, [5, [4, [3, 2]]]]])))
IO.puts(Day18.explode([7, [6, [5, [4, [3, 2]]]]]) == [7, [6, [5, [7, 0]]]])
IO.puts(inspect(Day18.explode([[6, [5, [4, [3, 2]]]], 1])))
IO.puts(Day18.explode([[6, [5, [4, [3, 2]]]], 1]) == [[6, [5, [7, 0]]], 3])
IO.puts(inspect(Day18.explode([[3, [2, [1, [7, 3]]]], [6, [5, [4, [3, 2]]]]])))
IO.puts(
Day18.explode([[3, [2, [1, [7, 3]]]], [6, [5, [4, [3, 2]]]]]) == [
[3, [2, [8, 0]]],
[9, [5, [4, [3, 2]]]]
]
)
IO.puts(inspect(Day18.explode([[3, [2, [8, 0]]], [9, [5, [4, [3, 2]]]]])))
IO.puts(
Day18.explode([[3, [2, [8, 0]]], [9, [5, [4, [3, 2]]]]]) == [
[3, [2, [8, 0]]],
[9, [5, [7, 0]]]
]
)
end
# SPLIT SAMPLES
if false do
IO.puts(inspect(Day18.split([[[[0, 7], 4], [15, [0, 13]]], [1, 1]]), charlists: :as_lists))
IO.puts(
Day18.split([[[[0, 7], 4], [15, [0, 13]]], [1, 1]]) == [
[[[0, 7], 4], [[7, 8], [0, 13]]],
[1, 1]
]
)
IO.puts(inspect(Day18.split([[[[0, 7], 4], [[7, 8], [0, 13]]], [1, 1]]), charlists: :as_lists))
IO.puts(
Day18.split([[[[0, 7], 4], [[7, 8], [0, 13]]], [1, 1]]) == [
[[[0, 7], 4], [[7, 8], [0, [6, 7]]]],
[1, 1]
]
)
end
# REDUCE SAMPLES
if false do
IO.puts(
inspect(Day18.reduce([[[[[4, 3], 4], 4], [7, [[8, 4], 9]]], [1, 1]]), charlists: :as_lists)
)
IO.puts(
Day18.reduce([[[[[4, 3], 4], 4], [7, [[8, 4], 9]]], [1, 1]]) == [
[[[0, 7], 4], [[7, 8], [6, 0]]],
[8, 1]
]
)
end
# SUM SAMPLES
# "[[[0,[4,5]],[0,0]],[[[4,5],[2,6]],[9,5]]]" |> Code.eval_string() |> elem(0)
input
|> String.split("\n", trim: true)
|> Enum.map(fn line -> line |> Code.eval_string() |> elem(0) end)
|> Enum.reduce(fn x, acc -> Day18.sum_and_reduce(acc, x) end)
|> Day18.magnitude()
Part b
numbers =
input
|> String.split("\n", trim: true)
|> Enum.map(fn line -> line |> Code.eval_string() |> elem(0) end)
for line_1 <- numbers,
line_2 <- numbers do
Day18.sum_and_reduce(line_1, line_2) |> Day18.magnitude()
end
|> Enum.max()