AStar A* 算法的Erlang实现

来源:互联网 发布:朗文字典 for mac 编辑:程序博客网 时间:2024/06/04 18:47
%% @author rolong@vip.qq.com%% 本代码来自 瑞仙的Erlang开发博客%% http://blog.csdn.net/zhongruixian-module(astar1).-export([         find_path/2         ,test/2        ]).-record(state, {          open_trees %% 开启列表          ,close_sets %% 关闭列表          ,parents_trees %% 父节点列表          ,xy %% 目标点         }).-record(point, {          xy = {0, 0}          ,g = 0          ,h = 0          ,f = 0         }).%% 1为向上,按顺时针依次为1~8-define(DIRS, [1,2,3,4,5,6,7,8]).%%' APItest(XY1, XY2) ->    Path = find_path(XY1, XY2),    io:format("Path:~n~p~n", [Path]),    show_path(Path).find_path(XY1, XY2) ->    State = #state{               open_trees = gb_trees:empty()               ,close_sets = gb_sets:new()               ,xy = XY2               ,parents_trees = gb_trees:empty()              },    StartPoint = #point{xy = XY1},    OpenTrees = gb_trees:enter(XY1, {0, 0, 0}, State#state.open_trees),    State1 = State#state{open_trees = OpenTrees},    find_next_point(StartPoint, State1).%%.%%' priv-spec walkable({X, Y}) -> true | false when      X :: integer(),      Y :: integer().%%'walkable函数根据具体点阵实现%% 示例如下:walkable({X, Y}) ->    {Row, Col} = map(size),    case X >= 0 andalso Y >= 0 andalso X < Row andalso Y < Col of        true ->            Block = map(block),            Nth = X + Y * Row + 1,            case string:substr(Block, Nth, 1) of                "1" -> true;                "0" -> false            end;        false -> false    end;walkable(_) -> false.map(size) ->    {20, 10};map(block) ->    %01234567890123456789    "11111111111111111111" % 0    "11111111111111111111" % 1    "11111111111111111111" % 2    "11111111000111111111" % 3    "11111111000111111111" % 4    "11111111000111111111" % 5    "11111111000111111111" % 6    "11111111000111111111" % 7    "11111111000111111111" % 8    "11111111111111111111" % 9    .%%.find_next_point(#point{xy = XY}, #state{xy = XY} = State) ->    get_path(XY, State#state.parents_trees, [XY]);find_next_point(#point{xy = XY} = CurPoint, State) ->    State1 = open2close(CurPoint, State),    %% 将周围点添加到开放列表中    AroundPoints = find_around_points(CurPoint, State1),    State2 = add_open_trees(AroundPoints, XY, State1),    case find_min_f_point(State2) of        none ->            io:format("Error coord:~w~n", [CurPoint#point.xy]),            [];        NextPoint ->            find_next_point(NextPoint, State2)    end.find_min_f_point(State) ->    Iter = gb_trees:iterator(State#state.open_trees),    find_min_f_point(Iter, -1, none).find_min_f_point(Iter, F, Point) ->    case gb_trees:next(Iter) of        none -> Point;        {XY, {G1, H1, F1}, Iter1} ->            case F1 < F orelse F =:= -1 of                true ->                    Point1 = #point{                                xy = XY                                ,g = G1                                ,h = H1                                ,f = F1                               },                    find_min_f_point(Iter1, F1, Point1);                false ->                    find_min_f_point(Iter1, F, Point)            end    end.xy2point({CurX, CurY}, ParentPoint, {DstX, DstY}) ->    #point{       xy = {X, Y}       ,g = G      } = ParentPoint,    AddG = if               CurX =:= X -> 10;               CurY =:= Y -> 10;               true -> 14           end,    CurH = (erlang:abs(CurX - DstX) + erlang:abs(CurY - DstY)) * 10,    CurG = G + AddG,    #point{       xy = {CurX, CurY}       ,g = CurG       ,h = CurH       ,f = CurG + CurH      }.%% 找出周围点find_around_points(Point, State) ->    #state{       close_sets = CloseSets      } = State,    #point{       xy = {X, Y}      } = Point,    F = fun(Dir, Acc) ->                XY1 = get_next_coord(Dir, X, Y),                case walkable(XY1) of                    true ->                        case gb_sets:is_element(XY1, CloseSets) of                            true -> Acc;                            false ->                                Point1  = xy2point(XY1, Point, State#state.xy),                                [Point1 | Acc]                        end;                    false -> Acc                end        end,    lists:foldl(F, [], ?DIRS).add_open_trees([Point | Tail], ParentXY, State) ->    case gb_trees:lookup(Point#point.xy, State#state.open_trees) of        {_XY, {G, _H, _F}} ->            case Point#point.g < G of                true ->                    State1 = add_open_trees1(Point, ParentXY, State),                    add_open_trees(Tail, ParentXY, State1);                false ->                    add_open_trees(Tail, ParentXY, State)            end;        none ->            State1 = add_open_trees1(Point, ParentXY, State),            add_open_trees(Tail, ParentXY, State1)    end;add_open_trees([], _ParentXY, State) ->    State.add_open_trees1(Point, ParentXY, State) ->    #point{xy = XY, g = G, h = H, f = F} = Point,    OpenTrees1 = gb_trees:enter(XY, {G, H, F}, State#state.open_trees),    ParentsTrees1 = gb_trees:enter(XY, ParentXY, State#state.parents_trees),    State#state{      open_trees = OpenTrees1      ,parents_trees = ParentsTrees1     }.open2close(Point, State) ->    OpenTrees = gb_trees:delete(Point#point.xy, State#state.open_trees),    CloseSets = gb_sets:add(Point#point.xy, State#state.close_sets),    State#state{      open_trees = OpenTrees      ,close_sets = CloseSets     }.get_next_coord(1,X,Y)->{X,Y-1};get_next_coord(2,X,Y)->{X+1,Y-1};get_next_coord(3,X,Y)->{X+1,Y};get_next_coord(4,X,Y)->{X+1,Y+1};get_next_coord(5,X,Y)->{X,Y+1};get_next_coord(6,X,Y)->{X-1,Y+1};get_next_coord(7,X,Y)->{X-1,Y};get_next_coord(8,X,Y)->{X-1,Y-1}.get_path(XY, ParentsTrees, Acc) ->    case gb_trees:lookup(XY, ParentsTrees) of        none -> Acc;        {value, XY1} ->            get_path(XY1, ParentsTrees, [XY1 | Acc])    end.%%'用于测试打印show_path(XYs) ->    Block = map(block),    {Row, Col} = map(size),    Len = Row * Col,    show_path(XYs, Row, Col, Len, Block).show_path([{X, Y} | XYs], Row, Col, Len, Block) ->    LeftLen = X + Y * Row,    RightLen = Len - LeftLen - 1,    Left = string:left(Block, LeftLen),    Right = string:right(Block, RightLen),    Block1 = Left ++ "*" ++ Right,    show_path(XYs, Row, Col, Len, Block1);show_path([], Row, _Col, Len, Block) ->    show_path1(Row, Len, Block, "").show_path1(_Row, Len, _Block, Acc) when Len =< 0 ->    io:format("~n~s~n", [Acc]);show_path1(Row, Len, Block, Acc) ->    Len1 = Len - Row,    Left = string:left(Block, Row),    Block1 = string:right(Block, Len1),    Acc1 = Acc ++ Left ++ "\n",    show_path1(Row, Len1, Block1, Acc1).%%.%%.%%% vim: set foldmethod=marker filetype=erlang foldmarker=%%',%%.:


1 0
原创粉丝点击