我如何使用 chess.js 节点模块实现 minimax

问题描述

我目前正在使用 chess.js、chessboard.js 和 minimax 算法创建一个国际象棋引擎。我最终想实现 alpha-beta,但现在,我只想让 minimax 工作。计算机好像在思考,但通常只做 Nc6。如果我将 pawn 移动到 d4,它通常需要骑士,但有时它只是在骑士打开的位置来回移动车。如果骑士没有什么可拿的,计算机就会移动车或其他一些毫无意义的移动。我最好的猜测是所有的移动都返回相同的估值,因此它只是在可能的移动数组中进行第一个移动,因此左上角的车是主要目标。我应该注意到,我的部分困惑与递归函数的工作方式有关,而且我在网上找到的关于递归函数的大部分内容都让我比刚开始时更加困惑。

我使用 Express.js 和 public/javascripts 中的 chessboard.js 配置作为包含在 index.ejs 文件夹中的 boardInit.js,当用户移动时,一个 Post 请求被发送到 /moveVsComp .它将它发送到服务器,在那里 /moveVsComp 的 app.post 函数告诉 chess.js 进行玩家所做的移动。

在玩家移动被记录后,计算机调用computerMoveBlack函数。

发布请求中的函数调用:

  let compMove = computerMoveBlack(3);
  game.load(currentFen)
  game.move(compMove)
  res.status(200).send({snapback: false,fen: game.fen()})

computerMoveBlack 函数:

function computerMoveBlack(depth) {
  let bestMove = ['',105];
  for (let move of game.moves()) {
    game.move(move)
    let value = minimax(move,depth-1,false)
    if (value < bestMove[1]) {
      bestMove = [move,value]
    }
    game.undo()
  }
  console.log(bestMove[0])
  return bestMove[0]
}

这个函数循环遍历所有的移动,我使用它是因为这似乎是保持最佳移动的最佳方式,而不仅仅是返回当前头寸的估值。

极小极大函数:

function minimax(node,depth,maximizingPlayer) {
  let value = maximizingPlayer ? -105 : 105
  if (depth === 0 || game.game_over()) return getValuation()
  if (maximizingPlayer) {
    for (let move of game.moves()) {
      game.move(move)
      value = Math.max(value,minimax(move,false))
      game.undo()
    }
    return value
  } else {
    for (let move of game.moves()) {
      game.move(move)
      value = Math.min(value,true))
      game.undo()
    }
    return value
  }
}

getValuation 函数:

function getValuation() {
  let evalString = game.fen().split(' ')[0];
  let score = 0;
  score += (evalString.split('r').length -1) * -5 || 0;
  score += (evalString.split('b').length -1) * -3 || 0;
  score += (evalString.split('n').length -1) * -3 || 0;
  score += (evalString.split('q').length -1) * -9 || 0;
  score += (evalString.split('p').length -1) * -1 || 0;
  score += (evalString.split('R').length -1) * 5 || 0;
  score += (evalString.split('N').length -1) * 3 || 0;
  score += (evalString.split('B').length -1) * 3 || 0;
  score += (evalString.split('Q').length -1) * 9 || 0;
  score += (evalString.split('P').length -1) || 0;
  return score;
}

我应该注意,我知道在此用例中使用 FEN 进行估值的速度非常慢,但我不确定什么是更好的替代方案。

就像对问题的回顾一样,我试图弄清楚为什么它每次都在数组中进行第一步,我的函数格式有什么问题,以及有什么更好的方法来获得仓位的估值与 FEN 的字符串操作相反。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)