《2048》游戏在线试玩地址:

https://play2048.co/

如何解决《2048》游戏源于外网的一个讨论帖子,而这个帖子则是讨论如何解决该游戏的最早开始,可谓是“缘起”:

What is the optimal algorithm for the game 2048?

关于该游戏的相关内容前面已经写过一些内容:

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

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

自己为游戏《2048》编写了python版本的运行环境,没多久就又发现网上有其他网友也写了Python版本的《2048》游戏环境,也是出于好奇,想着看看到底是自己写的版本性能更好还是网友写的更好,于是做了一下对比,结果虽然要自己汗颜但还是有所收获的。

网友的实现版本:

https://github.com/moporgic/2048-Demo-Python

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

我所实现的版本:

https://gitee.com/devilmaycry812839668/td-tuple-net-for-2048/tree/master/environ

其中,env_5bits_2048.py为单环境运行版本,env_vec.py为多环境矢量运行版本。

自己实现的这两个环境代码性能比网友的2048-Demo-Python要差上不止几倍速度。

为了更好的进行对比,又新开了一个代码库:

https://gitee.com/devilmaycry812839668/2048-Demo-Python

下面的讨论所用到的算法代码均在该代码库中。

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

在项目https://gitee.com/devilmaycry812839668/2048-Demo-Python中共有4个《2048》游戏环境的实现,分别为文件:

py2048.py

py2048_1.py

py2048_2.py

env_5bits_2048.py

除此之外,还有调用这四个实现进行测试的主文件为main.py。

说明一下,虽然自己也编写过多环境矢量运行的代码env_vec.py,但是在实际运行过程中发现该代码运行效率十分低,远远低于其他版本的实现,因此这里就没有在项目库中将其加入。

py2048.py代码为moporgic编写的原始环境,通过下面的运行测试可以知道其性能是最好的。该版本实现用python的list类型来表示棋盘状态,同时对每一次的移动和所获奖励都是事实计算的,并没有采用缓存的机制。

py2048_1.py代码为移动缓存表方法,其在py2048.py的基础上将所有可能存在的行的移动后状态和所获奖励使用缓存表保存了下来,每一次对棋盘进行移动时部队下次棋盘状态和奖励进行计算而是直接从内存中的缓存表中取出对应行移动后的行和奖励值。与py2048.py最大的不同就是该实现将棋盘变化后的行状态通过预计算的方法保存到了缓存表中,通过对缓存表中数据的读取减少了计算量。但是非常不幸的是通过下面的测试我们知道该种实现并不能提升性能,甚至该版本远不如py2048.py版本。

py2048_2.py代码为移动缓存表改进后的方法py2048_1.py对移动后的每行计算奖励后对其加和并减去惩罚值才可以得到真正的得分数,在py2048_1.py中每行在一次移动后需要两次循环遍历棋盘状态的各个行,以来读取缓存中移动后的行状态而奖励值,而在py2048_2.py中对移动后行状态及奖励的读取只需要在一次移动后遍历一次棋盘状态的各行即可,减少了对内存的读取。

env_5bits_2048.py 代码为个人设计的缓存表方法,该方法和py2048_1.py类似,都是在每次移动后对棋盘各行进行两次遍历,但与py2048_1.py最大的不同就是这里没有使用list类型来表示棋盘状态而是使用numpy.array,而这个方法也是性能最差的。
 
 
对于测试结果个人给出的解释(特指python语言中):
1. 对于计算量较小的操作,使用预计算的方式缓存起来并不划算,因为对内存读取是要耗费较大时间的,而这个时间有可能已经大于了CPU重新计算这个结果所需的时间;
2. 循环操作是比较耗时的,尤其是频繁的循环操作,如果能降低循环操作的次数(使用for遍历的次数)可以一定程度上减少运算时长;
3. 在数据量较小的情况下,对list类型数据进行按索引读取和相等比较操作的性能要远远优于numpy.array类型。
 
 

----------------------------------------------------

测试平台:

Ubuntu22.04系统,i7-10700k CPU 工作频率为5.0Ghz

性能测试:

moporgic原始环境万次游戏的平均用时: 73.3795, 总步数:26108430

