Implementation of Cocos2d-x map walking 3: A * Algorithm

Source: Internet
Author: User

Implementation of Cocos2d-x map walking 3: A * Algorithm

 

1. Modify the Dijkstra implementation.


Review previous Dijkstra implementations. Dijkstra needs to select a vertex with the minimum path cost from a table Q. Our previous implementation was to put all vertices in this table Q at the beginning. After careful consideration, we will find that those vertices whose values are initialized to the maximum path cost, 0x0FFFFFFF, cannot be selected and do not need to be traversed for these vertices. The vertex with the smallest cost of the path retrieved from the table. If you retrieve one, the shortest path from the starting point is found to the vertex. These vertices do not need to be put back in the list.

 

We can make such a small Optimization for Dijkstra. Although it is still O (N ^ 2), the time complexity has not changed:

At the beginning, only the starting vertex is placed in the table.

If the relaxation succeeds, the vertex pointing to the Edge End is placed in the table.

 

In this case, Relax will return the result.

  

The implementation code is as follows:

 

Void Dijkstra: Execute (const Graph & Graph, const string & VetexId) {m_Ret.PathTree.clear (); const auto & Vertexes = Graph. getVertexes (); Vertex * pVertexStart = Vertexes. find (VetexId)-> second; vector <Vertex *> Q; // initialize the Vertex for (auto & it: Vertexes) {it. second-> PathfindingData. cost = 0x0FFFFFFF; pVertexStart-> PathfindingData. pParent = 0;} // initialize the start vertex pVertexStart-> PathfindingData. cost = 0; pVert ExStart-> PathfindingData. pParent = 0; // Add the starting vertex to the list q. push_back (pVertexStart); pVertexStart-> PathfindingData. flag = true; for (; Q. size ()> 0;) {// select the vertex auto v = ExtractMin (Q) for the minimum path estimation; v-> PathfindingData. flag = false; // "relax" const auto & EO = v-> GetEdgesOut (); for (auto & it: EO) {Edge * pEdge = it. second; Vertex * pVEnd = pEdge-> GetEndVertex (); bool bRet = Relax (v, pVEnd, pEdge -> GetWeight (); // If the relaxation succeeds, add it to the list. If (bRet & pVEnd-> PathfindingData. flag = false) {Q. push_back (pVEnd); pVEnd-> PathfindingData. flag = true ;}// end for} // end}

 

Dijkstra is smarter than BFS. BFS just "blindly" extracts elements from the queue for extension. Dijkstra knows that node extension should be selected with the lowest path cost each time.


2. A * Algorithm
Dijkstra is smarter than BFS, while A * is smarter and faster than Dijkstra. A * improve the extension rules by calling A heuristic function. It tries its best to avoid extending other useless vertices. Its goal is to go straight to the destination. In this case, it seems that A * has long eyes and can see how far the current position is from the target point. The biggest difference between A * And Dijkstra is that they have "Eyes": heuristic functions.

The heuristic function will tell A * which vertex should be extended first. What is a heuristic function? Formula: F = G + H. Simply put, the path cost of the current vertex (G) + the estimated cost of the current vertex from the target vertex (F)

Previously, Dijkstra was modified and optimized to make it more like the * algorithm. Here, we change the heuristic data of Dijkstra from the vertex with the minimum path cost to the vertex with the minimum F value (the value of the heuristic function) to *. How to Design the valuation function H? Here, we can take the distance from the vertex to the target vertex.

We need to make the following changes to the Dijkstra and data structure:

1. Add a Heuristic field to the data structure of the vertex class. This field is used by the * algorithm to save the value calculated by the heuristic function. As follows:

 

Class Vertex {//... omitting some irrelevant functions and fields // The precursor Vertex of the data struct Pathfinding {// required by the public: // Pathfinding algorithm as before. Vertex * pParent; // path Cost estimation int Cost; // identifier int Flag; // The value calculated by the Heuristic function int Heuristic; Pathfinding () {pParent = 0; cost = 0; Flag = 0; Heuristic = 0;} PathfindingData ;}

 

2. Change Dijkstra's Relax relaxation function to limit the value of heuristic function F. If the calculated F value is smaller than the original F value of the vertex, the parent node, actual path cost, and F value of the vertex will be updated.

3. Each cycle determines whether the vertex with the minimum F value is the target vertex. If the target vertex is located, the path is found and the algorithm ends.

Like Dijkstra, the * algorithm finds the vertex with the minimum F value from the list and will no longer go to the list.

The following is my implemented A * algorithm.

AStar. h

 

 

# Pragma once # include GraphPathfinding. h # include
 
  
Class AStar: public GraphPathfinding {public: AStar ();~ AStar (); public: // estimate the cost of the vertex to the target vertex std: function
  
   
Estimate; public: virtual void Execute (const Graph & Graph, const string & VetexId) override; private: // extract the Vertex inline Vertex * ExtractMin (vector <Vertex *> & Q) for minimum path valuation; // Relax inline bool Relax (Vertex * v1, Vertex * v2, int Weight); public: void SetTarget (Vertex * pVTarget) {m_pVTarget = pVTarget;} private: Vertex * m_pVTarget ;};
  
 

 

 

AStar. cpp

 

 

# Include AStar. hAStar: AStar () {} AStar ::~ AStar () {} void AStar: Execute (const Graph & Graph, const string & VetexId) {const auto & Vertexes = Graph. getVertexes (); Vertex * pVertexStart = Vertexes. find (VetexId)-> second; vector <Vertex *> Q; // initialize the Vertex for (auto & it: Vertexes) {Vertex * pV = it. second; pV-> PathfindingData. cost = 0; pV-> PathfindingData. pParent = 0; pV-> PathfindingData. heuristic = 0x0FFFFFFF; pV-> PathfindingData. flag = false;} // Initialize the start vertex pVertexStart-> PathfindingData. pParent = 0; pVertexStart-> PathfindingData. cost = 0; pVertexStart-> PathfindingData. heuristic = Estimate (pVertexStart, m_pVTarget); // puts the starting vertex in the list Q. push_back (pVertexStart); pVertexStart-> PathfindingData. flag = true; for (; Q. size ()> 0;) {// select the vertex auto v = ExtractMin (Q) for the minimum path estimation; v-> PathfindingData. flag = false; if (v = m_pVTarget) {return;} // All Perform "relaxation" const auto & EO = v-> GetEdgesOut (); for (auto & it: EO) {Edge * pEdge = it. second; Vertex * pVEnd = pEdge-> GetEndVertex (); bool bRet = Relax (v, pVEnd, pEdge-> GetWeight (); // If the relaxation succeeds, add it to the list. If (bRet & pVEnd-> PathfindingData. flag = false) {Q. push_back (pVEnd); pVEnd-> PathfindingData. flag = true ;}// end for} // end for} Vertex * AStar: ExtractMin (vector <Vertex *> & Q) {Vertex * Ret = 0; ret = Q [0]; int pos = 0; for (int I = 1, size = Q. size (); I <size; ++ I) {if (Ret-> PathfindingData. heuristic> Q [I]-> PathfindingData. heuristic) {Ret = Q [I]; pos = I ;}} Q. erase (Q. begin () + pos); return Ret;} bool AStar: Relax (Vertex * v1, Vertex * v2, int Weight) {// here is the heuristic function int G = v1-> PathfindingData. cost + Weight; // get the actual path price from V1 to V2 int H = Estimate (v2, m_pVTarget ); // estimate the path cost of V2 to the target node. int nHeuristic = G + H; // actual + estimation = value of the heuristic function // if this path reaches the target, it will be calculated shorter, and if (nHeuristic <v2-> PathfindingData will be updated. heuristic) {v2-> PathfindingData. cost = G; v2-> PathfindingData. pParent = v1; v2-> PathfindingData. heuristic = nHeuristic; return true;} return false ;}

 

H function (estimate the cost of the current vertex to the target vertex) "outsourced" to external execution. Because the AStart class does not know the existence of the MapWalkVertex vertex class. Why is it necessary to "outsource" the execution instead of in the AStar class? To do this in the AStar class, you need to know the geometric position of each vertex, And the geometric position of the vertex is the attribute of the Node class of the Cocos2D-x. The AStar class should not be coupled with other things. In order to be "independent" and "General", the calculation H will be executed in the Observer mode and "outsourcing.

 

The usage of the AStar class is as follows:

 

// A *'s H valuation function auto Estimate = [] (const Vertex * pVCurrent, const Vertex * pVTarget)-> int {map1_vertex * pMwv1 = (map1_vertex *) pVCurrent-> UserData. find (mwv)-> second; map1_vertex * pMwv2 = (map1_vertex *) pVTarget-> UserData. find (mwv)-> second; Point v = pMwv1-> getPosition ()-pMwv2-> getPosition (); int H = v. getLength (); return H ;}; AStar; // set the destination vertex AStar. setTarget (pVertexTarget); // sets the H valuation function AStar. estimate = Estimate; // start to execute AStar. execute (* m_pGraph, pMwvStart-> GetGraphVertex ()-> GetId ());

 

OK, A * is finished. Run the test:

 

 



Tested. Our A * can find the shortest path. And the execution speed is faster than Dijkstra and Spfa.

 

3. Download the source code project in this article:

Http://download.csdn.net/detail/stevenkylelee/7734787

 

 

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.