代码之家  ›  专栏  ›  技术社区  ›  Rexam

如何提高chess.js的minimax性能?

  •  0
  • Rexam  · 技术社区  · 8 年前


    我尝试使用chess.js和chessboard.js编写一个国际象棋引擎,使用带有alpha beta修枝的minimax算法。问题是,算法需要很长的时间来执行所有评估并决定要进行的移动,即使 depth=3 . 我怎样才能提高性能?

    以下是我的minimax实现:

    var minimax = function (depth, game, alpha, beta, isAIplaying) {
    
      // end branch: simply evaluate and return the current score of the board
      if (depth === 0) {
        return evaluateBoard(game);
      }
    
      // list of all the possible moves in current status
      var newGameMoves = game.moves();
      if (isAIplaying) {
          var bestMove = -9999;
          for (var i = 0; i < newGameMoves.length; i++) {
              game.move(newGameMoves[i]);
              bestMove = Math.max(bestMove, minimax(depth - 1, game, !isAIplaying));
              game.undo();
              alpha = Math.max(alpha, bestMove);
              if (beta <= alpha) {
                return bestMove;
              }
          }
          return bestMove;
      } else {
          var bestMove = 9999;
          for (var i = 0; i < newGameMoves.length; i++) {
              game.move(newGameMoves[i]);
              bestMove = Math.min(bestMove, minimax(depth - 1, game, !isAIplaying));
              game.undo();
              beta = Math.min(beta, bestMove);
              if (beta <= alpha) {
               return bestMove;
              }
          }
          return bestMove;
      }
    };
    

    该函数是在以下代码中调用的,其中black必须决定要采取哪种措施:

    var possibleMoves = game.moves(); 
    
    // game over
    if (possibleMoves.length === 0) 
      return;
    
    var best_score = -9999;
    var bestMoveFound;
    
    for(var i=0; i<possibleMoves.length; ++i){
      game.move(possibleMoves[i]); // make one possible move
    
       // minimax: take the current status of the game
      // it is not Black's turn
      var score = minimax(3, game, -10000, 10000, false);
    
      // if I get a better score then I store it
      if(score >= best_score){
        best_score = score;
        bestMoveFound = i;
      }
    
      // undo move
      game.undo();
    }
    
    // make the best move (update both the game and the board on the screen)
    game.move(possibleMoves[bestMoveFound]);
    board.position(game.fen());
    

    其中,以下是评估功能:

    var evaluateBoard = function(current_game) {
        var status = current_game.fen();
    
        var score = 0;
    
        // calculate score for the current situation
        var fen_idx = 0;
        var piece = status[fen_idx];
        while(piece != ' '){
          switch(piece){
            case 'p': score += pawn; break;
            case 'n': score += knight; break;
            case 'b': score += bishop; break;
            case 'r': score += tower; break;
            case 'q': score += queen; break;
            case 'k': score += king; break;
            case 'P': score -= pawn; break;
            case 'N': score -= knight; break;
            case 'B': score -= bishop; break;
            case 'R': score -= tower; break;
            case 'Q': score -= queen; break;
            case 'K': score -= king; break;
            default: break;
          }
    
          ++fen_idx;
          piece = status[fen_idx];
        }
    
        return score;
    };
    

    pawn , bishop 其他的是简单的常量 p 表示一个黑色的兵 P 表示白色。你有什么办法可以提高成绩吗?

    1 回复  |  直到 8 年前
        1
  •  0
  •   TheSlater    8 年前

    评估fen字符串的想法看起来很快,但是您的程序必须为游戏树的每一个假期计算fen字符串。这真的很慢,因为它必须扫描电路板上的每一个数字,也必须扫描电路板上的每一个空的正方形,在64个正方形上形成一个循环。您不应该这样做,但要将板上的数字保留在一个列表中,以便计算与源代码的模拟量。

    如果在船上取下或替换一个零件,最好是有一个所有平和的和,只加上或减去一个值。因此,您的评估函数中没有计算,您的引擎将更快。根据我的经验,如果您的评估功能只是对双方工件值的比较,那么您应该在<2秒内达到深度7。

    推荐文章