Автор оригинала: FreeCodeCamp Community Member.
Я боролся в течение часов прокручивания по учебникам, наблюдая за видео и стучаю головой на столом, пытаясь построить непобедимый Tic Tac Toe Goye с надежным искусственным интеллектом. Поэтому, если вы проходите подобное путешествие, я хотел бы представить вам алгоритм MiniMax.
Как и профессиональный шахматист, этот алгоритм впереди видит несколько шагов вперед и ставит себя в обувь своего противника. Он продолжает играть впереди, пока он не достигнет терминала договоренности о доске ( терминальное государство ), что приводит к тому, что галстук, выигрыш или потеря. Один раз в терминальном состоянии AI назначает произвольное положительное оценку (+10) для выигрыша, отрицательной оценки (-10) для потери или нейтральной оценки (0) для галстука.
В то же время алгоритм оценивает ходы, которые приводят к терминальному состоянию на основе поворота игроков. Он выберет ход с максимальной оценкой, когда он является поворотом AI и выберите движение с минимальным баллом, когда он является поворотом человека человека. Используя эту стратегию, MiniMax избегает потерять человека.
Попробуйте для себя в следующей игре предпочтительно, используя браузер Chrome.
Алгоритм MiniMax может быть лучше всего определить как рекурсивная функция, которая делает следующие вещи:
- Вернуть значение, если обнаружено состояние терминала (+10, 0, -10)
- пройти через доступные пятна на доске
- Вызовите функцию MiniMax на каждом доступном месте (рекурсия)
- Оценить возвратные значения из вызовов функций
- и вернуть лучшее значение
Если вы новичок в концепции рекурсии, я рекомендую смотреть это видео от Harvard’s CS50.
Чтобы полностью понять мыслительный процесс MiniMax, давайте реализуем его в коде и увидимся в действии в следующих двух разделах.
Минимакс в коде
Для этого учебника вы будете работать над ближним конечным состоянием игры, которая показана на рисунке 2 ниже. Поскольку MiniMax оценивает каждое состояние игры (сотни тысяч), ближнее конечное состояние позволяет следить за рекурсивными вызовами MiniMax проще (9).
Для следующего рисунка предположим, что AI IS X, а человека является O.
Чтобы работать с домом Ti Tac Toe еще легко, вы должны определить его как массив с 9 элементами. Каждый элемент будет иметь свой индекс в качестве значения. Это пригодится позже. Поскольку вышеупомянутая доска уже заполнена некоторыми ходами X и Y, давайте определим доску с ходами X и Y уже в нем ( оригинальная ).
var origBoard = ["O",1,"X","X",4,"X",6,"O","O"];
Тогда заявляйте AiPlayer и Huplayer Переменные и установите их на «X» и «O» соответственно Отказ
Кроме того, вам нужна функция, которая ищет выигрышные комбинации и возвращает True, если он найдет один, и функция, которая перечисляет индексы доступных пятен в доске.
/* the original board O | | X --------- X | | X --------- | O | O */ var origBoard = ["O",1 ,"X","X",4 ,"X", 6 ,"O","O"]; // human var huPlayer = "O"; // ai var aiPlayer = "X"; // returns list of the indexes of empty spots on the board function emptyIndexies(board){ return board.filter(s => s != "O" && s != "X"); } // winning combinations using the board indexies function winning(board, player){ if ( (board[0] == player && board[1] == player && board[2] == player) || (board[3] == player && board[4] == player && board[5] == player) || (board[6] == player && board[7] == player && board[8] == player) || (board[0] == player && board[3] == player && board[6] == player) || (board[1] == player && board[4] == player && board[7] == player) || (board[2] == player && board[5] == player && board[8] == player) || (board[0] == player && board[4] == player && board[8] == player) || (board[2] == player && board[4] == player && board[6] == player) ) { return true; } else { return false; } }
Теперь давайте погрузимся в хорошие части, определяя функцию MiniMax с двумя аргументами Newboard и Игрок Отказ Тогда вам нужно найти индексы доступных пятен в доске и установить их в переменной под названием Доступные пятна Отказ
// the main minimax function function minimax(newBoard, player){ //available spots var availSpots = emptyIndexies(newBoard);
Кроме того, вам нужно проверить состоянию терминала и возвращать значение соответственно. Если o выигрывает, вы должны вернуть -10, если X выигрывает, вы должны вернуть +10. Кроме того, если длина доступны Массив равен нулю, что означает, что для игры нет больше места, игра привела к галстуке, и вы должны вернуть ноль.
// checks for the terminal states such as win, lose, and tie //and returning a value accordingly if (winning(newBoard, huPlayer)){ return {score:-10}; } else if (winning(newBoard, aiPlayer)){ return {score:10}; } else if (availSpots.length === 0){ return {score:0}; }
Далее необходимо собирать оценки из каждого из пустых мест, чтобы оценить позже. Поэтому сделать массив под названием движется и петля через пустые пятна при сборе указателя каждого хода и оценка в объекте под названием Переместить Отказ
Затем установите номер индекса пустой пятно, который был сохранен в виде номеров в оригинальная к индексу свойства Переместить объект. Позже установите пустое место на Newboard к текущему плееру и позвоните в MiniMax Функция с другим игроком и вновь изменено Newboard Отказ Далее вы должны хранить объект, вызванный из MiniMax Функциональный вызов, который включает в себя Оценка Имущество для Оценка Собственность Переместить объект.
Наконец, MiniMax сбрасывает Newboard к чему это было раньше и толкает Переместить объект к движется множество.
// an array to collect all the objects var moves = []; // loop through available spots for (var i = 0; i < availSpots.length; i++){ //create an object for each and store the index of that spot var move = {}; move.index = newBoard[availSpots[i]]; // set the empty spot to the current player newBoard[availSpots[i]] = player; /*collect the score resulted from calling minimax on the opponent of the current player*/ if (player == aiPlayer){ var result = minimax(newBoard, huPlayer); move.score = result.score; } else{ var result = minimax(newBoard, aiPlayer); move.score = result.score; } // reset the spot to empty newBoard[availSpots[i]] = move.index; // push the object to the array moves.push(move); }
Затем алгоритм MiniMax должен оценить лучшее Переместить В движется множество. Это должно выбрать Переместить С наивысшим баллом, когда играет AI, и Переместить с самой низкой оценкой, когда играет человек. Поэтому, если Игрок это AiPlayer , он устанавливает переменную под названием Bestscore на очень низкое количество и петли через движется Массив, если Переместить имеет более высокий Оценка чем Bestscore алгоритм хранит, что Переместить Отказ В случае, если есть движения с аналогичным баллом, только первый будет сохранен.
Тот же процесс оценки происходит, когда Игрок это Huplayer , но на этот раз Bestscore будет установлен на высокое число, и MiniMax ищет движение с самым низким баллом для хранения.
В конце Minimax возвращает объект, хранящийся в BestMove Отказ
// if it is the computer's turn loop over the moves and choose the move with the highest score var bestMove; if(player === aiPlayer){ var bestScore = -10000; for(var i = 0; i < moves.length; i++){ if(moves[i].score > bestScore){ bestScore = moves[i].score; bestMove = i; } } }else{ // else loop over the moves and choose the move with the lowest score var bestScore = 10000; for(var i = 0; i < moves.length; i++){ if(moves[i].score < bestScore){ bestScore = moves[i].score; bestMove = i; } } } // return the chosen move (object) from the moves array return moves[bestMove]; }
В следующем разделе давайте перейдем на строку кода по строке, чтобы лучше понять, как ведет себя функцию MiniMax, учитывая плату, показанную на рисунке 2.
Минимакс в действии
Используя следующий рисунок, давайте следуем вызовам функции алгоритма ( FC ) один за другим.
Примечание. На рисунке 3 большое количество представляет собой каждую функцию вызова и уровни относятся к тому, сколько шагов впереди игры играет алгоритм.
1. оригинальная и AiPlayer подается в алгоритм. Алгоритм производит список трех пустых пятен, которые он находит, проверяет состояния клемма и циклы через каждое пустое место, начиная с первого. Тогда это меняет Newboard Размещая AiPlayer в первом пустом месте. После этого Это называет себя Newboard и Huplayer и ждет Fc, чтобы вернуть значение.
2. Хотя первый FC все еще работает, второй начнет, сделав список двух пустых пятен, которые он находит, проверяет состояния клемма и петли через пустое место, начиная с первого. Тогда это меняет Newboard Размещая Huplayer в первом пустом месте. После этого Это называет себя Newboard и AiPlayer и ждет Fc, чтобы вернуть значение.
3. Наконец, алгоритм производит список пустых пятен и находит победу для человека после проверки состояний терминала. Следовательно, он возвращает объект со средством оценки и стоимостью -10.
4. Алгоритм производит список пустых пятен и находит победу для человека после проверки состояний терминала. Следовательно, он возвращает объект со средством оценки и стоимостью -10.
5. На пятом ФК алгоритм производит список пустых пятен и находит победу для человека после проверки состояний терминала. Следовательно, он возвращает объект со средством оценки и стоимостью +10.
6. 6-й FC начинается, сделав список двух пустых пятен, которые он находит, проверяет состояния терминалов, а петли через две пустые пятна, начиная с первого. Тогда это меняет Newboard Размещая Huplayer в первом пустом месте. После этого Это называет себя Newboard и AiPlayer и ждет ФК, чтобы вернуть счет.
7. Теперь алгоритм на два уровня глубоко в рекурсии. Он делает список пустого пятна, которое он находит, проверяет состояния терминалов и меняет Newboard Размещая AiPlayer в пустом месте. После этого Это называет себя Newboard и Huplayer и ждет Fc, чтобы вернуть счет, чтобы он мог оценить его.
8. На 8-м ФК Алгоритм делает пустой список пустых пятен, и находит победу для AiPlayer После проверки состояний терминала. Следовательно, он возвращает объект с свойством оценки и стоимостью +10 одного уровня вверх (7-й ФК).
9. Далее алгоритм производит список пустых мест и находит победу для AiPlayer После проверки состояний терминала. Следовательно, он возвращает объект с счетными свойствами и значением +10.
В приведенном выше сценарии MiniMax завершается, что перемещение x до середины доски приводит к достижению наилучшего результата.:)
Конец!
К настоящему времени вы должны быть в состоянии понять логику позади алгоритма MiniMax. Используя эту логику, попробуйте реализовать алгоритм MiniMax самостоятельно или найти вышеуказанный образец на Github или Кодепен и оптимизировать его.
Спасибо за прочтение! Если вам понравилась эта история, не забудьте поделиться этим в социальных сетях.
Особые благодаря тупы Yilmaz, Рику Макгавину и Джавиду Аскерова для рассмотрения этой статьи.