Ошибка таймаута на любой плате выше 3х3 (на 3х3 работает плавно) - PullRequest
0 голосов
/ 28 мая 2019

ОБНОВЛЕНИЕ: Я обнаружил, что если мой массив orgiBoard больше 10, то возникает ошибка тайм-аута, если он равен 10 или низок, все в порядке.Однако я не знаю и не понимаю, почему это происходит.Есть идеи?

Я пишу тактическую игру с минимаксным алгоритмом с использованием JS.Мне удалось добраться до точки, когда пользователь играет против ИИ на доске 3х3.Однако при попытке воспроизведения на 4x4 или 5x5 возникает ошибка Timeout, как в случаях бесконечных циклов, и заставляет браузер зависать.

Я проверял свой код, если есть какой-либо бесконечный цикл или похожая проблема, но я не нашеллюбой.Может быть, мой способ реализации алгоритма - это работа, и для любой доски размером больше 3х3 он не будет работать?

Вот логика для доски 4х4:

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];
}

Ожидаемое значение для ИИ: игранаилучший возможный способ (это делается на 3х3), не позволяющий игроку выиграть.Acutal: ошибка тайм-аута на любой доске размером больше 3x3

...