移动缓存表方法万次游戏的平均用时: 132.7472, 总步数:26115191
移动缓存表改进后方法万次游戏的平均用时:115.6608, 总步数:26129569
个人设计的缓存表方法万次游戏的平均用时:342.4837, 总步数:25777707

-----------------------------------------------------------------------

再探 游戏 《 2048 》 —— AI方法—— 缘起、缘灭(6) —— Python版本实现的《2048》游戏环境运行性能对比的更多相关文章

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

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

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

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

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

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

  4. 再探jQuery

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

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

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

  6. Spark Streaming揭秘 Day7 再探Job Scheduler

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

  7. 第四节:SignalR灵魂所在Hub模型及再探聊天室样例

    一. 整体介绍 本节:开始介绍SignalR另外一种通讯模型Hub(中心模型,或者叫集线器模型),它是一种RPC模式,允许客户端和服务器端各自自定义方法并且相互调用,对开发者来说相当友好. 该节包括的 ...

  8. 深入出不来nodejs源码-内置模块引入再探

    我发现每次细看源码都能发现我之前写的一些东西是错误的,去改掉吧,又很不协调,不改吧,看着又脑阔疼…… 所以,这一节再探,是对之前一些说法的纠正,另外再缝缝补补一些新的内容. 错误在哪呢?在之前的初探中 ...

  9. 再探Redux Middleware

    前言 在初步了解Redux中间件演变过程之后,继续研究Redux如何将中间件结合.上次将中间件与redux硬结合在一起确实有些难看,现在就一起看看Redux如何加持中间件. 中间件执行过程 希望借助图 ...

  10. c++再探string之eager-copy、COW和SSO方案

    在牛客网上看到一题字符串拷贝相关的题目,深入挖掘了下才发现原来C++中string的实现还是有好几种优化方法的. 原始题目是这样的: 关于代码输出正确的结果是()(Linux g++ 环境下编译运行) ...

随机推荐

  1. 在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadLocal 事务控制)

    1. 在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadLocal 事务控制) @ 目录 1. 在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadL ...

  2. json字符串转换对象或列表,多了字段不会报错

    json字符串转换对象或列表,多了字段不会报错 //DEMO1 转换对象 应用 riskId public class Item { private String id; private String ...

  3. python重拾基础第二天

    本节内容 列表.元祖操作 字符串操作 字典操作 集合操作 文件操作 字符编码与转码 三元运算&生成式&成员运算&解压法&队列堆栈&数据类型转换 1. 列表操作 ...

  4. 韦东山freeRTOS系列教程之【第六章】信号量(semaphore)

    目录 系列教程总目录 概述 6.1 信号量的特性 6.1.1 信号量的常规操作 6.1.2 信号量跟队列的对比 6.1.3 两种信号量的对比 6.2 信号量函数 6.2.1 创建 6.2.2 删除 6 ...

  5. Java 表达式执行引擎 jexl

    介绍 JEXL的全称是Java表达式语言(Java Expression Language),简单的说,它可以配合我们的Java程序运算一些简单的表达式. 具体可以识别哪些表达式? 包含最基本的加减乘 ...

  6. 为什么springboot推荐使用Thymeleaf?

    前端那么多好的框架 为什么springboot推荐使用Thymeleaf? 前端框架和模板引擎不是一种东西: 模板引擎:Thymeleaf.freemarker.JSP. 前端框架:vue.angul ...

  7. Mysql 日期查询今天、昨天、近7天、近30天、本月、上一月、本季

    今天 select * from 表名 where to_days(时间字段名) = to_days(now()); 昨天 SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ...

  8. dubbo面试题及答案

    Dubbo是什么? Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架,现已成为 Apache 基金会孵化项目. 面试官问你如果这个都不清楚,那下面的就没必要问了. 官网:ht ...

  9. 【JavaScript】js中的浅拷贝与深拷贝与手写实现

    前言 什么是深拷贝与浅拷贝?深拷贝与浅拷贝是js中处理对象或数据复制操作的两种方式.‌在聊深浅拷贝之前咱得了解一下js中的两种数据类型: 基本数据类型(6种) String.Number.Object ...

  10. [oeasy]python0133_[趣味拓展]好玩的unicode字符_另类字符_上下颠倒英文字符

    另类字符 回忆上次内容 上次再次输出了大红心<span style="font-size:64px;color:red"></span> 找到了红心对应的编 ...