Files
adventofcode/2021/day15/day15.erl
2023-11-16 10:48:53 +00:00

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.