前言:
  闲得没事, 网上搜"游戏AI", 看到一篇<<2048游戏的最佳算法是?来看看AI版作者的回答>>的文章. 而这篇文章刚好和之前讲的对弈类游戏AI对应上. 于是有了想法, 想把它作为一个实例来进行解读, 从而对之前偏理论的文章做个总结.
  承接上四篇博文:
  (1). 评估函数+博弈树算法
  (2). 学习算法
  (3). 博弈树优化
  (4). 游戏AI的落地
  可能有些人会疑惑? 2048并非对弈类类型? 传统的博弈树模型是否能应用于此? 客官莫急, 让我们来一步步揭开谜底.

导读:
  本文是对<<2048游戏的最佳算法是?来看看AI版作者的回答>>文章, 以及原作者提供的AI代码进行解读的文章.
  如果有兴趣, 可点击试玩的游戏链接, 可查阅的源代码链接
  

建模:
  之前的对弈类游戏, 博弈双方的地位都是对等的. 但这边只有游戏者一人, 对手在哪里?
  让人脑洞大开的是, 2048游戏AI的设计者, 创造性把棋局环境本身做为了博弈的另一方.
  当然双方追求的胜利目标不一样:
  • 游戏者(AI): 追求2048及2048以上的方块出现
  • 棋局环境: 填满棋局格子, 使得4个方向皆不能移动
  游戏模型就演变成了信息完备的对弈问题. 而传统博弈树和技巧就自然有了用武之地.

评估函数:
  依据游戏经验, 作者选用了如下评估因素:
  (1) 单调性: 指方块从左到右、从上到下均遵从递增或递减.
  (2) 平滑性: 指每个方块与其直接相邻方块数值的差,其中差越小越平滑.
  (3) 空格数: 局面的空格总数.
  (4) 最大数: 当前局面的最大数字, 该特征为积极因子.
  采用线性函数, 并添加权重系数:

// static evaluation function
AI.prototype.eval = function() {
var emptyCells = this.grid.availableCells().length; var smoothWeight = 0.1,
//monoWeight = 0.0,
//islandWeight = 0.0,
mono2Weight = 1.0,
emptyWeight = 2.7,
maxWeight = 1.0; return this.grid.smoothness() * smoothWeight
//+ this.grid.monotonicity() * monoWeight
//- this.grid.islands() * islandWeight
+ this.grid.monotonicity2() * mono2Weight
+ Math.log(emptyCells) * emptyWeight
+ this.grid.maxValue() * maxWeight;
};

  评: 前3项能衡量一个局面的好坏, 而最大数该项, 则让游戏AI多了一点积极和"冒险". 权重系数设定和特征选择其实是个技术活, 作者在这有他的尝试和权衡.

博弈:
  游戏AI的决策过程, 是标准的maxmin search和alpha+beta pruning的实现. 所有的方向(上下左右)都会去尝试.
  然而在游戏本身做决策时, 不是每个空格都去尝试填{2, 4}. 而是选择了最坏的局面, 做为搜索分支的剪枝条件. 选择性地丢弃了很多搜索分支.

    // try a 2 and 4 in each cell and measure how annoying it is
// with metrics from eval
var candidates = [];
var cells = this.grid.availableCells();
var scores = { 2: [], 4: [] };
for (var value in scores) {
for (var i in cells) {
scores[value].push(null);
var cell = cells[i];
var tile = new Tile(cell, parseInt(value, 10));
this.grid.insertTile(tile);
scores[value][i] = -this.grid.smoothness() + this.grid.islands();
this.grid.removeTile(cell);
}
} // now just pick out the most annoying moves
var maxScore = Math.max(Math.max.apply(null, scores[2]), Math.max.apply(null, scores[4]));
for (var value in scores) { // 2 and 4
for (var i=0; i<scores[value].length; i++) {
if (scores[value][i] == maxScore) {
candidates.push( { position: cells[i], value: parseInt(value, 10) } );
}
}
}

  对于选择性忽略搜索节点, 其实很有争议. 在某些情况下, 会失去获取最优解的机会. 不过砍掉了很多分支后, 其搜索深度大大加强. 生存能力更强大.

迭代深搜:
  不同的javascript引擎其性能差异较大, 若需要限定时间搜索时. 这时迭代深搜就"粉墨登场"了.

// performs iterative deepening over the alpha-beta search
AI.prototype.iterativeDeep = function() {
var start = (new Date()).getTime();
var depth = 0;
var best;
do {
var newBest = this.search(depth, -10000, 10000, 0 ,0);
if (newBest.move == -1) {
break;
} else {
best = newBest;
}
depth++;
} while ( (new Date()).getTime() - start < minSearchTime);
return best
}

  超时判断在每个深度探索结束后进行, 这未必会精确, 甚至误差很大. 我还是推崇前文谈到过的实现方式.
  不管怎样, 作者基本达到了其每100ms决策一步的要求.

总结:
  前几篇博文涉及到很多点, 都在该2048游戏AI中有所体现. 2048游戏作为非典型的对弈类游戏, 本不太合适作为具体案例来讲解. 但对于原作者创造性的思维和建模, 我们作为后辈可以学到更多. 把环境拟人化的对弈模型, 也是面对反馈类场景的一种很好的评估决策思路.
  本文在编写前, 并没注意该博文<<2048 AI 程序算法分析>>的存在. 编写过程中, 借鉴了该文, 也添加了自己的一些认识.

