寻路算法实例解析:贪吃蛇AI的实现
本文是寻路算法的实际应用篇,以贪吃蛇AI的实现为例进行详细解析。
1. 有趣的贪吃蛇示例
首先,我们来看一个在微博上很火的贪吃蛇动图。这次我们尝试用代码来模拟这个过程,说不定上面的动图就是计算机程序实现的。
2. 贪吃蛇移动的特点
在讲解贪吃蛇AI之前,我们先了解一下贪吃蛇移动的特点。从物理层面看,当贪吃蛇移动时,给人的感觉是整个蛇身向右移动了一步,尤其是在蛇身很长的情况下,感觉移动一步需要做很多操作。但在计算机中,我们可以简化这个过程。假设用一个数组来存储组成贪吃蛇的所有格子,那么移动一步的操作就是:将蛇即将到达的格子插入到数组的头部,然后移除数组的最后一个元素。通过这两个简单的操作,就完成了整条蛇的移动。在继续往下看之前,建议大家仔细思考一下这个移动过程。
此外,在实现贪吃蛇AI时,我们需要考虑一个关键问题:怎样保证贪吃蛇永远不死?我们知道,无论贪吃蛇往哪个方向前进一步,其尾巴所在的格子都会空出来。因此,让贪吃蛇追着自己的尾巴移动,就可以保证它永远不会死亡。
3. 寻路算法之A*算法
通常情况下,贪吃蛇需要找到一条最短路线去吃苹果,这时A寻路算法就可以发挥作用了。如果您对A算法还不了解,可以先阅读《Cocos2d - x寻路算法之三 A Star》这篇文章。在使用A*算法时,需要特别注意两个问题:
- 排除蛇身格子:整个蛇的身体所在的格子是不可接触的,在寻路时需要将这些格子排除掉。
- 动态寻路:由于贪吃蛇的移动是一个动态过程,每走一步都需要重新进行寻路,而不是一次寻路完成后就沿着该路线一直走。这是因为蛇尾巴的位置会不断空出来,导致地图状态发生变化。
4. 单纯使用寻路算法遇到的问题
4.1 进入死胡同
黄色代表贪吃蛇的头部,红色是要吃的目标。根据寻路算法得出的黑色路线是最短路线,但可以想象,按照这条路线吃完目标后,贪吃蛇就会陷入死路。
4.2 找不到路线
当贪吃蛇足够长时,苹果可能会出现在蛇身体包围的圈内。如图所示,黄色表示蛇头,此时蛇就无法找到到达苹果的路线。
4.3 最短路线留下过多空洞
观察下面的图,红色表示当前出现的苹果,橙色表示吃完红色苹果后苹果可能出现的位置。如果我们简单地采用最短路线去吃红色苹果(即无脑往左走),那么橙色苹果就会出现在蛇的包围圈中,后续要吃到这个苹果就会非常困难,需要走很多步。此时,更好的走法是尽可能多地绕圈,将空白区域填满,而不是单纯追求最短路线,要为后续的行动做好规划。
5. 贪吃蛇的最佳无脑模式
考虑到上述第4.3点的问题,我们会觉得实现贪吃蛇AI是一个颇具挑战性的问题,甚至可能涉及到“一笔画问题”。不过,通过多次玩贪吃蛇游戏,我们发现了一种“无脑模式”,可以填满整个游戏区域。具体策略是:在游戏区域的最后一行空出来,作为逃生路线,然后让蛇像弹簧一样无脑向右推进。吃完苹果后,从底部绕回最左边,继续采用这种策略,直到填满整个游戏区域。
6. 贪吃蛇AI的实现策略
在实现贪吃蛇AI之前,一定要先理解上述内容。我们知道,让蛇追着尾巴跑可以保证它不会死亡。因此,在以最短路线去吃苹果时,需要给自己留一条后路。具体策略如下:
策略1
如果吃完苹果后还能找到到达自己尾巴的路线,才去吃这个苹果。以下是对应的伪代码:
// 伪代码示例,具体实现需根据编程语言调整
if (canFindPathToTailAfterEatingApple()) {
eatApple();
}
策略2
如果找不到吃苹果的路线,或者吃完苹果后无法找到到达自己尾巴的路线,那么就在蛇头周围找一个格子。这个格子需要满足两个条件:
- 条件1:走完这个格子后能找到到达尾巴的路线。
- 条件2:这个格子到苹果的距离是最远的。
对于策略2中的条件1,由于我们的AI基础是基于策略1,所以肯定能够找到满足该条件的格子。策略2的伪代码如下:
// 伪代码示例,具体实现需根据编程语言调整
if (!canFindPathToApple() ||!canFindPathToTailAfterEatingApple()) {
Grid bestGrid = findBestGridAroundHead();
moveToGrid(bestGrid);
}
function findBestGridAroundHead() {
// 遍历蛇头周围的格子
// 筛选出能找到到尾巴路线的格子
// 选择到苹果距离最远的格子
// 返回该格子
}
需要注意的是,在策略2中,我们没有使用高深的算法,仅仅是将蛇往离苹果最远的格子移动。运行贪吃蛇程序后,我们会发现贪吃蛇AI可以正常工作了。这看似是在往远离目标的方向行动,但实际上蛇在绕圈的过程中,绕过了大部分身体,之后就可以使用策略1找到路线了。
然而,在观察贪吃蛇AI的移动过程中,不可避免地会出现第4.3点提到的问题,即后期留下太多空洞,贪吃蛇需要追随自己的尾巴移动很久才能吃到一个苹果。我们可以结合第5点提到的无脑模式,在游戏后期不再以最短路线去吃苹果,而是采用无脑绕圈的方式。我们发现,策略2中的条件2在后期会产生这种无脑绕圈的效果。当蛇的长度达到整个游戏格子数量的一半时,我们就认为进入了游戏后期。在后期,选择离苹果最远且能到达尾巴的格子移动,会无意中产生无脑绕圈的效果,就像围绕圆心(目标)不断接近一样。
7. 最终贪吃蛇AI效果图
(此处可插入最终贪吃蛇AI运行的效果图)
8. 贪吃蛇AI在线试玩地址
本贪吃蛇AI是用Cocos2d HTML5实现的,您可以通过以下链接进行在线试玩: