作为小学期程序设计训练大作业的一部分,也是自己之前思考过的一个问题,终于利用小学期完成了贪吃蛇AI的一次尝试,下作一总结。
背景介绍:
首先,我针对贪吃蛇AI这一关键词在百度和google上尽心了检索,大致获得了一下信息
1、A*寻路算法是人工智能中的一个经典算法,很多AI利用这个算法提高性能。
2、在alphaGo一战成名,人工智能家喻户晓之后,有一个贪吃蛇AI吃满全屏的GIF图已读在微博疯转。
3、这个GIF图早在2013年就已经出现了(其实比alphaGo早)。
4、国内过于贪吃蛇AI(也就是百度得到的信息)的文章中比较有参考价值的只有两篇:如何用Python写一个贪吃蛇AI 以及 贪吃蛇 AI 的实现 snake AI。但感觉这两篇的算法还是很初级的,我认为不能保证每次都吃满全屏。
5、那张吃满全屏的GIF是一个俄罗斯人实现的(最后一段还出现了俄文),联想俄罗斯方块,大概俄罗斯程序员就喜欢写这些东西自娱自乐吧。
6、仔细观察那张GIF,可以断定绝对不是简单的盲目搜索算法,肯定使用了比较高级的AI算法(从蛇吃食物的路径可窥探一二)。
7、没有可以直接参考的代码,虽然有份python代码,但已经基本看不懂了。。。。
我的设计:
首先,我的出发点是希望尽可能利用数据结构课上学到的知识解决这个问题,所以我没用A*(运行之后的效率还是很可观的),更没用其他高级的AI算法。其次,我希望尽量把问题集中在算法设计上(后来证明这个想法还是很明智的),所以放弃了用Java的Swing以及Java2D做图形界面的打算,直接控制台编程,使用C/C++编写代码(后来证明这个想法太愚蠢了)。
这里直接写我的思路,如果看过上面两个链接的文章理解下面内容肯定更容易。如果没看,就记住两句话,蛇追着自己的尾巴走肯定就不会死,因为尾巴永远在留出空间。蛇每次只移动一步,因为局势时刻在变化。
首先,分析蛇的状态无非以下三种:
1、能吃食物,吃完食物后还能找到尾巴,这时候就直接去吃食物。
2、蛇不能吃食物,或者吃食物后找不到尾巴(找不到尾巴还去吃是不允许的,这回导致吃完后无路可走),这时候就跟着蛇尾巴走,走到能去吃食物为止(为什么能走到下面解释)。
3、在状态2的前提下,尾巴都找不到,这时候只能随便走一步了(Wander,其实wander策略时这类游戏很重要的一种思想,我也是看过一些书之后才明白)。
以上,也是我检索到的AI算法的核心部分,但是,在实践中,我发现很多细节这些文章都没有说清楚,实践起来是不允许有一点差错的,所以,结合自己的实践,对这几种情况做一下更详细的分析:
1、能吃食物,并且吃完之后能找到尾巴。这种情况只在蛇身较短的时候出现,而且这里吃完之后能找到尾巴,指的是沿最短路径去吃。或许,走最短路吃完食物找不到尾巴了,而走一条较长的路径能找到,但还是认为后一种不属于状态一,否则,编写代码将变得十分复杂。但是有时候,可能不止一个方向到食物的路径最短,这时候可以用类似蒙特卡洛法随机选择方向,可以提高吃完食物后找到尾巴的可能性,实践证明也确实如此。
2、追着尾巴走,也是又讲究的,首先,要保证走完这一步后还能继续找到尾巴,这是基本前提,其次,如果两个方向都能找到尾巴,应该选择离食物较远的方向(注意不是离食物较近或者离尾巴较近),应为只有这样,才能保证留出了足够空间给蛇去吃食物。
3、在我查阅的文章中Wander的策略都是比较简单的随机,但是,我觉得用DFS找出一条比较深的路,按这条路走比较好,但是注意不能贴着墙完全按最深路走,否则会导致蛇无法回头,像这样。
这样,这个算法就可以写成一下伪代码:
1 if 可以吃食物 2 if 虚拟蛇沿规则最短路吃食物后能找到尾巴 3 真实蛇移动一步 4 重新判断 5 else if 虚拟蛇沿不规则最短路去吃食物能找到尾巴 6 真实蛇移动一步 7 重新判断 8 else if 可知到达自己的尾巴并且移动一步已让可以到达自己尾巴 9 选择离食物最远的位置移动 10 重新判断 11 else 12 DFS向最深的路径移动一步
纸上得来终觉浅,理解这个算法最好的方式还是实践!实践之后才发现,吃满全屏并不是想象的那么容易,从博弈的角度来看,蛇的信息始终是不完全的,所以,必须有更优秀的算法,才能解决这一问题,除非到一定长度开始沿一条可以遍历所有位置的路径循环反复的绕,但这样太没意思了。记得貌似就有一个比赛是关于AI贪吃蛇的,但确实没检索到太多信息。希望以后还有机会研究出更优的算法。
demo: