Как устроены боты для мафии: подозрения, блеф и балансировка

Онлайн-игре в мафию трудно собрать полноценный стол: для партии обычно нужны от шести до десяти участников. Чтобы пустующие места не мешали запуску игры, разработчик создал ботов для мини-приложения в Telegram и MAX. Они не просто голосуют случайным образом, а анализируют события, выдвигают обвинения, оправдываются и иногда пытаются обмануть остальных.
Главная задача заключалась в том, чтобы сделать ботов сопоставимыми со средними игроками. Слишком сильный искусственный участник быстро угадывает мафию и лишает игру интриги, а слишком слабый голосует наугад и разрушает баланс. Поэтому поведение ботов строится на ограниченной информации и наборе простых правил: они не должны быть ни чрезмерно агрессивными, ни откровенно неразумными.
Информация только из доступных игроку источников
Бот получает тот же набор данных, что и живой участник. В его распоряжении находятся собственная роль, результаты ночных действий, открытые события стола и опубликованные голоса. Доступа к внутреннему состоянию игрового движка у него нет. Для этого используется отдельное представление состояния viewFor(playerId), которое не позволяет случайно передать боту лишние сведения.
Подозрения формируются из наблюдаемых фактов: проверок комиссара, вскрытых ролей выбывших игроков и голосов. Отдельные реплики тоже учитываются, но имеют небольшой вес. Публичное обвинение добавляет цели примерно 0,4 пункта подозрения, а шёпот немного влияет на оценки обоих участников. Ни один единичный сигнал не должен автоматически определять решение.
Для хранения состояния бот использует память с несколькими структурами. В ней записываются подозрения в отношении игроков, достоверно известные роли, число уже обработанных событий, факт выступления в текущем раунде и сведения о том, о ком комиссар уже рассказал столу. Для мафии дополнительно хранится признак использования блефа в текущей партии.
Голоса, слухи и поведение ролей
Открытые голосования становятся одним из основных источников информации для города. Если выбывший оказался мирным, те, кто голосовал за его изгнание, получают дополнительные очки подозрения. Если же изгнали мафиози, подозрительным может показаться игрок, голосовавший за другую кандидатуру. Такие правила не дают однозначного ответа, но постепенно меняют расстановку доверия.
Боты за одним столом не обмениваются тайными сообщениями. Вместо этого используется общая шина слухов: когда участник сообщает что-то важное, событие становится доступным всем и получает числовой вес. Например, заявление о проверке игрока на мафию усиливает подозрение к цели, а раскрытие себя комиссаром, наоборот, повышает доверие к заявившему. Это упрощённая модель того, насколько стол верит словам, но её достаточно, чтобы поведение ботов напоминало коллективную игру.
Комиссар не раскрывается автоматически после каждой успешной проверки. Если он постоянно сообщает о найденной мафии, его почти наверняка устранят следующей ночью. Поэтому бот раскрывается с некоторой вероятностью, а доктор часто, но не всегда, пытается его лечить. Такая неопределённость помогает сохранить у города шанс на продолжение расследования.
Мафия отвечает на обвинения отрицанием и старается перевести внимание на другого подозрительного игрока. Днём бот обычно поддерживает кандидатуру, которая уже выглядит сомнительно, а ночью следует общему решению мафии, чтобы голоса команды не распадались. Иногда он может пойти на рискованный блеф и заявить, что является комиссаром и уже проверил конкретного игрока.
Именно блеф оказался самым опасным элементом баланса. В первой версии заявления мафии имели такой же вес, как и настоящие признания комиссара. В результате боты-мафиози слишком часто убеждали город казнить мирных. Разработчик сделал блеф редким и менее убедительным для остальных участников: неподтверждённому заявлению теперь доверяют меньше.
Балансировка с помощью симуляций
Для проверки правил был написан отдельный прогонщик партий. Он запускает тысячи игр за столами от шести до 24 мест, используя детерминированный генератор случайных чисел. Благодаря seed любую необычную партию можно повторить и изучить. Независимые симуляции распределяются по ядрам процессора, поэтому 10 000 партий проходят примерно за секунду.
Симуляции помогли найти несколько проблем. В прогоне обнаружился баг, из-за которого игровая фаза иногда переключалась дважды: движок сам переходил к утру, а тестовый скрипт повторно вызывал advance(). Ошибку исправили сравнением ключа фазы до и после перехода.
На больших столах слишком сильным оказался маньяк. Его поведение изменили: теперь он может идти за большинством или выступать против игроков, которым доверяет город, и постепенно выдаёт себя. Отдельно пересмотрели первую ночь. Раньше мафия сразу стреляла наугад, поэтому появилась «ночь знакомства»: мафиози узнают друг друга, дон ищет комиссара, а комиссар уже проводит проверку. Потерю первого выстрела компенсировали дополнительным мафиози на столах от шести игроков.
Автор подчёркивает, что симуляции ботов не заменяют партии с людьми. Однако они хорошо выявляют грубые перекосы и регрессии, поэтому прогон стал обязательным перед каждым изменением правил.
Общая игра в Telegram и MAX
Приложение построено на React, Fastify и Postgres и запускается как мини-приложение в Telegram и MAX. Оба мессенджера передают подписанные данные инициализации, которые проверяются с помощью HMAC-SHA256 на основе токена бота. В MAX строка может приходить дополнительно закодированной, поэтому приложение проверяет оба варианта.
Пользователи получают идентификаторы с префиксами платформы, например tg:123 или max:456, но внутри игры это обычные участники одного стола. Приглашения формируются под платформу создателя ссылки, а для перехода в другой мессенджер предусмотрена отдельная кнопка.
В качестве главного архитектурного вывода разработчик отмечает, что игровой движок стоило сразу сделать чистой функцией от состояния и времени — advance(now), без встроенных таймеров. Это упростило бы тестирование и ускорило симуляции. Не менее важным оказалось раннее выделение функции viewFor: единая точка формирования видимого игроку состояния снижает риск утечки информации и автоматически ограничивает знания ботов.


