惊了,用Python写了一个AI贪吃蛇,追着你跑的那种

else:

Wander一段时间

问题就出在蛇发现它自己和食物间有路径,就二话不说跑去吃食物了。它没有考虑到,你这一去把食物给吃了后形成的局势(蛇身布局), 完全就可能让你挂掉。(比如进入了一个自己蛇身围起来的封闭小空间)

so,为了能让蛇活得久一些,它还要更高瞻远瞩才行。

高瞻远瞩版本


我们现在已经有了一个比较低端的版本,而且对问题的认识也稍微深入了一些。现在可以进行一些比较慎密和严谨的分析了。首先,让我们罗列一些问题:(像头脑风暴那样,想到什么就写下来即可)

  • 蛇和食物间有路径直接就去吃,不可取。那该怎么办?

  • 如果蛇去吃食物后,布局是安全的,是否就直接去吃?(这样最优吗?)

  • 怎样定义布局是否安全?

  • 蛇和食物之间如果没有路径,怎么办?

  • 最短路径是否最优?(这个明显不是了)

  • 那么,如果布局安全的情况下,最短路径是否最优?

  • 除了最短路径,我们还可以怎么走?S形?最长?

  • 怎么应对蛇身越来越长这个问题?

  • 食物是随机出现的,有没可能出现无解的布局?

  • 暴力法(brute force)能否得到最优序列?(让贪吃蛇尽可能地多吃食物)

只要去想,问题还挺多的。这时让我们以面向过程的思想,带着上面的问题, 把思路理一理。一开始,蛇很短(初始化长度为1),它看到了一个食物, 使用BFS得到矩形中每个位置到达食物的最短路径长度。在没有蛇身阻挡下, 就是曼哈顿距离。然后,我要先判断一下,贪吃蛇这一去是否安全。所以我需要一条虚拟的蛇,它每次负责去探路。如果安全,才让真正的蛇去跑。当然,虚拟的蛇是不会绘制出来的,它只负责模拟探路。那么, 怎么定义一个布局是安全的呢?如果你把文章开头那张动态图片中蛇的销魂走位好好的看一下, 会发现即使到最后蛇身已经很长了,它仍然没事一般地走出了一条路。而且, 是跟着蛇尾走的!嗯,这个其实不难解释,蛇在运动的过程中,消耗蛇身, 蛇尾后面总是不断地出现新的空间。蛇短的时候还无所谓,当蛇一长, 就会发现,要想活下来,基本就只能追着蛇尾跑了。在追着蛇尾跑的过程中, 再去考虑能否安全地吃到食物。(下图是某次BFS后,得到的一个布局, 0代表食物,数字代表该位置到达食物的距离,+号代表蛇头,*号代表蛇身, -号代表蛇尾,#号代表空格,外面的一圈#号代表围墙)

1

2

3

4

5

6

7

# # # # #

0 1 2 3 4

1 2 3 # 5

2 3 4 - 6

3 + * * 7

4 5 6 7 8

# # # # #

经过上面的分析,我们可以将布局是否安全定义为蛇是否可以跟着蛇尾运动, 也就是蛇吃完食物后,蛇头和蛇尾间是否存在路径,如果存在,我就认为是安全的。

OK,继续。真蛇派出虚拟蛇去探路后,发现吃完食物后的布局是安全的。那么, 真蛇就直奔食物了。等等,这样的策略好吗?未必。因为蛇每运动一步, 布局就变化一次。布局一变就意味着可能存在更优解。比如因为蛇尾的消耗, 原本需要绕路才能吃到的食物,突然就出现在蛇眼前了。所以,真蛇走一步后, 更好的做法是,重新做BFS。然后和上面一样进行安全判断,然后再走。

接下来我们来考虑一下,如果蛇和食物之间不存在路径怎么办?上文其实已经提到了做法了,跟着蛇尾走。只要蛇和食物间不存在路径, 蛇就一直跟着蛇尾走。同样的,由于每走一步布局就会改变, 所以每走一步就重新做BFS得到最新布局。

好了,问题又来了。如果蛇和食物间不存在路径且蛇和蛇尾间也不存在路径, 怎么办?这个我是没办法了,选一步可行的路径来走就是了。还是一个道理, 每次只走一步,更新布局,然后再判断蛇和食物间是否有安全路径;没有的话,蛇头和蛇尾间是否存在路径;还没有,再挑一步可行的来走。

上面列的好几个问题里都涉及到蛇的行走策略,一般而言, 我们会让蛇每次都走最短路径。这是针对蛇去吃食物的时候, 可是蛇在追自己的尾巴的时候就不能这么考虑了。我们希望的是蛇头在追蛇尾的过程中, 尽可能地慢。这样蛇头和蛇尾间才能腾出更多的空间,空间多才有得发展。所以蛇的行走策略主要分为两种:

1

2

  1. 目标是食物时,走最短路径

  2. 目标是蛇尾时,走最长路径

那第三种情况呢?与食物和蛇尾都没路径存在的情况下, 这个时候本来就只是挑一步可行的步子来走,最短最长关系都不大了。至于人为地让蛇走S形,我觉得这不是什么好策略,最初版本中已经分析过它的问题了。(当然,除非你想使用最最无懈可击的那个版本,就是完全不管食物, 让蛇一直走S,然后在墙边留下一条过道即可。这样一来, 蛇总是可以完美地把所有食物吃完,然后占满整个空间,可是就很boring了。没有任何的意思)

上面还提到一个问题:因为食物是随机出现的,有没可能出现无解的局面?答案是:有。我运行了程序,然后把每一次布局都输出到log,发现会有这样的情况:

1

2

3

4

5

6

7

# # # # #

* * * * *

* * - 0 *

* * # + *

* * * * *

* * * * *

# # # # #

其中,+号是蛇头,-号是蛇尾,*号是蛇身,0是食物,#号代表空格,外面一圈# 号代表墙。这个布局上,食物已经在蛇头面前了,可是它能吃吗?不能!因为它吃完食物后,长度加1,蛇头就会把0的位置填上,布局就变成:

1

2

3

4

5

6

7

# # # # #

* * * * *

* * - + *

* * # * *

* * * * *

* * * * *

# # # # #

此时,由于蛇的长度加1,蛇尾没有动,而蛇头被自己围着,挂掉了。可是, 我们却还有一个空白的格子#没有填充。按照我们之前教给蛇的策略, 面对这种情况,蛇头就只会一直追着蛇尾跑,每当它和食物有路径时, 它让虚拟的蛇跑一遍发现,得到的新布局是不安全的,所以不会去吃食物, 而是选择继续追着蛇尾跑。然后它就这样一直跑,一直跑。死循环, 直到你按ESC键为止。

由于食物是随机出现的,所以有可能出现上面这种无解的布局。当然了, 你也可以得到完满的结局,贪吃蛇把整个矩形都填充满。

上面的最后一个问题,暴力法是否能得到最优序列。从上面的分析看来, 可以得到,但不能保证一定得到。

最后,看看高瞻远瞩的蛇是怎么跑的吧:

矩形大小10*20,除去外面的边框,也就是8*18。Linux下录完屏再转成GIF格式的图片, 优化前40多M,真心是没法和Windows的比。用下面的命令优化时, 有一种系统在用生命做优化的感觉:

1

convert output.gif -fuzz 10% -layers Optimize optimised.gif

最后还是拿到Windows下用AE,三下五除二用图片序列合成的动态图片 (记得要在format options里选looping,不然图片是不会循环播放的)

Last but not least


如果对源代码感兴趣,请戳链接:https://github.com/Hawstein/snake-ai

另外,本文的贪吃蛇程序使用了curses模块, 类Unix系统都默认安装的,使用Windows的童鞋需要安装一下这个模块, 送上地址: 需要curses请戳我

以上的代码仍然可以继续改进(现在加注释不到300行,优化一下可以更少), 也可用pygame或是pyglet库把界面做得更加漂亮,Enjoy!

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)

