四年前曾经写过一过博客:

对 游戏 《 2048 》 的一些思考

虽然过去几年了,但是这个游戏一直没有搞懂该怎么使用AI算法来进行求解,这里再次对这个问题进行一些探索。

========================================

首先说明下,这个《2048》游戏确实很火,自己当年也是好一通研究,最后还是无疾而终,最近无意间又想起这个东西来了,正好这几年也是在从事AI方面的事情,想想自己这么长时间的一些积累或许可以再次尝试这个游戏的AI解决了。

这个《2048》游戏的AI解决难易适中,不想围棋那种需要Alpha go这种庞大的算法和计算平台要求,但是又不能依靠简单的遍历搜索来训练较好的解决方案,在一定level上来说这个游戏的难易度很适合个人AI玩家来尝试和练手的。

AI算法并不同于机器学习算法,应该说AI算法是包括机器学习算法的,或者说机器学习算法是AI算法的一个子集。只要可以替代人类脑力或体力去自动化解决问题的算法我们都可以认为是AI算法,也就是说AI算法就是可以模仿人类功能的计算机算法,而机器学习算法是指通过数据不断训练来使算法学习到适合的模型参数或模型结构的方法,机器学习主要体现在两个点:一个是原来训练和学习的数据;一个是可以根据数据来进行训练的学习,学习模型参数或模型结构。

外网对于《2048》游戏的AI解法早有讨论,比较有代表性的为:

What is the optimal algorithm for the game 2048?

其中,投票率最高的解决方法是启发式AI算法:

该启发式AI方法的github代码地址:

https://github.com/nneonneo/2048-ai

该代码clone在国内gitee代码库上:

https://gitee.com/devilmaycry812839668/highest_vote_2048_ai

=========================================================

我们这里主要是针对投票率最高的对应的启发式算法 鬼&泣 / 2048-ai 进行分析。

启发式算法,某种程度上我们可以将其理解为基于预设规则的算法。人类解决某件事情所采用的方法可以理解为人类的策略或规则,但是人类针对某件事情所采用的策略或规则很难翻译成计算机语言,那么如何把人类的策略翻译成计算机可以识别并执行的策略呢?根据计算机可以识别并执行的策略或规则所设计的算法我们一般叫做启发式算法。

在《2048》游戏中人类在打游戏时所采用的策略一般有:

参考:https://soft.zol.com.cn/jingyan/59663.html

高分法则:

最大数尽可能放在角落。

数字按顺序紧邻排列。

首先满足最大数和次大数在的那一列/行是满的。

时刻注意活动较大数(32以上)旁边要有相近的数。

以大数所在的一行为主要移动方向

不要急于“清理桌面”。

需要注意的是,为了保持最大数在角落,所有最大数可能移动的方向都不能再操作了,比如选择了左上角,那么就不能向右和向下移动其他的方块,这样操作的灵活性会相对减少,难度就会增加。这时,建议玩家除了选定一个角以外,再固定一条边,将大的数字放这条边上,这样就可以朝三个方向移动,比如选定左上角,填满最大数右边的所有方块,就可以朝上,左,右三个方向移动了。

经过分析可以知道在《2048》游戏中我们人类在操作时所遵循的规则一般有:保证最大的数字和第二大的数字在角落上不动,这边我们需要保证最大数字的一边被其他数字填满,这样的话保证最大数字不动的前提下可以有三个方向可以被用来操作。

根据 https://stackoverflow.com/questions/22342854/what-is-the-optimal-algorithm-for-the-game-2048 中最高投票率的回帖,我们需要遵守的规则还可以有:保证最大可能性有空格出现,最大可能性有一行或一列中有相同数字挨着的出现(可以在下一步中被合并),尽量保证每行或每列都是保证单调增或减的数字排列等。

可以看到人类的策略虽然人类用来理解还是可以的,但是如何翻译成计算机可以理解的语言呢,从而根据计算机可以理解的语言或规则编写出启发式算法呢。在  鬼&泣 / 2048-ai  中则把不同情况的游戏画面(数字排序顺序)根据刚才人类的评价和遵循规则给出评分,并根据某步操作后获得的后续操作得到的画面加权值最高(最高得分)来给出下一步的操作,该种方式所设计的启发式算法被证明可以有效的解决《2048》游戏。

