Это проект моей магистерской диссертации. Любой, кто заинтересован в создании мощного искусственного интеллекта для маджонга, может расширить возможности моего агента. Для получения более подробной информации о применяемых алгоритмах и причинах их использования свяжитесь со мной по электронной почте.
Если вы хотите разработать свой собственный агент для маджонга, этот репозиторий также можно использовать в качестве платформы для тестирования в реальном времени ( с участием реальных игроков ). Тогда вы сможете сэкономить все свое время на поиске лучшей стратегии для своего агента. Кроме того, библиотека разработки (сканирование и предварительная обработка игровых журналов, расчет шантина, победного счета и т. д.) теперь доступна по адресу: https://github.com/erreurt/MahjongKit.
Следующее обновление скоро выйдет :
Требуется лучшая разработка функций. Решите, следует ли вызывать объединение/вызов Riichi или нет, используя случайный лес (вместо правил условий).
В процессе : обучение модели прогнозирования ожидающих плиток с помощью LSTM.
Внимание : если вы тестируете своего бота одновременно с более чем 4 учетными записями под одним и тем же IP-адресом, ваш IP-адрес будет заблокирован tenhou.net на 24 часа. (Я точно не знаю правил бана игроков, но это все выводы из моих наблюдений.)
Автор | Цзяньян Тан (Томас) |
---|---|
Электронная почта | [email protected] |
Маджонг — это стратегическая игра для четырех игроков с неполной информацией. Основными проблемами разработки интеллектуального агента для игры в маджонг являются, например, сложные правила игры, огромное пространство поиска, множество противников и несовершенная информация. В нескольких существующих работах были предприняты попытки решить эти проблемы с помощью моделирования дерева Монте-Карло, подбора функции полезности с помощью контролируемого обучения или модели оппонентов с помощью алгоритмов регрессии. Тем не менее, эффективность умных агентов, играющих в маджонг, все еще далека от результатов лучших игроков-людей. На основе статистического анализа игры в маджонг и экспертных знаний людей в этой работе был предложен интеллектуальный агент маджонга. Для решения проблем современной работы в этой работе были применены эвристические технологии и расширенная модель оппонентов, достигнутая за счет использования упаковки многослойных перцептронов. Эксперименты показывают, что предлагаемый агент превосходит современный агент, а примененная модель оппонентов оказывает существенное положительное влияние на производительность агента. Кроме того, из экспериментов можно выделить несколько интересных моментов, которые весьма значимы для будущей работы.
Правила игры в японский риичи-маджонг можно найти на https://en.wikipedia.org/wiki/Japanese_Mahjong.
Реализованный клиент позволяет запускать агент маджонга непосредственно через программу, а не в веб-браузере. Сайт онлайн-игры в японский риичи-маджонг: http://tenhou.net/.
Левая сторона представляет собой типичный сценарий японского стола Риичи-маджонг. Это изображение представляет собой снимок экрана графического интерфейса, реализованного для отладки.
Предлагаемый агент маджонга был протестирован на сайте tenhou.net. Испытание проводилось в двух вариантах: с защитной моделью и без. Необработанные логи игры и промежуточные результаты игры можно найти в другом моем репозитории: https://github.com/erreurt/Experiments-result-of-mahjong-bot. Эксперименты проводились с версией агента в Experiment_ai.py .
Для версии с моделью защиты было сыграно 526 игр, а для версии без модели защиты — 532 игры. Это не так много, как две родственные работы, но, как показано на рисунке конвергенции поведения производительности агента, 526 игр вполне достаточно.
Расширенную работу Мизуками можно рассматривать как лучшего и самого надежного агента по маджонгу в английской литературе на данный момент. Здесь представлено сравнение игры моего агента по маджонгу и игры Мизуками:
[1] | [2] | [3] | [4] | |
---|---|---|---|---|
Сыграно игр | 526 | 532 | 2634 | 1441 |
ставка за 1 место | 23,95% | 22,65% | 24,10% | 25,30% |
ставка за 2 место | 26,62% | 25,92% | 28,10% | 24,80% |
рейтинг за 3 место | 31,75% | 25,71% | 24,80% | 25,10% |
рейтинг за 4 место | 17,68% | 25,71% | 23,00% | 24,80% |
процент побед | 24,68% | 26,50% | 24,50% | 25,60% |
проиграть ставку | 13,92% | 20,21% | 13,10% | 14,80% |
фиксированный уровень | 2.21 Дэн | 0,77 Дэн | 1.14 Дэн | 1.04 Дэн |
[1] Мой агент по маджонгу с моделью защиты
[2] Мой агент по маджонгу без модели защиты
[3] Расширенная работа Мизуками : Мизуками Н., Цуруока Ю.. Создание компьютерного игрока в маджонг на основе симуляции Монте-Карло и моделей противников. В: Конференция IEEE по вычислительному интеллекту и играм (CIG), 2015 г., стр. 275–283. ИИЭР (2015)
[4] Мизуками и др. ал. : Н. Мизуками, Р. Накахари, А. Ура, М. Мива, Ю. Цуруока и Т. Чикаяма. Реализация компьютерной программы маджонга для четырех игроков путем контролируемого обучения с изолированными аспектами многопользовательской игры. Сделки Общества обработки информации Японии, том. 55, нет. 11, стр. 1–11, 2014 г. (на японском языке).
Обратите внимание, что при игре в маджонг попадание на 4-е место определенно является табу, так как при этом снижается уровень очков. В результате скорость попадания игрока на 4-е место имеет решающее значение для его общих результатов. У моего бота фиксированный уровень лучше именно из-за низкого рейтинга 4-го места.
Чтобы запустить агент маджонга, необходимо указать несколько конфигураций. Как показано в следующем примере из main.py:
def run_example_ai ():
ai_module = importlib . import_module ( "agents.random_ai_example" )
ai_class = getattr ( ai_module , "RandomAI" )
ai_obj = ai_class () # [1]
player_module = importlib . import_module ( "client.mahjong_player" )
opponent_class = getattr ( player_module , "OpponentPlayer" ) # [2]
user = "ID696E3BCC-hLHNE8Wf" # [3]
user_name = "tst_tio" # [4]
game_type = '1' # [5]
logger_obj = Logger ( "log1" , user_name ) # [6]
connect_and_play ( ai_obj , opponent_class , user , user_name , '0' , game_type , logger_obj ) # play one game
def run_jianyang_ai ():
ai_module = importlib . import_module ( "agents.jianyang_ai" )
waiting_prediction_class = getattr ( ai_module , "EnsembleCLF" )
ensemble_clfs = waiting_prediction_class ()
ai_class = getattr ( ai_module , "MLAI" )
ai_obj = ai_class ( ensemble_clfs ) # [1]
opponent_class = getattr ( ai_module , "OppPlayer" ) # [2]
user = "ID696E3BCC-hLHNE8Wf" # [3]
user_name = "tst_tio" # [4]
game_type = '1' # [5]
logger_obj = Logger ( "log_jianyang_ai_1" , user_name ) # [6]
connect_and_play ( ai_obj , opponent_class , user , user_name , '0' , game_type , logger_obj )
Экземпляр AI : экземпляр класса агента маджонга. В этом репозитории представлены три версии агента Mahjong. Первый находится в агентах.random_ai_example.py . Это демонстрационный класс, показывающий потенциальным разработчикам, как реализовать свои собственные агенты. Второй находится в агентах.experiment_ai.py , и результаты эксперимента, приведенные в части 4, генерируются этим ИИ. Третий — это современный ИИ, он находится в агентах.jianyang_ai.py .
Класс игрока-соперника : класс игрока-соперника. В client.mahjong_player можно использовать класс OppentPlayer по умолчанию. Если кто-то расширил класс OppentPlayer из-за дополнительных потребностей, эта переменная должна быть установлена в соответствующий класс.
Идентификатор пользователя : токен в форме, показанной в примере, полученный после регистрации на tenhou.net. ВНИМАНИЕ: Пожалуйста, используйте свой собственный идентификатор пользователя. Если один и тот же идентификатор слишком часто используется под разными IP-адресами, учетная запись будет временно заблокирована tenhou.net.
Имя пользователя : соответствующее имя пользователя, которое вы создали при регистрации на tenhou.net. Эта переменная предназначена только для идентификации ваших журналов тестирования.
Тип игры : Тип игры кодируется как 8-битное целое число. Ниже приводится описание каждого бита.
Примеры:
- Tenhou.net does not provide all possibility of the above specified combinations. Most online players play on configurations for example "1", "137", "193", "9"
Регистратор : Для инициализации регистратора необходимы два параметра. Первый — это определяемый пользователем идентификатор регистратора, поэтому разработчики могут свободно называть его/ее историю тестов.
После указания всех этих конфигураций просто бросьте все эти параметры в функцию connect_and_play() . Тогда пришло время посмотреть шоу вашего агента по маджонгу!!!
Для бота Mahjong необходимо реализовать четыре функции, как показано в классе «interface» в Agents.ai_interface . Рекомендуется, чтобы ваш агент был наследником AIInterface. Более глубокое объяснение и простой пример этих функций см. в документации по агентам.random_ai_example.py .
class AIInterface ( MainPlayer ):
def to_discard_tile ( self ):
raise NotImplementedError
def should_call_kan ( self , tile136 , from_opponent ):
raise NotImplementedError
def try_to_call_meld ( self , tile136 , might_call_chi ):
raise NotImplementedError
def can_call_reach ( self ):
raise NotImplementedError
to_discard_tile : на основе всей доступной информации о состоянии игры эта функция возвращает плитку, которую нужно сбросить. Возврат представляет собой целое число в диапазоне 0–135. Всего в игре Маджонг 136 фишек, т.е. 34 вида фишек и по 4 копии каждого вида. В разных случаях мы используем либо форму 34 (каждое число соответствует одному виду плитки), либо форму 136 (каждое число соответствует плитке). Обратите внимание, что здесь возврат должен быть в форме 136.
must_call_kan : https://en.wikipedia.org/wiki/Japanese_Mahjong#Making_melds_by_calling. Эта функция должна решить, должен ли агент вызывать объединение kan(Quad). tile136 обозначает плитку, которую сбросил какой-то противник, и которую агент может использовать для формирования комбинации канов. from_oppent указывает, формирует ли агент комбинацию кан путем сброса противника (три плитки в руке и противник сбрасывает четвертую) или своими собственными плитками (все четыре плитки в руке).
try_to_call_meld : https://en.wikipedia.org/wiki/Japanese_Mahjong#Making_melds_by_calling. Эта функция решает, должен ли агент вызывать комбинацию Pon(Triple)/Chi(Sequence). tile136 обозначает плитку в форме 136, которую сбросили некоторые противники. may_call_chi указывает, может ли агент объявить комбинацию Чи, поскольку комбинация Чи может быть вызвана только со сбросом противника на левом сиденье.
can_call_reach : https://en.wikipedia.org/wiki/Japanese_Mahjong#R%C4%ABchi. Эта функция решает, должен ли агент требовать Риичи.
Если класс агента Маджонга является подклассом класса AIInterface , информация, указанная ниже, может быть доступна внутри класса агента, как указано.
Доступ | Тип данных | Изменяемый | Описание |
---|---|---|---|
self.tiles136 | список целых чисел | Да | ручная плитка в форме 136 |
self.hand34 | список целых чисел | Н | тайлы рук в форме 34 (tile34 = tile136//4) |
self.discard136 | список целых чисел | Да | сбросы агента в 136-с |
self.discard34 | список целых чисел | Н | сбросы агента в 34-форме |
self.meld136 | список экземпляров Meld | Да | вызываемые комбинации агента, экземпляры класса Meld в client.mahjong_meld.py |
self.total_melds34 | список списка целых чисел | Н | вызываемые объединения агента в 34-форме |
self.meld34 | список списка целых чисел | Н | вызванные комбинации пон/чау агента в 34-форме |
self.pon34 | список списка целых чисел | Н | вызываемый пон объединяет агента в 34-форме |
self.chow34 | список списка целых чисел | Н | так называемая еда объединяет агента в 34-форме |
self.minkan34 | список списка целых чисел | Н | так называемые минканы объединяют агента в 34-форме |
self.ankan34 | список списка целых чисел | Н | названный анкан объединяет агента в 34-форме |
свое имя | нить | Да | имя учетной записи |
собственный уровень | нить | Да | уровень счета |
самостоятельное сиденье | целое число | Да | ID места, у агента всегда 0 |
self.dealer_seat | целое число | Да | идентификатор места дилера |
self.is_dealer | логическое значение | Н | является ли агент дилером или нет |
self.reach_status | логическое значение | Да | указывает, заявил ли агент Риичи |
self.just_reach() | логическое значение | Н | действительно ли агент только что забрал Риичи |
self.tmp_rank | целое число | Да | ранг агента в текущей игре |
самооценка | целое число | Да | счет агента в текущей игре |
self.is_open_hand | логическое значение | Н | вызывал ли агент уже открытые объединения |
self.turn_num | целое число | Н | номер текущего хода |
self.player_wind | целое число | Н | Игрок Ветра — это один из видов яку |
self.round_wind | целое число | Н | круглый ветер — это один из видов яку |
self.bonus_honors | список целых чисел | Да | все тайлы персонажей, на которых есть яку |
Доступ к экземпляру класса противника можно получить, вызвав self.game_table.get_player(i) с i, равным 1,2,3, что указывает на соответствующий идентификатор противника.
Доступ | Тип данных | Изменяемый | Описание |
---|---|---|---|
.discard136 | список целых чисел | Да | сброс наблюдаемого противника в 136-с |
.discard34 | список целых чисел | Н | сброс наблюдаемого противника в 34-форме |
.meld136 | список экземпляров Meld | Да | названные комбинации наблюдаемого противника |
.total_melds34 | список списка целых чисел | Н | названные комбинации наблюдаемого противника в 34-форме |
.meld34 | список списка целых чисел | Н | названные комбинации пон/чау наблюдаемого противника в 34-форме |
.pon34 | список списка целых чисел | Н | вызванные пон-слияния наблюдаемого противника в 34-форме |
.chow34 | список списка целых чисел | Н | названные комбинации наблюдаемого противника в 34-форме |
.минкан34 | список списка целых чисел | Н | названные минканы объединяются наблюдаемым противником в 34-форме |
.ankan34 | список списка целых чисел | Н | названный анкан объединяет наблюдаемого противника в 34-форме |
.safe_tiles | список целых чисел | Да | тайлы в форме 34, которые абсолютно безопасны для агента, т.е. наблюдаемый противник не может выиграть с этими тайлами |
.имя | нить | Да | имя противника |
.уровень | нить | Да | уровень противника |
.сиденье | целое число | Да | идентификатор места наблюдаемого соперника |
.dealer_seat | целое число | Да | идентификатор места дилера |
.is_dealer | логическое значение | Н | является ли наблюдаемый оппонент дилером или нет |
.reach_status | логическое значение | Да | указывает, заявил ли наблюдаемый оппонент Риичи |
.just_reach() | логическое значение | Н | действительно ли наблюдаемый противник только что забрал Риичи |
.tmp_rank | целое число | Да | ранг наблюдаемого противника в текущей игре |
.счет | целое число | Да | счет наблюдаемого противника в текущей игре |
.is_open_hand | логическое значение | Н | объявил ли наблюдаемый оппонент открытые комбинации |
.turn_num | целое число | Н | номер текущего хода |
.player_wind | целое число | Н | Игрок Ветра — это один из видов яку |
.round_wind | целое число | Н | круглый ветер — это один из видов яку |
.bonus_honors | список целых чисел | Да | все тайлы персонажей, на которых есть яку |
Чтобы получить доступ к информации об игровом столе, можно вызвать self.game_table
Доступ | Тип данных | Изменяемый | Описание |
---|---|---|---|
.bot | экземпляр класса агента | Да | экземпляр класса агента |
.get_player(я) | экземпляр класса противника | Да | экземпляр класса противника, i=1,2,3 |
.dealer_seat | целое число | Да | идентификатор места дилера |
.bonus_indicator | список целых чисел | Да | бонусные показатели в 136-форме |
.round_number | целое число | Да | круглое число |
.reach_sticks | целое число | Да | Сколько палочек Риичи лежит на столе. Игрок, который выиграет следующим, получит все очки этих клюшек Риичи. |
.honba_sticks | целое число | Да | Сколько палочек хонба лежит на столе. В случае победы игрок получит дополнительные очки по палочкам хонба. |
.count_ramaining_tiles | целое число | Да | Количество оставшихся нераскрытых плиток |
.раскрытый | список целых чисел | Да | Каждый элемент в списке указывает, сколько копий этой конкретной плитки было обнаружено (сброшенные, открытые комбинации, бонусные индикаторы и т. д.) |
.round_win | целое число | Н | круглый ветер — это один из видов яку |
.bonus_tiles | список целых чисел | Н | Список бонусных плиток. Каждое появление бонусных плиток на плитках рук считается яку. |
.last_discard | целое число | Н | Самый последний сброс противника, этот тайл абсолютно безопасен по правилам. |
мой профессор Йоханнес Фюрнкранц (Группа инженерных знаний Дармштадтского технического университета)
мой руководитель Тобиас Йоппен (Группа инженерии знаний Дармштадтского университета)