Я разработал AI 2048, используя оптимизацию expectimax вместо поиска минимакса, используемого алгоритмом @ ovolve. ИИ просто выполняет максимизацию всех возможных ходов, после чего следует ожидание всех возможных порождений тайлов (взвешенных по вероятности тайлов, т.е. 10% для 4 и 90% для 2). Насколько я знаю, невозможно сократить оптимизацию expectimax (кроме удаления крайне маловероятных ветвей), и поэтому используемый алгоритм представляет собой тщательно оптимизированный поиск методом перебора.
Представление
ИИ в его конфигурации по умолчанию (максимальная глубина поиска 8) занимает от 10 мс до 200 мс, чтобы выполнить ход, в зависимости от сложности положения доски. При тестировании ИИ достигает средней скорости перемещения 5-10 ходов в секунду в течение всей игры. Если глубина поиска ограничена 6 ходами, ИИ может легко выполнить более 20 ходов в секунду, что делает его интересным для просмотра .
Чтобы оценить результативность ИИ, я запускал ИИ 100 раз (подключался к браузерной игре через пульт дистанционного управления). Для каждой плитки ниже приведены пропорции игр, в которых эта плитка была достигнута хотя бы один раз:
2048: 100%
4096: 100%
8192: 100%
16384: 94%
32768: 36%
Минимальная оценка по всем пробегам была 124024; максимальный результат - 794076. Средний балл - 387222. ИИ никогда не удавалось получить плитку 2048 (поэтому он никогда не проигрывал игру ни разу в 100 играх); на самом деле, он получил плитку 8192 хотя бы раз в каждом заезде!
Вот скриншот лучшего пробега:
Эта игра заняла 27830 ходов за 96 минут, или в среднем 4,8 хода в секунду.
Реализация
Мой подход кодирует всю доску (16 записей) в виде единого 64-битного целого числа (где плитки - это nybbles, то есть 4-битные порции). На 64-битной машине это позволяет передавать всю плату в одном регистре машины.
Операции сдвига битов используются для извлечения отдельных строк и столбцов. Одна строка или столбец - это 16-разрядная величина, поэтому таблица размером 65536 может кодировать преобразования, которые работают с одной строкой или столбцом. Например, перемещения реализованы как 4 поиска в предварительно вычисленной «таблице эффектов перемещения», которая описывает, как каждое перемещение влияет на одну строку или столбец (например, таблица «перемещение вправо» содержит запись «1122 -> 0023», описывающую, как строка [2,2,4,4] становится строкой [0,0,4,8] при перемещении вправо).
Оценка также осуществляется с помощью таблицы поиска. Таблицы содержат эвристические оценки, рассчитанные для всех возможных строк / столбцов, а итоговая оценка для доски - это просто сумма значений таблицы для каждой строки и столбца.
Это представление доски, наряду с подходом поиска таблиц для перемещения и подсчета очков, позволяет ИИ за короткий промежуток времени искать огромное количество игровых состояний (более 10 000 000 игровых состояний в секунду на одном ядре моего ноутбука середины 2011 года).
Сам поиск expectimax закодирован как рекурсивный поиск, который чередуется между шагами «ожидания» (тестирование всех возможных мест и значений появления тайлов и взвешивание их оптимизированных оценок по вероятности каждой возможности) и шагами «максимизации» (тестирование всех возможных ходов). и выбрать тот, который набрал лучший результат). Поиск по дереву завершается, когда он видит ранее увиденную позицию (используя таблицу транспонирования ), когда он достигает предопределенного предела глубины или когда он достигает состояния доски, которое крайне маловероятно (например, оно было достигнуто путем получения 6 "4" тайлов в ряд от стартовой позиции). Типичная глубина поиска составляет 4-8 ходов.
Эвристика
Несколько эвристик используются для направления алгоритма оптимизации к выгодным позициям. Точный выбор эвристики оказывает огромное влияние на производительность алгоритма. Различные эвристики взвешиваются и объединяются в позиционную оценку, которая определяет, насколько «хороша» данная позиция доски. Поиск оптимизации будет нацелен на максимизацию средней оценки всех возможных позиций на доске. Фактическая оценка, показанная в игре, не используется для подсчета очков на доске, поскольку она слишком сильно взвешена в пользу объединения плиток (когда отложенное объединение может принести большую выгоду).
Первоначально я использовал две очень простые эвристики, предоставляя «бонусы» для открытых квадратов и для получения больших значений на краю. Эти эвристики работали довольно хорошо, часто достигая 16384, но никогда не доходя до 32768.
Петр Моровек (@xificurk) взял мой ИИ и добавил две новые эвристики. Первой эвристикой было наказание за наличие немонотонных рядов и столбцов, которые увеличивались по мере увеличения рангов, гарантируя, что немонотонные ряды небольших чисел не будут сильно влиять на счет, но немонотонные ряды больших чисел существенно ухудшают счет. Вторая эвристика подсчитала количество потенциальных слияний (смежных равных значений) в дополнение к открытым пространствам. Эти две эвристики служат для продвижения алгоритма к монотонным доскам (которые легче объединить) и к позициям досок с большим количеством слияний (поощряя его выравнивать слияния, где это возможно, для большего эффекта).
Кроме того, Петр также оптимизировал эвристические веса, используя стратегию «мета-оптимизации» (используя алгоритм, называемый CMA-ES ), где сами веса были скорректированы для получения максимально возможного среднего балла.
Эффект этих изменений чрезвычайно значим. Алгоритм пошел от достижения плитки 16384 примерно в 13% случаев до достижения ее в течение 90% времени, и алгоритм начал достигать 32768 за 1/3 времени (тогда как старая эвристика никогда не производила плитку 32768) ,
Я считаю, что есть еще возможности для улучшения эвристики. Этот алгоритм определенно еще не «оптимален», но я чувствую, что он приближается.
То, что ИИ достигает плитки 32768 в более чем трети своих игр, является огромной вехой; Я буду удивлен, узнав, достиг ли кто-либо из игроков-людей отметки 32768 в официальной игре (т.е. без использования таких инструментов, как savestates или undo). Я думаю, что 65536 плитка в пределах досягаемости!
Вы можете попробовать ИИ для себя. Код доступен по адресу https://github.com/nneonneo/2048-ai .