【发布时间】:2018-02-15 19:57:33
【问题描述】:
我正在尝试使用极小极大算法在 JavaScript 中实现井字游戏。我一生都无法弄清楚我的代码有什么问题。调试递归函数太难了:-/ 好吧,这是完整的代码,我觉得有必要包含所有代码,包括 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 选择了非常差的位置,而我总是赢,这肯定不是目的——我试图实现一个无与伦比的井字游戏 AI!
【问题讨论】:
-
i spot !== ai -
赢了真好! :-)
-
您可能想回答自己的问题,而不是使用“已解决”标签编辑您的问题
-
好的,我是 Stackoverflow 的新手,我不知道。谢谢!
标签: javascript tic-tac-toe minimax