Tic tac toe with minimax算法

时间:2017-08-07 19:20:10

标签: javascript algorithm angular tic-tac-toe minimax

我对minimax算法很困惑。我花了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;

启动板看起来:

star board

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

enter image description here

我试图调试,但我仍然无法找到错误。

1 个答案:

答案 0 :(得分:3)

<html> <head> <title>Form</title> <meta charset="utf-8"> <script type="text/javascript"> function validateform(){ var age=parseInt(document.aform.age.value); var sex=document.aform.sex.value; if (last == ""){ alert("Last name can't be blank."); return false; } if (age < 18){ alert("You are not old enough to fill out the form.") return false; } if (sex == 'M' || sex == 'm' || sex == 'F' || sex == 'f'){ return true; } else{ alert("Please enter a valid gender"); return false; } } </script> <body> <form action="" method="post" name="aform"> <table> <tr> <td>Enter first name</td><td><input type="text" name="first" /></td></tr> <tr><td>Enter last name</td><td><input type="text" name="last" id="last" />*</td></tr> <tr><td>Enter your age</td><td><input type="text" name="age" id="age" size=5 />*</td></tr> <tr><td>Enter your sex</td><td><input type="text" name="sex" id="sex" size=2 />*</td></tr> <tr><td>Enter your favorite color</td><td><input type="text" name="color" /></td></tr> <tr><td><input type="button" value="Submit" onclick="validateform();" /></td></tr> </table> </form> </body> </html> 方法中,这些行:

makeBestMove

应使用赋值等于:

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

board[i][j] = this.currentPlayer; ... board[i][j] = " "; 是一个比较运算符。因此,您要比较值并获取===而不更改任何内容。

目前,由于您在调用true之前未进行任务,因此每次都会返回相同的minimax结果。