Javascript 基于minimax算法的Tic-tac-toe

Javascript 基于minimax算法的Tic-tac-toe,javascript,algorithm,angular,tic-tac-toe,minimax,Javascript,Algorithm,Angular,Tic Tac Toe,Minimax,我对极大极小算法感到困惑。我已经花了两天时间,仍然找不到错误。你能看一下我的代码来帮我找到任何bug吗 export default class TicTacToeController { /*@ngInject*/ constructor($scope) { this.board = new Array(3); this.players = { ai: "x", player: "o" }; this.move = {

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

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;
导出默认类控制器{
/*@Nginect*/
构造函数($scope){
this.board=新阵列(3);
这是一个游戏玩家={
ai:“x”,
玩家:“o”
};
此.move={
行:“,
单元格:“
};
this.currentPlayer=this.players.ai;
this.humanMove=false;
这个.fillBoard();
此.board[0][0]=“x”;
此.board[0][1]=“o”;
此.board[0][2]=“x”;
此.board[1][0]=“x”;
此.board[1][1]=“x”;
此.board[1][2]=“o”;
此.board[2][0]=“o”;
$scope.$watch(“ticTac.currentPlayer”,player=>{
if(player==this.players.player){
this.humanMove=true;
}否则{
本.艾莫夫(本.董事会);
}
})
}
填充板(){
对于(变量i=0;i<3;i++){
此.board[i]=新阵列(3);
对于(var j=0;j<3;j++){
此.board[i][j]=“”;
}
}
}
评估(委员会){
//检查行
对于(变量行=0;行<3;行++){
如果(板[行][0]==板[行][1]&板[行][1]==板[行][2]){
if(board[row][0]==this.players.ai){
返回10;
}else if(board[row][0]==this.players.player){
返回-10;
}
}
}
//检查列
for(变量col=0;col<3;col++){
如果(单板[0][col]==单板[1][col]&&board[1][col]==单板[2][col]){
if(board[0][col]==this.players.ai){
返回10;
}else if(棋盘[0][col]==this.players.player){
返回-10;
}
}
}
//检查对角线
如果(单板[0][0]==单板[1][1]&&单板[1][1]==单板[2][2]){
if(board[0][0]==this.players.ai){
返回10;
}else if(棋盘[0][0]==this.players.player){
返回-10;
}
}
如果(单板[0][2]==单板[1][1]&单板[1][1]==单板[2][0]){
if(board[0][2]==this.players.ai){
返回10;
}else if(棋盘[0][2]==this.players.player){
返回-10;
}
}
//如果没有玩家赢了,返回0
返回0;
}
极小极大(单板,isMax){
var得分=本次评估(董事会);
如果(分数===10 | |分数===-10){
返回分数;
}
如果(!this.isMoveLeft(板)){
返回0;
}
if(isMax){
var-best=-1000;
对于(变量i=0;i<3;i++){
对于(var j=0;j<3;j++){
如果(板[i][j]=“”){
board[i][j]=this.players.ai;
best=Math.max(best,this.minimax(board,!isMax));
董事会[i][j]=”;
}
}
}
回报最好;
}否则{
var最佳值=1000;
对于(变量i=0;i<3;i++){
对于(var j=0;j<3;j++){
如果(板[i][j]=“”){
board[i][j]=this.players.player;
best=Math.min(best,this.minimax(board,!isMax));
董事会[i][j]=”;
}
}
}
回报最好;
}
}
isMoveLeft(板){
对于(变量i=0;i<3;i++){
对于(var j=0;j<3;j++){
如果(板[i][j]=“”)
返回true;
}
}
返回false;
}
makeBestMove(板){
var-bestVal=-1000;
this.move.row=-1;
this.move.cell=-1;
对于(变量i=0;i<3;i++){
对于(var j=0;j<3;j++){
如果(板[i][j]=“”){
板[i][j]==此.currentPlayer;
var moveVal=此.minimax(板,假);
板[i][j]=”;
如果(移动值>最佳值){
this.move.row=i;
this.move.cell=j;
bestVal=moveVal;
}
}
}
}
把这个还给我;
}
艾莫夫(董事会){
var-currentMove;
如果(!this.isMoveLeft(this.board)){
返回;
}
currentMove=此.makeBestMove(板);
线路板[currentMove.row][currentMove.cell]=此.currentPlayer;
this.currentPlayer=this.players.player;
}
makeMove(行、单元格){
if(此.board[行][单元格]==“”){
this.board[行][单元格]=this.players.player;
}
this.currentPlayer=this.players.ai;
}
}
导出默认控制器;
启动板看起来:

正如您所看到的,下一个最佳移动应该是(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
结果