167 lines
4.7 KiB
Erlang
167 lines
4.7 KiB
Erlang
%% 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.
|