A_Star算法

编程

摘录A*算法的erlang实现

  • 原作者出自:https://stevegilham.blogspot.com/2008/10/first-refactoring-of-star-in-erlang.html

-module(a_star).

-export([main/0]).

astar(Start,Goal) ->

Closedset = sets:new(), % The set of nodes already evaluated.

Openset = sets:add_element(Start,sets:new()), %The set of tentative nodes to be evaluated

Fscore = dict:append(Start, h_score(Start), dict:new()),

Gscore = dict:append(Start, 0, dict:new()), % Distance from start along optimal path.

CameFrom = dict:append(Start, none, dict:new()),

astar_step(Goal, Closedset, Openset, Fscore, Gscore, CameFrom).

astar_step(Goal, Closedset, Openset, Fscore, Gscore, CameFrom) ->

case sets:size(Openset) of

0 ->

failure;

_ ->

case best_step(sets:to_list(Openset), Fscore, none, infinity) of

Goal ->

reconstruct_path(CameFrom, Goal);

X ->

NextOpen = sets:del_element(X, Openset),

NextClosed = sets:add_element(X, Closedset),

Neighbours = neighbour_nodes(X),

{NewOpen, NewF, NewG, NewFrom} = scan(X, Neighbours, NextOpen, NextClosed, Fscore, Gscore, CameFrom),

astar_step(Goal, NextClosed, NewOpen, NewF, NewG, NewFrom)

end

end.

scan(_X, [], Open, _Closed, F, G, From) ->

{Open, F, G, From};

scan(X, [Y|N], Open, Closed, F, G, From) ->

case sets:is_element(Y, Closed) of

true ->

scan(X, N, Open, Closed, F, G, From);

false ->

[G0] = dict:fetch(X, G),

TrialG = G0 + dist_between(X,Y),

case sets:is_element(Y, Open) of

true ->

[OldG] = dict:fetch(Y, G),

case TrialG < OldG of

true ->

{NewF, NewG, NewFrom} = update(X, Y, F, G, From, TrialG),

scan(X, N, Open, Closed, NewF, NewG, NewFrom);

false ->

scan(X, N, Open, Closed, F, G, From)

end;

false ->

NewOpen = sets:add_element(Y, Open),

{NewF, NewG, NewFrom} = update(X, Y, F, G, From, TrialG),

scan(X, N, NewOpen, Closed, NewF, NewG, NewFrom)

end

end.

update(X, Y, OldF, OldG, OldFrom, GValue) ->

KeyF = dict:is_key(Y, OldF),

KeyG = dict:is_key(Y, OldG),

KeyFrom = dict:is_key(Y, OldFrom),

case {KeyF, KeyG, KeyFrom} of

{true, _, _} ->

update(X, Y, dict:erase(Y, OldF), OldG, OldFrom, GValue);

{_, true, _} ->

update(X, Y, OldF, dict:erase(Y, OldG), OldFrom, GValue);

{_, _, true} ->

update(X, Y, OldF, OldG, dict:erase(Y, OldFrom), GValue);

_ ->

NewFrom = dict:append(Y, X, OldFrom),

NewG = dict:append(Y, GValue, OldG),

NewF = dict:append(Y, GValue + h_score(Y), OldF), % Estimated total distance from start to goal through y.

{NewF, NewG, NewFrom}

end.

reconstruct_path(CameFrom, Node) ->

case dict:fetch(Node, CameFrom) of

[none] ->

[Node];

[Value] ->

[Node | reconstruct_path(CameFrom, Value)]

end.

best_step([H|Open], Score, none, _) ->

[V] = dict:fetch(H, Score),

best_step(Open, Score, H, V);

best_step([], _Score, Best, _BestValue) ->

Best;

best_step([H|Open], Score, Best, BestValue) ->

[Value] = dict:fetch(H, Score),

case Value < BestValue of

true ->

best_step(Open, Score, H, Value);

false ->

best_step(Open, Score, Best, BestValue)

end.

%% specialize for the torch-carrier problem

%% bits 0-4 represent torch, 1m, 2m, 5m, 10m

%% set bit = on the near side

%% Every possible crossing of one or two

swaps() ->

[3,5,9,17, 7, 11,13, 19,21,25].

crossing_time(Swap) ->

if

Swap band 16 > 0 ->

10;

Swap band 8 > 0 ->

5;

Swap band 4 > 0 ->

2;

true ->

1

end.

%% presentation form

display(Swap) ->

if

Swap band 16 > 0 ->

compound(Swap, 16);

Swap band 8 > 0 ->

compound(Swap, 8);

Swap band 4 > 0 ->

compound(Swap, 4);

Swap band 2 > 0 ->

compound(Swap, 2);

true ->

""

end.

compound(Swap, Bit) ->

string:concat( erlang:integer_to_list(crossing_time(Swap)),

decorate(display(Swap bxor Bit))).

decorate(Value) ->

case string:len(Value) of

0 ->

Value;

_ ->

string:concat("+", Value)

end.

neighbour_nodes(X) ->

Result = [],

compatible(X, equivalent_point(X), Result, swaps()).

equivalent_point(X) ->

case X band 1 of

1 ->

X;

0 ->

31 bxor X

end.

compatible(_X, _Y, Outlist, []) ->

Outlist;

compatible(X, Y, Outlist, [Swap|Inlist]) ->

case (Y band Swap) of

Swap ->

New = X bxor Swap,

compatible(X, Y, [New|Outlist], Inlist);

_ ->

compatible(X, Y, Outlist, Inlist)

end.

dist_between(X,Y) ->

Swap = X bxor Y,

crossing_time(Swap).

h_score(Node) ->

crossing_time(Node).

main() ->

[H|Trace] = lists:reverse(astar(31, 0)),

Time = print_result(Trace, H, 0),

io:format("Time taken = ~B minutes~n", [Time]) .

print_result([], _Prev, Time) ->

Time;

print_result([H|Trace], Prev, Time) ->

Swap = H bxor Prev,

print_swap(Swap, H band 1),

Interval = Time + crossing_time(Swap),

print_result(Trace, H, Interval).

print_swap(Swap, Side) ->

case Side of

0 ->

io:format( " ~s -->;~n", [display(Swap)]);

1 ->

io:format( "<-- ~s~n", [display(Swap)])

end.

以上是 A_Star算法 的全部内容, 来源链接: utcz.com/z/514786.html

回到顶部