秋月疾风

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

本文译自 Introduction to A*.

对一个物体来说,移动起来很容易,而寻路则相对复杂。

为什么需要寻路算法?请看——

有一个单位,最初位于地图的底部 start,并希望到达顶部 goal。

没有寻路算法的极端情况:

    他可以移动的区域(浅红色)中没有任何阻挡,因此他径直前进。直到在弧形障碍物中心,检测到了障碍物,然后他改变方向。最后沿着(红色)路径绕过“U”形障碍物。

拥有寻路算法:

    他扫描更大的区域(浅蓝色),发现较短的路径(蓝色),从而避免走进凹形障碍物。

 

另外,你也可以完善移动算法以解决这个陷阱情况:

一种方法是,避免生成凹陷障碍物。

另一种方法是,将障碍物的凸包标记为障碍物(只有在目的地位于内部时才进入)。

 

寻路算法的奥义之一,就是不会等到最后一刻才发现障碍。

我们需要在寻路算法移动算法之间进行权衡。

提前规划通常较慢,但能给出更好的路径;直线移动通常计算地更快,但可能绕路、或是走进死胡同。

如果环境中的障碍物经常移动,那么提前规划就不那么有价值了。

 

博主建议同时使用——

在起点与目的地距离很远时、或是有大型、移动缓慢的障碍物时,进行路径规划;

而在区域较小、有快速变化和较短路径时可以考虑直接移动。

 

算法

博主写了一个新的页面,包含了动态演示,可以参见 Introduction to the A* Algorithm.

寻路算法经常被应用在图论中。

而图论中的图,在数学意义上,是一组顶点。其中一部分顶点是连通、可通行的。

 

将游戏地图平铺开来,可以视为一张图。

每个单位地块都可以看作一个顶点(或者说网格),相邻的顶点之间有连接的边:

 

假设我们使用的是二维的网格

如果你之前没有了解过图,可以看这个网页

稍后,我将讨论如何从游戏世界中构建其他类型的图(未译)。因为大多数AI或者算法研究的寻路算法,都是针对任意图形,而不是基于网格的游戏而设计的。

 

我们可以通过一些常识来优化寻路算法,比如——

距离方面:当两个东西相距较远时,则需要更长时间才能从起点移动到终点。

方向方面:如果目的地在东边,那么向东走比向西走更容易到达。

对称性方面:大多数时候,(向北走、再向东走),与(向东走、再向北走)是相同的。

 

Dijkstra算法和BFS

Dijkstra 算法从起点开始,遍历周围的顶点。

它重复检查最近的、尚未检查的顶点,将其添加到“即将进行遍历周围顶点”的顶点集合。

它从起点向外扩展,直到达到目标。

 

Dijkstra 算法能够保证找到一条最短路径。(注1:只要没有边具有负开销)(注2:“一条最短路径”,因为经常存在多个开销相等的最短路径。)

在下图中,粉红色方块是起点,蓝色方块是目的地,青色区域显示Dijkstra算法扫描的区域。最淡的青色区域距离起点最远,形成了探索的“前沿”:

 

 

贪心算法(Greedy Best-First-Search)以类似的方式工作,区别在于它有一些估算(即启发式,顶点距离目的地的距离 

对于贪心算法来说,下一次进行检查的顶点,不是选择最接近起点的顶点,而是选择最接近目的地的顶点

 

贪心算法不保证找到最短的路径。

然而,它比 Dijkstra 算法运行得快很多,因为它用的启发式函数非常快速地引导它朝向目的地。

例如,如果目的地位于起点的南边,则贪心算法将倾向于关注向南的路径。

在下图中,黄色表示具有高启发式值(达到目标的高成本)的节点,黑色表示具有低启发式值的节点(达到目标的低成本)。它表明,与Dijkstra的算法相比,贪心算法可以非常快速地找到路径:

上面这两个例子都说明了最简单的情况 - 当地图没有障碍物时,最短路径确实是一条直线。

 

让我们考虑上一节中描述的凹陷障碍。

Dijkstra的算法搜索了更多格子(即更耗时),但保证找到最短的路径:

另一方面,贪心的Best-First-Search做的工作较少,但显然,路径不太好:

贪心算法会试图朝着目标径直前进,即使它不是最好的路径。

它只考虑了(从当前顶点到达目的地)的成本 而 忽略了(从起点到当前顶点)的路径成本,所以它会继续前进,即便所使用的路径会变得非常长。

 

将这两种算法结合起来会不会很奶思?

A* 是在1968年开发的,用于结合启发式方法(如贪心算法)和其他更 oldschool 的方法(如 Dijsktra 算法)。

这有点不一般。

因为启发式算法通常会为您提供一种解决问题的近似方法,而无法保证最优解。

而 A* 建立在启发式的基础之上,虽然启发式本身并不能保证,但 A* 可以保证最短的路径。

 

 A* 算法

维基页面

A* 在寻路算法中非常受欢迎。因为它非常灵活,可以在各种环境中使用。

像 Dijkstra 算法一样,A* 可以用来找到最短的路径。

像贪心算法一样,A* 可以使用启发式来指导自己。在简单的情况下,它与贪心算法一样快:

在具有凹陷障碍物的示例中,A* 可以找到与 Dijkstra 一样的最佳路径:

 

A* 成功的秘诀在于它结合了 Dijkstra 算法使用的信息(支持接近起点的顶点)和贪心算法使用的信息(支持接近目标的顶点)。

 

在讨论 A* 时,我们会提到以下几个值:

g(n) 表示从起点到当前顶点确切成本

h(n) 表示从当前顶点到目的地的启发式估计成本

在上图中,黄色点表示远离目的地的顶点,蓝绿色点表示远离起点的顶点。

A* 在从起点移动到目的地时会平衡两者。

 

每次通过主循环,它检查具有 g(n) + h(n) 最低的顶点

在这里,用 f(n) 表示路径总长,f(n) =  g(n) + h(n) 。

posted on 2018-11-27 13:43  危危_Ver程序员  阅读(1393)  评论(0编辑  收藏  举报