Крестики-нолики: оценка эвристической ценности узла - PullRequest
0 голосов
/ 09 сентября 2018

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

Однако, я не понимаю, что когда Minimax используется напустая доска, возвращаемое значение всегда равно 0 (что имеет смысл, потому что игра всегда заканчивается ничьей, если оба игрока играют оптимально).

Таким образом, Minimax всегда выбирает первый тайл как лучший ход, когда AI равен X (поскольку все ходы возвращают 0 в качестве значения).То же самое происходит для второго хода, и он всегда выбирает второй тайл.Как я могу исправить эту проблему, чтобы мой ИИ выбирал ход с большей вероятностью выигрыша?Вот оценка и минимаксная функция, которую я использую (с альфа-бета-обрезкой):

int evaluate(char board[3][3], char AI)
{
for (int row = 0; row<3; row++)
{
    if (board[row][0] != '_' && board[row][0] == board[row][1] && board[row][1] == board[row][2])
    {
        if (board[row][0]==AI)
        {
            return +10;
        }
        else
        {
            return -10;
        }
    }
}

for (int col = 0; col<3; col++)
{
    if (board[0][col] != '_' && board[0][col] == board[1][col] && board[1][col] == board[2][col])
    {
        if (board[0][col]==AI)
        {
            return +10;
        }

        else
        {
            return -10;
        }
    }
}

if (board[1][1] != '_' && ((board[0][0]==board[1][1] && board[1][1]==board[2][2]) || (board[0][2]==board[1][1] && board[1][1]==board[2][0])))
{
    if (board[1][1]==AI)
    {
        return +10;
    }
    else
    {
        return -10;
    }
}

return 0;
}

int Minimax(char board[3][3], bool AITurn, char AI, char Player, int depth, int alpha, int beta)
{
bool breakout = false;
int score = evaluate(board, AI);

if(score == 10)
{
    return score - depth;
}
else if(score == -10)
{
    return score + depth;
}
else if(NoTilesEmpty(board))
{
    return 0;
}

if(AITurn == true)
{
    int bestvalue = -1024;
    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j<3; j++)
        {
            if(board[i][j] == '_')
            {
                board[i][j] = AI;
                bestvalue = max(bestvalue, Minimax(board, false, AI, Player, depth+1, alpha, beta));
                alpha = max(bestvalue, alpha);
                board[i][j] = '_';
                if(beta <= alpha)
                {
                    breakout = true;
                    break;
                }
            }
        }
        if(breakout == true)
        {
            break;
        }
    }
    return bestvalue;
}

else if(AITurn == false)
{
    int bestvalue = +1024;
    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j<3; j++)
        {
            if(board[i][j] == '_')
            {
                board[i][j] = Player;
                bestvalue = min(bestvalue, Minimax(board, true, AI, Player, depth+1, alpha, beta));
                beta = min(bestvalue, beta);
                board[i][j] = '_';
                if(beta <= alpha)
                {
                    breakout = true;
                    break;
                }
            }
        }
        if(breakout == true)
        {
            break;
        }
    }
    return bestvalue;
}
}

Ответы [ 2 ]

0 голосов
/ 09 сентября 2018

Организуйте свой код в меньшие подпрограммы, чтобы он выглядел аккуратнее и легче для отладки. Помимо рекурсивной минимаксной функции, очень важна функция генерации всех возможных действительных перемещений и надежная подпрограмма оценки (чего здесь не хватает).

Например, в начале игры алгоритм оценки должен возвращать ненулевой счет, каждая позиция должна иметь относительный индекс выигрыша (например, средняя позиция может иметь немного больший вес, чем углы).

Ваше минимаксное граничное условие - вернуть, если нет пустых позиций в ячейках; является ошибочным, поскольку он будет оценивать, даже если в предыдущем слое произошел ход победы / поражения. Такие условия будут ухудшаться в более сложных играх AI.

Если вы новичок в minimax, вы можете найти множество готовых для компиляции примеров кодов на CodeReview

0 голосов
/ 09 сентября 2018

Минимакс предполагает оптимальную игру, поэтому максимизация «вероятности выигрыша» не является осмысленным понятием: так как другой игрок может форсировать ничью, но не может форсировать победу, он всегда будет форсировать ничью.Если вы хотите играть оптимально против игрока, который не вполне рациональн (что, конечно, является одним из двух способов выиграть *), вам нужно будет предположить некоторое распределение вероятностей по ходам противника и использовать что-то вроде ExpectMinimax.где с некоторой вероятностью ход противника отменяется случайной ошибкой.В качестве альтернативы, вы можете сознательно ограничить слой минимаксного поиска, используя эвристику для игры противника за пределами определенной глубины (но все же ищите в игровом дереве свои собственные ходы).

* Другой способ - неиграть.

...