A * lua implementation of the pathfinding algorithm and lua
I haven't written a blog for a long time, and I feel a little decadent. Recently I have known many of my peers, and I just graduated from college. I think they are very good and realize the gap between myself and them, it is a bit inferior. There are also some reasons for not writing a blog, of course, because of work, there is a little lack of experience, but also to take on the pressure of a project, the original National Day back to the need to improve this pathsearching function, as a result, when I first went to my girlfriend's house, I didn't touch my computer. The first night I went back to Shanghai was full of my thoughts. I couldn't sleep in bed at AM, this month, with the development of the project, the pressure is getting bigger and bigger. During the working period, I woke up and couldn't sleep, hoping to survive this period of adaptation. As for path searching, I encountered an interview A few months ago. The interviewer asked me to write this algorithm on the computer. Since I have not read A * before, I just had this concept, therefore, you can only write it on your own. Finally, I took the initiative to tell the interviewer that the name can be implemented using the * algorithm. Finally, my persistence impressed the interviewer. Today, I encountered the same problem, which made me struggle for a day or two. I wrote my learning experience again.
I. Problem Overview: The game has two sides: the enemy and the enemy, and there are 40 squares. When it is our turn to the military commanders, we must first display the position where our military commanders can act, this involves determining the power of our military commanders and budget the path in advance. Here, we also need to consider the blocking of the enemy and landmarks (such as bombs and momentum), the consumption of special squares on the power of the armed forces, and the blocking rules between the enemy. When I encountered this problem, I asked the boss what path finding algorithm he used. He recommended Dijstra algorithm, but after reading it, I felt that it was not very suitable for my needs. First: I think the Dijstra algorithm is the best path choice for directed graphs, and the path length between nodes must be known first. However, if I want to set up forty squares in pairs, it will be a little complicated and will move with the change of martial arts, the map changes from time to time, making it more complex. Second, the Distra algorithm is not blocked. Of course, you can record several paths and then block the optimal path. I feel a little complicated. However, my first suggestion should be that the * algorithm is very close, and then consult the boss. The boss said that the distance between A * squares must be equal or else it is complicated. Then I would like to consult other experienced colleagues in the company. Of course, I have a different saying: What is the depth and breadth of traversal? I don't feel a definite saying. I had A hard time deciding on my choice for A day and did not dare to choose it easily. If I had to worry A little about it, I might have to work for A few days, but I still insisted on my own ideas to use. Ii. About *
A * general formula F = G + HG: it indicates the moving cost of moving from start A to the specified square on the grid (I didn't consider moving in the oblique direction here ), it can also be understood as the weight H of the node: it indicates the estimated cost of moving from the square to the end of B. Here, it is generally used to calculate the distance * coefficient 3. pathfinding Idea 1. start from start A and add it to "enable list" 2. find the four points around which point A can reach. The points that are reachable here refer to the nodes in the list that are not blocked and no longer closed, and add them to the open list, and set their parent node as A3. Delete Vertex a from the Enable list and add it to the close list. Closing the list is the checkpoint node that does not need to be detected. 4. check all the squares that are adjacent to each other. If these squares are not enabled, add them to the Enable list, calculate the GHF value of these squares, and set its parent node 5. if a neighboring square D is already in the "enable list", check whether the G value is lower if a new path (that is, path passing through C) is used to reach it, if the new G value is lower, change its "parent square" to the currently selected Square C and re-calculate it. Its F value and G value (H value does not need to be recalculated, because H value remains unchanged for each square ). if the new G value is relatively high, it means that it is not a wise choice to reach D after C, because it requires a further path. At this time, we will not do anything. when the checklist is enabled, the path is found. For detailed illustration, refer to the explanation provided by other netizens. I will not elaborate on it here. Iv. Path Retrieval
When we find the last vertex, we find its parent node layer by layer and iterate until the end is not empty. 5. Data Structure Point class
Module ('point', package. seeall) -- require ("script/battle/BattleCommon") -- calculate the F value function CalcF (point) point. F = point. G + point. henderson function create (posId) local point = {} point. parentPoint = {} point. step = 1 -- used to calculate the h value local x, y = BattleCommon. convertPosIdToCoord (posId) point. F = 0point. G = 0point. H = 0point. X = y -- point. the value range is [1, 5] point. Y = x -- point. the value range of Y is [1, 8] point. posId = posIdpoint. calcF = CalcFreturn pointendreturn PointMaze Structure
-- Create a terrain function create (tb) local maze = {} maze based on a table. step = 1 -- the basic distance between the grid and the grid, used to calculate the H value maze. mazeArray = tbmaze. openList = TabledArray. create () -- enable the list maze. closeList = TabledArray. create () -- close the list maze. findPath = findPathreturn mazeend
Vi. Main Code
Module ('maze', package. seeall) require ("script/battle/TabledArray") require ("script/battle/BattleCommon") require ("script/battle/Point ") -- function getMinPoint (pointsList) local minPoint = pointsList. tbl [1] for I = 1, pointsList: getSize () doif minPoint. f> pointsList. tbl [I]. F thenminPoint = pointsList. tbl [I] endendreturn minPointend -- check whether there is a blocking. If not, it is truefunction checkBlock (maze, x, y, roleFl Ag) -- x range [1, 5] y range [1, 8] if roleFlag = BattleCommon. BATTLE_GROUP_ALLIES then -- our camp if maze. mazeArray [x] [y] [1] = 0 or maze. mazeArray [x] [y] [1] = 1 thenreturn true -- no elsereturn blocking false endelseif roleFlag = BattleCommon. BATTLE_GROUP_ENEMY thenif maze. mazeArray [x] [y] [1] = 0 or maze. mazeArray [x] [y] [1] = 2 thenreturn true -- The elsereturn is not blocked; false endendend -- whether the vertex function existsXY (list, x, y) of x and y in the list) If list: getSize ()> 0 thenfor I, point in pairs (list. tbl) doif point. X = x and point. Y = y thenreturn trueendendreturn falseend -- whether the list contains a vertex function existsPoint (list, point) for I, p in pairs (list. tbl) doif (p. X = point. x) and (p. Y = point. y) thenreturn trueendreturn falseend -- function canReach (maze, startPoint, x, y, roleFlag) if (not checkBlock (maze, x, y, roleFlag )) or existsXY (maze. c LoseList, x, y) then -- close the point in the list or block return falseelseif (math. abs (x-startPoint.X) + math. abs (y-startPoint.Y) = 1) thenreturn trueendendend -- get the adjacent vertex function getSurroundPoints (maze, point, roleFlag) local surroundPoints = TabledArray. create () for I = point. x-1, point. X + 1 dofor j = point. y-1, point. Y + 1 doif I> 0 and I <6 and j> 0 and j <9 then -- exclude cousin if BattleCommon. distanceFromTo (point. posId, Ba TtleCommon. convertToPositionId (J-1, I-1) <2 thenif canReach (maze, point, I, j, roleFlag) thensurroundPoints: append (maze. mazeArray [I] [j] [2]) endendendendendreturn surroundPoints -- return the end of the set of point -- calculate the G value function CalcG (point) local G = point. glocal parentG = 0if point. parentPoint thenparentG = point. parentPoint. gendreturn G + parentGendfunction foundPoint (tempStart, point) local G = CalcG (point) if G <Point. G thenpoint. parentPoint = tempStartpoint. G = Gpoint: CalcF () endendfunction notFoundPoint (maze, tempStart, point) point. parentPoint = tempStartpoint. G = CalcG (point) point: CalcF () maze. openList: append (point) endfunction getPoint (list, data) for I, point in pairs (list. tbl) doif point. posId = data. posId thenreturn pointendendreturn nilend -- find the path (start path) local function findPath (maze, startPoint, endPoi Nt, roleFlag) maze. openList: append (startPoint) while maze. openList: getSize ()~ = 0 do -- find the minimum value of F: local tempStart = getMinPoint (maze. openList) maze. openList: removeById (1) maze. closeList: append (tempStart) -- finds its adjacent points: local surroundPoints = getSurroundPoints (maze, tempStart, roleFlag) for I, point in pairs (surroundPoints. tbl) doif existsPoint (maze. openList, point) then -- calculate the G value. If it is larger than the original value, nothing will be done. Otherwise, set its parent node to the current node and update G and FfoundPoint (tempStart, point) else -- if they do not start the list, add it, set the parent node, and calculate the GHFnotFoundPoint (maze, tempStart, point) endend. if the last one exists, if getPoint (maze. openList, endPoint) thenreturn getPoint (maze. openList, endPoint) endendreturn getPoint (maze. openList, endPoint) end -- create a terrain function create (tb) local maze = {} maze based on a table. step = 1 -- the basic distance between the grid and the grid, used to calculate the H value maze. mazeArray = tbmaze. openList = TabledArray. create () -- enable the list maze. closeList = TabledArray. create () -- close the list maze. findPath = findPathreturn mazeendreturn Maze
Call Method
Function printPath (presentPoint) local pathArray = TabledArray. create () while presentPoint dopathArray: preppend (presentPoint. posId) presentPoint = presentPoint. parentPointendlocal startPoint = pathArray: get (2) local endPoint = pathArray: getLast () cclog (startPoint) cclog (endPoint) cclog ("from ".. startPoint .. "".. endPoint .. "Path:") for I, p in pairs (pathArray. tbl) docclog (p) endend
local array = battleBoard:createBoxPoints(cRole:getFlag(),40)local maze = Maze.create(array)local startPoint = Point.create(cRole:getPositionId())local endPoint = Point.create(40)local presentPoint = maze:findPath(startPoint,endPoint,cRole:getFlag())printPath(presentPoint)
VII. Running Effect
The mobile phone test results are still acceptable. It seems that using A * on A square with A size of 255*255 still will not have A significant impact on efficiency. If you need to contact us, please feel free to contact us.
A * pathfinding Algorithm
A * Algorithm
?? Heuristic Search
-Three functions are involved in the search.
?? G (n) = consumption from initial node to node n
?? H (n) = evaluate the consumption from node n to the target node, and inspire the Function
?? F (n) = g (n) + h (n) optimal evaluation from the start point to the target point
-Each time, the node with the minimum f (n) value is selected as the next node,
Until the destination node is reached
-The success of A * algorithm depends largely on the construction of the h (n) function.
?? Open list and Closed list are widely used in various games.
-Open list
?? Contains nodes that we have not processed
?? We put the Start Node in the Open list at first.
-Closed list
?? Contains the nodes we have processed
?? When the algorithm is started, the Closed list is empty. A * algorithm pseudo code initializes the OPEN list.
Initialize the CLOSED list
Create a destination node called node_goal
Create the Start Node. It is called node_start.
Add node_start to the OPEN list
While OPEN list is not empty {
Retrieve the node n with the lowest f (n) value from the OPEN list
Add node n to the CLOSED list
If node n is equal to node_goal, we find the path, and the program returns n
Else generates each subsequent node n of node n'
Foreach node n's successor node n '{
Set the parent node of n to n.
Calculate the value of the heuristic evaluation function h (n') and evaluate the cost from n' to node_goal.
Computing g (n') = g (n) + overhead from n' to n
Calculate f (n') = g (n') + h (n ')
If n' is located in the OPEN or CLOSED list and the existing f (n) is better than then discards n', processing the subsequent N'
Delete node n' from OPEN and CLOSED
Add node n' to OPEN list
}
}
Return failure (we have searched all the nodes, but still cannot find a path)
To use C ++ to implement the * path search algorithm code, you must encapsulate it into A function. The function prototype is Cpoint * CGetPath (Cpoint start, Cpoint end
Short Circuit with ring K
Const int maxn = 1001; // maximum number of nodes
Const int inf = 1 <20;
Struct node // a star node
{
Int v;
Int len;
Bool operator <(const node a) const
{
Return len> a. len;
}
};
Struct point // graph Node
{
Int v, w;
};
Vector <point> g [maxn], reg [maxn]; // g indicates the source image adjacent table, and reg indicates the reverse graph critical table.
Int dis [maxn], visit [maxn], out [maxn], n, m, s, t, K;
Void init ()
{
For (int I = 1; I <= n; I ++)
{
G [I]. clear (); reg [I]. clear ();
}
}
Void dij ()
{
Memset (visit, 0, sizeof (visit ));
For (int I = 1; I <= n; I ++)
Dis [I] = inf;
Dis [t] = 0;
While (1)
{
Int temp = inf;
Int p =-1;
For (int I = 1; I <= n; I ++)
If (! Visit [I] & dis [I] <temp)
{
Temp = dis [I];
P = I;
}
If (p =-1)
Break;
Visit [p] = 1;
For (int I = 0; I <reg [p]. size (); I ++)
If (! Visit [reg [p] [I]. v] & dis [reg [p] [I]. v]> dis [p] + reg [p] [I]. w)
Dis [reg [p] [I]. v] = dis [p] + reg [p] [I]. w;
}
}
Int astar ()
{
Dij ();
Memset (out, 0, sizeof (out); // records the number of times the node sends out the queue. The value of out [t] is the I short circuit mark.
Priority_queue <node> q;
Node temp;
Temp. v = s; temp. len = dis [s];
Q. push (temp );
While (! Q. empty () & out [t] <K)
{
Temp = q. top ();
Q. pop ();
If (out [temp. v]> = K) continue;
Out [temp. v] ++;
If (out [t] = K & temp. v = t)
Return temp. len;
For (int I = 0; I <g [temp. v]. size (); I ++ ...... the remaining full text>