Недавно в одном из постов в Telegram мне попалась статья о том, как реализовали шахматы на основе Rich-текста — это «Rich Text Chess». Меня это зацепило: Rich-сообщения не уводят пользователя из Telegram, и клиенту гораздо проще взаимодействовать с ботом, не покидая привычный интерфейс.

Шахматы меня заворожили вдвойне — я люблю эту игру. Поэтому я начал разбираться, как это устроено под капотом. Оказалось, всё довольно просто: доска — это таблица, доступная в Rich-сообщениях, а фигуры расположены в её ячейках. Такая таблица создаётся специальным ботом на основе callback-логики. Разобравшись в этом принципе, я понял, что таблицы можно использовать для самых разных игр — и первое, что пришло в голову, это «Сапёр».

Первый MVP за пять минут

Тут на помощь пришла нейросеть. Буквально за пять минут я накидал первый рабочий прототип — без ручной раскладки сетки, без написания логики игры с нуля. Бот уже как-то работал, но выглядел откровенно сыро.

MVP
MVP

Дальше я занялся внешним видом: как сделать таблицу удобной для игры и как подобрать правильные кастомные эмодзи. Именно на этом этапе тесты заняли неожиданно много времени — до поздней ночи я руками собирал запросы на отправку таблицы, подбирал расположение элементов и эмодзи-наборы.

Ловушка с кастомными эмодзи

Изначально я пошёл неправильным путём: решил сделать собственные кастомные эмодзи под оригинальную графику «Сапёра». Нашёл на GitHub исходные картинки классической игры и хотел собрать из них набор эмодзи. Но этот путь оказался слишком долгим — я не умею создавать кастомные эмодзи и не силён в Photoshop, так что на это ушло бы ещё несколько суток.

Решение пришло само — я просто выспался. На следующее утро понял, что достаточно поискать готовый набор кастомных эмодзи с цифрами в стиле «мини». В таблице всего два типа ячеек: заголовок (тёмная ячейка — закрытое, неоткрытое поле) и обычная ячейка (светлая — открытая). Добавление цифр в эмодзи позволило имитировать открытие клетки, как в оригинальной игре.

Проблема с состоянием игры

Следующая сложность была архитектурной. Я попросил вывести в лог всё, что присылает Telegram при нажатии на ячейку, и обнаружил: в самом сообщении нигде не зашита информация о том, какие конкретно элементы находятся в этой игре. Нейросеть предложила решение — хранить игру каждого пользователя в памяти сервера. Но это в корне неправильный подход: он нагружает сервер и раздувает память при большом количестве игроков.

Вместо этого я использовал другой подход: в callback-данных, которые прикреплены к каждой ячейке, добавил дополнительный параметр — невидимый пользователю, но понятный боту. Он указывает, какая ячейка нажата и что нужно показать следующим — скрытую бомбу или скрытую цифру.

Нейросеть также предупреждала, что при таком подходе «любой сможет разгадать игру». Но я задал себе вопрос: а зачем это нужно? Кто-то будет перехватывать сообщения от Telegram-бота, заходить под чужим кодом ради разгадывания «Сапёра»? Маловероятно, и выделка точно не стоит овчинки.

Почему я не стал разворачивать Redis и Postgres для работы игры

Нейросеть предлагала поднять Redis или Postgres под эту задачу — но это явно избыточное решение для такой простой игры. Я решил проще: при каждой отправке сообщения зашивать в callback всю информацию об игре целиком, а на сервере просто разбирать этот код.

Главный вывод из этого опыта: если вы вайб-кодите с нейросетью, всегда проверяйте, какую логику она закладывает и зачем. Часто ИИ склонен всё усложнять там, где достаточно простого решения.

Что дальше?

Вот такая игра получилась — попробуйте сами https://t.me/RichSapperBot. У меня уже есть пара идей, какие ещё игры можно реализовать через геймификацию в Telegram, чтобы раскачивать активность в группах. Об этом напишу в одном из следующих постов тут или в моем телегарм канале, если найду время всё оформить.