前言

之前写过一篇关于贪吃蛇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 不可行的情况下采用此策略,可是貌似不是目前的主要矛盾就放弃了(还有一部分原因是尝试了一下,没写出来。。。)

策略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时蛇的形态可能很特殊),所以可以多设置几种无聊必胜 策略,防止某一策略不可行

参考

AI贪吃蛇(二)的更多相关文章

  1. Python制作AI贪吃蛇

    前提:本文实现AI贪吃蛇自行对战,加上人机对战,文章末尾附上源代码以及各位大佬的链接,还有一些实现步骤,读者可再次基础上自行添加电脑VS电脑和玩家VS玩家(其实把人机对战写完,这2个都没什么了,思路都 ...

  2. AI贪吃蛇前瞻——基于Dijkstra算法的最短路径问题

    在贪吃蛇流程结构优化之后,我又不满足于亲自操刀控制这条蠢蠢的蛇,干脆就让它升级成AI,我来看程序自己玩,哈哈. 一.Dijkstra算法原理 作为一种广为人知的单源最短路径算法,Dijkstra用于求 ...

  3. Python制作AI贪吃蛇,很多很多细节、思路都写下来了!

    前提:本文实现AI贪吃蛇自行对战,加上人机对战,读者可再次基础上自行添加电脑VS电脑和玩家VS玩家(其实把人机对战写完,这2个都没什么了,思路都一样) 实现效果: 很多人学习python,不知道从何学 ...

  4. Python-pygame案例AI贪吃蛇

    # coding: utf-8 import pygame,sys,time,random from pygame.locals import * # 定义颜色变量 redColour = pygam ...

  5. C++ 贪吃蛇二维

    #include <iostream> #include <conio.h> #include <windows.h> #include <time.h> ...

  6. 数据结构算法C语言实现(九)--- 拓展:由迷宫问题引申的AI贪吃蛇

    一.简述 [开发中]由于期末时间有限,而且要用到后面的最短路径(可能),所以打算小学期在实现这一部分

  7. 浅析初等贪吃蛇AI算法

    作为小学期程序设计训练大作业的一部分,也是自己之前思考过的一个问题,终于利用小学期完成了贪吃蛇AI的一次尝试,下作一总结. 背景介绍: 首先,我针对贪吃蛇AI这一关键词在百度和google上尽心了检索 ...

  8. 如何用python制作贪吃蛇以及AI版贪吃蛇

    用python制作普通贪吃蛇 哈喽,大家不知道是上午好还是中午好还是下午好还是晚上好! 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很 ...

  9. 贪吃蛇AI

    贪吃蛇AI 作者:CodeNoob 转载请标明作者和出处 序言 前几天在网上看到一张让人涨姿势的图片,这张图片我很早以前看过,当时就觉得肯定是程序实现的,只是当时还比较渣,不会算法.这次学了java也 ...

随机推荐

  1. fillStyle径向渐变

    <!DOCTYPE HTML> <head> <meta charset = "utf-8"> <title>canvas</ ...

  2. iPhone 6 被盗记录二【写在315前夕:苹果售后福州直信创邺在没有三包的情况下帮小偷翻新、助力小偷换机销赃!无视王法。让人震惊,痛心,憎恨!消费者很受伤很无奈】

    投诉公司: 北京直信创邺数码科技有限公司  标题: 写在315前夕:苹果售后在没有三包的情况下帮小偷翻新.助力小偷换机销赃!无视王法.让人震惊,痛心,憎恨!消费者很受伤很无奈 期望: 还我手机,或者赔 ...

  3. C# Combobox 设置 value

    因为ComboxItem是Object对象,而控件自身没有Value属性.所以,需要自定义一个类,用其对象来存储Text,Value. public class ComboxItem    {     ...

  4. android 发送短信功能

    private void sendSMS(String num,String smsBody) { String phoneNum = "smsto:" + num; Uri sm ...

  5. 关于java中MessageFormat.format中单引号问题

    我们知道java中可以用MessageFormat.format来格式化字符串.这个方法在我们的实际开发中经常用到,有点类似模板,这样我们就不需要用很恶心的拼接字符串了.如下面 String s1=& ...

  6. 关于linx中man命令内容中第一行数字的含义

    我们知道linux中man这玩意特别厉害,我们要查么个命令的使用方法.如man ls 出现如下内容 关于这写数字的含义如下表格

  7. Fragment 与Activity

    一个Activity 对应 多个Fragment; 每一个类 extends Fragment , 一个Activity 可以同时显示多个 Fragment; Fragment是依赖于Activity ...

  8. Tomcat 启动花费很长时间的解决方案

    原始解决方案链接 将 $JAVA_PATH/jre/lib/security/java.security 中的 securerandom.source=file:/dev/urandom 替换为 se ...

  9. Eclipse debug断点调试代码时出现source not found问题

    偶尔调试代码的时候会出现这种事情,之前并没有特别注意,今天稍微搜集一下相关资料: 1.跳转到的代码的确没有源码,下载源码后选择源码位置后便会正常显示源码. 2.源码和class文件不一致.即便勾选了a ...

  10. 使用IntelliJ IDEA搭建多maven模块JAVA项目

    一.新建项目和模块 步骤: 1. 新建一个项目,因为maven管理jar包非常方便,故此处建立一个maven项目:New Project->Maven->(Create from arch ...