A*寻路算法(For 初学者) - ToBin的博客 - 博客园

来源:百度文库 编辑:神马文学网 时间:2024/04/25 23:30:05

A*寻路算法(For 初学者)

This article has been translated into Spanish and French. Other translations are welcome.

While it is easy once you get the hang of it, the A* (pronouncedA-star) algorithm can be complicated for beginners. There are plenty ofarticles on the web that explain A*, but most are written for peoplewho understand the basics already. This one is for the true beginner.
虽然掌握了A*(读作A-star)算法就认为它很容易,对于初学者来说,它却是复杂的。网上有很多解释A*的文章,不过大多数是写给理解了基础知识的人。本文是给初学者的。

This article does not try to be the definitive work on the subject.Instead it describes the fundamentals and prepares you to go out andread all of those other materials and understand what they are talkingabout. Links to some of the best are provided at the end of thisarticle, under Further Reading.
本文并不想成为关于这个主题的权威论文。实际上它讨论了基础知识并为你做一些准备,以便进一步阅读其他资料和理解它们讨论的内容。本文的后面列出了几个最好的文章,在进阶阅读中。

Finally, this article is not program-specific. You should be able toadapt what's here to any computer language. As you might expect,however, I have included a link to a sample program at the end of thisarticle. The package contains two versions: one in C++ and one in BlitzBasic. It also contains executables if you just want to see A* inaction.
最后,本文不是编程规范的。你应该能够改写这里的东西到任何计算机语言上。如你所期望的,同时,我包含了一个示例程序的链接,在本文后面结束的地方。这个程序包有两个版本:一个是C++,另一个用Blitz Basic语言编写。如果你只是想看看A*的行为,里面也含有可执行exe文件。

But we are getting ahead of ourselves. Let's start at the beginning ...
但我们要超越自己。让我们从头开始 ...

介绍:搜索区域Introduction: The Search Area
Let's assume we have someone who wants to get from point A to point Band that a wall separates the two points. This is illustrated in thegraphic found below, with green being the starting point A, red beingthe ending point B, and the blue filled squares being the wall inbetween.
我们假设某人想从A点到达B点,一堵墙把它们分开了。如下图所示,绿色是开始点A,红色是结束点B,而蓝色填充的方块是中间的墙。


[图 1][Figure 1]

The first thing you should notice is that we have divided our searcharea into a square grid. Simplifying the search area, as we have donehere, is the first step in pathfinding. This particular method reducesour search area to a simple two dimensional array. Each item in thearray represents one of the squares on the grid, and its status isrecorded as walkable or unwalkable. The path is found by figuring outwhich squares we should take to get from A to B. Once the path isfound, our person moves from the center of one square to the center ofthe next until the target is reached.
你应该注意的第一件事是,我们把搜索区域分割成了方块的格子。简化搜索区域,如你目前完成的那样,这是寻路的第一步。这个特殊方法把搜索区域简化成了一个二维数组。数组的每一个项目代表了格子里的一个方块,它的状态记录成可行走和不可行走。通过计算出从A到达B应该走哪些方块,就找到了路径。一旦路径找到,我们的人从一个方块的中心移动到下一个方块的中心,直到抵达目标。

These center points are called "nodes". When you read about pathfindingelsewhere, you will often see people discussing nodes. Why not justrefer to them as squares? Because it is possible to divide up yourpathfinding area into something other than squares. They could berectangular, hexagons, or any shape, really. And the nodes could beplaced anywhere within the shapes ? in the center or along theedges, or anywhere else. We are using this system, however, because itis the simplest.
这些中心点称作“节点”。当你在其它地方阅读关于寻路时,你将经常发现人们讨论节点。为什么不直接把它们认为是方块呢?因为有可能你要把你的寻路区域以非方块的东西来分割。它们可能是矩形,六角形,或任何形状,真的。而节点可以放到形状内的任何位置。在中心,或者沿着边缘,或其它地方。然而我们使用这个系统,因为它最简单。

