AI-2048 注释

针对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 注释的更多相关文章
- 【数论  dp】2048
		考场上一个DFS优化乱加就对了一个无解的点 题目描述 给定一个长度为 n 的数列,在这个数列中选取一个子序列使得这个子序列中的数能合出2048 对于合并操作,可以选择这个序列中的任意两个数进行合并,当 ... 
- bzoj 3851: 2048 dp优化
		3851: 2048 Time Limit: 2 Sec Memory Limit: 64 MBSubmit: 22 Solved: 9[Submit][Status] Description T ... 
- hdu  4945  2048  (dp+组合的数目)
		2048 Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submi ... 
- 2018 AI产业界大盘点
		2018 AI产业界大盘点 大事件盘点 “ 1.24——Facebook人工智能部门负责人Yann LeCun宣布卸任 Facebook人工智能研究部门(FAIR)的负责人Yann LeCun宣布卸 ... 
- 【cocos2d-x 手游研发----怪物智能AI】
		原创文章,转载请注明出处:http://www.cnblogs.com/zisou/p/cocos2d-xARPG4.html 谈到怪物AI,我觉得就比较话多了,首先理解一下(Artificial I ... 
- 【noip模拟赛 sword,zero,2048】 题解
		1.光剑 (sword.pas/c/cpp) [题目描述] 小林和亮亮各有一把光剑,长度分别为 a 和 b,他们拿光剑进行比试.每一回合,长光剑会砍向短光剑,砍完后,短光剑完好无损,而长光剑则被截成两 ... 
- Mysql启动失败 MYSQL:The server quit without updating PID file
		MySQL5.6启动时出错 提示MYSQL:The server quit without updating PID file 首先执行 /bin/mysqld_safe --user=mysql & ... 
- unity3d 中文乱码解决方法——cs代码文件格式批量转化UTF8
		在Unity3d中经常会碰到中文乱码的问题,比如代码中的[AddComponentMenu("GameDef/AI/战机AI")],注释,中文文本等等 其原因在于,unity本身是 ... 
- HDU 4945 (dp+组合数学)
		2048 Problem Description Teacher Mai is addicted to game 2048. But finally he finds it's too hard to ... 
- 对弈类游戏的人工智能(5)--2048游戏AI的解读
		前言: 闲得没事, 网上搜"游戏AI", 看到一篇<<2048游戏的最佳算法是?来看看AI版作者的回答>>的文章. 而这篇文章刚好和之前讲的对弈类游戏AI对 ... 
随机推荐
- Kafka系列2-producer和consumer报错
			1. 使用127.0.0.1启动生产和消费进程: 1)启动生产者进程: bin/kafka-console-producer.sh --broker-list 127.0.0.1:9092 --top ... 
- Linux 用户及权限详解
			Linux 用户及权限详解 用户 , 组 ,权限 安全上下文(secure context): 权限: r,w,x 文件: r : 可读,可以使用类似cat 等命令查看文件内容. w : 可写,可以编 ... 
- 常见的磁盘I/O和网络I/O优化技巧
			磁盘I/O 优化 性能检测 应用程序通过访问磁盘来读取数据,而磁盘I/O 通常都是很耗时间的,所以一般我们来判断I/O是否有瓶颈的时候,就需要一些参数指标来参考. WAIT 指标 :压测应用程序,查看 ... 
- Windows Server 2012 R2安装Oracle 11g问题
			1.[INS-13001]环境不满足最低要求 如图: oracle11g早于Windows Server 2012 R2 解决方法:找到解压目录../win64_11gR2_database\ ... 
- LOJ #6051. 「雅礼集训 2017 Day11」PATH
			完了感觉最近留了好多坑的说,这题也是模模糊糊地会一点 首先我们发现题目要求的是单调不上升的序列个数,那么一个套路就是用值减去下标 然后考虑连续位置的限制,这个我们做一个置换然后尽量向后取 这样拿值和位 ... 
- Cocoa包管理器之Carthage详解及CocoaPods中心化+Carthage的二进制化
			上篇博客详细的聊了CocoaPods的相关内容,今天我们就来介绍另一个Cocoa的包管理器Carthage.在上家公司用Swift开发工程时,用的就是Carthage.Carthage诞生于14年11 ... 
- 内核ring buffer -- kfifo
			目前kernel的kfifo根据版本有两种形式, 早期的函数形式和现在的宏定义形式 1. 早期的(linux-3.0.56/kernel/kfifo.c) 感兴趣读者可以自己看, 源码如下: /* * ... 
- js node.js 编写命令工具demo
			1 创建文件夹cli-demo 2 执行npm init 3 创建cli.js 文件 内容如下: //js文件变成可执行文件 #!/usr/bin/env node console.log(&quo ... 
- redis 初识
			架构 sharding redis 集群是主从式架构,数据分片是根据hash slot(哈希槽来分布) 总共有16384个哈希槽,所以理论上来说,集群的最大节点(master) 数量是16384个.一 ... 
- Java的数组,栈,队列
			import java.util.Arrays; public class Array<E> { private E[] data; private int size; //构造函数,传入 ... 
