You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
55 lines
2.1 KiB
55 lines
2.1 KiB
-module(day13).
|
|
|
|
-export([solve/1]).
|
|
|
|
solve(Input) ->
|
|
PacketPairs = binary:split(Input, <<"\n\n">>, [global, trim_all]),
|
|
Part1 = part1(PacketPairs),
|
|
{Part1, part2(Input)}.
|
|
|
|
part1(PacketPairs) -> part1(PacketPairs, {1, 0}).
|
|
|
|
part1([], {_Index, Score}) -> Score;
|
|
part1([PacketPair|Rest], {Index, Score}) ->
|
|
[LeftStr, RightStr] = binary:split(PacketPair, <<$\n>>, [trim_all]),
|
|
Left = parse_packet(LeftStr),
|
|
Right = parse_packet(RightStr),
|
|
NewScore = case compare(Left, Right) of
|
|
true -> Score + Index;
|
|
false -> Score
|
|
end,
|
|
part1(Rest, {Index+1, NewScore}).
|
|
|
|
part2(Input) ->
|
|
Packets0 = binary:split(Input, <<"\n">>, [global, trim_all]),
|
|
Packets1 = lists:filter(fun(X) -> byte_size(X) > 0 end, Packets0),
|
|
Packets2 = lists:map(fun parse_packet/1, Packets1),
|
|
Packets3 = [[[2]], [[6]] | Packets2], % add signal packets
|
|
Packets = lists:sort(fun compare/2, Packets3),
|
|
find([[2]], Packets) * find([[6]], Packets).
|
|
|
|
find(Item, List) -> find(Item, List, 1).
|
|
find(_Item, [], _Index) -> 0;
|
|
find(Item, [Item | _Rest], Index) -> Index;
|
|
find(Item, [_Head | Rest], Index) -> find(Item, Rest, Index+1).
|
|
|
|
compare([], []) -> undecided;
|
|
compare([], [_|_Rest]) -> true;
|
|
compare([_|_Rest], []) -> false;
|
|
compare([Left | LeftRest], [Right | RightRest]) when is_list(Left) and is_list(Right) ->
|
|
case compare(Left, Right) of
|
|
undecided -> compare(LeftRest, RightRest);
|
|
Result -> Result
|
|
end;
|
|
compare([Left | _] = Lefts, [Right | RightRest]) when is_list(Left) and is_integer(Right) ->
|
|
compare(Lefts, [[Right] | RightRest]);
|
|
compare([Left | LeftRest], [Right | _] = Rights) when is_integer(Left) and is_list(Right) ->
|
|
compare([[Left] | LeftRest], Rights);
|
|
compare([Value | Left], [Value | Right]) when is_integer(Value) -> compare(Left, Right);
|
|
compare([Left|_], [Right|_]) when is_integer(Left) and is_integer(Right) -> Left < Right;
|
|
compare(Left, Right) when is_integer(Left) and is_integer(Right) -> Left < Right.
|
|
|
|
parse_packet(Packet) ->
|
|
{ok, Tokens, _EndLine} = erl_scan:string(unicode:characters_to_list([Packet,$.])),
|
|
{ok, Parsed} = erl_parse:parse_term(Tokens),
|
|
Parsed.
|