我正在尝试使用minimax算法在JavaScript中实现TicTacToe游戏。我不能为我的生活弄清楚我的代码有什么问题。调试递归函数很难: - /嗯,这是完整的代码,我觉得需要包含所有这些,包括GUI逻辑。其中一些有点乱,我没有正确抽象一切 - 但除了minimax功能以外的所有其他工作正常。
var cnv, ctx, x_spacing, y_spacing;
var board = [0,1,2,3,4,5,6,7,8];
var player = 'X', ai = 'O';
window.onload = function() {
cnv = document.getElementById("cnv");
ctx = cnv.getContext("2d");
x_spacing = cnv.width / 3;
y_spacing = cnv.height / 3;
drawGrid();
cnv.addEventListener("click", playerMove);
}
function drawGrid() {
ctx.lineWidth = 4;
ctx.strokeStyle = '#fff';
ctx.beginPath();
for (let i=1; i<3; i++) {
ctx.moveTo(i*x_spacing, 4);
ctx.lineTo(i*x_spacing, cnv.height-4);
ctx.moveTo(4, i*y_spacing);
ctx.lineTo(cnv.width-4, i*y_spacing);
}
ctx.stroke();
}
function playerMove(evt) {
var rect = cnv.getBoundingClientRect();
var x = Math.floor((evt.clientX - rect.left) / x_spacing);
var y = Math.floor((evt.clientY - rect.top) / y_spacing);
var spot = y*3 + x;
if (board[spot] === player || board[spot] === ai) return false;
board[spot] = 'X';
drawX(x,y);
var bestMove = minimax(board, 0, true);
board[bestMove.index] = 'O';
y = Math.floor(bestMove.index / 3);
x = bestMove.index % 3;
drawO(x,y);
}
function drawX(x, y) {
ctx.beginPath();
ctx.moveTo(x * x_spacing + 10, y * y_spacing + 10);
ctx.lineTo((x+1) * x_spacing - 10, (y+1) * y_spacing - 10);
ctx.moveTo(x * x_spacing + 10, (y+1) * y_spacing - 10);
ctx.lineTo((x+1) * x_spacing - 10, y * y_spacing + 10);
ctx.stroke();
}
function drawO(x, y) {
ctx.beginPath();
ctx.arc((x + 0.5) * x_spacing, (y + 0.5) * y_spacing,
(x_spacing/2)-10,0, 2*Math.PI);
ctx.stroke();
}
function getAvailSpots(board) {
return board.filter(spot => spot !== ai && spot !== player);
}
function minimax(board, depth, isMaximizer) {
if (checkIfWin(ai)) return { score: 10 - depth };
else if (checkIfWin(player)) return { score: depth -10 };
var availSpots = getAvailSpots(board);
if (!availSpots.length) return { score: 0 };
var bestScore = (isMaximizer) ? -Infinity : Infinity;
var bestMove;
availSpots.forEach(spot => {
// make move on board
board[spot] = (isMaximizer) ? ai : player;
var result = minimax(board, depth+1, !isMaximizer);
bestScore = (isMaximizer)
? Math.max(result.score, bestScore)
: Math.min(result.score, bestScore);
bestMove = { index: spot, score: bestScore }
// undo move on board
board[spot] = spot;
});
return bestMove;
}
function checkIfWin(p) {
if (
(board[0] == p && board[1] == p && board[2] == p) ||
(board[3] == p && board[4] == p && board[5] == p) ||
(board[6] == p && board[7] == p && board[8] == p) ||
(board[0] == p && board[3] == p && board[6] == p) ||
(board[1] == p && board[4] == p && board[7] == p) ||
(board[2] == p && board[5] == p && board[8] == p) ||
(board[0] == p && board[4] == p && board[8] == p) ||
(board[2] == p && board[4] == p && board[6] == p)
) return true;
return false;
}
问题是minimax选择了非常差的点并且我总是赢,这肯定不是目的 - 我试图实现无与伦比的TicTacToe AI!</ p>
答案 0 :(得分:0)
已解决!事实证明我的极小极大算法是错误的,因为它总是选择板上最后一个可用的位置。我忘记在存储最佳移动时添加一些条件逻辑,如下所示:
function minimax(board, depth, aiTurn) {
if (checkIfWin(ai)) return { score: 10 - depth };
else if (checkIfWin(player)) return { score: depth -10 };
var availSpots = getAvailSpots(board);
if (!availSpots.length) return { score: 0 };
var bestScore = (aiTurn) ? -Infinity : Infinity;
var bestMove;
availSpots.forEach(spot => {
// make move on board
board[spot] = (aiTurn) ? ai : player;
var result = minimax(board, depth+1, !aiTurn);
if (aiTurn) {
if (result.score > bestScore) {
bestScore = result.score;
bestMove = { index: spot, score: bestScore };
}
}
else {
if (result.score < bestScore) {
bestScore = result.score;
bestMove = { index: spot, score: bestScore };
}
}
board[spot] = spot;
});
return bestMove;
}