Add solution for 2021 day 14

This commit is contained in:
Patrick Auernig 2021-12-14 17:00:45 +01:00
parent faabb2f188
commit 943557d106
9 changed files with 293 additions and 2 deletions

View File

@ -17,7 +17,7 @@
| 11 | ✓ | ✓ | [Crystal] |
| 12 | ✓ | ✓ | [Python] |
| 13 | ✓ | ✓ | [C++] |
| 14 | | | |
| 14 | ✓ | ✓ | [Erlang] |
| 15 | | | |
| 16 | | | |
| 17 | | | |
@ -49,3 +49,4 @@
[crystal]: https://crystal-lang.org
[python]: https://www.python.org
[c++]: https://isocpp.org
[erlang]: https://www.erlang.org

2
2021/day-14/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.beam
*.dump

6
2021/day-14/Justfile Normal file
View File

@ -0,0 +1,6 @@
@part PART INPUT_FILE="inputs/puzzle.txt":
erl -compile common.erl
escript part_{{PART}}.erl {{INPUT_FILE}}
clean:
rm -f *.beam *.dump

130
2021/day-14/common.erl Normal file
View File

@ -0,0 +1,130 @@
-module(common).
-export([parse_file/1, apply_rules/3, tally_elements/1, polymerization/3]).
-import(lists, [append/2]).
-import(string, [chomp/1, split/2, slice/2, slice/3]).
% File parsing
parse_rule(Raw) ->
[S, I] = split(chomp(Raw), " -> "),
#{{slice(S, 0, 1), slice(S, 1, 1)} => I}.
parse_seq(Sequence, Acc) ->
case slice(Sequence, 0, 1) of
"" -> Acc;
First -> parse_seq(slice(Sequence, 1), append(Acc, [First]))
end.
parse_lines(File, Mode, Sequence, Rules) ->
case {Mode, file:read_line(File)} of
{read_seq, {ok, "\n"}} ->
parse_lines(File, read_rules, Sequence, Rules);
{read_seq, {ok, Val}} ->
NextSequence = parse_seq(chomp(Val), []),
parse_lines(File, read_seq, NextSequence, Rules);
{read_rules, {ok, Val}} ->
NextRules = maps:merge(Rules, parse_rule(Val)),
parse_lines(File, read_rules, Sequence, NextRules);
{read_rules, eof} ->
{Sequence, Rules}
end.
parse_file(Path) ->
{ok, File} = file:open(Path, [read]),
parse_lines(File, read_seq, [], #{}).
% Helper functions
each_cons2(List = [A, B | _], F) when is_function(F) ->
Result = F(A, B),
each_cons2(tl(List), [Result], F).
each_cons2([A, B], Acc, F) when is_function(F) ->
Result = F(A, B),
lists:append(Acc, [Result]);
each_cons2(List = [A, B | _], Acc, F) when is_function(F) ->
Result = F(A, B),
each_cons2(tl(List), lists:append(Acc, [Result]), F).
succ(V) -> V + 1.
% Slow algorithm
apply_rules(Sequence, _, 0) ->
Sequence;
apply_rules(Sequence, Rules, Times) ->
NextSequence = apply_rules(Sequence, Rules),
apply_rules(NextSequence, Rules, Times - 1).
apply_rules(Sequence, Rules) ->
Cons = each_cons2(Sequence, fun (A, B) ->
[A, maps:get({A, B}, Rules), B]
end),
flatten_seq(Cons, []).
tally_elements(Sequence) ->
tally_elements(Sequence, #{}).
tally_elements([], Acc) ->
Acc;
tally_elements([Head | Tail], Acc) ->
Tally = maps:put(Head, 1 + maps:get(Head, Acc, 0), Acc),
tally_elements(Tail, Tally).
flatten_seq([[A, B, C]], Acc) ->
lists:append(Acc, [A, B, C]);
flatten_seq([[A, B | _] | Tail], Acc) ->
flatten_seq(Tail, lists:append(Acc, [A, B])).
% Fast algorithm
apply_rule(Pair, Rules) ->
maps:get(Pair, Rules).
update_tally({A, R, B}, Occ, Tally) ->
AddOccurences = fun(V) -> V + Occ end,
Tmp = maps:update_with({A, R}, AddOccurences, Occ, Tally),
maps:update_with({R, B}, AddOccurences, Occ, Tmp).
polymerization(Sequence, Rules, Times) when is_list(Sequence) ->
Cons = each_cons2(Sequence, fun(A, B) -> {A, B} end),
% first tally up all entries and build the counters
{Tally, Counter} = lists:foldl(fun(Pair = {A, _}, {Tal, Cnt}) ->
T = maps:update_with(Pair, fun succ/1, 1, Tal),
C = maps:update_with(A, fun succ/1, 1, Cnt),
{T, C}
end, {#{},#{}}, Cons),
% because the last one got skipped we have to add it manually
{_, Last} = lists:last(Cons),
Counter2 = maps:update_with(Last, fun succ/1, 1, Counter),
polymerization(Rules, Tally, Counter2, Times).
polymerization(_, _, Counter, 0) ->
Counter;
polymerization(Rules, Tally, Counter, Times) ->
{NewTally, NewCounter} = polymerization_step(Rules, Tally, Counter),
polymerization(Rules, NewTally, NewCounter, Times - 1).
polymerization_step(Rules, Tally, Counter) ->
maps:fold(fun({A, B}, Occ, {NewTally, NewCounter}) ->
Re = apply_rule({A, B}, Rules),
% Update occurance and element counters
NewTally2 = update_tally({A, Re, B}, Occ, NewTally),
NewCounter2 = maps:update_with(Re, fun(V) -> V + Occ end, 1, NewCounter),
{NewTally2, NewCounter2}
end, {#{}, Counter}, Tally).

View File

@ -0,0 +1,102 @@
KOKHCCHNKKFHBKVVHNPN
BN -> C
OS -> K
BK -> C
KO -> V
HF -> K
PS -> B
OK -> C
OC -> B
FH -> K
NV -> F
HO -> H
KK -> H
CV -> P
SC -> C
FK -> N
VV -> F
FN -> F
KP -> O
SB -> O
KF -> B
CH -> K
VF -> K
BH -> H
KV -> F
CO -> N
PK -> N
NH -> P
NN -> C
PP -> H
SH -> N
VO -> O
NC -> F
BC -> B
HC -> H
FS -> C
PN -> F
CK -> K
CN -> V
HS -> S
CB -> N
OF -> B
OV -> K
SK -> S
HP -> C
SN -> P
SP -> B
BP -> C
VP -> C
BS -> K
FV -> F
PH -> P
FF -> P
VK -> F
BV -> S
VB -> S
BF -> O
BB -> H
OB -> B
VS -> P
KB -> P
SF -> N
PF -> S
HH -> P
KN -> K
PC -> B
NB -> O
VC -> P
PV -> H
KH -> O
OP -> O
NF -> K
HN -> P
FC -> H
PO -> B
OH -> C
ON -> N
VN -> B
VH -> F
FO -> B
FP -> B
BO -> H
CC -> P
CS -> K
NO -> V
CF -> N
PB -> H
KS -> P
HK -> S
HB -> K
HV -> O
SV -> H
CP -> S
NP -> N
FB -> B
KC -> V
NS -> P
OO -> V
SO -> O
NK -> K
SS -> H

View File

@ -0,0 +1,18 @@
NNCB
CH -> B
HH -> N
CB -> H
NH -> C
HB -> C
HC -> B
HN -> C
NN -> C
BH -> H
NC -> B
NB -> B
BN -> B
BB -> N
BC -> B
CC -> N
CN -> C

16
2021/day-14/part_one.erl Normal file
View File

@ -0,0 +1,16 @@
-module(part_one).
-export([main/1]).
-import(common, [parse_file/1, polymerization/3]).
main(Args) ->
Path = lists:last(Args),
{Sequence, Rules} = parse_file(Path),
Counter = polymerization(Sequence, Rules, 10),
Values = maps:values(Counter),
Max = lists:max(Values),
Min = lists:min(Values),
io:format("~p~n", [Max - Min]).

16
2021/day-14/part_two.erl Normal file
View File

@ -0,0 +1,16 @@
-module(part_two).
-export([main/1]).
-import(common, [parse_file/1, polymerization/3]).
main(Args) ->
Path = lists:last(Args),
{Sequence, Rules} = parse_file(Path),
Counter = polymerization(Sequence, Rules, 40),
Values = maps:values(Counter),
Max = lists:max(Values),
Min = lists:min(Values),
io:format("~p~n", [Max - Min]).

View File

@ -8,4 +8,4 @@
- [2018](2018/README.md) (0% completed)
- [2019](2019/README.md) (0% completed)
- [2020](2020/README.md) (20% completed)
- [2021](2021/README.md) (52% completed)
- [2021](2021/README.md) (56% completed)