============================================

下面给出在  鬼&泣 / 2048-ai   中对在Firefox浏览器下自动运行游戏《2048》。

具体见: https://gitee.com/devilmaycry812839668/highest_vote_2048_ai/tree/devilmaycry

在Firefox浏览器中自动运行游戏,其原理就是利用浏览器调试模式下可以自动运行传入的js脚本,从而实现在浏览器中调试js程序的目的。由于《2048》游戏一般均为js语言编写的,我们打开游戏的原始页面则会自动在浏览器中加载《2048》游戏的js代码,然后我们在Firefox浏览器开启调试模式情况下为该页面注入自己编写的js代码来实现获得《2048》游戏的状态信息和得分情况,同时我们还可以通过注入JS代码的方式模拟键盘操作来实现自动操控《2048》页面游戏的目的。

使用Firefox浏览器进行调试需要设置浏览器:

浏览地址框中输入 about:config

设置选项:

  • devtools.debugger.prompt-connection 为 false
  • devtools.debugger.remote-enabled 为 true
  • devtools.chrome.enabled 为 true

============================================

设置好Firefox后需要关闭浏览器。

再次打开Firefox需要采用运行命令行的方式启动Firefox:

firefox --start-debugger-server 32000

使用Firefox浏览器运行一次:

brower_autorun/2048_demo.py -b firefox
 

使用Firefox浏览器运行100次: (把100次的运行结果保存在调用命令执行的当前目录下的result.log)

brower_autorun/2048_100times_evalue.py -b firefox 
 

执行上面命令结果将被保存在highest_vote_2048_ai文件夹下面result.log文件中:

result.log 中保存的结果格式为:score, maxval, elapse_time, moveno
含义为:
得分,最大数,总运行时长(秒),总执行步数
 

=============================================

在  2048_100times_evalue.py 中:

如果返回的游戏状态字段为"ended",那么则意味则游戏是结束状态。

游戏表现形式为:

如果游戏状态为“ended”后需要调用  gamectrl.restart_game()  方法来获取新一局的游戏。

 
 
 

对于游戏状态为 “win”  时需要调用  gamectrl.continue_game() 方法,该方法的使用意义并不是很了解,因为是follow其他人的工作,所以也就这样承接下来这个操作了。

获取当前游戏的得分值:

获取当前游戏的状态值:

获得的board为16个元素的列表,每个元素取值范围为0~15,形式如:

[

[3,0,1,2],

[4,5,6,7],

[8,9,10,11],

[12,13,14,15],

]

如果进行状态打印的话我们需要把每个元素x 进行2**x 操作。

如果进行算法可以识别的形式,需要如下操作:

=============================================

在《2048》游戏中, 行为2 2 2 2,右移得 0 0 4 4, 再次右移得 0 0 0 8 。

=============================================

在maser分支中,编译代码( ubuntu系统中 ):

./configure

make

