极小极大算法的井字游戏

Tic tac toe with minimax algorithm

我对极小极大算法感到困惑。我已经花了 2 天,仍然找不到错误。你能看一下我的代码来帮助我找出任何错误吗?

export default class TicTacToeController {
  /*@ngInject*/
  constructor($scope) {
    this.board = new Array(3);

    this.players = {
      ai: "x",
      player: "o"
    };

    this.move = {
      row: "",
      cell: ""
    };

    this.currentPlayer = this.players.ai;
    this.humanMove = false;

    this.fillBoard();
    this.board[0][0] = "x";
    this.board[0][1] = "o";
    this.board[0][2] = "x";
    this.board[1][0] = "x";
    this.board[1][1] = "x";
    this.board[1][2] = "o";
    this.board[2][0] = "o";

    $scope.$watch("ticTac.currentPlayer", player => {
      if(player === this.players.player) {
        this.humanMove = true;
      } else {
        this.aiMove(this.board);
      }
    })

  }

  fillBoard() {
    for (var i = 0; i < 3; i++) {
      this.board[i] = new Array(3);

      for (var j = 0; j < 3; j++) {
        this.board[i][j] = " ";
      }
    }
  }

  evaluate(board) {
    //check rows
    for (var row = 0; row < 3; row++) {
      if (board[row][0] === board[row][1] && board[row][1] === board[row][2]) {
        if (board[row][0] === this.players.ai) {
          return 10;
        } else if (board[row][0] === this.players.player) {
          return -10;
        }
      }
    }

    //check columns
    for (var col = 0; col < 3; col++) {
      if (board[0][col] === board[1][col] && board[1][col] === board[2][col]) {
        if (board[0][col] === this.players.ai) {
          return 10;
        } else if (board[0][col] === this.players.player) {
          return -10;
        }
      }
    }

    //check for diagonals
    if (board[0][0] === board[1][1] && board[1][1] === board[2][2]) {
      if (board[0][0] === this.players.ai) {
        return 10;
      } else if (board[0][0] === this.players.player) {
        return -10;
      }
    }

    if (board[0][2] === board[1][1] && board[1][1] === board[2][0]) {
      if (board[0][2] === this.players.ai) {
        return 10;
      } else if (board[0][2] === this.players.player) {
        return -10;
      }
    }

    //if no player won return 0
    return 0;
  }

  minimax(board, isMax) {
    var score = this.evaluate(board);

    if (score === 10 || score === -10) {
      return score;
    }

    if(!this.isMoveLeft(board)) {
      return 0;
    }

    if (isMax) {

      var best = -1000;

      for (var i = 0; i < 3; i++) {
        for (var j = 0; j < 3; j++) {

          if (board[i][j] === " ") {
            board[i][j] = this.players.ai;

            best = Math.max(best, this.minimax(board, !isMax));

            board[i][j] = " ";
          }
        }
      }
      return best;

    } else {

      var best = 1000;

      for (var i = 0; i < 3; i++) {
        for (var j = 0; j < 3; j++) {

          if (board[i][j] === " ") {
            board[i][j] = this.players.player;

            best = Math.min(best, this.minimax(board, !isMax));

            board[i][j] = " ";
          }
        }
      }

      return best;
    }
  }

  isMoveLeft(board) {
    for (var i = 0; i < 3; i++) {
      for (var j = 0; j < 3; j++) {
        if (board[i][j] === " ")
          return true;
      }
    }
    return false;
  }

  makeBestMove(board) {
    var bestVal = -1000;

    this.move.row = -1;
    this.move.cell = -1;

    for(var i = 0; i < 3; i++) {
      for (var j = 0; j < 3; j++) {
        if(board[i][j] === " ") {
          board[i][j] === this.currentPlayer;

          var moveVal = this.minimax(board, false);

          board[i][j] === " ";

          if(moveVal > bestVal) {
            this.move.row = i;
            this.move.cell = j;
            bestVal = moveVal;
          }
        }
      }
    }

    return this.move;
  }

  aiMove(board) {
    var currentMove;

    if(!this.isMoveLeft(this.board)) {

      return;
    }

    currentMove = this.makeBestMove(board);
    board[currentMove.row][currentMove.cell] = this.currentPlayer;
    this.currentPlayer = this.players.player;
  }

  makeMove(row, cell) {

    if(this.board[row][cell] === " ") {
      this.board[row][cell] = this.players.player;
    }
    this.currentPlayer = this.players.ai;
  }
}

export default TicTacToeController;

启动板看起来是:

如你所见,下一个最佳着法应该是 (2,2),但是 minimax 算法将值设置为 (2,0)。

我试过调试,还是找不到错误。

在您的 makeBestMove 方法中,这些行:

board[i][j] === this.currentPlayer;
...
board[i][j] === " ";

应该使用赋值等于:

board[i][j] = this.currentPlayer;
...
board[i][j] = " ";

=== 是比较运算符。因此,您正在比较这些值并在不更改任何内容的情况下获得 true

目前,由于您没有在调用 minimax 之前进行赋值,因此每次都会返回相同的 best 结果。