-
Notifications
You must be signed in to change notification settings - Fork 0
/
day_18.ex
103 lines (81 loc) · 3.19 KB
/
day_18.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
defmodule Aoc.Y2021.Day18 do
@moduledoc """
Solved https://adventofcode.com/2021/day/18
"""
import Aoc.Helper.IO
def solve_part1(data), do: data |> add |> calc_mag
def solve_part2(data, result \\ -1) do
for a <- data, b <- data, reduce: result do
result -> [a, b] |> add |> calc_mag |> max(result)
end
end
def add(data), do: add(hd(data), tl(data))
def add(result, []), do: result
def add(current, [h | rest]), do: [current, h] |> inc_depth |> reduce |> add(rest)
def inc_depth(snails), do: snails |> Enum.concat() |> Enum.map(fn {depth, snail} -> {depth + 1, snail} end)
def reduce(snails),
do:
if((new = explode(snails)) != snails,
do: reduce(new),
else: if((new = split(snails)) != snails, do: reduce(new), else: new)
)
def explode(snails), do: explode(snails, snails, 0)
def explode([], result, _i), do: result
def explode([{depth, num} | _snails], result, i) when depth == 4 do
result
|> then(fn result ->
if i > 0 do
{prev_depth, prev_num} = Enum.at(result, i - 1)
List.replace_at(result, i - 1, {prev_depth, num + prev_num})
else
result
end
end)
|> then(fn result ->
if i + 2 < length(result) do
{prev_depth, prev_num} = Enum.at(result, i + 2)
List.replace_at(result, i + 2, {prev_depth, prev_num + (Enum.at(result, i + 1) |> elem(1))})
else
result
end
end)
|> List.pop_at(i + 1)
|> elem(1)
|> List.replace_at(i, {3, 0})
end
def explode([_snail | snails], result, i), do: explode(snails, result, i + 1)
def split(snails, prev \\ [])
def split([], prev), do: Enum.reverse(prev)
def split([{depth, snail} | snails], prev) when snail > 9,
do: Enum.reverse(prev) ++ [{depth + 1, floor(snail / 2)}, {depth + 1, ceil(snail / 2)}] ++ snails
def split([snail | snails], prev), do: split(snails, [snail | prev])
def calc_mag(snails), do: calc_mag(snails, 3)
def calc_mag([{_, num1}, {_, num2}], 0), do: num1 * 3 + num2 * 2
def calc_mag(snails, n),
do:
if((new = reduce_mag(snails, n)) != snails,
do: calc_mag(new, n),
else: calc_mag(new, n - 1)
)
def reduce_mag(snails, depth), do: reduce_mag(snails, snails, depth, 0)
def reduce_mag([], result, _depth, _i), do: result
def reduce_mag([{depth, num} | _snails], result, depth, i) do
num1 = Enum.at(result, i + 1) |> elem(1)
List.replace_at(result, i, {depth - 1, num * 3 + num1 * 2})
|> List.pop_at(i + 1)
|> elem(1)
end
def reduce_mag([_ | snails], result, depth, i), do: reduce_mag(snails, result, depth, i + 1)
def flat_list(snails, depth \\ 0, flat_list \\ [])
def flat_list([], _depth, flat_list), do: flat_list
def flat_list([snail | snails], depth, flat_list) when is_list(snail),
do: flat_list(snails, depth, flat_list(snail, depth + 1, flat_list))
def flat_list([num | snails], depth, flat_list), do: flat_list(snails, depth, [{depth, num} | flat_list])
def get_input() do
get_string_input("2021", "18")
|> String.split("\n", trim: true)
|> Enum.map(&Code.string_to_quoted/1)
|> Enum.map(&(elem(&1, 1) |> flat_list() |> Enum.reverse()))
end
def solved_status(), do: :solved
end