Компьютер не проиграть в крестики-нолики

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

Я читал об алгоритме минимакса, но я его не понимаю. Как использовать этот алгоритм, чтобы компьютер мог выигрывать или рисовать, но никогда не проигрывать?

4 ответов


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

концептуальная реализация

таким образом, вы создаете ветвящуюся структуру:

  • ИИ возомнил себя делать каждый ход
  • AI их воображает, что пользователь делает каждый ход они могут сделать после каждого своего хода
  • тогда ИИ представляет каждый из своих следующих юридических шагов
  • etc.

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

фактической реализации

здесь этот подход хорошо работает с рекурсивной функцией. Каждый уровень функции опрашивает все свои ветви; передавая им возможное будущее и возвращает -1,0,+1; выбирая лучший результат для текущего игрока в каждой точке. Верхний уровень выбирает ход, на самом деле не зная, как каждое будущее проходит, насколько хорошо они получаются.

псевдо код

Я предполагаю, что в этом псевдо-коде +1-выигрыш AI, 0 - рисунка, -1 пользователь теряет

determineNextMove(currentStateOfBoard)
    currentBestMove= null
    currentBestScore= - veryLargeNumber

    for each legalMove
        score=getFutureScoreOfMove(stateOfBoardAfterLegalMove , AI’sMove)
        if score>currentBestScore
            currentBestMove=legalMove
            currentBestScore=score
        end
    end

    make currentBestMove

end

getFutureScoreOfMove(stateOfBoard, playersTurn)

    if no LegalMoves
       return 1 if AI wins, 0 if draw, -1 if user wins
    end


    if playersTurn=AI’sTurn
        currentBestScore= - veryLargeNumber //this is the worst case for AI
    else
        currentBestScore= + veryLargeNumber //this is the worst case for Player
    end

    for each legalMove
        score=getFutureScoreOfMove(stateOfBoardAfterLegalMove , INVERT playersTurn)
        if playersTurn ==AI’sTurn AND score>currentBestScore //AI wants positive score
           currentBestScore=score
        end
        if playersTurn ==Users’sTurn AND score<currentBestScore //user wants negative score
           currentBestScore=score
        end

     end

     return currentBestScore
end

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

соображения для больших проблем

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


я делал такую штуку лет 5 назад. Я сделал исследования. В tic tac toe Это не займет много времени, вам просто нужно подготовить шаблоны для первых двух или трех ходов.

нужно проверить как играть:

  1. компьютер начинается сначала.
  2. игрок начинает первым.

есть 9 различных стартовых позиций:

Start positions

но на самом деле только 3 из них отличаются (другие повернутый.) Поэтому после этого вы увидите, что нужно делать после некоторых конкретных ходов, я думаю, вам не нужны никакие алгоритмы в этом случае, потому что tic tac toe окончание определяется по первым шагам. Так что в этом случае вам понадобится несколько if-else или switch заявления и random генератор.


tic tac toe принадлежат к группе игр, которые не будут потеряны, если вы знаете, как играть, поэтому для таких игр вам не нужно использовать деревья и модифицированные алгоритмы сортировки. Написать такой алгоритм вам нужно всего несколько функций:

  1. CanIWin() чтобы проверить, если компьютер имеет 2 подряд и можно выиграть.
  2. ShouldIBlock() чтобы проверить, если игрок не имеет 2 в ряд и нужно заблокировать его.

эти две функции должны быть вызваны в этом порядке, если это возвращает true вам нужно либо выиграть, либо не позволить игроку выиграть.

после этого вам нужно сделать другие расчеты для перемещения.

одна исключительная ситуация, когда компьютер начинает игру. Вам нужно выбрать ячейку, которая принадлежит наибольшему количеству разных направлений (их 8 - 3 горизонтальных, вертикальных и 2 диагональных). В таком алгоритме компьютер всегда будет выбирать центр, потому что он имеет 4 направления, вы должны добавить небольшую возможность выбрать второй лучший возможность сделать игру немного более привлекательным.

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

после этого у вас будет несколько возможные ячейки, чтобы поставить свою метку. Поэтому вам нужно проверить последовательность необходимых ходов, потому что у вас будет несколько вариантов, и может быть, один из них приведет вас к потере. Так что после этого вы будете иметь набор, и вы можете случайным образом выбрать ход, или выбрать тот, с большим счетом.

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


сделайте вспомогательную программу для прогнозирования случаев, с которыми пользователь может выиграть. Затем вы можете сказать своему ИИ, чтобы сделать то, что пользователь должен сделать, чтобы выиграть.