In-depth A * algorithm ---- Analysis of the Application of A * Algorithm in searching the Shortest Path

I. Preface

Here I will discuss the practical application of the * algorithm, and give an example of the * Algorithm in the shortest path search. It is worth noting that the basic concepts of a * are not introduced here. If you are still not clear about the * algorithm, please refer to the companion article "first understanding a * algorithm".

The example here is a source program on the Amit homepage. You can download it from the Amit website or on my website. When using this source program, you should abide by certain conventions.

Ii. Programming principles of a * Algorithm

As I said in "first recognized a * algorithm", a * algorithm is the best priority algorithm. There are only some constraints. Let's take a look at how the best priority algorithm is written.

The following State space is available: (the starting position is A, the target position is P, and the number after the letter indicates the estimated value of the node)

Set two tables: open and closed during the search process. The Open Table stores all the nodes that have been generated but not tested. The closed table records the accessed nodes. One step in the algorithm is to rearrange the Open table based on the evaluation function. In this way, only the nodes with the best status in the Open table are considered in each step of the loop. The specific search process is as follows:

1) initial status:

Open = [A5]; closed = [];

2) estimate A5, search for sub-nodes, and put them in the Open table;

Open = [B4, C4, D6]; closed = [A5]

3) estimate B4, search for subnodes, and put them into the open table;

Open = [C4, E5, F5, D6]; closed = [B4, A5]

4) estimate C4; search for subnodes and put them into the open table;

Open = [H3, G4, E5, F5, D6]; closed = [C4, B4, A5]

5) estimate H3, search for sub-nodes, and put them in the Open table;

Open = [O2, P3, G4, E5, F5, D6]; closed = h3c4, B4, A5]

6) estimate O2, search for sub-nodes, and put them into the open table;

Open = [P3, G4, E5, F5, D6]; closed = [O2, H3, C4, B4, A5]

7) estimate P3 and the solution has been obtained;

After reading the specific process, let's look at the pseudo program. The pseudo program of the algorithm is as follows:

Best_first_search ()

{

Open = [Start Node]; closed = [];

While (Open table is not empty)

{

Obtain a node X from open and delete it from the Open table.

If (X is the target node)

{

Obtain Path; Return Path;

}

For (Y of each X subnode)

{

If (Y is not in the Open table or close table)

{

Evaluate the estimated value of Y and insert y into the Open table. // No sorting has been performed.

}

Else

If (Y in the Open table)

{

If (the estimated value of Y is smaller than the estimated value of Open table)

Update the valuation value in the Open table;

}

Else // y in the close table

{

If (the estimated value of Y is less than the estimated value of close table)

{

Update the valuation value in the close table;

Remove nodes from the close table and put them in the Open table;

}

}

Insert x nodes into the close table;

Sort the nodes in the Open table according to the estimated value;

} // End

} // End while

} // End func

Ah! When the pseudo program comes out, it should not be a problem to write a source program. The program of the * algorithm is the same as that of the algorithm. You only need to pay attention to the H (n) constraints of g (n) In the evaluate function. If you are not clear about it, you can refer to the first generation of a * algorithm. Now, we can go to another important topic and use the * algorithm to search for the shortest path. Before that, you 'd better understand the algorithm carefully. You can contact me if you have no idea. My email is at the end of the article.

3. Use the * algorithm to search for the shortest path

In game design, the shortest path search is often involved. Now, a better method is to use the * Algorithm for design. We don't need to worry about the benefits of him. It's good! ^ _*

Note that all of the following statements are based on the classastar program. You can download this program here. This process is a complete project. Contains an EXE file. You can check it out first.

