%% to compile: erlc day3A.erl %% to run: erl -noshell -s day3 solve %% -module(day11). -export ([solve/0, solve/1, solve/2]). -export ([read_input/0]). -compile([export_all]). 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'), Data = read_input(IO), file:close(IO), Data. read_input(IO) -> read_input(IO, []). read_input(IO, Input) -> case read_line(IO) of 'eof' -> Input; Line -> read_input(IO, Input ++ [Line]) end. read_line(IO) -> case file:read_line(IO) of 'eof' -> 'eof'; {ok, Line} -> [ X - $0 || X <- Line, [X] /= "\n"] end. solution1(Input) -> Coords = coords(Input), Data = [ {X, init_data(X, Input)} || X <- Coords], put(flash, 0), sn1_step(Data, 0), get(flash). sn1_step(Data, 100) -> Data; sn1_step(Data, Count) -> Step1 = step1(Data), Step2 = step2(Step1), sn1_step(Step2, Count + 1). solution2(Input) -> Coords = coords(Input), Data = [ {X, init_data(X, Input)} || X <- Coords], put(flash, 0), sn2_step(Data, 0). sn2_step(Data, Count) -> Step1 = step1(Data), Step2 = step2(Step1), case all_flash(Step2) of 'true'-> Count + 1; 'false' -> sn2_step(Step2, Count + 1) end. all_flash(Data) -> lists:all(fun({_,V}) -> V == 0 end, Data). coords([H|_] = Table) -> X = length(H), Y = length(Table), lists:flatten([[{A,B} || A <- lists:seq(1,X)] || B <- lists:seq(1,Y)]). step1(Data) -> lists:map(fun({C, X}) -> case X of 9 -> incr_flash(), {C, 'flash'}; _ -> {C, X + 1} end end, Data). step2(Data) -> case is_flash(Data) of 'true' -> flash(Data); 'false' -> clear_flashed(Data) end. is_flash(Data) -> lists:any(fun({_, X}) -> X == 'flash' end, Data). flash(Data) -> NewData = flash(Data, Data), step2(flashed(Data, NewData)). flash([], Acc) -> Acc; flash([{{X,Y},V}|T], Acc) when V == 'flash' -> flash(T, increase_neighbors({X,Y}, Acc)); flash([_|T], Acc) -> flash(T, Acc). clear_flashed(Data) -> clear_flashed(Data, []). clear_flashed([], Acc) -> lists:reverse(Acc); clear_flashed([{C, V}|T], Acc) when V == 'flashed' -> clear_flashed(T, [{C, 0}|Acc]); clear_flashed([H|T], Acc) -> clear_flashed(T, [H|Acc]). flashed(OldData, NewData) -> lists:zipwith(fun({C, V}, N) -> case V of 'flash' -> {C, 'flashed'}; _ -> N end end, OldData, NewData). increase_neighbors({X,Y}, Data) -> Neigbours = [{X+1,Y},{X-1,Y},{X,Y+1},{X,Y-1},{X+1,Y+1},{X+1,Y-1},{X-1,Y+1},{X-1,Y-1}], increase_neighbor(Neigbours, Data). increase_neighbor([], Data) -> Data; increase_neighbor([{X,Y}|T], Data) when X < 1; Y < 1; X > 10; Y > 10 -> io:format("ignore: ~p~n",[{X,Y}]), increase_neighbor(T,Data); increase_neighbor([H|T], Data) -> case get_value(H, Data) of 'flash' -> increase_neighbor(T, Data); 'flashed' -> increase_neighbor(T, Data); 9 -> incr_flash(), increase_neighbor(T, set_value(H, Data, 'flash')); V -> increase_neighbor(T, set_value(H, Data, V + 1)) end. get_value(C, Table) -> {C, V} = lists:keyfind(C, 1, Table), V. set_value(C, Table, V) -> lists:keyreplace(C, 1, Table, {C, V}). init_data({X,Y}, Table) -> lists:nth(X, lists:nth(Y, Table)). incr_flash() -> put(flash, get(flash) + 1).