开始搜索Starting the Search
Once we have simplified our search area into a manageable number ofnodes, as we have done with the grid layout above, the next step is toconduct a search to find the shortest path. In A* pathfinding, we dothis by starting at point A, checking the adjacent squares, andgenerally searching outward until we find our target.
一旦我们把搜索区域简化成了可以管理的大量节点,就象我们上面所做的那样采用格子的布局,下一步就是引导一个搜索来找出最短路径。在A*寻路的做法,我们从开始点A做起,检查它周围的方块,并且向外普通的搜索,直到找到目标

We begin the search by doing the following:
我们这样开始搜索:

Begin at the starting point A and add it to an "open list" of squaresto be considered. The open list is kind of like a shopping list. Rightnow there is just one item on the list, but we will have more later. Itcontains squares that might fall along the path you want to take, butmaybe not. Basically, this is a list of squares that need to be checkedout.
从开始点A起,添加它到待考虑的方块的“开放列表”。开放列表有点象购物列表。此时只有一个项目在里面,但很快我们会得到更多。它包含了你可能取用的沿途的方块,也可能不用它。基本上,这是需要检查的方块的列表。

Look at all the reachable or walkable squares adjacent to the startingpoint, ignoring squares with walls, water, or other illegal terrain.Add them to the open list, too. For each of these squares, save point Aas its "parent square". This parent square stuff is important when wewant to trace our path. It will be explained more later.
观察开始点邻近的所有可到达或可行走的方块,忽略有墙,水或其他非法地形的方块。也把它们添加到开放列表。对每一个方块,保存A 点作为它们的“父亲”。这个父亲方块在跟踪路径时非常重要。后面会更多的解释。

Drop the starting square A from your open list, and add it to a "closedlist" of squares that you don't need to look at again for now.
把开始方块A从开放列表中取出,并放到“封闭列表”内,它是所有现在不需要再关注的方块的列表。

At this point, you should have something like the followingillustration. In this diagram, the dark green square in the center isyour starting square. It is outlined in light blue to indicate that thesquare has been added to the closed list. All of the adjacent squaresare now on the open list of squares to be checked, and they areoutlined in light green. Each has a gray pointer that points back toits parent, which is the starting square.
在此,你应该有了类似下图的东西。在这个图中,中间的深绿色的方块就是开始方块。它有浅蓝色的外框,表示它被添加到封闭列表了。所有的相邻方块现在都进入要检查的方块的开放列表中了,它们有浅绿的外框。每一个都有灰色的指针指回它的父亲,它就是开始方块。


[图 2][Figure 2]

Next, we choose one of the adjacent squares on the open list and moreor less repeat the earlier process, as described below. But whichsquare do we choose? The one with the lowest F cost.
下一步,我们从开放列表中,选出一个相邻的方块,然后多多少少重复早先的过程,下面会说到。但是我们选择哪一个呢?具有最小F值的那个。

路径排序Path Scoring
The key to determining which squares to use when figuring out the path is the following equation:
找到形成路径的方块的关键是下面的等式:

F = G + H

where
这里

G = the movement cost to move from the starting point A to a givensquare on the grid, following the path generated to get there.
G = 从开始 点A到格子中给定方块的移动代价,沿着到达该方块而生成的那个路径。
H = the estimated movement cost to move from that given squareon the grid to the final destination, point B. This is often referredto as the heuristic, which can be a bit confusing. The reason why it iscalled that is because it is a guess. We really don't know the actualdistance until we find the path, because all kinds of stuff can be inthe way (walls, water, etc.). You are given one way to calculate H inthis tutorial, but there are many others that you can find in otherarticles on the web.
H = 从格子中给定 的方块到最终目标B点的评估移动代价。这种方式通常称作试探法,有点让人混乱。因为这是一个猜测,所以得到这个称谓。在找到路径之前,我们真的不知道实际的距离,因为途中有各种东西(墙,水,等等)。在本教程里给出了一种计算H的方法,但在网上你能找到很多其他的文章。
Our path is generated by repeatedly going through our openlist and choosing the square with the lowest F score. This process willbe described in more detail a bit further in the article. First let'slook more closely at how we calculate the equation.
我们需要的路径是这样生成的:反复的遍历开放列表,选择具有最小F值的方块。这个过程在本文稍后会详细描述。先让我们看看如何计算前面提到的等式。

