【更新】算法
稍微将A*算法进行修正,使用BFS(按F值对open表排序),另外,新增评估函数,用来测量当前点到终点的线段上的随机某一点是不是墙或已访问结点,是的话返回1,不然返回0。框架
function path_add_barrial_tracing(state, pt1, pt2) local xabs, yabs = math.abs(pt1.x - pt2.x), math.abs(pt1.y - pt2.y) if xabs == 0 or yabs == 0 then return 0 end local xr, yr = math.ceil(math.random(1,xabs)), math.ceil(math.random(1,yabs)) local v = path_get_point(state, {x= xr, y= yr}) if v ~= 1 then return 1 else return 0 end end
效果图:dom
-----------------------------------------------------函数
看到过相似的将寻路算法可视化的文章。spa
寻思着将它们整合进游戏框架,整体上说,整合难度比较低。.net
先前实现了TableLayout,设定长宽,能够均匀排布容器内各元素。题图中的方格也是这样的实现思路。code
只实现了广度遍历BFS和深度遍历DFS,二者是经典的遍历算法。blog
书上通常采用open和closed两个表的方式,这里为了图简单,就用一张表实现了。图的结构二维矩阵表示,1表示未访问过,三、4表示起点和终点,2表示墙,6及以上表示访问过。那么每次访问只要将矩阵中的值标记下便可。排序
两种算法只是对于表的添加方式不一样,DFS是添加到头部,BFS是添加到尾部。游戏
这里主要的难点在于,方块的颜色是渐变的,离起点(红色)近的呈黑色,远的呈天蓝色。计算方式是求任意点到起点的距离,而后根据HSL转换到RGB,HSL的色相是固定的,而亮度是能够调整的,从而实现渐变效果。
-------------------------------------------------
下面实现(伪)A*算法。
BFS和DFS方法都有缺点:BFS能找到全局最优,然而它须要将全部位置都访问一遍,耗时间;DFS快,但只是局部最优,且DFS如何挑选需展开的结点也没有明确规定。
A*对上述方式有了改进。A*给出了一个评估函数F。F=G+H。G是当前移动量,H是评估的待移动距离,二者总和是当前结节的评估值,固然,值越小,走这条路的可能性越大。
解决方法很简单:令G=累积的移动距离;令H=当前位置离终点的哈密顿距离。在展开结点的时候,对待选结点按F值排序,使F值最小的最早展开,从而节省时间。
A*的实现通常用open和closed表,它将open表中的结点按F排序,选代价最小的展开。也就是说,A*算法每一次将open表中的结点进行排序,而A*的展开方式相似于BFS。为何是基于BFS?由于BFS产生的open表结点是当前已遍历结点的轮廓,这有点像最小生成树算法,从当前轮廓中挑选代价最小的结点进行展开。惟一影响A*效率的就是F的计算方法。
PS:因为偷懒,实现A*与上面的不一样!上面是将open进行排序,而我只将当前结点的相邻结点进行排序,因此算法效果确定没A*好。再者,本系列的目标是作GUI,算法可视化只是一个demo。
A*算法的关键是设立一个评估函数,就如同阿法狗对局面的估计同样。它采用的其实相似于最小生成树的方式(把格子想成上下左右相连的图),只是最小生成树的挑选规则是肯定的(路径长度肯定),A*的挑选规则是不肯定的(评估函数不精准)。这致使最小生成树产生最优解,而A*不必定能获得最优解。