Skip to content

Commit 635bac4

Browse files
committed
Add days 9 and 10
1 parent 2ffb40e commit 635bac4

File tree

4 files changed

+369
-0
lines changed

4 files changed

+369
-0
lines changed

09.exs

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
defmodule Puzzle do
2+
defmodule Group do
3+
defstruct [:type, :level, content: ""]
4+
end
5+
6+
def total_score(data) do
7+
stats = stream_stats(data)
8+
# stats |> IO.inspect(label: "Stats")
9+
10+
stats.groups
11+
|> Enum.filter(&(&1.type == :plain))
12+
|> Enum.map(&(&1.level))
13+
|> Enum.sum
14+
end
15+
16+
def garbage_chars(data) do
17+
stats = stream_stats(data)
18+
# stats |> IO.inspect(label: "Stats")
19+
20+
stats.groups
21+
|> Enum.filter(&(&1.type == :garbage))
22+
|> Enum.map(&(byte_size(&1.content)))
23+
|> Enum.sum
24+
end
25+
26+
@initial_stats %{stack: [], ignore: false, groups: []}
27+
28+
defp stream_stats(stream, stats \\ @initial_stats)
29+
defp stream_stats("", stats), do: stats
30+
31+
defp stream_stats("!" <> rest, %{ignore: false} = stats) do
32+
# IO.puts "Char: !"
33+
stream_stats(rest, %{stats | ignore: true})
34+
end
35+
36+
defp stream_stats(<<_char::utf8>> <> rest, %{ignore: true} = stats) do
37+
# IO.puts "Ignoring char: #{<<char::utf8>>}"
38+
stream_stats(rest, %{stats | ignore: false})
39+
end
40+
41+
defp stream_stats(<<char::utf8>> <> rest, stats) do
42+
# IO.puts "Char: #{<<char::utf8>>}"
43+
44+
{current, stack} = List.pop_at(stats.stack, 0)
45+
46+
stats =
47+
if current && current.type == :garbage do
48+
case char do
49+
?> ->
50+
# IO.puts "\tClosing garbage group!"
51+
%{stats | stack: stack, groups: [current | stats.groups]}
52+
53+
_ ->
54+
# IO.puts "\tContent: #{<<char::utf8>>}"
55+
current = %{current | content: current.content <> <<char::utf8>>}
56+
%{stats | stack: [current | stack]}
57+
end
58+
else
59+
case char do
60+
?{ ->
61+
# IO.puts "\tNew group!"
62+
group = %Group{type: :plain, level: next_level(current)}
63+
%{stats | stack: [group | [current | stack]]}
64+
65+
?} ->
66+
# IO.puts "\tClosing group!"
67+
%{stats | stack: stack, groups: [current | stats.groups]}
68+
69+
?< ->
70+
# IO.puts "\tNew garbage group!"
71+
group = %Group{type: :garbage, level: next_level(current)}
72+
%{stats | stack: [group | [current | stack]]}
73+
74+
_ ->
75+
# IO.puts "\tContent: #{<<char::utf8>>}"
76+
current = %{current | content: current.content <> <<char::utf8>>}
77+
%{stats | stack: [current | stack]}
78+
end
79+
end
80+
81+
stream_stats(rest, stats)
82+
end
83+
84+
defp next_level(nil), do: 1
85+
defp next_level(current_group) do
86+
current_group.level + 1
87+
end
88+
end
89+
90+
mode = List.first(System.argv)
91+
92+
if mode == "test" do
93+
ExUnit.start()
94+
95+
defmodule PuzzleTest do
96+
use ExUnit.Case
97+
98+
describe "total_score(data) for 1 group" do
99+
test "returns expected" do
100+
data = "{}"
101+
score = Puzzle.total_score(data)
102+
assert score == 1
103+
end
104+
end
105+
106+
describe "total_score(data) for 3 groups" do
107+
test "returns expected" do
108+
data = "{{{}}}"
109+
score = Puzzle.total_score(data)
110+
assert score == 6
111+
end
112+
end
113+
114+
describe "total_score(data) for 6 groups" do
115+
test "returns expected" do
116+
data = "{{{},{},{{}}}}"
117+
score = Puzzle.total_score(data)
118+
assert score == 16
119+
end
120+
end
121+
122+
describe "total_score(data) for 5 groups" do
123+
test "returns expected" do
124+
data = "{{<ab>},{<ab>},{<ab>},{<ab>}}"
125+
score = Puzzle.total_score(data)
126+
assert score == 9
127+
end
128+
end
129+
130+
describe "total_score(data) for 5 groups with !!" do
131+
test "returns expected" do
132+
data = "{{<!!>},{<!!>},{<!!>},{<!!>}}"
133+
score = Puzzle.total_score(data)
134+
assert score == 9
135+
end
136+
end
137+
138+
describe "total_score(data) for 2 groups" do
139+
test "returns expected" do
140+
data = "{{<a!>},{<a!>},{<a!>},{<ab>}}"
141+
score = Puzzle.total_score(data)
142+
assert score == 3
143+
end
144+
end
145+
146+
describe "garbage_chars(data) for 1 group" do
147+
test "returns expected" do
148+
data = "<>"
149+
chars = Puzzle.garbage_chars(data)
150+
assert chars == 0
151+
end
152+
end
153+
154+
describe "garbage_chars(data) for 1 < group" do
155+
test "returns expected" do
156+
data = "<<<<>"
157+
chars = Puzzle.garbage_chars(data)
158+
assert chars == 3
159+
end
160+
end
161+
162+
describe "garbage_chars(data) for 1 mixed group" do
163+
test "returns expected" do
164+
data = "<{o\"i!a,<{i<a>"
165+
chars = Puzzle.garbage_chars(data)
166+
assert chars == 10
167+
end
168+
end
169+
170+
describe "garbage_chars(data) for 1 big group" do
171+
test "returns expected" do
172+
data = "{{<a!>},{<a!>},{<a!>},{<ab>}}"
173+
chars = Puzzle.garbage_chars(data)
174+
assert chars == 17
175+
end
176+
end
177+
end
178+
else
179+
data = "09.txt" |> File.read! |> String.trim_trailing
180+
score = Puzzle.total_score(data)
181+
IO.puts "The total score is: #{score}"
182+
183+
chars = Puzzle.garbage_chars(data)
184+
IO.puts "The number of garbage chars is: #{chars}"
185+
end

0 commit comments

Comments
 (0)