更新: 我发现当我的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的任何板上的超时错误