Очень интересная проблема с алгоритмом MiniMax. Что может вызвать такое поведение? - PullRequest
0 голосов
/ 31 октября 2018

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

Вот моя минимаксная функция:

// Game states are represented by Node objects (holds the move and the board in that state)
//ValueStep is just a pair holding the minimax value and a game move (step) 

private ValueStep minimax(Node gameState,int depth,int alpha,int beta) {

  //Node.MAXDEPTH is a constant
  if(depth == Node.MAXDEPTH || gameOver(gameState.board)) {
      return new ValueStep(gameState.heuristicValue(),gameState.step);
  }

  //this method definately works. child nodes are created with a move and an 
  //updated board and MAX value
  //which determines if they are the maximizing or minimizing players game states.
  gameState.children = gameState.findPossibleStates();

  if(state.MAX) { //maximizing player
      ValueStep best = null;

      for(Node child: gameState.children) {

          ValueStep vs = new ValueStep(minimax(child,depth+1,alpha,beta).value,child.move);

          //values updated here if needed
          if(best==null || vs.value > best.value) best = vs;

          if(vs.value > alpha) alpha = vs.value;

          if(alpha >= beta) break;
      }

      return best;

  } else { //minimizing player
      ValueStep best = null;

      for(Node child: gameState.children) {

          ValueStep vs = new ValueStep(minimax(child,depth+1,alfa,beta).value,child.move);

          if(best==null || vs.value < best.value) best = vs;

          if(vs.value < beta) beta = vs.value;

          if(alpha >= beta) break;
      }

      return best;
  }

}

Сначала я подумал, что проблема в моей функции оценки, но если это так, я не смог ее найти. В этой игре у обоих игроков есть оценка, и моя функция просто вычисляет эвристическое значение из разницы очков. Вот оно:

public int heuristicValue() {

       //I calculate the score difference here in this state and save it in 
       //the variable scoreDiff. scoreDiff will be positive if I am winning 
       //here, negative if im loosing.

        //"this" is a Node object here. If the game is over here, special
        //heuristic values are returned, depending on who wins (or if its a 
        //draw) 
        if(gameOver(this.board)) {
            if(scoreDiff>0) {
                return Integer.MAX_VALUE;  
            } else if(scoreDiff==0) {
                return 0;
            } else {
                return Integer.MIN_VALUE;
            }
        }

        int value = 0;
        value += 100*scoreDiff; //caluclate the heuristic value using the score differerence. If its high, the value will be high as well 

      return value;
  }

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

1 Ответ

0 голосов
/ 01 ноября 2018

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

Ваш алгоритм Minimax не различает эти ходы, а просто воспроизводит тот, который оказывается первым в вашем gameState.children списке. Это может быть быстрый, неглубокий выигрыш или медленный, очень глубокий выигрыш.

Существует два простых способа сделать алгоритм Minimax приоритетным для быстрых выигрышей над медленными выигрышами:

  1. Наилучшим вариантом (поскольку он также имеет много других преимуществ) является использование Итеративное углубление . Вы можете посмотреть это подробнее, но основная идея состоит в том, что сначала вы выполняете поиск минимаксного с пределом глубины 1, затем еще один с ограничением глубины 2, затем с пределом глубины 3 и т. Д. Как только один из ваших поисков доказывает выигрыш, вы можете прекратить поиск и сыграть этот выигрышный ход. Это заставит ваш алгоритм всегда отдавать предпочтение самым коротким выигрышам (потому что они будут найдены первыми).
  2. Кроме того, вы можете изменить функцию heuristicValue() для включения глубины поиска. Например, вы можете вернуть Integer.MAX_VALUE - depth в выигрышных позициях. Это сделает более быстрые выигрыши на самом деле с немного большей оценкой.
...