再探 游戏 《 2048 》 —— AI方法—— 缘起、缘灭(1) —— Firefox浏览器下自动运行游戏篇的更多相关文章

  1. 跟k8s工作负载Deployments的缘起缘灭

    跟k8s工作负载Deployments的缘起缘灭 考点之简单介绍一下什么是Deployments吧? 考点之怎么查看 Deployment 上线状态? 考点之集群中能不能设置多个Deployments ...

  2. 再探JS数组原生方法—没想到你是这样的数组

    最近作死又去做了一遍javascript-puzzlers上的44道变态题,这些题号称"JS语言专业八级"的水准,建议可以去试试,这里我不去解析这44道题了, ...

  3. Android 带你玩转实现游戏2048 其实2048只是个普通的控件(转)

    1.概述 博主本想踏入游戏开放行业,无奈水太深,不会游泳:于是乎,只能继续开发应用,但是原生Android也能开发游戏么,2048.像素鸟.别踩什么来着:今天给大家带来一篇2048的开发篇,别怕不分上 ...

  4. Android 带你玩转实现游戏2048 其实2048只是个普通的控件

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40020137,本文出自:[张鸿洋的博客] 1.概述 博主本想踏入游戏开放行业,无 ...

  5. 【再探backbone 02】集合-Collection

    前言 昨天我们一起学习了backbone的model,我个人对backbone的熟悉程度提高了,但是也发现一个严重的问题!!! 我平时压根没有用到model这块的东西,事实上我只用到了view,所以昨 ...

  6. 再探jQuery

    再探jQuery 前言:在使用jQuery的时候发现一些知识点记得并不牢固,因此希望通过总结知识点加深对jQuery的应用,也希望和各位博友共同分享. jQuery是一个JavaScript库,它极大 ...

  7. H5版俄罗斯方块(3)---游戏的AI算法

    前言: 算是"long long ago"的事了, 某著名互联网公司在我校举行了一次"lengend code"的比赛, 其中有一题就是"智能俄罗斯方 ...

  8. [老老实实学WCF] 第五篇 再探通信--ClientBase

    老老实实学WCF 第五篇 再探通信--ClientBase 在上一篇中,我们抛开了服务引用和元数据交换,在客户端中手动添加了元数据代码,并利用通道工厂ChannelFactory<>类创 ...

  9. Spark Streaming揭秘 Day7 再探Job Scheduler

    Spark Streaming揭秘 Day7 再探Job Scheduler 今天,我们对Job Scheduler再进一步深入一下,对一些更加细节的源码进行分析. Job Scheduler启动 在 ...

  10. Andorid游戏2048开发(一)

    最近有一款Android平台下的游戏很是火爆----2048.下面记录一下开发过程.由于笔者是Android开发的初学者,所以希望借以此文熟悉整个Android开发的流程. 首先创建Game2048的 ...

随机推荐

  1. ftl生成模板并从前台下载

    1.生成模板的工具类 package com.jesims.busfundcallnew.util; import freemarker.template.Configuration; import ...

  2. work08

    day09作业: 必做题:========================================第一题: 1.定义一个Animal类,包含如下行为: eat() 打印"要吃饭&qu ...

  3. jqurey基础知识和常用事件方法

    样式文件不需要<style>标签 引用style文件的方法 <link href="main.css" rel="stylesheet" st ...

  4. (四)Redis 缓存应用、淘汰机制

    1.缓存应用 一个系统中不同层面数据访问速度不一样,以计算机为例,CPU.内存和磁盘这三层的访问速度从几十 ns 到 100ns,再到几 ms,性能的差异很大,如果每次 CPU 处理数据时都要到磁盘读 ...

  5. K-means聚类是一种非常流行的聚类算法

    K-means聚类是一种非常流行的聚类算法,它的目标是将n个样本划分到k个簇中,使得每个样本属于与其最近的均值(即簇中心)对应的簇,从而使得簇内的方差最小化.K-means聚类算法简单.易于实现,并且 ...

  6. 16-Docker核心概念

    Docker镜像 Docker 镜像类似于操作系统镜像,可以将它理解为一个只读的模板. 例如,一个镜像可以包含一个基本的操作系统环境,里面仅安装了Apache应用程序,可以把它称为一个Apache镜像 ...

  7. UF_MB_ask_button_id 测试

    # tesy UF_MB_ask_button_id import NXOpen import NXOpen_UF as nuf def main(): ses = NXOpen.Session.Ge ...

  8. 拟合算法与matlab工具包实现

    与插值问题不同,在拟合问题中不需要曲线一定经过给定的点.拟合问题的目标是寻求一个函数(曲线),使得该曲线在某种准则下与所有的数据点最为接近,即曲线拟合的最好(最小化损失函数) 目录 一.插值和拟合的区 ...

  9. Spring5.X的bean的scope作用域

    scope属性 singleton:单例,默认值,调用getBean方法返回是同一个对象,实例会被缓存起来,效率比较高,当一个bean被标识为singleton时候,spring的IOC容器中只会存在 ...

  10. Java-Filter:过滤器请求拦截

    1.概念 web中的过滤器:当访问服务器资源时,过滤器可以将请求拦截下来,完成一些特殊的功能 过滤器的作用: 一般用于完成通用的操作,如:登录验证,统一编码处理,敏感字符过滤 2.快速入门 1.步骤 ...