针对2048游戏,有人实现了一个AI程序,可以以较大概率(高于90%)赢得游戏,并且作者在

stackoverflow上简要介绍了AI的算法框架和实现思路。

有博客介绍了其中涉及的算法,讲的很好

其中算法的主要是在ai.js文件中。我加了很多的注释在其中,方便大家理解。

function AI(grid) {
this.grid = grid;
} // 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;
}; // alpha-beta depth first search
AI.prototype.search = function(depth, alpha, beta, positions, cutoffs) {
var bestScore;
var bestMove = -1;
var result; // the maxing player
if (this.grid.playerTurn) {
bestScore = alpha;
//遍历四个方向
for (var direction in [0, 1, 2, 3]) {
var newGrid = this.grid.clone();
//逐一搜寻方向
if (newGrid.move(direction).moved) {
positions++;
//如果已经赢了直接返回
if (newGrid.isWin()) {
return { move: direction, score: 10000, positions: positions, cutoffs: cutoffs };
}
//如果还没有赢得话就继续想下走
var newAI = new AI(newGrid);
//当深度为0的时候停止
if (depth == 0) {
result = { move: direction, score: newAI.eval() };
} else {//继承父节点的alpha
//递归的搜寻 注意每移动一次轮次翻转 player->computer->player->computer->....
result = newAI.search(depth-1, bestScore, beta, positions, cutoffs);
if (result.score > 9900) { // win
result.score--; // to slightly penalize higher depth from win
}
positions = result.positions;
cutoffs = result.cutoffs;
}
//如果返回的分数>当前最好分数则给bestScore和bestMove重新赋值
if (result.score > bestScore) {
bestScore = result.score;
bestMove = direction;
}
//如果最好的分数大于beta也即意味着上一层节点不会继续向下走 切分
if (bestScore > beta) {
cutoffs++
//既然不会往这儿走,那么分数还是你上层的beta return { move: bestMove, score: beta, positions: positions, cutoffs: cutoffs };
}
}
}
} else { // computer's turn, we'll do heavy pruning to keep the branching factor low
bestScore = beta; // 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();
//分数为2 或者 4
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);
//算出分数,下面的计算可以看出要算出分数最大的,我们知道min节点是使游戏变得更难
//那么smoothness要越小越好,所以加上符号(越大越好) islands意味着有数字的格子,当然越多越好
//通俗理解就是不能合并在一起的越多越好
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) } );
}
}
} // search on each candidate
for (var i=0; i<candidates.length; i++) {
var position = candidates[i].position;
var value = candidates[i].value;
var newGrid = this.grid.clone();
var tile = new Tile(position, value);
newGrid.insertTile(tile);
newGrid.playerTurn = true;
positions++;
newAI = new AI(newGrid);
//min节点往下的alpha还是上层的,beta是最好的分数,也就是说下层节点如果你取得的最大值只能是beta,
//如果大于beta我会把你pass掉
result = newAI.search(depth, alpha, bestScore, positions, cutoffs);
positions = result.positions;
cutoffs = result.cutoffs;
//竟然有比beta还小的分数,好,我选择你
if (result.score < bestScore) {
bestScore = result.score;
}
//如果最好的分数小于上层的下界 意味着上层节点肯定不会继续向下走
if (bestScore < alpha) {
cutoffs++;
//返回的分数是还是上层的值也就是说你反正不会走我这条路,那你的分数还是你原来的分数
//关于此处的move:null 注意上面的result的depth是继承父节点的,意味着depth>0
//也就是说最后一步必为max节点,min节点是不会有move操作的,所以直接返回null
return { move: null, score: alpha, positions: positions, cutoffs: cutoffs };
}
}
}
//计算到最好返回这些计算的值
return { move: bestMove, score: bestScore, positions: positions, cutoffs: cutoffs };
} // performs a search and returns the best move
AI.prototype.getBest = function() {
return this.iterativeDeep();
} // performs iterative deepening over the alpha-beta search
AI.prototype.iterativeDeep = function() {
var start = (new Date()).getTime();
var depth = 0;
var best;
//没有规定固定的depth 而是规定了计算时间,在规定时间内能计算到的深度
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
} AI.prototype.translate = function(move) {
return {
0: 'up',
1: 'right',
2: 'down',
3: 'left'
}[move];
}

以上就是根据我的理解所做的注释,供大家参考如果有错误请大家指正!

