【问题标题】:Minimax function for TicTacToe-game not working properly. I always winTicTacToe 游戏的 Minimax 功能无法正常工作。我总是赢
【发布时间】: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


【解决方案1】:

已解决! 结果我的极小极大算法有问题,因为它总是选择棋盘上最后一个可用的位置。在存储可能的最佳移动时,我忘记添加一些条件逻辑,如下所示:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    相关资源
    最近更新 更多