-module(day18). -export ([solve/0, solve/1]). -compile ([export_all]). solve() -> solve(['1']), solve(['2']), init:stop(). solve(['1']) -> io:format("The solution to ~p puzzle1 is: ~p~n", [?MODULE, solve(1)]); solve(1) -> solution1(); solve(['2']) -> io:format("The solution to ~p puzzle2 is: ~p~n", [?MODULE, solve(2)]); solve(2) -> solution2(). solution1() -> {ok, IO} = file:open("input.txt", 'read'), Ans = maybe_reduce(read_line(IO), IO), file:close(IO), magnitude(Ans). solution2() -> {ok, IO} = file:open("input.txt", 'read'), Numbers = read_all_lines(read_line(IO), IO, []), file:close(IO), io:format("total:~p lines: ~p~n", [length(Numbers), Numbers]), max_magnitude(Numbers). read_all_lines('eof', _IO, Acc) -> Acc; read_all_lines(Line, IO, Acc) -> read_all_lines(read_line(IO), IO, [Line|Acc]). read_line(IO) -> case file:read_line(IO) of {ok, Line} -> {ok, Tokens, _} = erl_scan:string(Line ++ "."), {ok, Term} = erl_parse:parse_term(Tokens), Term; 'eof' -> 'eof' end. max_magnitude(Numbers) when is_list(Numbers) -> lists:max([ max_magnitude(lists:split(I, Numbers)) || I <- lists:seq(1, length(Numbers))]); max_magnitude({List1, List2}) -> [H|T] = lists:reverse(List1), max_magnitude(H, T ++ List2). max_magnitude(Number, Rest) -> lists:foldl(fun(N, MaxMag) -> case magnitude(reduce([Number, N])) of Mag when Mag > MaxMag -> Mag; _ -> MaxMag end end, 0, Rest). magnitude(A) when is_integer(A) -> A; magnitude([A,B]) -> (3 * magnitude(A)) + (2 * magnitude(B)). maybe_reduce(A, IO) -> case read_line(IO) of 'eof' -> A; B -> maybe_reduce(reduce([A,B]), IO) end. reduce(N) -> case maybe_explode(N, 0) of {true, New, _, _} -> reduce(New); false -> case maybe_split(N) of {true, New} -> reduce(New); false -> N end end. maybe_explode([A,B], Depth) when Depth >= 4, is_integer(A), is_integer(B) -> {true, 0, A, B}; maybe_explode([A,B], Depth) -> case maybe_explode(A, Depth+1) of {true, New, AddA, AddB} -> {true, [New, add_explode({b, AddB}, B)], AddA, 0}; false -> case maybe_explode(B, Depth+1) of {true, New, AddA, AddB} -> {true, [add_explode({a, AddA}, A), New], 0, AddB}; false -> false end end; maybe_explode(N, _) when is_integer(N) -> false. add_explode({_, Add}, Num) when is_integer(Num) -> Add + Num; add_explode({b, Add}, [A,B]) -> [add_explode({b, Add}, A), B]; add_explode({a, Add}, [A,B]) -> [A, add_explode({a,Add}, B)]. maybe_split(N) when is_integer(N) -> case N > 9 of true -> Left = N div 2, Right = case Left*2 == N of true -> Left; false -> Left+1 end, {true, [Left, Right]}; false -> false end; maybe_split([A, B]) -> case maybe_split(A) of {true, NewA} -> {true, [NewA, B]}; false -> case maybe_split(B) of {true, NewB} -> {true, [A, NewB]}; false -> false end end.