-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday05.ex
89 lines (72 loc) · 2.04 KB
/
day05.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
defmodule AdventOfCode.Day05 do
def part_1(input) do
{rules, updates} = parse_input(input)
updates
|> Enum.map(&if is_ordered?(rules, &1), do: get_middle(&1), else: 0)
|> Enum.sum()
end
def part_2(input) do
{rules, updates} = parse_input(input)
updates
|> Enum.reject(&is_ordered?(rules, &1))
|> Enum.map(&fix_order(rules, &1))
|> Enum.map(&get_middle/1)
|> Enum.sum()
end
def is_ordered?(rules, values) do
values
|> Enum.with_index()
|> Enum.reduce_while(true, fn {value, index}, _ ->
{h, [_ | t]} = Enum.split(values, index)
if Enum.all?(h, &(&1 in rules[value].after)) and Enum.all?(t, &(&1 in rules[value].before)) do
{:cont, true}
else
{:halt, false}
end
end)
end
def get_middle(values), do: Enum.at(values, div(length(values), 2))
def fix_order(rules, values) do
Enum.reduce(values, [], &add_in_order(&2, &1, rules))
end
def add_in_order([], value, _rules), do: [value]
def add_in_order([h | t], value, rules) do
if h in rules[value].before do
[value, h | t]
else
[h | add_in_order(t, value, rules)]
end
end
# Functions to parse the input
def parse_input(input) do
[input_1, input_2] = String.split(input, "\n\n", trim: true)
rules = parse_rules(input_1)
updates = parse_updates(input_2)
{rules, updates}
end
def parse_rules(input) do
Enum.reduce(String.split(input, "\n"), %{}, fn line, acc ->
[a, b] = String.split(line, "|") |> Enum.map(&String.to_integer/1)
a_update =
acc
|> Map.get(a, %{before: [], after: []})
|> Map.update!(:before, &[b | &1])
b_update =
acc
|> Map.get(b, %{before: [], after: []})
|> Map.update!(:after, &[a | &1])
acc
|> Map.put(a, a_update)
|> Map.put(b, b_update)
end)
end
def parse_updates(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
line
|> String.split(",")
|> Enum.map(&String.to_integer/1)
end)
end
end