Browse Source

rf: 代码整理

master
SisMaker 4 years ago
parent
commit
14f6d9a120
1 changed files with 465 additions and 0 deletions
  1. +465
    -0
      src/testCase/bStar.erl

+ 465
- 0
src/testCase/bStar.erl View File

@ -0,0 +1,465 @@
-module(bStar). %% B星寻路逻辑
-include("utComMisc.hrl").
-compile(export_all).
-export([
bstar_search/5
, test/0
, test/1 %% B星寻路
]).
%%
-define(cell_state_none, none).
-define(cell_state_balk, balk).
-define(cell_state_close, close).
-define(cell_state_open, open).
%%
-define(branch_dir_none, 0).
-define(branch_dir_left, 1).
-define(branch_dir_right, 2).
%% -define(branch_dir_count, 3).
-define(MAX_DIRECTION, 4). %%
-record(pos, {x, y}).
-record(cell, {
x = 0 %% X轴上的坐标,
, y = 0 %% Y轴上的坐标,
, s = ?cell_state_none %%
, g = 0 %%
%% ,h = 0 %%
, px = -1 %%
, py = -1 %%
, branch = ?branch_dir_none %%
, dir = -1 %%
, reel = 0 %%
, angle = 0
}).
-record(map_config, {
weight = 100
, height = 100
}).
-record(bstar_map, {
origin = #cell{}
, target = #cell{}
, map_config
, open_list = []
, cell_dict = dict:new()
}).
%% B星搜索
%% @spec() -> false | [#cell{}]
bstar_search(MapConfig, StartX, StartY, EndX, EndY) ->
FirstCell = #cell{x = StartX, y = StartY},
TarGet = #cell{x = EndX, y = EndY},
BStarMap2 = #bstar_map{origin = FirstCell, target = TarGet, map_config = MapConfig, open_list = [FirstCell]},
start_search(BStarMap2).
start_search(#bstar_map{open_list = []}) ->
false;
start_search(#bstar_map{open_list = [CurrentCell | Rest], target = Target} = BStarMap) ->
if
%%
CurrentCell#cell.branch =:= ?branch_dir_none ->
case find_next(CurrentCell, BStarMap) of
{Dir, NextCell, BStarMap2} ->
case NextCell#cell.x =:= Target#cell.x andalso NextCell#cell.y == Target#cell.y of
true -> %%
NextCell2 = NextCell#cell{px = CurrentCell#cell.x, py = CurrentCell#cell.y, g = CurrentCell#cell.g + 1},
NewBStarMap = save_cell(BStarMap2, NextCell2),
buildPath(NewBStarMap);
_ ->
%%
case search_free(CurrentCell, NextCell, Dir, BStarMap2) of
{true, OpenList, BStarMap3} ->
start_search(BStarMap3#bstar_map{open_list = Rest ++ OpenList});
{false, BStarMap3} ->
start_search(BStarMap3#bstar_map{open_list = Rest})
end
end;
_ ->
false
end;
true ->
%%
%% 沿
Dir = get_branchDir(CurrentCell#cell.branch, CurrentCell#cell.dir),
Dir2 = Dir + ?MAX_DIRECTION - 1,
Dir3 = ?IIF(Dir2 >= ?MAX_DIRECTION, Dir2 - ?MAX_DIRECTION, Dir2),
case get_branch(CurrentCell, CurrentCell#cell.branch, Dir3, BStarMap) of
{true, OpenCell, BStarMap2} ->
BStarMap3 = close_cell(BStarMap2, CurrentCell),
start_search(BStarMap3#bstar_map{open_list = Rest ++ [OpenCell]});
{find, BStarMap2} ->
buildPath(BStarMap2);
{false, BStarMap2} ->
BStarMap3 = close_cell(BStarMap2, CurrentCell),
start_search(BStarMap3#bstar_map{open_list = Rest})
end
end.
%% ,
search_free(CurrentCell, #cell{s = ?cell_state_none} = NextCell, _Dir, BStarMap) ->
NextCell2 = NextCell#cell{px = CurrentCell#cell.x, py = CurrentCell#cell.y, g = CurrentCell#cell.g + 1, s = ?cell_state_open},
BStarMap2 = save_cell(BStarMap, NextCell2),
BStarMap3 = close_cell(BStarMap2, CurrentCell),
{true, [NextCell2], BStarMap3};
%% ,
search_free(CurrentCell, #cell{s = ?cell_state_close}, _Dir, BStarMap) ->
BStarMap2 = close_cell(BStarMap, CurrentCell),
{false, BStarMap2};
%% ,
search_free(CurrentCell, #cell{s = ?cell_state_open}, _Dir, BStarMap) ->
BStarMap2 = close_cell(BStarMap, CurrentCell),
{false, BStarMap2};
%% ,
search_free(CurrentCell, NextCell, Dir, BStarMap) ->
{OpenedList, NewBStarMap} =
case get_left_right(CurrentCell, NextCell, ?branch_dir_left, Dir, BStarMap) of
{false, TempBStarMap} ->
{[], TempBStarMap};
{true, Left, TempBStarMap} ->
{[Left], TempBStarMap}
end,
{OpenedList2, NewBStarMap2} =
case get_left_right(CurrentCell, NextCell, ?branch_dir_right, Dir, NewBStarMap) of
{false, TempBStarMap2} ->
{OpenedList, TempBStarMap2};
{true, Right, TempBStarMap2} ->
{[Right | OpenedList], TempBStarMap2}
end,
NewBStarMap3 = close_cell(NewBStarMap2, CurrentCell),
{true, OpenedList2, NewBStarMap3}.
%%
get_left_right(CurrentCell, NextCell, BranchDir, Dir, #bstar_map{origin = Origin} = BStarMap) ->
TestDir = get_branchDir(BranchDir, Dir),
case get_branchAround(CurrentCell, BranchDir, TestDir + 1, BStarMap) of
false ->
{false, BStarMap};
{Cell, TestDir2, Count} ->
Cell2 = Cell#cell{branch = BranchDir, dir = branchAround(BranchDir, TestDir2)},
case get_left_right2(CurrentCell, Cell2, BranchDir) of
false ->
{false, BStarMap};
Cell3 ->
Angle = g_GetDirAngle(Origin#cell.x, Origin#cell.y, Cell2#cell.x, Cell2#cell.y, NextCell#cell.x, NextCell#cell.y),
Angle2 = case BranchDir of
?branch_dir_left ->
?IIF(Angle > 32, 64 - Angle, 0 - Angle);
_ ->
?IIF(Angle > 32, Angle - 64, Angle)
end,
Cell4 = Cell3#cell{reel = Count + 1, s = ?cell_state_open, angle = Angle2},
BStarMap2 = save_cell(BStarMap, Cell4),
{true, Cell4, BStarMap2}
end
end.
%%
get_left_right2(CurrentCell, #cell{s = ?cell_state_none} = NextCell, _BranchDir) ->
NextCell#cell{
px = CurrentCell#cell.x
, py = CurrentCell#cell.y
, g = CurrentCell#cell.g + 1
};
get_left_right2(CurrentCell, #cell{s = ?cell_state_close} = NextCell, BranchDir) ->
BranchDir2 = contrary_branch_dir(BranchDir),
if
NextCell#cell.branch =:= BranchDir2 andalso NextCell#cell.x == CurrentCell#cell.px andalso NextCell#cell.y =:= CurrentCell#cell.py ->
false;
NextCell#cell.g > CurrentCell#cell.g + 1 ->
NextCell#cell{
px = CurrentCell#cell.x
, py = CurrentCell#cell.y
, g = CurrentCell#cell.g + 1
};
true ->
NextCell
end;
get_left_right2(CurrentCell, #cell{s = ?cell_state_open} = NextCell, _BranchDir) ->
case NextCell#cell.g > CurrentCell#cell.g + 1 of
true ->
NextCell#cell{
px = CurrentCell#cell.x
, py = CurrentCell#cell.y
, g = CurrentCell#cell.g + 1
};
_ ->
NextCell
end;
get_left_right2(_CurrentCell, NextCell, _BranchDir) ->
NextCell.
%%
get_branch(CurrentCell, BranchDir, Dir, BStarMap) ->
get_branch([0, 1, 2, 3], CurrentCell, BranchDir, Dir, BStarMap).
get_branch([], _CurrentCell, _BranchDir, _Dir, BStarMap) ->
{false, BStarMap};
get_branch([Count | Rest], CurrentCell, BranchDir, Dir, #bstar_map{target = Target, map_config = #map_config{weight = Weight, height = Height}} = BStarMap) ->
Dir2 = ?IIF(Dir >= ?MAX_DIRECTION, Dir - ?MAX_DIRECTION, Dir),
NextDir = branchAround(BranchDir, Dir2),
Around = around(NextDir),
NextX = CurrentCell#cell.x + Around#pos.x,
NextY = CurrentCell#cell.y + Around#pos.y,
case NextY < 0 orelse NextY >= Height orelse NextX < 0 orelse NextX >= Weight of
true ->
{false, BStarMap};
_ ->
NextCell = get_cell(BStarMap, NextX, NextY),
if
NextCell#cell.s /= ?cell_state_balk -> %%
case NextCell#cell.x =:= Target#cell.x andalso NextCell#cell.y =:= Target#cell.y of %%
true ->
NextCell2 = NextCell#cell{px = CurrentCell#cell.x, py = CurrentCell#cell.y, g = CurrentCell#cell.g + 1},
BStarMap2 = save_cell(BStarMap, NextCell2),
{find, BStarMap2};
false ->
get_branch2(CurrentCell, NextCell, BranchDir, NextDir, Count, BStarMap)
end;
true -> %%
get_branch(Rest, CurrentCell, BranchDir, Dir + 1, BStarMap)
end
end.
%%
get_branch2(CurrentCell, #cell{s = ?cell_state_none} = NextCell, BranchDir, NextDir, Count, BStarMap) ->
NextCell2 = NextCell#cell{
px = CurrentCell#cell.x
, py = CurrentCell#cell.y
, g = CurrentCell#cell.g + 1
},
NextCell3 = get_branch_i(CurrentCell, NextCell2, BranchDir, NextDir, Count, BStarMap),
{true, NextCell3, save_cell(BStarMap, NextCell3)};
get_branch2(CurrentCell, #cell{s = ?cell_state_close} = NextCell, BranchDir, NextDir, Count, BStarMap) ->
BranchDir2 = contrary_branch_dir(BranchDir),
if
NextCell#cell.branch =:= BranchDir2 andalso NextCell#cell.x =:= CurrentCell#cell.px andalso NextCell#cell.y =:= CurrentCell#cell.py andalso NextCell#cell.dir /= NextDir ->
{false, BStarMap};
NextCell#cell.branch =:= BranchDir andalso NextCell#cell.dir == NextDir ->
{false, BStarMap};
NextCell#cell.branch =:= ?branch_dir_none andalso NextCell#cell.g > CurrentCell#cell.g ->
{false, BStarMap};
NextCell#cell.g > CurrentCell#cell.g + 1 ->
NextCell2 = NextCell#cell{px = CurrentCell#cell.x, py = CurrentCell#cell.y, g = CurrentCell#cell.g + 1},
NextCell3 = get_branch_i(CurrentCell, NextCell2, BranchDir, NextDir, Count, BStarMap),
{true, NextCell3, save_cell(BStarMap, NextCell3)};
true ->
NextCell3 = get_branch_i(CurrentCell, NextCell, BranchDir, NextDir, Count, BStarMap),
{true, NextCell3, save_cell(BStarMap, NextCell3)}
end;
get_branch2(CurrentCell, #cell{s = ?cell_state_open} = NextCell, BranchDir, NextDir, Count, BStarMap) ->
if
NextCell#cell.branch == BranchDir andalso NextCell#cell.dir == NextDir ->
{false, BStarMap};
NextCell#cell.g > CurrentCell#cell.g + 1 ->
NextCell2 = NextCell#cell{
px = CurrentCell#cell.x
, py = CurrentCell#cell.y
, g = CurrentCell#cell.g + 1
},
NextCell3 = get_branch_i(CurrentCell, NextCell2, BranchDir, NextDir, Count, BStarMap),
{true, NextCell3, save_cell(BStarMap, NextCell3)};
true ->
NextCell3 = get_branch_i(CurrentCell, NextCell, BranchDir, NextDir, Count, BStarMap),
{true, NextCell3, save_cell(BStarMap, NextCell3)}
end;
get_branch2(_CurrentCell, _NextCell, _BranchDir, _NextDir, _Count, BStarMap) ->
{false, BStarMap}.
%%% ************************************************** **************************************************
%%
get_branch_i(CurrentCell, NextCell, BranchDir, NextDir, Count, #bstar_map{origin = Origin} = _BStarMap) ->
Reel = CurrentCell#cell.reel + Count - 1,
Reel2 = ?IIF(Reel < 0, 0, Reel),
Angle = g_GetDirAngle(Origin#cell.x, Origin#cell.y, NextCell#cell.x, NextCell#cell.y, CurrentCell#cell.x, CurrentCell#cell.y),
Angle2 = case BranchDir of
?branch_dir_left -> ?IIF(Angle > 32, 64 - Angle, 0 - Angle);
_ -> ?IIF(Angle > 32, Angle - 64, Angle)
end,
Angle3 = CurrentCell#cell.angle + Angle2,
{Angle4, Reel3} = ?IIF(Angle3 >= 64, {Angle3 - 64, Reel2 - 4}, {Angle3, Reel2}),
NextCell2 = NextCell#cell{reel = Reel3, s = ?cell_state_open, angle = Angle4},
?IIF(NextCell2#cell.reel > 0, NextCell2#cell{branch = BranchDir, dir = NextDir}, NextCell2#cell{branch = ?branch_dir_none, dir = -1, angle = 0}).
%%
find_next(CurrentCell, BStarMap) ->
find_next([0, 1, 2, 3], CurrentCell, BStarMap).
find_next([], _CurrentCell, _BStarMap) ->
?PRINT("find_next:err:~w", [_CurrentCell]),
ok;
find_next([Dir | Rest], CurrentCell, #bstar_map{target = Target, map_config = #map_config{weight = Weight, height = Height}} = BStarMap) ->
Around = around(Dir),
NextX = CurrentCell#cell.x + Around#pos.x,
NextY = CurrentCell#cell.y + Around#pos.y,
case NextY < 0 orelse NextY >= Height orelse NextX < 0 orelse NextX >= Weight of
true ->
NewBStarMap = save_cell(BStarMap, CurrentCell#cell{s = ?cell_state_close}),
find_next(Rest, CurrentCell, NewBStarMap);
_ ->
DirDiff = g_GetDirDiff(CurrentCell#cell.x, CurrentCell#cell.y, Target#cell.x, Target#cell.y, NextX, NextY),
case DirDiff =< 8 of
true ->
NextCell = get_cell(BStarMap, NextX, NextY),
{Dir, NextCell, BStarMap};
_ ->
find_next(Rest, CurrentCell, BStarMap)
end
end.
%%
get_cell(#bstar_map{cell_dict = Dict, map_config = MapConfig}, X, Y) ->
case dict:find({X, Y}, Dict) of
{ok, O} -> O;
_ ->
CellState = ?IIF(lib_map:is_walkable_by_index(MapConfig, X, Y), ?cell_state_none, ?cell_state_balk),
#cell{x = X, y = Y, s = CellState}
end.
%%
save_cell(#bstar_map{cell_dict = Dict} = BStarMap, #cell{x = X, y = Y} = Cell) ->
NewDict = dict:store({X, Y}, Cell, Dict),
BStarMap#bstar_map{cell_dict = NewDict}.
%%
close_cell(BStarMap, Cell) ->
Cell2 = get_cell(BStarMap, Cell#cell.x, Cell#cell.y),
save_cell(BStarMap, Cell2#cell{s = ?cell_state_close}).
%%
around(0) -> #pos{x = 0, y = 1};
around(1) -> #pos{x = -1, y = 0};
around(2) -> #pos{x = 0, y = -1};
around(3) -> #pos{x = 1, y = 0}.
%%
g_GetDirDiff(OriginX, OriginY, TargetX, TargetY, X, Y) ->
TargetDir = g_GetDirIndex(OriginX, OriginY, TargetX, TargetY),
TestDir = g_GetDirIndex(OriginX, OriginY, X, Y),
DirDiff = TargetDir - TestDir,
DirDiff2 = ?IIF(DirDiff < 0, DirDiff + 64, DirDiff),
?IIF(DirDiff2 > 32, 64 - DirDiff2, DirDiff2).
%%
g_GetDirAngle(OriginX, OriginY, TargetX, TargetY, X, Y) ->
TargetDir = g_GetDirIndex(OriginX, OriginY, TargetX, TargetY),
TestDir = g_GetDirIndex(OriginX, OriginY, X, Y),
DirAngle = TargetDir - TestDir,
case DirAngle < 0 of
true -> DirAngle + 64;
_ -> DirAngle
end.
%% 36064
g_GetDirIndex(X1, Y1, X2, Y2) when X1 =:= X2 andalso Y1 =:= Y2 -> -1;
g_GetDirIndex(X1, Y1, X2, Y2) when X1 =:= X2 andalso Y2 > Y1 -> 0;
g_GetDirIndex(X1, Y1, X2, Y2) when X1 =:= X2 andalso Y2 < Y1 -> 32;
g_GetDirIndex(X1, Y1, X2, Y2) when Y1 =:= Y2 andalso X2 > X1 -> 48;
g_GetDirIndex(X1, Y1, X2, Y2) when Y1 =:= Y2 andalso X2 < X1 -> 16;
g_GetDirIndex(X1, Y1, X2, Y2) ->
X = X2 - X1,
Y = Y2 - Y1,
Distance = math:sqrt(X * X + Y * Y),
Sin = Y / Distance,
Radian = math:asin(Sin),
Angle = 180 / (math:pi() / Radian),
Angle2 = if
X > 0 andalso Y > 0 ->
Angle;
X > 0 andalso Y < 0 ->
360 + Angle;
X < 0 andalso Y < 0 ->
180 + Angle;
true ->
180 + Angle
end,
(48 + round(Angle2 * 64 / 360)) rem 64.
branchAround(0, 0) -> 0;
branchAround(0, 1) -> 1;
branchAround(0, 2) -> 2;
branchAround(0, 3) -> 3;
branchAround(1, 0) -> 0;
branchAround(1, 1) -> 3;
branchAround(1, 2) -> 2;
branchAround(1, 3) -> 1;
branchAround(2, 0) -> 0;
branchAround(2, 1) -> 1;
branchAround(2, 2) -> 2;
branchAround(2, 3) -> 3.
%%
buildPath(#bstar_map{origin = Origin, target = Target} = BStarMap) ->
Current = get_cell(BStarMap, Target#cell.x, Target#cell.y),
buildPath(Current, Origin, [], BStarMap).
buildPath(Current, Origin, Res, BStarMap) ->
if
Current#cell.x =:= Origin#cell.x andalso Current#cell.y =:= Origin#cell.y ->
Res;
true ->
NewCurrent = get_cell(BStarMap, Current#cell.px, Current#cell.py),
buildPath(NewCurrent, Origin, [Current | Res], BStarMap)
end.
%%
contrary_branch_dir(?branch_dir_left) ->
?branch_dir_right;
contrary_branch_dir(_) ->
?branch_dir_left.
%% Dir
get_branchDir(Branch, CurDir) ->
get_branchDir([0, 1, 2, 3], Branch, CurDir).
get_branchDir([], _, _CurDir) ->
throw({badarg, get_branchAround});
get_branchDir([Dir | Rest], Branch, CurDir) ->
case branchAround(Branch, Dir) == CurDir of
true -> Dir;
_ -> get_branchDir(Rest, Branch, CurDir)
end.
%% Around
get_branchAround(CurrentCell, Branch, TestDir, BStarMap) ->
get_branchAround([0, 1, 2, 3], CurrentCell, Branch, TestDir, BStarMap).
get_branchAround([], _CurrentCell, _Branch, _TestDir, _BStarMap) ->
false;
get_branchAround([Count | Rest], CurrentCell, Branch, TestDir, #bstar_map{map_config = #map_config{weight = Weight, height = Height}} = BStarMap) ->
TestDir2 = ?IIF(TestDir =:= ?MAX_DIRECTION, 0, TestDir),
BranchAround = branchAround(Branch, TestDir2),
Around = around(BranchAround),
NextX = CurrentCell#cell.x + Around#pos.x,
NextY = CurrentCell#cell.y + Around#pos.y,
if
NextX < 0 orelse NextX >= Weight orelse NextY < 0 orelse NextY >= Height ->
false;
true ->
NextCell = get_cell(BStarMap, NextX, NextY),
if
NextCell#cell.s /= ?cell_state_balk ->
{NextCell, TestDir2, Count};
true ->
get_branchAround(Rest, CurrentCell, Branch, TestDir2 + 1, BStarMap)
end
end.
%% ******************************* **************************************
test() ->
MapConfig = lib_map:get_map_config(1000001),
bstar_search(MapConfig, 28, 44, 132, 44).
test(Max) ->
MapConfig = lib_map:get_map_config(1000001),
test(MapConfig, Max, 28, 44, 132, 44).
test(MapConfig, Max, X1, Y1, X2, Y2) ->
List = lists:seq(1, Max),
statistics(wall_clock),
[bstar_search(MapConfig, X1, Y1, X2, Y2) || _ <- List],
{_, Time} = statistics(wall_clock),
io:format("t=~p ", [Time]).
is_walkable_by_index(MapConfig, X, Y) ->
true.

Loading…
Cancel
Save