AI-2048 注释的更多相关文章

  1. 【数论 dp】2048

    考场上一个DFS优化乱加就对了一个无解的点 题目描述 给定一个长度为 n 的数列,在这个数列中选取一个子序列使得这个子序列中的数能合出2048 对于合并操作,可以选择这个序列中的任意两个数进行合并,当 ...

  2. bzoj 3851: 2048 dp优化

    3851: 2048 Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 22  Solved: 9[Submit][Status] Description T ...

  3. hdu 4945 2048 (dp+组合的数目)

    2048 Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submi ...

  4. 2018 AI产业界大盘点

    2018  AI产业界大盘点 大事件盘点 “ 1.24——Facebook人工智能部门负责人Yann LeCun宣布卸任 Facebook人工智能研究部门(FAIR)的负责人Yann LeCun宣布卸 ...

  5. 【cocos2d-x 手游研发----怪物智能AI】

    原创文章,转载请注明出处:http://www.cnblogs.com/zisou/p/cocos2d-xARPG4.html 谈到怪物AI,我觉得就比较话多了,首先理解一下(Artificial I ...

  6. 【noip模拟赛 sword,zero,2048】 题解

    1.光剑 (sword.pas/c/cpp) [题目描述] 小林和亮亮各有一把光剑,长度分别为 a 和 b,他们拿光剑进行比试.每一回合,长光剑会砍向短光剑,砍完后,短光剑完好无损,而长光剑则被截成两 ...

  7. Mysql启动失败 MYSQL:The server quit without updating PID file

    MySQL5.6启动时出错 提示MYSQL:The server quit without updating PID file 首先执行 /bin/mysqld_safe --user=mysql & ...

  8. unity3d 中文乱码解决方法——cs代码文件格式批量转化UTF8

    在Unity3d中经常会碰到中文乱码的问题,比如代码中的[AddComponentMenu("GameDef/AI/战机AI")],注释,中文文本等等 其原因在于,unity本身是 ...

  9. HDU 4945 (dp+组合数学)

    2048 Problem Description Teacher Mai is addicted to game 2048. But finally he finds it's too hard to ...

  10. 对弈类游戏的人工智能(5)--2048游戏AI的解读

    前言: 闲得没事, 网上搜"游戏AI", 看到一篇<<2048游戏的最佳算法是?来看看AI版作者的回答>>的文章. 而这篇文章刚好和之前讲的对弈类游戏AI对 ...

随机推荐

  1. Daily Life 01

    2019-03-03 我不擅于用文字记录自己的生活,因为很长时间一个人习惯了随意简单的生活,觉得很多事留给回忆就好,另一方面文笔不好,怕自己流出的文字不有趣,过于流水.有看过一些身边人写的随记,都有写 ...

  2. 在离线环境中安装Visual Stuido 2017

    在离线环境中安装Visual Stuido 2017 0x00 写在前面的废话 因为工作上大多数都是在离线环境中进行的,进出离线环境很麻烦,所以之前很长一段时间都在使用VS2010.后来尝试换了VS2 ...

  3. 【RL-TCPnet网络教程】第38章 TFTP简单文件传输基础知识

    第38章      TFTP简单文件传输基础知识 本章节为大家讲解TFTP(Trivial File Transfer Protocol,简单文件传输协议)的基础知识,方便后面章节的实战操作. (本章 ...

  4. 怎么用Mac电脑创建多个桌面

    区别于win的单个桌面,Mac电脑可以设置多个桌面,方面用户处理各种多乱杂的情况.究竟怎么用Mac电脑创建多个桌面呢?一起来看看吧! 1.首先打开Mission Control,点击偏好设置 2.然后 ...

  5. Solr 14 - SolrJ操作SolrCloud集群 (Solr的Java API)

    目录 1 pom.xml文件的配置 2 SolrJ操作SolrCloud 1 pom.xml文件的配置 项目的pom.xml依赖信息请参照: Solr 09 - SolrJ操作Solr单机服务 (So ...

  6. springboot~WebTestClient的使用

    在使用springboot进行开发时,单元测试是必要的,当你建立一个spring项目时,它会为我们自己生成一个测试项目,当你的项目开始过程中,测试用例是同时要进行的,我们在进行WEB层的集成测试时,可 ...

  7. Golang 入门 : 映射(map)

    映射是一种数据结构,用于存储一系列无序的键值对,它基于键来存储值.映射的特点是能够基于键快速检索数据.键就像是数组的索引一样,指向与键关联的值.与 C++.Java 等编程语言不同,在 Golang ...

  8. C++ 编程技巧笔记记录(持续更新)

    C++是博大精深的语言,特性复杂得跟北京二环一样,继承乱得跟乱伦似的. 不过它仍然是我最熟悉且必须用在游戏开发上的语言,这篇文章用于挑选出一些个人觉得重要的条款/经验/技巧进行记录总结. 文章最后列出 ...

  9. mysql索引规范

    索引并不是越多越好!索引可以提高查询效率,但会降低增删改效率.但多了甚至会降低查询效率. Innodb是按照主键索引的顺序来组织表,如没有建立主键,mysql会选择第一个非空唯一索引做为主键,或生成一 ...

  10. Java8内存模型—永久代(PermGen)和元空间(Metaspace)

    一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫“栈 ...