A*路径寻找-献给初学者

在网上看了几篇关于A*的文章,都没怎么看懂,其中包括翻译国外作者写的这篇于是打算直接看原文了,看了后发现有的并没有很仔细地翻译。为了能便于自己理解,打算再翻译一遍,有些地方就简单翻译了。

---------------------------------------------------------------------------------------------------------------------

先给出一个原文连接http://www.policyalmanac.org/games/aStarTutorial.htm。接下来翻译。


A*(读作A-start)算法对初学者来说比较复杂。但是网上也有很多介绍该算法的,然而大多数都是写给那些有基础的人看的。这篇文章是写给真正的初学者的(就是我了微笑)。

这篇文章并不是该主题的权威探讨。相反,它描述了一些基本原理使得你具备阅读其他材料并能理解其他材料的能力。文章末尾提供了一些比较好的链接,以供进一步阅读。

最后,这篇文章并不是讲编程的,你应该能够根据这篇文章所讲的用其他任何编程语言来实现。然而,正如你期望的一样,我在文章末尾也提供了一个示例程序。该程序包括两个版本:C++和Blitz Basic。如果你只想看看它是怎么运行的,也有可执行的程序。

有点言之过早了,让我们开始吧。。。


Introduction: The Search Area

假设有个人想从A点到达B点,并假设A和B之间有道墙。如下图所示,绿色的是起始点A,红色的是终点B,蓝色区域就是墙。


图一


你需要知道的第一件事是我们已经把搜索区域划分成了单元格。简化搜索区域是路径查找的第一步。这个特殊的方法把搜索区域简化成了一个简单的二维数组。数组中的每个条目代表了表格中的一个单元,单元的状态被标为walkable或者unwalkable。我们要找的路径就是表格中从A到B所经过的单元格的集合。一旦找到了路径,我们就可以从一个单元的中心点到达下一个单元的中心点,直到到达目的单元。

这些中心点被称为“nodes”,为什么不叫squares呢?因为我们可以把区域分成其他形状,可以是长方形、三角形、六边形或其他形状。nodes可以放在这些形状中的任意一个位置--在中心或者在边缘或者其他地方。简单起见,这里我们使用square来描述。


Starting the Search

一旦我们简化了搜索区域为一些易处理的nodes,如前面一幅图所示,下一步就是寻找最短路径了。我们从起始点A开始,检查相邻squares,往外查找直到找到目标。

我们以如下步骤开始查找:

1、从A开始并将它添加到“open list”。这个就像一个shopping list。目前为止只有一个条目在列表中,以后还会有很多。总的来说,这个列表需要被进一步的检查。

2、查看与起始点相邻的所有reachable或者walkable的squares,把他们加入到open list,忽略墙、水或者其他illegal terrain。对于刚加入的每个square,把A点保存为他们的“parent square”。这个对回溯路径的时候很有用。

3、从open list中删除starting square A,并加入到“closed list”中,里面的squares暂时不会被查找。


目前为止,你脑子中应该有如下图的描绘了。深绿色的square是starting square。外层一圈描蓝表示该单元已经被加入到closed list中了。该单元周围8个squares(被绿色边框描着的)也被加入到了open list中待以后查找,其中每一个都有一个指向parent square的指针,这个parent square就是starting square。

 

图2

接下来,我们从open list中选择一个相邻square,差不多重复之前的过程。但是选哪个呢?当然是F值最小的啦。


Path Scoring

选哪些square的关键在于以下公式:

F=G+H

G:从starting point A开始移动到一个指定square的代价。

H:从一个给定square移动到最终目的square B的估计代价。这就是所谓的启发式。之所以这么称呼是因为那个值只是个猜想。在找到路径之前我们还不知道实际的距离,因为路上会有各种障碍(比如墙,水之类的)。这篇文章给了一个计算该值的方法,但是网上也有很多用其他方法计算该值的文章。


通过遍历open list并选择最小F值的square来生成路径。这之前需要计算G和H值,计算一个square的G值的方法是根据它是处于parent square的水平、垂直或者对角线位置来相应加上10或者14,并且还要加上parent square的G值。我们的例子中使用10来表示水平和垂直移动一格的代价,用14来表示对角线移动一个的代价。因为对角线是边的根号2倍,所以我们取这样的值,同时也便于计算。


