最近作到一道题,题目以下:php
有 A、B 两点,中间有一堆障碍物,求出A点到B的可行的路径,写出一个 DEMO 并可用任何语言实现(要求能够任意设置 A、B 点和障碍物的位置,须要作UI)。html
首先,理解一下题意,须要求出 A、B 两点的可行路线,要注意的是能够任意设置 A、B 两点位置以及障碍物的位置且须要作 UI。题目需一句话带过,但须要作很多的工做。嗯,很明显,这是一道考算法逻辑还有 UI 的题目。git
如今咱们将主要工做放在如何去求出 A、B 两点的可行的路径呢?github
估计看到题目,不少人都会无从下手。但再认真想一想,其实这道题目就相似咱们平常用的导航,寻找起点和终点可行的最短路线。那么,咱们可使用搜寻算法解决这一道题目。搜寻算法有不少种,如:最佳优先搜索算法 (Best-First Search)、戴克斯特拉算法(Dijkstra)、A 搜寻算法和迭代加深 A 算法(IDA* )等等。web
先来了解一下 A* 搜寻算法:算法
A* 算法综合了 最佳优先搜索算法 (Best-First Search) 和 戴克斯特拉算法(Dijkstra)的优势:在进行启发式搜索提升算法效率的同时,能够保证找到一条最优路径(基于评估函数) 维基百科数组
A* 搜寻算法的估算函数:函数
f(n) = g(n) + h(n)
g(n) 表示起点到任意点 n 的距离,h(n) 表示任意点 n 到目标点的距离,f(n) 则表示任意点 n 到起点以及目标点的和。f(n) 越小时,那么起点到目标点的可行路径越小。post
接下来咱们使用图文来讲明一下咱们该如何计算:优化
咱们能够将全部格子看做一个二维数组,里面分为可行以及不可行(即障碍物)。咱们将起始点标记为 A 以及目标点(终点)标记为 B,此处咱们忽略可斜走的状况(由于须要作各类限制,略麻烦),本文 Open List
存放全部 A 附近可行的方格,Close List
存放已行的不须要再关注的方格。
(图一)
可见图一,起点 A 上下左右有四个方格,右边格子为障碍物,再次咱们则忽略它,那么起点 A 相邻可行的格子有上左下这三个。咱们设置一个 Open List
用于存放可行的方格,以及一个 Close List
用于记录已行方格。首先将起点 A 放进 Open List
中,而后搜寻起点 A 附近可行方格放到 Open List
中做记录。
从上面 A 搜寻算法的简单了解,咱们可知 A 搜寻算法的估算函数是:f(n) = g(n) + h(n)
。
A 相邻的长方形 f(n) 越小,则 A 到达 B 的可行路径最短,所以咱们须要选择最小 f(n) 的长方形行走。接下来看看咱们如何去计算 f(n) 的值。
为了方便计算,咱们将方格的长宽设置为 1 ,若是可斜走那么每个的斜线为 。固然为了方便计算可以使用长宽为 10,斜线为 14 的比例来计算。
(图二)
如图二,起点 A 有三块可行的方格,咱们标记为粉红色,那么首先咱们计算这三个方格的 g 值。起点 A 的上左下的方格分别离 A 点距离 g(n) 为 1 ,因此标记粉红色的上左下的方格 g(n) 值为 1。
那么接下来计算 h(n) 值,计算 h(n) 值时忽略障碍物,即全部方格可行的状况下计算(若是可行斜线状况下,那么在计算 h(n) 值的时候不计算斜走的状况,只计算任意点直行到终点距离)。那么可计算出起点 A 下方的方格 h(n) 等于 7,左方 h(n) 等于 9,上方 h(n) 等于 9。那么得出上左下三个方格的 f(n) 值:
起点 A 上方:f(n) = g(n) + h(n) = 1 + 9 = 10
起点 A 左方:f(n) = g(n) + h(n) = 1 + 9 = 10
起点 A 下方:f(n) = g(n) + h(n) = 1 + 7 = 8
由上面的计算可得出起点 A 下方的 f(n) 值为最小,那么咱们第一步走到起点 A 下方的方格。那么将起点 A 下方的方格存到 Close List
,且同时从 Open List
中移除。
(图三)
如图三,咱们走了第一步后 A 点去到了起点的下方一个,那个继续去计算,因为上面起点已经存在于 Close List
以及已存在于 Open List
的格子咱们不须要再关注,那么图上可看到 A 点接着可行点只有左右两点,那么计算 A 点到左边格子 g(n) 为 2,h(n) 为 8,右边格子 g(n) 为 2,h(n) 为 6。那么 A 点左边格子 f(n) 等于 10,右边格子 f(n) 等于 8,所以咱们第二步走 A 点右边格子,将格子从 Open List
移除,存进 Close List
(如图四)。
(图四)
以此类推,咱们最终可得出的路径(如图五)。
(图五)
如图五,绿色路径为可行的最短路径,红色标志的则是已存在于 Open List
的方格。
基本原理就是如此,代码我就不一一列出来,我会放到 Github 或者看看 Jsfiddle 上面,有兴趣的能够看一下,对应方法也有对应的注释。能够看一下最终实现的 效果
动画演示各类算法地址:http://www.webhek.com/post/pathfinding.html
新手一枚,若是有什么写错的或者很差的地方,请各位大大指点探讨一下,我会不断优化提高。
哦,最近本人在找工做,期待工做地区广州、深圳、佛山,若有好工做或者内推等能够私聊一下我。