|
|
@ -4,8 +4,12 @@ |
|
|
|
|
|
|
|
|
solve(Input) -> |
|
|
solve(Input) -> |
|
|
Board = parse_board(Input), |
|
|
Board = parse_board(Input), |
|
|
Result = find_path(find_start(Board), find_goal(Board), Board), |
|
|
|
|
|
{Result, none}. |
|
|
|
|
|
|
|
|
Result1 = find_path(find_start(Board), find_goal(Board), Board), |
|
|
|
|
|
%Part |
|
|
|
|
|
Part2Goal = fun(Node) -> value(Board, Node) == $a end, |
|
|
|
|
|
Part2Neighbors = fun(Node) -> neighbors2(Board, Node) end, |
|
|
|
|
|
{ok, Result2} = bfs(find_goal(Board), Part2Neighbors, Part2Goal), |
|
|
|
|
|
{Result1, Result2}. |
|
|
|
|
|
|
|
|
find_start({W, H, _Data} = Board) -> |
|
|
find_start({W, H, _Data} = Board) -> |
|
|
[Pos] = lists:filter(fun(P) -> raw_value(Board, P) == $S end, [ {X, Y} || X <- lists:seq(0, W-1), Y <- lists:seq(0, H-1) ]), |
|
|
[Pos] = lists:filter(fun(P) -> raw_value(Board, P) == $S end, [ {X, Y} || X <- lists:seq(0, W-1), Y <- lists:seq(0, H-1) ]), |
|
|
@ -43,11 +47,19 @@ valid_move(State, {StartX, StartY}=Start, {MoveX, MoveY} = Move) -> |
|
|
true -> true |
|
|
true -> true |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
valid_move2(State, Start, Move) -> |
|
|
|
|
|
value(State, Move) - value(State, Start) >= -1. |
|
|
|
|
|
|
|
|
neighbors(State, Pos) -> |
|
|
neighbors(State, Pos) -> |
|
|
PossibleNeighbors0 = [ vec_add(Pos, Dir) || Dir <- [{0,-1}, {0, 1}, {1, 0}, {-1, 0}]], |
|
|
PossibleNeighbors0 = [ vec_add(Pos, Dir) || Dir <- [{0,-1}, {0, 1}, {1, 0}, {-1, 0}]], |
|
|
PossibleNeighbors1 = lists:filter(fun(Move) -> valid_position(State, Move) end, PossibleNeighbors0), |
|
|
PossibleNeighbors1 = lists:filter(fun(Move) -> valid_position(State, Move) end, PossibleNeighbors0), |
|
|
lists:filter(fun(Move) -> valid_move(State, Pos, Move) end, PossibleNeighbors1). |
|
|
lists:filter(fun(Move) -> valid_move(State, Pos, Move) end, PossibleNeighbors1). |
|
|
|
|
|
|
|
|
|
|
|
neighbors2(State, Pos) -> |
|
|
|
|
|
PossibleNeighbors0 = [ vec_add(Pos, Dir) || Dir <- [{0,-1}, {0, 1}, {1, 0}, {-1, 0}]], |
|
|
|
|
|
PossibleNeighbors1 = lists:filter(fun(Move) -> valid_position(State, Move) end, PossibleNeighbors0), |
|
|
|
|
|
lists:filter(fun(Move) -> valid_move2(State, Pos, Move) end, PossibleNeighbors1). |
|
|
|
|
|
|
|
|
vec_add({X1, Y1}, {X2, Y2}) -> {X1+X2, Y1+Y2}. |
|
|
vec_add({X1, Y1}, {X2, Y2}) -> {X1+X2, Y1+Y2}. |
|
|
vec_sub({X1, Y1}, {X2, Y2}) -> {X1-X2, Y1-Y2}. |
|
|
vec_sub({X1, Y1}, {X2, Y2}) -> {X1-X2, Y1-Y2}. |
|
|
vec_norm({X1, Y1}) -> abs(X1)+abs(Y1). |
|
|
vec_norm({X1, Y1}) -> abs(X1)+abs(Y1). |
|
|
@ -85,4 +97,26 @@ a_star({_Heuristic, Distance, Parent, Curr}, Goal, Open, Closed, State) -> |
|
|
{ok, NextCurrNode, NextOpen} -> a_star(NextCurrNode, Goal, NextOpen, Closed#{Curr=>{Distance, Parent}}, State) |
|
|
{ok, NextCurrNode, NextOpen} -> a_star(NextCurrNode, Goal, NextOpen, Closed#{Curr=>{Distance, Parent}}, State) |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
bfs(Position, NeighborFn, GoalFn) -> |
|
|
|
|
|
do_bfs0(Position, NeighborFn, GoalFn, 0, priq:new(), #{}). |
|
|
|
|
|
do_bfs0(Position, NeighborFn, GoalFn, Distance, Queue, Visited) when is_map_key(Position, Visited) -> |
|
|
|
|
|
do_bfs2(Position, NeighborFn, GoalFn, Distance, Queue, Visited); |
|
|
|
|
|
do_bfs0(Position, NeighborFn, GoalFn, Distance, Queue, Visited) -> |
|
|
|
|
|
case GoalFn(Position) of |
|
|
|
|
|
true -> {ok, Distance}; |
|
|
|
|
|
false -> do_bfs1(Position, NeighborFn, GoalFn, Distance, Queue, Visited) |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
do_bfs1(Position, NeighborFn, GoalFn, Distance, Queue, Visited) -> |
|
|
|
|
|
WeightedNeighbors = lists:map(fun (Node) -> {Distance+1, Node} end, NeighborFn(Position)), |
|
|
|
|
|
UpdatedQueue = lists:foldl(fun priq:insert/2, Queue, WeightedNeighbors), |
|
|
|
|
|
do_bfs2(Position, NeighborFn, GoalFn, Distance, UpdatedQueue, Visited). |
|
|
|
|
|
|
|
|
|
|
|
do_bfs2(_Position, _NeighborFn, _GoalFn, _Distance, empty, _Visited) -> |
|
|
|
|
|
{error, no_path}; |
|
|
|
|
|
do_bfs2(Position, NeighborFn, GoalFn, _Distance, Queue, Visited) -> |
|
|
|
|
|
{ok, {NextDistance, NextPosition}} = priq:peek_min(Queue), |
|
|
|
|
|
{ok, NextQueue} = priq:delete_min(Queue), |
|
|
|
|
|
do_bfs0(NextPosition, NeighborFn, GoalFn, NextDistance, NextQueue, Visited#{Position => []}). |
|
|
|
|
|
|
|
|
%calculate_path(Goal, Closed) -> {Goal, Closed}. |
|
|
%calculate_path(Goal, Closed) -> {Goal, Closed}. |