%% to compile: erlc day3A.erl %% to run: erl -noshell -s day5 solve %% -module(day16). -compile(export_all). -export ([solve/0, solve/1, solve/2]). -export ([read_input/0]). solve() -> solve(['1']), solve(['2']), init:stop(). solve(A) -> solve(A, read_input()). solve(['1'], D) -> io:format("The solution to ~p puzzle1 is: ~p~n", [?MODULE, solve(1, D)]); solve(1, D) -> solution1(D); solve(['2'], D) -> io:format("The solution to ~p puzzle2 is: ~p~n", [?MODULE, solve(2, D)]); solve(2, D) -> solution2(D). read_input() -> {ok, IO} = file:open("input.txt", 'read'), {ok, Line} = file:read_line(IO), file:close(IO), hexstr_to_bin(string:strip(Line, 'both', $\n)). hexstr_to_bin(S) -> hexstr_to_bin(S, []). hexstr_to_bin([], Acc) -> list_to_binary(lists:reverse(Acc)); hexstr_to_bin([X,Y|T], Acc) -> {ok, [V], []} = io_lib:fread("~16u", [X,Y]), hexstr_to_bin(T, [V | Acc]); hexstr_to_bin([X|T], Acc) -> {ok, [V], []} = io_lib:fread("~16u", lists:flatten([X,"0"])), hexstr_to_bin(T, [V | Acc]). bin_to_hexstr(Bin) -> lists:flatten([io_lib:format("~2.16.0B", [X]) || X <- binary_to_list(Bin)]). solution1(Input) -> D = unpack(Input, [], not is_zero_bitstring(Input)), io:format("Pkt: ~p~n", [D]), count_versions(D, 0). solution2(Input) -> D = unpack(Input, [], not is_zero_bitstring(Input)), io:format("Pkt: ~p~n", [D]), calc(D). calc({_,literal, V}) -> V; calc({_,Op, V}) -> ?MODULE:Op(V); calc([{_,Op, V}]) -> ?MODULE:Op(V). sum(Args) -> io:format("sum: ~p~n", [Args]), lists:foldl(fun(X, Acc) -> calc(X) + Acc end, 0, Args). product(Args) -> io:format("product: ~p~n", [Args]), lists:foldl(fun(X, Acc) -> calc(X) * Acc end, 1, Args). min(Args) -> io:format("min: ~p~n", [Args]), lists:min([calc(X) || X <- Args]). max(Args) -> io:format("max: ~p~n", [Args]), lists:max([calc(X) || X <- Args]). lt([A,B] = Args) -> io:format("lt: ~p~n", [Args]), case calc(A) < calc(B) of 'true' -> 1; 'false' -> 0 end. gt([A,B] = Args) -> io:format("gt: ~p~n", [Args]), case calc(A) > calc(B) of 'true' -> 1; 'false' -> 0 end. eq([A,B] = Args) -> io:format("eq: ~p~n", [Args]), case calc(A) == calc(B) of 'true' -> 1; 'false' -> 0 end. count_versions([{Ver, Type, Rest}|T], Acc) -> count_versions(T, count_versions(Rest, Acc) + Ver); count_versions(_, Acc) -> Acc. is_zero_bitstring(BitString) -> Size = erlang:bit_size(BitString), <<0:Size>> =:= BitString. unpack(Data, [], 'false') -> Data; unpack(Input, Acc, 'false') -> Acc; unpack(Input, Acc, 'true') -> {{Ver, Type, Data}, Rest} = unpack(Input), io:format("unpacking data: ~p~n", [Data]), lists:reverse(unpack(Rest, Acc ++ [{Ver, Type, unpack(Data, [], is_bitstring(Data) andalso not is_zero_bitstring(Data))}], not is_zero_bitstring(Rest))). %% Literal unpack(<>) -> io:format("V:~p, T:literal~n", [V]), unpack_literal(V, Rest); %% Operator length type id 0 unpack(<>) -> io:format("V:~p, T:operator I:0~n", [V]), unpack_operator_0(V, T, Rest); %% Operator length type id 1 unpack(<>) -> io:format("V:~p, T:operator I:1~n", [V]), unpack_operator_1(V, T, Rest). unpack_literal(V, Pkt) -> unpack_literal(V, Pkt, <<>>, 0). unpack_literal(V, <<1:1, Value:4, Rest/bitstring>>, Acc, Count) -> unpack_literal(V, Rest, <>, Count + 1); unpack_literal(V, <<0:1, Value:4, Rest/bitstring>>, Acc, Count) -> L = <>, Size = (Count + 1) * 4, io:format("unpack_literal value: ~p size:~p rest:~p~n", [Value, Size, Rest]), <> = L, {{V, literal, X}, Rest}. unpack_operator_0(V, T, <>) -> io:format("operator0 length:~p~n", [Length]), <> = Rest0, {Rest1, Decoded} = unpack_len(Length, Rest0, []), {{V, operator_type(T), Decoded}, Rest1}. unpack_operator_1(V, T, <>) -> {Rest1, Decoded} = unpack_count(Num, Rest, []), io:format("operator1 num of packets:~p Decoded:~p, Rest:~p~n", [Num,Decoded,Rest1]), {{V, operator_type(T), Decoded}, Rest1}. unpack_len(0, Pkt, Acc) -> {Pkt, Acc}; unpack_len(Length, Pkt, Acc) -> {L, R} = unpack(Pkt), io:format("unpack_len: length:before ~p after: ~p~n", [Length, Length - bit_size(Pkt) + bit_size(R)]), unpack_len(Length - bit_size(Pkt) + bit_size(R), R, Acc ++ [L]). unpack_count(0, Pkt, Acc) -> {Pkt, Acc}; unpack_count(Num, Pkt, Acc) -> {L, R} = unpack(Pkt), unpack_count(Num - 1, R, Acc ++ [L]). operator_type(0) -> 'sum'; operator_type(1) -> 'product'; operator_type(2) -> 'min'; operator_type(3) -> 'max'; operator_type(5) -> 'gt'; operator_type(6) -> 'lt'; operator_type(7) -> 'eq'.