Автор оригинала: 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, Рику Макгавину и Джавиду Аскерова для рассмотрения этой статьи.