H可以用多种方法来估计,我们这里用曼哈顿方法(Manhattan method)来计算。用该方法计算的时候是沿着水平和垂直距离的,并且忽略沿途的障碍物。计算结果为走过的步数乘以10。


从技术上来说,曼哈顿方法是一个inadmissible heuristic,因为它有点高估了剩余距离,但这便于理解。关于这个问题可以看这里


搜索的第一步的结果如下图所示。F、G、H的值也标上了。


图三


我们来看,绿色square的水平、垂直方向上的squares的G都是10,对角线上的都为14。H值则是当前square到红色square的水平加垂直距离。

Continuing the Search

接着,我们简单的从open list中选择F值最小的square,接下来对选择得到的当前square(记为A)进行如下操作:
4)从open list中删除A并加入到closed list中。
5)检查和A相邻的所有squares,忽略那些已经在closed list中或者不能走到(墙、水或其他禁止区域)的squares,将不在open list中的squares加入到open list中,并将新加入的squares的parent设置为当前square,还需要计算G、H和F值。
6)如果有A的相邻square已经在open list中了,就把A的G值加上10或者14,和当前相邻的square进行比较。如果比它大就什么也不做。如果比它小,意味着有一条新的更好的路径,并把当前相邻的square的parent设置为A(在图中,只需要把箭头换个指向就行)。最后,重新计算当前相邻的square的F和G值。如果还有问题,请看下面的图示。



我们看下它是怎么工作的。在最初的9个square中,starting square(绿色)已经从open list中删除并加入到closed list中了,只剩下8个。选中starting square右边的square为next square(蓝色线框住的),明显它的F值最小。

第一步,从open list中删除next square并加入到closed list中(这就是为什么它被蓝色框框住)。接着检查它的相邻squares。其中有三个是障碍物,一个在closed list中,忽略它们。其余四个都在open list中。所以我们需要看看从next square到它们的距离是不是比它们原来的距离更近。比如,next square的上面的square的G值为14,而从next square走到那里的距离为20(next square的G=10加上10为20),显然大于14,因此如果那样走不是一条好路经。如果从图上看的话,显然按着对角线走更加近。

同理,其余三个square也都是同样的结果。这一轮过去后,两个被蓝色框框住的为最终路径的一部分。接着再从open list中选一个F值最小的square为next square。假设我们选的是下面的那个,因为有两个F值都为54(从speed的角度来说,选你最后加到open list的要快点。但这影响不是很大,只不过搜索结果会有好几条路径)。如下图:


这时候next square的相邻squares中有两个障碍物、一个走不过去(右下角那个,因为需要把右边的墙角挖掉才能走过去,但这规则根据你的节点怎么摆放而定)、两个在open list中,忽略它们。下面的两个square不在open list中,因此把它们加入到open list中,修改parent指针。剩下的左边那个已经在open list中了,按照前面的方法检查。接着再从open list中选择一个F值最小的。

如此循环,直到我们把target square加入closed list为止,最终结果如下图:


绿色边框的为加入到open list中的squares,蓝色边框的为加入到closed list中的,红色为目标点。其中,绿色square下面和上面的第二个square的parent指针在遍历过程中有变化过(如果自己一步步去画出来看就能发现)。接着,从红色square的parent指针回溯到起点,便是一条A*路径。如下图:


Summary of the A* Method

总结一下步骤:

1)把starting square(或者node)加入到open list。
2)重复以下步骤:
     a)在open list中找到F最小的square。记为current square。
     b)把current square从open list中移到closed list中。
     c)对current square的8个相邻square做如下事
         忽略该忽略的square,然后往下
         如果不在open list中,加入open list。把parent设置为current square。计算F,G和H值。
         如果在open list中,判断G值,如果有更小的G值,把parent设置为current square,重新计算F和G值。
     d)当出现以下情况时结束:
          已经把target square加入到closed list中,意味着路径已被找到,或者
          找不到target并且open list为空,意味着没有路径。
3)保存路径。从终点按照parent指针回溯到起点。

后面还有,是一些注意事项,希望了解的可以阅读原文。

最后还有一个介绍游戏中路径查找算法的网址在这里
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值