First, review. The core of the * algorithm is the evaluation function f (n), which consists of g (N) and H (n. G (n) is the price that has passed, and H (n) is the estimated price of N to the target. In this example, g (n) indicates the depth from the starting node to N nodes in the state space, and H (n) indicates the straight line distance from the position of the map where n nodes are located to the target position. Ah! One is the state space and the other is the actual map. Do not make a mistake. In detail, there is an object A. The coordinates on the map are (XA, ya), and the coordinates of the target B to which a wants to reach are (XB, Yb ). When you start searching, set a Start Node 1 to generate eight child nodes 2-9 because there are eight directions.

Take a closer look at how the G (N) and H (n) values of Node 1, 9, and 17 are calculated. Now we should know how f (n) in the following program is computed. I started to explain the source program. In fact, this program is a typical textbook-like program. That is to say, as long as you understand the above pseudo program, this program is very easy to understand. However, he is somewhat different from the pseudo-program above, and I will discuss it later.

First look at the search main function:

Void astarpathfinder: findpath (INT Sx, int Sy, int dx, int Dy)

{

Node * node, * bestnode;

Int tilenumdest;

// Obtain the target location for judgment

Tilenumdest = tilenum (sx, Sy );

// Generate open and closed tables

Open = (node *) calloc (1, sizeof (node ));

Closed = (node *) calloc (1, sizeof (node ));

// Generate the Start Node and put it in the Open Table

Node = (node *) calloc (1, sizeof (node ));

Node-> G = 0;

// This is the H value.

Node-> H = (DX-SX) * (DX-SX) + (dy-sy) * (dy-sy); // shocould really use SQRT ().

// This is the calculated F value, that is, the estimated value

Node-> F = node-> G + node-> h;

Node-> nodenum = tilenum (dx, Dy );

Node-> X = DX;

Node-> Y = Dy;

Open-> nextnode = node; // make open list point to first node

For (;;)

{// Obtain a node with the best valuation value from the Open Table

Bestnode = returnbestnode ();

// Exit if the node is the target node

If (bestnode-> nodenum = tilenumdest) // if we 've found the end, break and finish

Break;

// Otherwise, child nodes are generated.

Generatesuccessors (bestnode, Sx, Sy );

}

Path = bestnode;

}

Let's take a look at generatesuccessors:

Void astarpathfinder: generatesuccessors (node * bestnode, int dx, int Dy)

{

Int X, Y;

// Oh! Generate child nodes in eight directions in sequence, which is simple!

// Upper-left

If (freetile (x = bestnode-> X-tilesize, y = bestnode-> Y-tilesize ))

Generatesucc (bestnode, X, Y, dx, Dy );

// Upper

If (freetile (x = bestnode-> X, Y = bestnode-> Y-tilesize ))

Generatesucc (bestnode, X, Y, dx, Dy );

// Upper-right

If (freetile (x = bestnode-> X + tilesize, y = bestnode-> Y-tilesize ))

Generatesucc (bestnode, X, Y, dx, Dy );

// Right

If (freetile (x = bestnode-> X + tilesize, y = bestnode-> Y ))

Generatesucc (bestnode, X, Y, dx, Dy );

// Lower-right

If (freetile (x = bestnode-> X + tilesize, y = bestnode-> Y + tilesize ))

Generatesucc (bestnode, X, Y, dx, Dy );

// Lower

If (freetile (x = bestnode-> X, Y = bestnode-> Y + tilesize ))

Generatesucc (bestnode, X, Y, dx, Dy );

// Lower-left

If (freetile (x = bestnode-> X-tilesize, y = bestnode-> Y + tilesize ))

Generatesucc (bestnode, X, Y, dx, Dy );

// Left

If (freetile (x = bestnode-> X-tilesize, y = bestnode-> Y ))

Generatesucc (bestnode, X, Y, dx, Dy );

}

Look at the most important function generatesucc:

Void astarpathfinder: generatesucc (node * bestnode, int X, int y, int dx, int Dy)

{

Int g, tilenums, c = 0;

Node * Old, * successor;

// Calculate the G value of the subnode

G = bestnode-> G + 1; // G (successor) = g (bestnode) + cost of getting from bestnode to successor

Tilenums = tilenum (x, y); // identification purposes

// Do subnodes open the table again?

If (old = checkopen (tilenums ))! = NULL) // if equal to null then not in open list, else it returns the node in old

{

// If

For (C = 0; C <8; C ++) if (bestnode-> child [c] = NULL) // Add old to the list of bestnode's children (or successors ).

Break;

Bestnode-> child [c] = old;

// Compare the estimated value in the Open table with the current estimated value (as long as the G value is compared)

If (g) // if our new G value is parent = bestnode;

Old-> G = g;

Old-> F = G + Old-> h;

}

}

Else // in the closed table?

If (old = checkclosed (tilenums ))! = NULL) // if equal to null then not in open list, else it returns the node in old

{

// If

For (C = 0; C <8; C ++) if (bestnode-> child [c] = NULL) // Add old to the list of bestnode's children (or successors ).

Break;

Bestnode-> child [c] = old;

// Compare the estimated value in the closed table with the current estimated value (as long as the G value is compared)

If (g) // if our new G value is parent = bestnode;

Old-> G = g;

Old-> F = G + Old-> h;

// Update the estimated values of all old subnodes in sequence.

Propagatedown (old); // since we changed the G value of old, we need

// To propagate this new value downwards, I. e.

// Do a depth-first traversal of the tree!

}

}

Else // neither in the Open Table nor in the close table

{

// Generate a new node

Successor = (node *) calloc (1, sizeof (node ));

Successor-> parent = bestnode;

Successor-> G = g;

Successor-> H = (X-dx) * (X-dx) + (Y-dy) * (Y-dy); // shocould do SQRT (), but since we don't really

Successor-> F = G + successor-> H; // care about the distance but just which branch looks

Successor-> X = x; // better this shocould suffice. anyayz it's faster.

Successor-> Y = y;

Successor-> nodenum = tilenums;

// Insert the table into the Open table and sort the table at the same time.

Insert (successor); // insert successor on open list WRT F

For (C = 0; C <8; C ++) if (bestnode-> child [c] = NULL) // Add old to the list of bestnode's children (or successors ).

Break;

Bestnode-> child [c] = successor;

}

}

Haha! A * I understand the algorithm! Of course, I hope you will feel this way! But I have to say a few more words. Take a closer look at this sequence and you will find that this program is somewhat different from the pseudo program I mentioned earlier. In the generatesucc function, when the subnode is in the closed table, the child node is not deleted from the closed table and put into the Open table. Instead, it directly recalculates the estimated values of all the subnodes of the node (using the propagatedown function ). This is faster! In addition, when the subnode is in an Open table or a closed table, after the estimated value is re-calculated, the nodes in the Open table are not re-ordered. Why not? :-(, Will it be a small bug. Do you know how to tell me?

Okay! The main contents are all finished. Let's take a closer look at the source program! I hope I can help you a little bit. If you disagree with the point in the article or have a better explanation, let me know.