zoukankan      html  css  js  c++  java
  • JavaScript中国象棋程序(4)

    “JavaScript中国象棋程序” 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序。这是教程的第4节。

    程序的最终效果点击这里查看

    这一系列共有9个部分:

    0、JavaScript中国象棋程序(0)- 前言

    上一节的程序,电脑是在随机走棋,这样太没劲了。这一节我们的程序中加入极大极小搜索算法,这样程序会稍微有点智商。不过棋力不高,也就是普通小学生的水平吧。

    4.1、局面评估

    局面评估,就是判断局面对红方(或黑方)的优势,并把优势量化。棋子价值可用以下不等式表达:

    > 车 > 马、炮 > 仕、相 > 兵

    棋子价值可以简单量化为:

    10

    20

    20

    40

    45

    90

    1000

    但是棋子价值是跟位置有关系的,比如兵在过河前价值很小,过河后价值大涨。在我们的程序中,兵的位置价值数组如下:

    [	// 兵
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  9,  9,  9, 11, 13, 11,  9,  9,  9,  0,  0,  0,  0,
        0,  0,  0, 19, 24, 34, 42, 44, 42, 34, 24, 19,  0,  0,  0,  0,
        0,  0,  0, 19, 24, 32, 37, 37, 37, 32, 24, 19,  0,  0,  0,  0,
        0,  0,  0, 19, 23, 27, 29, 30, 29, 27, 23, 19,  0,  0,  0,  0,
        0,  0,  0, 14, 18, 20, 27, 29, 27, 20, 18, 14,  0,  0,  0,  0,
        0,  0,  0,  7,  0, 13,  0, 16,  0, 13,  0,  7,  0,  0,  0,  0,
        0,  0,  0,  7,  0,  7,  0, 15,  0,  7,  0,  7,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    ]
    

    在初始位置,中兵价值15,其他四个位置价值都是7。位于九宫的中心位置时,价值达到最高的44。这个数组肯定不是凭空想象出来的,应该是象棋百科全书网的前辈,经过无数次的试验得到的。

    帅的位置价值数组如下:

    [	// 帅
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0, 11, 15, 11,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    ]

    帅是无价的。没有了帅,游戏是要结束的。数组里的1、2、11、15仅仅表示了帅的位置分值,并不是说帅只值这个数。由于兵、帅的位置没有重合,这两个数组可以合并。

    如此一来,每种棋子就都会有一个与绝对位置相关的价值数组,因此我们的程序里有一个常量数组PIECE_VALUE[7][256]。该数组只提供了红方的位置分值。想获得黑方的位置分值,使用前面介绍过的函数SQUARE_FLIP(sq)翻转一下位置即可。此外,我们在Position对象中定义vlWhite和vlBlack两个属性,分别表示红方和黑方棋子价值。每次调用addPiece(sq, pc, bDel)增删棋子时,都会更新vlWhite和vlBlack。获取红方优势的局面评估函数:

    Position.prototype.evaluate = function() {
      var vl = this.vlWhite - this.vlBlack;
      return vl;
    }

    4.2、简单的两层搜索

     

    圆形节点为红方走棋的局面,方形节点为黑方走棋局面,红色数字为局面估值(也就是红方的优势)。深度优先遍历这个搜索树。

    1)、初始局面为A,该红方走棋。红方有B1、B2、B3三种走法。

    2)、假设红方选择第一种走法,走到了局面B1。

    3)、在局面B1,该黑方走棋。黑方有C1、C2、C3三种走法。

    4)、C1、C2、C3是叶子节点,调用局面评估函数,算得局面估值(也就是红方优势)分别是8、10、15。

    5)、回到局面B1,此时该黑方走棋。黑方后完后,红方优势越小,对黑方越有利。黑方自然会走到对自己最有利的C1局面。此时我们认为,B1局面的估值是8。

    6)、同样的方法,B2、B3的估值分别是5、10。

    7)、回到初始局面A,红方走棋。现在已经知道,选择第一种走法,最终估值为8;选择第二种走法,最终估值为5;选择第三种走法,最终估值为10。估值就是红方的优势,红方自然会选择对自己优势最大的走法,也就是走到局面B3。

    8)、可知行棋路线为A -> B3 -> C7。

    A点选择估值最大的局面,称为极大点;B1、B2、B3选择估值最小的局面,称为极小点。

    4.3、极大点搜索算法

    在程序中,定义一个全局变量,表示搜索深度:

    var MINMAXDEPTH = 3;

    也就是说,程序会搜索3层。当然你也可以改为4,这样电脑的棋力会更强。当搜索深度超过4时,电脑会走得很慢很慢。根节点的层次是MINMAXDEPTH,每往下搜索一层,层次减1。当层次为0时,不再向下搜索,而是调用评估函数计算估值。

    伪代码如下:

    // 极大点搜索
    Search.prototype.maxSearch = function(depth) {
      如果depth等于0,调用评估函数并返回分值
      
      var vlBest = 负无穷;			// 初始最优值
      var mvs = 当前局面全部走法;		// 生成当前局面的所有走法
      var value = 0;
      for (var i = 0; i < mvs.length; i ++) {
    	执行招法mvs[i]
    	调用极小点搜索算法,深度设为depth-1,并将返回值赋给value
    	撤销招法mvs[i]
    	
    	if (value > vlBest) {		// 寻找最大估值
    	  vlBest = value;
    	  if (depth == MINMAXDEPTH) {	// 如果回到了根节点,需要记录根节点的最佳走法
    	    记录根节点的最佳走法
    	  }
    	}	
      }  
      return vlBest;			// 返回当前节点的最优值
    }

    4.4、极小点搜索算法

    极小点搜索这与极大点搜索很相似,但有3处不同:

    1)、初始最优值为正无穷。

    2)、递归调用的是极大点搜索算法。(而极大点搜索算法会递归调用极小点搜索算法)

    3)、寻找的是最小估值。

    4.5、极大极小搜索算法

    if (该红方走棋) {

      调用极大点搜索算法,深度为MINMAXDEPTH

    } else {

      调用极小点搜索算法,深度为MINMAXDEPTH

    }

    4.6、核心代码说明

    本节的代码可以在 Github 下载,也可以直接clone

    git clone -b step-4 https://github.com/Royhoo/write-a-chinesechess-program

    Board中新增或修改的主要属性和方法:

    1)、result

    对局结果,有4种状态。

    0表示结果未知(正在战斗中,这有在这一状态下,程序才响应用户的点击事件)

    1表示你赢了(也就是电脑输了)

    2表示和棋

    3表示你输了(也就是电脑赢了)

    Position中新增或修改的主要属性和方法:

    1)、vlWhite

    红方所有棋子的价值

    2)、vlBlack

    黑方所有棋子的价值

    3)、addPiece(sq, pc, bDel)

    此方法增加了一项功能,就是在增减棋子时,更新vlWhite和vlBlack。

    4)、checked()

    判断老将是否被对方攻击。具有攻击性的棋子是车、马、炮、兵。我们要判断对方的这四类棋子是否攻击到了己方老将,以及是否将帅对脸。算法如下:

    1、假设帅(将)是车,判断它是否能吃到对方的车和将(帅)。如果能吃到对方的车,说明己方帅(将)被对方车攻击;如果能吃到将(帅),说明存在将帅对脸。

    2、假设帅(将)是炮,判断它是否能吃到对方的炮。

    3、假设帅(将)是马,判断它是否能吃到对方的马,需要注意的是,帅(将)的马腿用的数组是ADVISOR_DELTA,而不是KING_DELTA。

    4、假设帅(将)是过河的兵(卒),判断它是否能吃到对方的卒(兵)。

    5)、makeMove()

    改方法做了一些改进。如果移动棋子后,发现老将被对方攻击,也就是说这步棋是去送死的,那么就要撤销对棋子的移动,并返回false。

    Search中新增或修改的主要属性和方法:

    1)、mvResult

    这是搜索算法找到的最佳走法,随后电脑就会执行这步棋。

    2)、maxSearch()

    极大点搜索算法

    3)、minSearch()

    极小点搜索算法

    4)、maxMinSearch()

    极大极小搜索算法

  • 相关阅读:
    Android中Context具体解释 ---- 你所不知道的Context
    JDK6、Oracle11g、Weblogic10 For Linux64Bit安装部署说明
    matplotlib 可视化 —— 定制 matplotlib
    matplotlib 可视化 —— 移动坐标轴(中心位置)
    matplotlib 可视化 —— 移动坐标轴(中心位置)
    matplotlib 可视化 —— 定制画布风格 Customizing plots with style sheets(plt.style)
    matplotlib 可视化 —— 定制画布风格 Customizing plots with style sheets(plt.style)
    指数函数的研究
    指数函数的研究
    指数分布的研究
  • 原文地址:https://www.cnblogs.com/royhoo/p/6425658.html
Copyright © 2011-2022 走看看