As described above, G is the movement cost to move from the startingpoint to the given square using the path generated to get there. Inthis example, we will assign a cost of 10 to each horizontal orvertical square moved, and a cost of 14 for a diagonal move. We usethese numbers because the actual distance to move diagonally is thesquare root of 2 (don't be scared), or roughly 1.414 times the cost ofmoving horizontally or vertically. We use 10 and 14 for simplicity'ssake. The ratio is about right, and we avoid having to calculate squareroots and we avoid decimals. This isn't just because we are dumb anddon't like math. Using whole numbers like these is a lot faster for thecomputer, too. As you will soon find out, pathfinding can be very slowif you don't use short cuts like these.
如上所述,G是经由到达它的路径,从开始点到给定方块的移动代价。在本例中,我们为每个水平/垂直的移动指定代价为10,而斜角的移动代价为14。我们使用这些值,因为斜角移动的实际距离是2的平方根(别害怕),或者大概1.414倍的水平/垂直的移动代价。出于简化的目的使用了10和14。比例大致是正确的,而我们却避免了方根和小数的计算。倒不是我们没有能力做或者不喜欢数学。使用这些数字也能让计算更快一些。以后你就会发现,如果不使用这些技巧,寻路的计算非常慢。

Since we are calculating the G cost along a specific path to a givensquare, the way to figure out the G cost of that square is to take theG cost of its parent, and then add 10 or 14 depending on whether it isdiagonal or orthogonal (non-diagonal) from that parent square. The needfor this method will become apparent a little further on in thisexample, as we get more than one square away from the starting square.
既然我们沿着到达给定方块的路径来计算G的值,找出那个方块的G值的方法就是找到其父亲的G值,再加上10或者14而得,这依赖于他处于其父亲的斜角或者直角(非斜角)而定。这在本例后面会更加清晰,随着我们从开始点离开而得到更多的方块。

H can be estimated in a variety of ways. The method we use here iscalled the Manhattan method, where you calculate the total number ofsquares moved horizontally and vertically to reach the target squarefrom the current square, ignoring diagonal movement. We then multiplythe total by 10. This is called the Manhattan method because it's likecalculating the number of city blocks from one place to another, whereyou can't cut across the block diagonally. Importantly, whencalculating H, we ignore any intervening obstacles. This is an estimateof the remaining distance, not the actual distance, which is why it'scalled the heuristic. Want to know more? You can find equations andadditional notes on heuristics here.
H能通过多种方法估算。我们这里用到的方法叫做Manhattan方法,计算从当前方块经过水平/垂直移动而到达目标方块的方块总数。然后将总数乘以10。这种方法之所以叫做Manhattan方法,因为他很象计算从一个地点到达另一个地点的城市街区数量计算,此时你不能斜向的穿越街区。重要的是,当计算H的时候,要忽略任何路径中的障碍。这是一个对剩余距离的估算值,而不是实际值,这就是试探法的称谓由来。想知道更多?关于试探法的更多说明在这里。

F is calculated by adding G and H. The results of the first step in oursearch can be seen in the illustration below. The F, G, and H scoresare written in each square. As is indicated in the square to theimmediate right of the starting square, F is printed in the top left, Gis printed in the bottom left, and H is printed in the bottom right.
G和H相加就算出了F。第一步搜索的结果见下图的描述。F,G,和H值都写入了每个方块。如开始方块相邻右边的方块,F显示在左上方,G显示在左下方,而 H显示在右下方。



[图 3][Figure 3]

So let's look at some of these squares. In the square with the lettersin it, G = 10. This is because it is just one square from the startingsquare in a horizontal direction. The squares immediately above, below,and to the left of the starting square all have the same G score of 10.The diagonal squares have G scores of 14.
好,让我们来观察某些方块。在有字母的方块中,G = 10。这是由于在水平方向上从开始点(到那里)只有一个方块(的距离)。开始点相邻上方,下方和左边的方块都具有同样的G值:10。斜角的方块G值为 14。

The H scores are calculated by estimating the Manhattan distance to thered target square, moving only horizontally and vertically and ignoringthe wall that is in the way. Using this method, the square to theimmediate right of the start is 3 squares from the red square, for a Hscore of 30. The square just above this square is 4 squares away(remember, only move horizontally and vertically) for an H score of 40.You can probably see how the H scores are calculated for the othersquares.
H的计算通过估算Manhattan距离而得,即:水平/垂直移动,忽略途中的障碍,到达红色的目标方块的距离。用这种方法,开始点相邻右边的方块和红色方块相距3个方块,那么H值就是30。其上的方块距离为4(记住,只能水平或者垂直移动),H就是40。你也许可以看看其他方块的H值是如何算出的。

The F score for each square, again, is simply calculated by adding G and H together.
每个方块的F值,再说一下,不过就是G和H相加。

持续的搜索Continuing the Search
To continue the search, we simply choose the lowest F score square fromall those that are on the open list. We then do the following with theselected square:
为了继续搜索,我们简单的选择开放列表里具有最小F值的方块。然后对选定的方块做如下操作:

Drop it from the open list and add it to the closed list.
将他从开放列表取出,并加入封闭列表。
Check all of the adjacent squares. Ignoring those that are on theclosed list or unwalkable (terrain with walls, water, or other illegalterrain), add squares to the open list if they are not on the open listalready. Make the selected square the "parent" of the new squares.
测试所有的相邻方块。忽略封闭列表内的和不可行走的(墙,水及其它非法地形)方块,如果方块不在开放列表中,则添加进去。将选定方块作为这些新加入方块的父亲。
If an adjacent square is already on the open list, check to see if thispath to that square is a better one. In other words, check to see ifthe G score for that square is lower if we use the current square toget there. If not, don't do anything.
On the other hand, if the G cost of the new path is lower, change theparent of the adjacent square to the selected square (in the diagramabove, change the direction of the pointer to point at the selectedsquare). Finally, recalculate both the F and G scores of that square.If this seems confusing, you will see it illustrated below.
如果一个相邻方块已经存在于开放列表,检查到达那个方块的路径是否更优。换句话说,检查经由当前方块到达那里是否具有更小的G 值。如果没有,不做任何事。
相反,如果新路径的G值更小,把这个相邻方块的父亲改为当前选定的方块(在上图中,修改其指针方向指向选定方块)。最后,重新计算那个方块的F和G值。如果这样还是很迷惑的话,后面还会有图解说明。

Okay, so let's see how this works. Of our initial 9 squares, we have 8left on the open list after the starting square was switched to theclosed list. Of these, the one with the lowest F cost is the one to theimmediate right of the starting square, with an F score of 40. So weselect this square as our next square. It is highlight in blue in thefollowing illustration.
好了,让我们看看它是怎样工作的。在初始的9个方块中,当开始方块被纳入封闭列表后,我们的开放列表就只有8个方块了。在这些块中,具有最小F值的是开始方块相邻右边的那个,其F值为40。所以我们选定这个块作为下一个方块。在随后的图例中,它以高亮的蓝色表示。



[图 4][Figure 4]

First, we drop it from our open list and add it to our closed list(that's why it's now highlighted in blue). Then we check the adjacentsquares. Well, the ones to the immediate right of this square are wallsquares, so we ignore those. The one to the immediate left is thestarting square. That's on the closed list, so we ignore that, too.
首先,我们把它从开放列表取出,并加入到封闭列表(这就是它现在是高亮的蓝色的原因)。然后我们检查相邻的方块。然而,这个方块相邻右边的是代表墙的方块,所以忽略它们。其相邻左边是开始方块。它处于封闭列表内,所以也忽略它

The other four squares are already on the open list, so we need tocheck if the paths to those squares are any better using this square toget there, using G scores as our point of reference. Let's look at thesquare right above our selected square. Its current G score is 14. Ifwe instead went through the current square to get there, the G scorewould be equal to 20 (10, which is the G score to get to the currentsquare, plus 10 more to go vertically to the one just above it). A Gscore of 20 is higher than 14, so this is not a better path. Thatshould make sense if you look at the diagram. It's more direct to getto that square from the starting square by simply moving one squarediagonally to get there, rather than moving horizontally one square,and then vertically one square.
其它4个已经在开放列表中了,所以我们需要检查经由当前方块到达他们是否是更优的路径,使用G值为参考点。我们来看看这个选定方块上面右边的那个方块。它的当前G值是14。如果我们经由当前方块到达那里,G值将是20(10,到达当前方块的G值,再加上10垂直移动到它上面的方块)。20>14,所以这不是一个好的路径。看看图解能更好的理解这些。从开始方块斜向移动到那个方块更直接,而不是水平移动一个方块,再垂直移动一个方块。

When we repeat this process for all 4 of the adjacent squares alreadyon the open list, we find that none of the paths are improved by goingthrough the current square, so we don't change anything. So now that welooked at all of the adjacent squares, we are done with this square,and ready to move to the next square.
当我们对已经存在于开放列表的所有4个相邻方块都重复这个过程,我们发现经由当前方块没有更佳的路径,所以什么也不用改变。现在看看所有的相邻方块,我们已经处理完毕,并准备移动到下一个方块。

So we go through the list of squares on our open list, which is nowdown to 7 squares, and we pick the one with the lowest F cost.Interestingly, in this case, there are two squares with a score of 54.So which do we choose? It doesn't really matter. For the purposes ofspeed, it can be faster to choose the last one you added to the openlist. This biases the search in favor of squares that get found lateron in the search, when you have gotten closer to the target. But itdoesn't really matter. (Differing treatment of ties is why two versionsof A* may find different paths of equal length.)
现在,我们再遍历开放列表,它只有7个方块了,选择具有最小F值的那个。有趣的是,此时有两个方块都有值54。那么我们选择哪个?实际上这不算什么。为了速度的目的,选择你最后加入到开放列表的那个方块更快。当你更接近目标的时候,它倾向于后发现的方块。但这真的没什么关系。(不同的处理造成了两个版本的A*可能找到不同的等长路径。)
So let's choose the one just below, and to the right of the starting square, as is shown in the following illustration.
我们选择下面的那个,位于开始方块的右边,如下图所示。


[图 5][Figure 5]

This time, when we check the adjacent squares we find that the one tothe immediate right is a wall square, so we ignore that. The same goesfor the one just above that. We also ignore the square just below thewall. Why? Because you can't get to that square directly from thecurrent square without cutting across the corner of the nearby wall.You really need to go down first and then move over to that square,moving around the corner in the process. (Note: This rule on cuttingcorners is optional. Its use depends on how your nodes are placed.)
这一次,当检查相邻的方块时,我们相邻右边的是一个墙方块,所以忽略它。对那个方块上面的块同样忽略。我们也忽略墙下面的方块。为什么?因为你不把临近墙的角切开就无法直接到达那个方块。实际上你需要先向下走,然后越过那个方块,在这个过程中都是围绕角在移动。(说明:切开角的规则是可选的。它的使用依赖于你的节点如何放置。)

That leaves five other squares. The other two squares below the currentsquare aren't already on the open list, so we add them and the currentsquare becomes their parent. Of the other three squares, two arealready on the closed list (the starting square, and the one just abovethe current square, both highlighted in blue in the diagram), so weignore them. And the last square, to the immediate left of the currentsquare, is checked to see if the G score is any lower if you go throughthe current square to get there. No dice. So we're done and ready tocheck the next square on our open list.
这样就剩下5个方块了。当前方块下的两个方块不在开放列表中,所以要添加他们,并把当前方块作为它们的父亲。在另外三个方块中,有两个已经在封闭列表中了(开始方块,和当前方块上面的那个,它们都用高亮的蓝色在图中标出来了),所以忽略它们。最后一个方块,当前方块相邻左边的那个,检查经由当前方块到达那里是否得到更小的G值。没有。所以处理完毕,并准备检查开放列表中的下一个方块。

We repeat this process until we add the target square to the open list,at which point it looks something like the illustration below.
我们重复这个过程,直到把目标点添加到开放列表,此时的情形如下图所示。

[图 6][Figure 6]

Note that the parent square for the square two squares below thestarting square has changed from the previous illustration. Before ithad a G score of 28 and pointed back to the square above it and to theright. Now it has a score of 20 and points to the square just above it.This happened somewhere along the way on our search, where the G scorewas checked and it turned out to be lower using a new path ? so theparent was switched and the G and F scores were recalculated. Whilethis change doesn't seem too important in this example, there areplenty of possible situations where this constant checking will makeall the difference in determining the best path to your target.
注意开始方块向下的第二个方块,在前面的描述中其父亲已经发生改变。开始它的G值为28,指向其右上角的方块。现在它的值是20,指向其上方的方块。这是在搜索方法中某处发生的吗?在那里G值被检查,而且使用新的路径后,它得到了更小的值。所以它的父亲切换了,G和F也重新计算。而这个改变在本例中不见得非常重要,还有足够多的可能位置,在决定最佳路径的时候,持续的检查会产生各种差别。

So how do we determine the actual path itself? Simple, just start atthe red target square, and work backwards moving from one square to itsparent, following the arrows. This will eventually take you back to thestarting square, and that's your path! It should look like thefollowing illustration. Moving from the starting square A to thedestination square B is simply a matter of moving from the center ofeach square (the node) to the center of the next square on the path,until you reach the target. Simple!
那么我们怎样决定实际的路径呢?简单,从红色目标方块开始,向后移动到它的父亲,跟从箭头的指示。最终你会回到开始方块,这就是路径!它应该如下图所示。从方块A移动到目标方块B就是从每一个方块(节点)的中心移动到路径上的下一个方块的中心的简单过程,直到到达目标。简单!

原帖:http://school.ogdev.net/ArticleShow.asp?id=1426&categoryid=10
这篇文章更详细:http://www.cppblog.com/christanxw/archive/2006/04/07/5126.html
A*寻路算法(For 初学者) - ToBin的博客 - 博客园 博客园 - ipointer - RETE算法的描述(原创) 常见算法笔试或面试题 - zhenjing的技术博客 - 博客园 3D游戏寻路算法(A*) 初学者怎样练好太极拳 - mimi480818的日志 - 网易博客 初学者怎样学习写诗呢?--王俊海的博客 怎样初步设置博客的页面(初学者进) 所有代码的粘贴法(献给初学者)博客技巧 初学者怎样练好太极拳 - mimi480818的日志 ,,网易博客 测试边框(音画初学者请进) - 冬韵如歌的日志 - 网易博客 MD5算法的JAVASCRIPT实现 - ※放飞自我※IT技术论坛※ - 博客园 基于朴素贝叶斯分类器的文本分类算法(上) - Phinecos(洞庭散人) - 博客园1 采用部分快速排序算法实现数组的部分排序 - eaglet - 博客园 常用算法大全-贪婪算法2 - DotNet笔记 - 博客园 博客园 - 嚎叫一声 - 算法与竞赛 遗传算法(Genetic Algorithm) - cutepig‘s 博客园 LZW压缩算法简介 - 爱东东 - 博客园 一个Dijkstra算法的完整Java程序实现,算法初学者必看! - brokencar的专栏 - CSDNBlog 公历历法::星期算法 -- 算法驿站 -- 编程爱好者博客 初学者不用愁 看看博客入门教材 一学就会 - 难忘知青的日志 - 网易博客 翻译:Single Sign-On for Everyone - Anders Liu的.NET空间 - 博客园 The value for the useBean class attribute is invalid 问题 - Yiling的眷眷 - 博客园 卸载QQ for Linux - join的日志 - 网易博客 博客园 - 灵感之源的Forgio-智能工厂 - 快速的字符串查找算法(Boyer-Moore)