Рубрики
Без рубрики

Как сделать свою игру Tic Tac Toe непобедим, используя алгоритм MiniMax

Я боролся в течение часов прокручивания по учебникам, наблюдая за видео и стучаю головой на столом, пытаясь построить непобедимый Tic Tac Toe Goye с надежным искусственным интеллектом. Поэтому, если вы проходите подобное путешествие, я хотел бы представить вам алгоритм MiniMax. Нравиться

Автор оригинала: FreeCodeCamp Community Member.

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

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

В то же время алгоритм оценивает ходы, которые приводят к терминальному состоянию на основе поворота игроков. Он выберет ход с максимальной оценкой, когда он является поворотом AI и выберите движение с минимальным баллом, когда он является поворотом человека человека. Используя эту стратегию, MiniMax избегает потерять человека.

Попробуйте для себя в следующей игре предпочтительно, используя браузер Chrome.

Алгоритм MiniMax может быть лучше всего определить как рекурсивная функция, которая делает следующие вещи:

  1. Вернуть значение, если обнаружено состояние терминала (+10, 0, -10)
  2. пройти через доступные пятна на доске
  3. Вызовите функцию MiniMax на каждом доступном месте (рекурсия)
  4. Оценить возвратные значения из вызовов функций
  5. и вернуть лучшее значение

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