写在最后:
  
如果你觉得这篇文章对你有帮助, 请小小打赏下. 其实我想试试, 看看写博客能否给自己带来一点小小的收益. 无论多少, 都是对楼主一种由衷的肯定.

  

对弈类游戏的人工智能(5)--2048游戏AI的解读的更多相关文章

  1. Cocos2d-x 3.x版2048游戏开发

    Cocos2d-x 3.x版2048游戏开发 本篇博客给大家介绍怎样高速开发2048这样一款休闲游戏,理解整个2048游戏的开发流程.从本篇博客你将能够学习到下面内容: 这里注明一下,本教程来自极客学 ...

  2. C++学习(三十九)(C语言部分)之 游戏项目(2048游戏)

    /***************************项目 2048**********************c语言编写 图形库制作时间:2019.04.03 准备工具: vs2013 图形库 i ...

  3. 对弈类游戏的人工智能(4)--游戏AI的落地

    前言: 对弈类游戏的智能算法, 网上资料颇多, 大同小异. 然而书上得来终觉浅, 绝知此事要躬行. 结合了自己的工程实践, 简单汇总整理下. 一方面是对当年的经典<<PC游戏编程(人机博弈 ...

  4. 2048游戏_QT实现

    #ifndef GAMEWIDGET_H #define GAMEWIDGET_H #include <QWidget> #include <QMouseEvent> #inc ...

  5. [python] python实现2048游戏,及代码解析。

    我初学python,有不对之处望大家指教.转载请征得同意. 我在网络上也找了一些2048游戏代码的讲解,但都不是特别详细.所以我希望能够尽量详细的讲解.同时,有的地方我也不懂,希望大家能帮助补充.我会 ...

  6. Android项目开发实战-2048游戏

    <2048>是一款比较流行的数字游戏,最早于2014年3月20日发行.原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台.这款游戏是基于&l ...

  7. 用Python做2048游戏 网易云课堂配套实验课。通过GUI来体验编程的乐趣。

    第1节 认识wxpython 第2节 画几个形状 第3节 再做个计算器 第4节 最后实现个2048游戏 实验1-认识wxpython 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiy ...

  8. android 2048游戏、kotlin应用、跑马灯、动画源码

    Android精选源码 2048游戏源码 android实现获取号码归属地和其他信息诈骗.骚扰 android kotlin仿开眼app源码 android多种reveal动画效果 android K ...

  9. Cocos2d-html5入门之2048游戏

    一.介绍 Cocos2d-JS是Cocos2d-x的Javascript版本,它的前身是Cocos2d-html5.在3.0版本以前叫做Cocos2d-html5,从3.0版本开始叫做Cocos2d- ...

随机推荐

  1. NRF52832学习笔记

    一.打印函数 printf("");用于在调试串口时在电脑端的串口调试工具上打印: 宏定义时每行后面的斜杠,在最后一行不加斜杠.

  2. [HIHO1079]离散化(线段树、染色)

    题目链接:http://hihocoder.com/problemset/problem/1079 MD坑爹,线段查询的时候左闭右开.插完挨个点找一遍扔set里,注意没染色的情况. #include ...

  3. js插入动态脚本

    原文章:https://www.w3cmm.com/dom/insert-javascript.html 动态脚本指的是在页面加载时不存在,但将来的某一时刻通过修改该DOM动态添加的脚本.和操作HTM ...

  4. 《BI那点儿事》数据流转换——OLE DB 命令转换

    OLE DB命令对数据流中的数据行执行一个OLE DB命令.它针对数据表中的每一行进行更新操作,可以事先将要更新的数据存放在表中.或者针对一个有输入参数的存储过程,可以将这些参数存放在一个数据表中,不 ...

  5. [bzoj2124]等差子序列(hash+树状数组)

    我又来更博啦     2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 941  Solved: 348[Submit][Statu ...

  6. Windows下面安装easy_install报UnicodeDecodeError: 'ascii' codec can't decode byte解决方法

    在运行python ez_setup.py install后, 发现是在下载并解压setuptools-2.1,并运行setup.py时出现如下错误: 提示D:\Python27\lib\mimety ...

  7. springMVC,mybatis配置事务

    首先应该对context:include-filter和context:exclude-filter有一个了解,include是包含这个,而不是只包含,下面会有例子看看: 这是我最开始配置的MVC的配 ...

  8. Unity中有两种Animation Clip

    http://blog.csdn.net/zzxiang1985/article/details/51291861 在Unity中,我们有两种方法创建Animation Clip. 一种(后面简称方法 ...

  9. stage3D之疑问

    1.stage3D本身是建立在图形API(如DirectX.Opengl等)之上的一套API,那么在创建stage3D demo时,如何指定使用哪种图形API呢?

  10. 加强型无穷集合:InfiniteList<T>,可指定遍历方向和偏移量,只要集合有元素并且偏移量不为 0,将永远遍历下去。

    主类: public class InfiniteList<T> : IEnumerable<T> { public List<T> SourceList { ge ...