%% to compile: erlc day3A.erl %% to run: erl -noshell -s day3 solve %% -module(day15). -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) -> Graph = astar:graph(Input), astar:search(Graph, {0, 0}, {99, 99}). solution2(Input) -> Graph = astar:graph(Input), astar:search(Graph, {0, 0}, {499, 499}). coords([H|_] = Table) -> X = length(H), Y = length(Table), lists:flatten([[{A,B} || A <- lists:seq(1,X)] || B <- lists:seq(1,Y)]). %init_data({X,Y}, Table) when X =< 100 andalso Y =< 100 -> % lists:nth(X, lists:nth(Y, Table)); init_data({X,Y}, Table) -> X1 = case (X rem 100) of 0 -> 100; A -> A end, Y1 = case (Y rem 100) of 0 -> 100; B -> B end, D = lists:nth(X1, lists:nth(Y1, Table)), D1 = (D + ((X-1) div 100) + ((Y-1) div 100)) rem 9, D2 = case D1 of 0 -> 9; C -> C end, %% io:format("~p -> ~p -> ~p~n", [{X,Y},{X1,Y1},{D,D2}]), D2. get_value({X,Y}, _Table) when X < 1; Y < 1; X > 500; Y > 500 -> 'invalid'; get_value({X,Y}, Table) -> %% {C, V} = lists:keyfind(C, 1, Data), %% V. X1 = case (X rem 100) of 0 -> 100; A -> A end, Y1 = case (Y rem 100) of 0 -> 100; B -> B end, D = lists:nth(X1, lists:nth(Y1, Table)), D1 = (D + ((X-1) div 100) + ((Y-1) div 100)) rem 9, D2 = case D1 of 0 -> 9; C -> C end, %% io:format("~p -> ~p -> ~p~n", [{X,Y},{X1,Y1},{D,D2}]), D2. get_neighbors({X,Y}, Data) -> Neigbours = [{X+1,Y},{X-1,Y},{X,Y+1},{X,Y-1}], lists:filter(fun({_,E}) -> E /= 'invalid' end, [{C, get_value(C, Data)} || C <- Neigbours]). build_graph(Coords, Data) -> Graph = digraph:new(), [digraph:add_vertex(Graph, C) || C <- Coords], add_edges(Graph, Data, Coords). make_coords(Coords, Loop) -> [{X * Loop , Y * Loop} || {X,Y} <- Coords]. add_edges(Graph, Data, []) -> Graph; add_edges(Graph, Data, [C|Rest]) -> Neighbors = get_neighbors(C, Data), [digraph:add_edge(Graph, C, X, V) || {X,V} <- Neighbors], add_edges(Graph, Data, Rest). dijkstra(Graph,Start_node_name) -> Paths = dict:new(), Unvisited = gb_sets:new(), Unvisited_nodes = gb_sets:insert({0,Start_node_name,root},Unvisited), Paths_updated = loop_through_nodes(Graph,Paths,Unvisited_nodes), Paths_updated. loop_through_nodes(Graph,Paths,Unvisited_nodes) -> %% We need this condition to stop looping through the Unvisited nodes if it is empty case gb_sets:is_empty(Unvisited_nodes) of false -> {{Current_weight,Current_name,Previous_node}, Unvisited_nodes_updated} = gb_sets:take_smallest(Unvisited_nodes), case dict:is_key(Current_name,Paths) of false -> Paths_updated = dict:store(Current_name,{Previous_node,Current_weight},Paths), Out_edges = digraph:out_edges(Graph,Current_name), Unvisited_nodes_updated_2 = loop_through_edges(Graph,Out_edges,Paths_updated,Unvisited_nodes_updated,Current_weight), loop_through_nodes(Graph,Paths_updated,Unvisited_nodes_updated_2); true -> loop_through_nodes(Graph,Paths,Unvisited_nodes_updated) end; true -> Paths end. loop_through_edges(Graph,[],Paths,Unvisited_nodes,Current_weight) -> Unvisited_nodes; loop_through_edges(Graph,Edges,Paths,Unvisited_nodes,Current_weight) -> [Current_edge|Rest_edges] = Edges, {Current_edge,Current_node,Neighbour_node,Edge_weight} = digraph:edge(Graph,Current_edge), case dict:is_key(Neighbour_node,Paths) of false -> Unvisited_nodes_updated = gb_sets:insert({Current_weight+Edge_weight,Neighbour_node,Current_node},Unvisited_nodes), loop_through_edges(Graph,Rest_edges,Paths,Unvisited_nodes_updated,Current_weight); true -> loop_through_edges(Graph,Rest_edges,Paths,Unvisited_nodes,Current_weight) end.