-
Notifications
You must be signed in to change notification settings - Fork 0
/
day_05.ex
94 lines (78 loc) · 2.72 KB
/
day_05.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
defmodule Aoc.Y2024.Day05 do
@moduledoc """
Solved https://adventofcode.com/2024/day/5
"""
import Aoc.Helper.IO
def solve_part1(data), do: data |> process(%{}, []) |> sum_correct_order()
def solve_part2(data), do: data |> process(%{}, []) |> sum_incorrect_order()
def sum_correct_order([], _, result), do: result
def sum_correct_order([a | rest], order, result) do
if is_valid?(a, order) do
sum_correct_order(rest, order, result + Enum.at(a, div(length(a), 2)))
else
sum_correct_order(rest, order, result)
end
end
def sum_correct_order({list, order}), do: sum_correct_order(list, order, 0)
def process([], order, ins), do: {ins, order}
def process([[key, value] | data], order, ins),
do: process(data, Map.update(order, key, [value], fn existing -> [value | existing] end), ins)
def process([a | data], order, ins), do: process(data, order, [a | ins])
def sum_incorrect_order([], _, result), do: result
def sum_incorrect_order([a | rest], order, result) do
if not is_valid?(a, order) do
sum_incorrect_order(rest, order, result + Enum.at(fix_list(a, order), div(length(a), 2)))
else
sum_incorrect_order(rest, order, result)
end
end
def sum_incorrect_order({list, order}), do: sum_incorrect_order(list, order, 0)
def fix_list(list, order) do
if not is_valid?(list, order) do
find_invalid_pair(list, order) |> swap(list) |> fix_list(order)
else
list
end
end
def find_invalid_pair(list, order) do
Enum.reduce_while(list, [], fn num, visited ->
if Map.has_key?(order, num) do
invalids = Map.get(order, num, []) |> Enum.filter(&(&1 in visited))
if invalids != [] do
{:halt, List.first(invalids) |> then(fn x -> {x, num} end)}
else
{:cont, [num | visited]}
end
else
{:cont, [num | visited]}
end
end)
end
def is_valid?(list, order) do
Enum.reduce_while(list, {[], true}, fn num, {visited, is_valid} ->
if Map.has_key?(order, num) do
if Enum.any?(Map.get(order, num, []), &(&1 in visited)) do
{:halt, {visited, false}}
else
{:cont, {[num | visited], is_valid}}
end
else
{:cont, {[num | visited], is_valid}}
end
end)
|> elem(1)
end
def swap({a, b}, list),
do:
list
|> List.update_at(Enum.find_index(list, fn x -> x == a end), fn _ -> b end)
|> List.update_at(Enum.find_index(list, fn x -> x == b end), fn _ -> a end)
def get_input() do
get_string_input("2024", "05")
|> String.split("\n", trim: true)
|> Enum.map(fn
x -> String.split(x, [",", "|"], trim: true) |> Enum.map(&String.to_integer/1)
end)
end
def solved_status(), do: :solved
end