Ошибка в алгоритме Negamax, связанная с оценочной функцией? Работает несколько раз, а не другие

Я пытаюсь разработать игру Tic-Tac-Toe с непревзойденным ИИ, и я нахожусь в точке, где моя функция negamax большую часть времени возвращает правильный результат. Однако иногда при определенных предсказуемых условиях компьютер выбирает движение доски, которое не имеет смысла и не может блокировать победу пользователя.

Основываясь на моих исследованиях, алгоритм negamax выглядит хорошо. Меня больше беспокоит, что в моей функции оценки может быть что-то не так; другими словами, в способе вычисления эвристического значения. Большая часть моей энергии была направлена ​​на борьбу с Негамаксом, поэтому другие функции были в основном запоздалыми.

Вот только один пример того, что я описываю:

// user: X, computer: O, turn: computer
// this scenario should return 1 to block user from [0, 1, 2]
// returns 5 when negamax called with compNum
// output is correct when negamax called with userNum (simulating user's turn)
var scenario01 = [
    userNum,    0,    userNum,
    userNum, compNum,    0,
    compNum,    0,       0
];

Столкнувшись с этим сценарием, вместо выбора квадрата 1 (верхняя середина: массив с нулевым индексом), чтобы заблокировать пользователя от достижения выигрыша, функция negamax выдает 5, квадрат, который не имеет непосредственного использования ни одному из игроков. Тем не менее, при тестировании, если я вызываю negamax по тому же сценарию с userNum в качестве аргумента, negamax выполняет свою работу и находит выигрышный квадрат 1 для пользователя.

Я знаю, что упускаю что-то обманчиво простое, и у меня есть ощущение, что это связано с тем, как я настроил userNum и compNum, и с тем, как они жестко запрограммированы. Возможно, я взял свои идеи Minimax и безуспешно перевел их на negamax, а это значит, что я не могу максимизировать ценность как для пользователя, так и для компьютера. Или я могу максимизировать с неправильной точки зрения игрока. Если бы кто-то любезно предоставил толчок в правильном направлении, я был бы благодарен.

Полная рабочая версия вместе с тестами доступна по адресу: https://repl.it/CnGD/4

Я не хотел размещать здесь огромную сумму, но я могу создать фрагмент на этом сайте, если потребуется.


Функция Негамакс

var negamax = (board, player, depth, lvl, α, β) => {
if ((board.getWinner(userNum, compNum) !== null) || depth >= lvl) {
    return board.getWinner(userNum, compNum);
    // also tried:  return board.score(depth) * player;
}
var highScore = -Infinity;
board.available().forEach(function (move) {
    board.mark(move, player);
    var score = -negamax(board, -player, depth + 1, lvl, -β, -α);
    board.undo(move);
    if (score > highScore) { // if better cell is found
        highScore = score; // note best score so far
        bestMove = move; // note best move so far
        α = Math.max(α, score);
        if (α >= β) { // alpha-beta pruning
            return bestMove;
        }
    }
});
return bestMove; };

Функция оценки

// these functions are part of a Board prototype
// I haven't included it all here, but will provide a link
getWinner: function (userNum, compNum) {
    return (
        this.validateWin(this.occupied(userNum)) ? userNum :
        this.validateWin(this.occupied(compNum)) ? compNum :
        this.matchAll(true) ? 0 :
        null
    );
},

score: function (depth) {
    if (board.getWinner(userNum, compNum) === userNum) {
        return depth - 10;
    } else if (board.getWinner(userNum, compNum) === compNum) {
        return 10 - depth; 
    } else {
        return 0;
    }
}

0 ответов

Другие вопросы по тегам