任何高于3x3的板上的超时错误(在3x3上正常工作)

时间:2019-05-28 16:35:18

标签: javascript timeout tic-tac-toe minimax

更新: 我发现当我的orgiBoard数组大于10时,如果超时错误为10或低,则一切正常。但是我不知道也不明白为什么会这样。有什么想法吗?

我正在使用JS编写带有minimax算法的tac-toe脚趾游戏。当用户在3x3板上对抗AI时,我设法做到了这一点。但是,当尝试在4x4或5x5上播放时,在无限循环情况下会发生超时错误,并使浏览器冻结。

如果有任何无限循环或类似问题,我已经检查了我的代码,但没有找到任何问题。也许我的方式是如何实现算法,对于任何大于3x3的板子,它都无法正常工作?

这是4x4电路板的逻辑:

document.getElementById("replay").addEventListener("click", startGame);

var orgiBoard;
var endFlag = false;
const humanPlayer = "O";
const ai = "X";
const winCombo = [
  [0, 1, 2, 3],
  [4, 5, 6, 7],
  [8, 9, 10, 11],
  [12, 13, 14, 15],
  [0, 4, 8, 12],
  [1, 5, 9, 13],
  [2, 6, 10, 14],
  [3, 7, 11, 15],
  [0, 5, 10, 15],
  [3, 6, 9, 12]
];

const cells = document.querySelectorAll(".cell");
startGame();

function startGame() {
  document.querySelector(".endgame").style.display = "none";
  endFlag = false;
  orgiBoard = Array.from(Array(16).keys());
  for (let i = 0; i < cells.length; i++) {
    cells[i].innerText = "";
    cells[i].style.removeProperty("background-color");
    cells[i].addEventListener("click", turnClick, false);
  }
}

function turnClick(square) {
  if (typeof orgiBoard[square.target.id] == "number") {
    turn(square.target.id, humanPlayer);
    if (!checkTie()) turn(bestSpot(), ai);
  }
}

function turn(squareId, player) {
  orgiBoard[squareId] = player;
  document.getElementById(squareId).innerText = player;
  let gameWon = checkWin(orgiBoard, player);
  if (gameWon) {
    gameOver(gameWon);
  } else {
    // this line is required only for 4x4 game mode becuase the AI is the last one who makes move if it comes to draw / tie
    checkTie();
  }
}

function checkWin(board, player) {
  let plays = board.reduce((a, e, i) => (e === player ? a.concat(i) : a), []);
  let gameWon = null;
  for (let [index, win] of winCombo.entries()) {
    if (win.every(elem => plays.indexOf(elem) > -1)) {
      gameWon = { index: index, player: player };
      break;
    }
  }
  return gameWon;
}

function gameOver(gameWon) {
  for (let index of winCombo[gameWon.index]) {
    document.getElementById(index).style.backgroundColor = "SkyBlue";
  }
  for (var i = 0; i < cells.length; i++) {
    cells[i].removeEventListener("click", turnClick, false);
  }
  endFlag = true;
  declareWinner(gameWon.player == humanPlayer ? "Player1 wins!" : "AI wins!");
}

function declareWinner(who) {
  document.querySelector(".endgame").style.display = "block";
  document.querySelector(".endgame .text").innerText = who;
}

function emptySquares() {
  return orgiBoard.filter(s => typeof s == "number");
}

function bestSpot() {
  // find best spot for AI player to play
  //return emptySquares()[0]; // returns 1st empty spot
  return minimax(orgiBoard, ai).index;
}

function checkTie() {
  if (endFlag) {
    return;
  } else if (emptySquares().length == 0) {
    for (let i = 0; i < cells.length; i++) {
      cells[i].style.backgroundColor = "YellowGreen";
      cells[i].removeEventListener("click", turnClick, false);
    }
    declareWinner("Game is draw");
    return true;
  }
  return false;
}

function minimax(newBoard, player) {
  var emptySpots = emptySquares();

  if (checkWin(newBoard, humanPlayer)) {
    return {score: -10};
  } else if (checkWin(newBoard, ai)) {
    return {score: 10};
  } else if (emptySpots.length === 0) {
    return {score: 0};
  }

  var moves = [];
  for (var i = 0; i < emptySpots.length; i++) {
    var move = {};
    move.index = newBoard[emptySpots[i]];
    newBoard[emptySpots[i]] = player;

    if (player == ai) {
      var result = minimax(newBoard, humanPlayer);
      move.score = result.score;
    } else {
      var result = minimax(newBoard, ai);
      move.score = result.score;
    }

    newBoard[emptySpots[i]] = move.index;

    moves.push(move);
  }
  var bestMove;
  if (player === ai) {
    var bestScore = -1000;
    for (var i = 0; i < moves.length; i++) {
      if (moves[i].score > bestScore) {
        bestScore = moves[i].score;
        bestMove = i;
      }
    }
  } else {
    var bestScore = 1000;
    for (var i = 0; i < moves.length; i++) {
      if (moves[i].score < bestScore) {
        bestScore = moves[i].score;
        bestMove = i;
      }
    }
  }
  return moves[bestMove];
}

期望AI:发挥最佳方式(在3x3上),不允许玩家获胜。 Acutal:大于3x3的任何板上的超时错误

0 个答案:

没有答案