1282296f86381401c05e862fe4e9.png)

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)

img
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Snake-AI,这是一个用 C/C 语言编贪吃蛇游戏的人工智能。AI 的目的是让蛇尽可能的吃更多的食物,直到吃满整个地图。想参与这个项目,请查看todos。Demo使用方法编译与运行:$ make $ make run为了解详细使用方法, 请查看主函数main()算法介绍函数Snake.decideNext(): 计算蛇S1的下一个移动方向D计算从蛇S1的头部到达食物的最短路径P1。派一条与蛇S1完全一样的虚拟蛇S2沿路径P1吃掉食物。计算从蛇S2的头部到其尾部的最长路径P2。如果路径P2存在,将移动方向D设置为路径P1的第一个方向,否则进行步骤4。计算从蛇S1的头部到达其尾部的最长路径P3。如果P3存在,将移动方向D设置为路径P3的第一个方向,否则进行步骤5。将移动方向D设置为离食物最远的方向。函数Map.findMinPath(): 计算两个位置间的最短路径算法建立在BFS的基础上。为了使路径尽可能直,每次遍历邻接点时,在当前移动方向上的位置会被优先遍历。效果展示:(绿色区域为搜索算法扫描到的区域,红色区域为最后计算出的最短路径,每个位置上的数字表示了从起始位置开始到该位置的最短距离)函数Map.findMaxPath(): 计算两个位置间的最长路径算法建立在DFS与贪心算法的基础上。每次遍历邻接点时,离目标位置最远(使用曼哈顿距离估计)的位置将会被优先遍历到。另外,为了使路径尽可能直,如果两个位置到目标位置的距离相等,在当前移动方向上的位置将被优先遍历到。这个问题是一个NP完全问题,此算法得出的结果路径只是一个近似最长路径。效果展示:(绿色区域为搜索算法扫描到的区域,红色区域为最后计算出的最长路径,每个位置上的数字表示了从该位置开始到目标位置的估计距离) 标签:Snake
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值