Adverserial ищут проблемы

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

Проблема или что в изменениях, что я попробовал это, AI принимает решение не заблокировать плеер, когда у плеера есть three-in-a-row, но иначе AI играет в идеальную игру, или что он предпочитает блокировать плеер, даже если у него есть шанс выиграть игру. Это также, кажется, имеет значение, является ли поисковая глубина даже или неровное число, как AI является штанами на голове, задержанными при поиске с 6 сгибами, который довольно говорит, что что-то неправильно.

Поиск

Используемый алгоритм является negamax с сокращением альфы - беты и реализован следующим образом:

private int Negamax(int depth, int alpha, int beta, Player player)
{
  Player winner;
  if (Evaluator.IsLeafNode(game, out winner))
  {
    return winner == player ? (10000 / depth) : (-10000 / depth);
  }

  if (depth == Constants.RecursionDepth)
  {
    return Evaluator.Evaluate(game, depth, player);
  }

  foreach (var move in moves)
  {
    int row;

    if (board.DoMove(move, player, out row))
    {
      var value = -Negamax(depth + 1, -beta, -alpha, (Player)1 - (int)player);

      board.UndoMove(move, row, player);

      if (value > alpha)
      {
        alpha = value;
        if (player == Player.AI)
        {
          bestColumn = move;
        }
      }

      if (alpha >= beta)
      {
        return alpha;
      }

    }
  }
  return alpha;
}

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

Оценка

Я основывал функцию оценки прочь того, что существует только 69 возможных способов надеть four-in-a-row 7x6 плата. У меня есть справочная таблица приблизительно 350 объектов, которая содержит hardcoded информацию для каждого столбца и строки, каких комбинаций победы row+column является частью. Например, для строки 0 и столбца 0, таблица похожа на это:

//c1r1
table[0][0] = new int[3];
table[0][0][0] = 21;
table[0][0][1] = 27;
table[0][0][2] = 61;

Это означает, что столбец 0, строка 0 является частью комбинации победы 21, 27 и 61.

У меня есть вторая таблица, которая содержит для обоих плееров, сколько камней она имеет в каждой из комбинаций победы. Когда я делаю перемещение затем, я делаю следующее:

public bool DoMove(int column, Player p, out int row)
{
  row = moves[column];

  if (row >= 0)
  {
    Cells[column + row * Constants.Columns] = p;

    moves[column]--;

    var combinations = this.Game.PlayerCombinations[p];

    foreach (int i in TerminalPositionsTable.Get(column,row))
    {
      combinations[i]++;
    }

    return true;
  }
  else
  {
    return false;
  }
}

Противоположное, конечно, делается для UndoMove.

Таким образом, после выполнения перемещения на столбце 0, строка 0 Player.Human, таблица будет заполнена значением 1 в индексе 21, 27 и 61. Если я делаю другое перемещение в ячейке, которая является также частью комбинации победы 27, то таблица комбинации плеера увеличена в от индексе 27 до 2.

Я надеюсь, что ясно дал понять, поскольку это привыкло в функции оценки к очень, быстро определяют, как близко плеер к выигрышу four-in-a-row.

Функция оценки, где я подозреваю проблему, находится, следующие:

public static int Evaluate(Game game, int depth, Player player)
{
  var combinations = game.PlayerCombinations[player];

  int score = 0;

  for (int i = 0; i < combinations.Length; i++)
  {
    switch (combinations[i])
    {
      case 1:
        score += 1;
        break;
      case 2:
        score += 5;
        break;
      case 3:
        score += 15;
        break;
    }
  }

  return score;
}

Так я просто цикл через 69 возможных комбинаций победы и добавляет сумму к счету на основе того, является ли это единственным камнем, two-in-a-row или три.

Часть, которой я все еще смущен в этом целом соперничающем поиске, - должен ли я заботиться, какой плеер, делающий, является перемещением? Я имею в виду, я должен передать в плеере как, я делаю здесь, или я должен всегда оценивать плату с точки зрения плеера AI? Я попробовал много комбинаций aiScore - humanScore, или просто всегда смотрите с точки зрения Player.AI, и такой. Но я поразил тупик и каждую комбинацию, которую я попробовал, был довольно испорчен.

Так:

  1. Логика моего тела оценки в его основе?
  2. Когда должен я 'переключать перспективу'?

Любая справка очень ценилась бы.

Обновление

Я реализовал предложения Brennan ниже, и в то время как это определенно очень улучшилось, по некоторым причинам это не блокирует three-in-a-rows ни на каком столбце, но этих двух, оставленных и самых правых, и только когда поисковая глубина является неравномерной. AI непобедим даже на поисковых глубинах, но только до глубины 8 и. Затем это отказывается блокироваться снова. Это довольно говорит, что я, вероятно, очень близок, но все еще имею некоторый решающий дефект.

Возможно, это имеет отношение ко мне устанавливающий столбец, AI должен отбросить камень в том, как Brennan прокомментировал, но я не знаю, когда еще установить его. Установка его только на глубине 0 не работает.

Обновление 2

Отредактированный код, поскольку это похоже теперь с изменениями Brennan.

Обновление 3

Созданный GitHub repo с полным кодом. Если Вы не знаете, как работать Мерзавец, просто загрузите zip-файл отсюда.

Это-.NET 4,0 проекта, и выполнение его создаст файлы журнала negamax алгоритма в Вашем каталоге документов/журналов. Решение также содержит тестовый проект, который содержит тест для каждого столбца платы, принимает ли AI решение заблокировать плеер, когда у плеера есть three-in-a-row там.

7
задан Bill the Lizard 18 September 2012 в 16:57
поделиться

2 ответа

Из-за этого у меня болит мозг, поэтому я не уверен, что это правильный ответ, но начнем.

В негамаксе счет всегда оценивается относительно игрока, находящегося в данный момент на ходу. Если это ход белых, то высокий балл для белых хорош. Если это ход черных, то высокий балл хорош для черных. Итак, если у вас есть листовой узел, то оценка + inf или -inf зависит не от того, является ли узел победой для белых или черных, а от того, является ли это победой для игрока, которого вы в данный момент оцениваете. Замените это:

return winner == Player.AI ? (10000 / depth) : (-10000 / depth);

следующим:

return winner == player ? (10000 / depth) : (-10000 / depth);

Аналогичная проблема существует в вашей функции оценки. Замените это:

return player == Player.AI ? score : -score;

на это:

return score;

Опять же, я не уверен, что это правильно. Но я надеюсь, что вы попробуете эти два изменения и дадите мне знать, сработают ли они. Мне очень любопытно!

2
ответ дан 7 December 2019 в 16:38
поделиться

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

Я также вижу проблему в вашей оценочной функции: она дает ценность ходам, у которых НЕТ надежды на победу. Допустим, у вас есть xoo.x, вы играете в o. Ваш распорядок гласит, что игра здесь стоит 15 очков, тогда как на самом деле она стоит 0. Любая выигрышная комбинация, которая уже содержит плитки от обоих игроков, никому не представляет ценности.

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

1
ответ дан 7 December 2019 в 16:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: