AI贪吃蛇(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_26118459/article/details/52887277

前言

之前写过一篇关于贪吃蛇AI的博客,当时虽然取得了一些成果,但是也存在许多问题,所以最近又花了三天时间重新思考了一下。以下是之前博客存在的一些问题:

  • 策略不对,只要存在找不到尾巴的情况就可能失败,所以这次的AI能保证始终找到尾巴。
  • 编程思路不对,当时用C语言编写的,原有的游戏规则和AI部分有耦合,所以甚至出现了吃自己身体的状况,这是完全可以避免的。

以上两个问题是最主要的,其他地方也还是有可取之处的。下面是本次的成果。

思路

首先,我在网上找了一份贪吃蛇游戏的成品,然后在此代码的基础之上修改,添加一个AI,在每次游戏刷新时更新方向,这样,只要返回的方向错误,游戏一定会终止。同时,这种思路也比较符合实际:实际中我们玩贪吃蛇游戏其实就是通过键盘向游戏返回一个方向。现在不过是由AI负责返回方向。

AI算法

角度一:路径规划

这也是我本次采用的策略,如果看过上文提到的博客,就应该比较清楚,但是具体的策略有了变化,伪代码如下:

if (蛇身长度 > N && 策略1可行) {
    执行策略1;
} else if (策略2可行) {
    执行策略2;
} else if (策略3可行){
    执行策略三;
}

具体解释一下:策略1 是非常无聊的做法,如下图,只要这样走一定会赢,但是显然没有任何价值,所以 N 越大,AI就越强。

示意图

策略2 是游戏早期会采用的一种策略,即利用A*算法 去寻找最短路径,如果按照路径去吃食物后还能找到尾巴就可行。但是也存在一个问题:有时候A*算法是行不通的但是稍微绕点路可能就行了,对于这种情况,我本想再添加一种策略,即遍历出所有路径,然后在策略1 不可行的情况下采用此策略,可是貌似不是目前的主要矛盾就放弃了(还有一部分原因是尝试了一下,没写出来。。。)
A*
策略3 就是策略不可行的时候,采取的追尾策略,但是如何追,看到一些文章说朝离食物最远的方向,可是,我却遭遇了死循环:
死循环
最后,我采取的策略是选择合法的方向中,离尾巴最远(DFS距离)的那个方向。
可以看到,无论哪个策略,都是可控的,能找到尾巴的,这也是成功的关键。

角度二:博弈

这部分是我的一些思考,未实践探索。
其实,很多AI问题都可以用博弈的观点来解决,有些很明显:比如五子棋,围棋,有些则不那么明显:比如贪吃蛇。
如何用博弈的观点来看呢(描述可能不严谨):

  • 博弈双方甲、乙
  • 甲方选择一个空位置放置目标
  • 乙方在不撞墙、不撞自身的前提下,在有限步骤内乙方需要吃掉食物。
  • 如果乙方吃掉食物,身体长度加一(如何增加有多种方式,比如原代码是吃完增加,我更习惯吃的那一步发生增加)
  • 如果甲没有位置放置目标则甲输,如果乙撞墙、撞自己、不能在有限步内吃到目标,任何一种情况发生都算输。

从经典贪吃蛇游戏的规则来看,甲采取的肯定不是最优策略,因为都知道食物是随机放置的,乙是否存在最优呢(这个我还不敢多做评论)

以上是我的一些想法,下图是一副几年前很火的图,图片是处理过的,用了2min,实际用时是13min,从花费的时间来看,我觉得如果这是AI(这个GIF是如何做出来的目前还不清楚,并不一定是AI),那一定得是搜索了博弈树,路径规划花13min是不太可能的:
经典

代码概述

AI我是用JavaScript写的,才看了《JavaScript权威指南》前几章,写的很烂(这也是最后的AI中有一些“不可表述”的奇怪bug的原因),没必要细细分析,说一下大体框架:

aiSetDirection:  AI入口
aiSetSituation:  将目标位置等信息存储起来,方便AI使用
aiGetPrePath:    策略1,返回第一种策略可行时的方向
aiGetBestPath:    策略2,使用A*算法返回可行时方向
aiFollowTail:     策略3,追着尾巴跑
aiJudgePath:      判断路径是否可行,策略2传入数组,策略三传入的数组实际只有一个元素
aiDFSPath:        返回蛇头朝四个方向移动(策略3中)时尾巴的DFS深度
aiTurnToDirection:将路径(下一步)转换为方向

贪吃蛇游戏是否存在最优解

目前,我还不能做最终定论,原因有以下几点:

  • 目前自己掌握的资料有限,是否有同类问题的学术研究,又或者在哪已经彻底解决了这个问题(目前的倾向是不能保证100%取胜)。所以我觉得自己还需要寻找更多的资料,比如相关的AI比赛也是有的,我目前还没有了解。
  • 目前无论用哪种语言,我都没法随心所欲的驾驭,需要用到的几个关键算法及其变种同样也没法熟练的使用。
  • 形式化的研究还没有开始,至少目前我想,对于这个问题,我想的还不够抽象。

源代码和在线演示

源代码托管在GitHub上了,欢迎star&fork
在线演示(不能保证每次成功):AI-Snake
视频:优酷(标清);youtube(高清)

总结

花了三天吧,敲了很多垃圾代码。算法不熟练,代码不熟练。事先规划不充分。

可改进之处:

  • 可以在早期多按照预定路径走几次,这样可以有效消除空位置。即 身长>N 改为 身长>N || (身长>n1 && 身长<N1) || ... 可以视为一种调节机制
  • 预定的路径有多种,有时候上文提到的路径可能不行(因为到达N时蛇的形态可能很特殊),所以可以多设置几种无聊必胜 策略,防止某一策略不可行

参考

猜你喜欢

转载自blog.csdn.net/baidu_26118459/article/details/52887277