«Новые Былины». Для dev, ops и любознательных людей +12



По многочисленным просьбам читателей начинается большой цикл статей о применении технологии бессерверных вычислений для разработки реального приложения. В этом цикле будет рассмотрена разработка приложения, тестирование и поставка конечным пользователям с использованием современных средств: микросервисной архитектуры приложения (в serverless варианте, на базе OpenFaaS), кластера kubernetes для развертывания приложения, базы данных MongoDB, ориентированной на облачные кластеризацию и применение, а также облачной шины NATS. Приложение реализует игру "Былины", один из вариантов популярной салонной игры "Мафия".


Что такое "Былины"?


Это вариант игры "Мафия", она же "Werewolf". В ее основе командная игра, при которой участники должны шаг за шагом узнать, кто есть кто, и попытаться выиграть. К сожалению, при игре по сети пропадает такая важная составляющая игры, как личное взаимодействие, а правила классической "Мафии" достаточно простые, поэтому для более нелинейного и интересного игрового процесса обычно добавляются другие персонажи, но в целом сохраняются основные черты оригинальной "Мафии", к примеру смена дня и ночи, ходы только ночью, а также союзы между участниками. Также важным отличием игры по сети является то, что ведущий (он же Мастер игры, Сказочник) это обычно компьютерная программа.


Описание игры


Правила игры, которую я хочу реализовать, взяты из старого irc-бота, которого я сохранил в личном архиве лет 10 назад. У "Былин" есть предыстория, которой начинается каждая игра:


В тридевятом царстве, в тридесятом государстве, за семью морями, жили себе поживали несколько деревушек, а в них Добры молодцы и Красны девицы. Сеяли они хлеб, да ходили в окрестный лесок по грибы и ягоды… И продолжалось так из века в век, пока страшная катастрофа не потрясла Землю и не стало зло расползаться по миру! Ночи сделались длинными и холодными, а темноте рыскали по лесу и забредали в деревню недобрые и страшные твари. Прилетел откуда-то Змей Горыныч и повадился воровать Красных девиц да отбирать все ценное у селян. Вредная и жадная Баба-Яга, прилетевшая на ступе из дальних лесов, смутила разум жителей, и даже кое-кто бросил ремесло и ушел в лес разбойничать, сколотил там шайку. Лиходеи повстречали Лешего, умевший превращаться в деревья да кусты, он стал следить за мирными селянами и служить разбойникам, вынюхивая, не затевают ли чего Добры молодцы для избавления своих поселений от нечисти. Добры молодцы и Красны девицы, уставшие от набегов Разбойников, да ужасных смертей от рук страшного Лиха Одноглазого, собрали золота и пригласили из соседнего города известного борца — Ивана-Царевича, пообещавшего избавить деревню от разбойников. На поляне в лесу Иван спас от неминуемой гибели Серого Волка, угодившего в яму-ловушку Разбойников. Взамен Волк пообещал сообщать Царевичу о разной лесной нечисти. Мимо проезжала известная целительница Василиса Премудрая, а когда увидела беду — осталась выхаживать жителей, пострадавших от нападений лихих. За лесом появился черный дворец, в котором, по слухам, поселился Кощей Бессмертный, каждую ночь он наведывался в деревни и околдовывал Добрых Молодцев и Красных Девиц, чтобы они не смели ослушаться его приказа, все делали так, как он скажет. А в Безжизненном Лесу поселился Кот-Баюн, и каждый, кто его встречал, засыпал мертвым сном после его сказок или погибал от его железных когтей.


Тридевятое царство


Как уже видно, игроки делятся на несколько групп:


  • мирные жители (Добры Молодцы, Красны Девицы, Иван-Царевич, Серый Волк и Василиса Премудрая)
  • разбойники (собственно разбойники, а также Баба-Яга и Леший)
  • независимые (Змей-Горыныч, Лихо Одноглазое, Царевна-Лягушка, Кощей Бессмертный, Кот-Баюн)

Цель игры, как было сказано выше, остаться в живых и победить. Противники должны так или иначе покинуть игру, а независимым так же следует остаться в живых до конца игры. В игре есть золото, своеобразная игровая валюта, которую игроки зарабатывают только внутри игры. Выигравшие получают золото. Чем больше золота, тем выше рейтинг игрока.


Остановлюсь чуть подробнее на описании персонажей.



Добрый Молодец



Красна Девица


Добрый Молодец и Красна Девица — самая массовая и основная роль в игре. Это мирные жители, которые по ночам спят, а днем работают. Ночью на них нападает кто-то из разбойников, Змей Горыныч и другие роли, а Василиса Премудрая их лечит. С некоторой, небольшой вероятностью Добрый молодец или Красна девица могут пережить нападение без ущерба (возможно, потеряв при этом золото), однако при этом все узнают псевдоним игрока следующим же днем после нападения\защиты. Ночью эти игроки не делают каких-либо ходов, а анализируют игровую ситуацию, исходя из сообщений в игровом чате. Днем же эти игроки решают путем голосования, кто из них не является Добрым молодцем или Красной девицей. Игрок, за которого проголосовало большинство других игроков, уходит из игры, оставшиеся получают или теряют золото. Если игроки не выбрали кого-либо большинством голосов, никто из игроков не будет казнен.



Иван-Царевич


Иван-Царевич — изначально анонимный защитник мирных жителей. По ночам проверяет роли других игроков, так как знает только одного своего союзника — Серого Волка. При непосредственном участии Серого Волка (который также может проверять роли других игроков) Иван-Царевич, вместо проверки, ночью может убить другого персонажа. Если в результате проверки Иван-Царевич видит роль Доброго Молодца или Красной Девицы у игрока, то может пригласить их к себе и познакомить с Серым Волком и другими Добрыми Молодцами и Красными Девицами. Ивану может помешать Царевна-Лягушка, которая его может ночью соблазнить, при этом не выдавая его роли другим игрокам днем. Если Иван сам обнаружит Царевну-Лягушку, то может ей предложить присоединиться к мирным жителям, однако если Царевна откажет, она погибает от руки Ивана. Змей-Горыныч также может мешать проверкам Ивана-Царевича, но, в отличие от Царевны-Лягушки, днем он расскажет остальным игрокам, кто из них — Иван-Царевич. Днем Иван-Царевич ничем не отличается от других Добрых Молодцев.



Серый Волк


Серый Волк — помощник Ивана-Царевича, чей острый нюх помогает Ивану найти других Добрых Молодцев и Красных Девиц. Серый Волк говорит этим игрокам, кто Иван-Царевич, а также сообщает о других игроках с ролями Добрых Молодцев и Красных Девиц. Если Волк обнаружит разбойника или другого противника, он незамедлительно сообщает об этом Ивану-Царевичу, чтобы тот на следующую ночь принял меры. Если на Волка нападет Царевна-Лягушка, он превращается в обычного Доброго молодца и не может проверить кого-либо, а Царевна не узнает, что на самом деле это был Серый Волк, так как Волк ночью не спит. Однако сам Волк при этом днем узнает, кто из игроков — Царевна-Лягушка, и может попытаться склонить остальных Добрых Молодцев и Красных Девиц, которых привел к Ивану-Царевичу, голосовать за казнь Царевны-Лягушки. Также на следующую ночь может попробовать анонимно склонить Царевну-Лягушку на сторону мирных жителей, чтобы она не трогала никого из них. Волк ночью может пожертвовать собой, чтобы спасти Ивана-Царевича или Василису Премудрую, если он предполагает, что те вдруг попадут под удар разбойников, или же были зомбированы Кощеем (у Волка вроженный иммунитет к чарам Кощея), но Волк после самопожертвования выбывает из игры.



Василиса Премудрая


Василиса Премудрая — играет за мирных жителей, однако они о ней не знают, поскольку Василиса очень скромная. Также Василиса Премудрая, когда лечит, не задает вопросов и как добрый доктор лечит всех подряд. Но если ее лекарство выпьет Кощей, Лихо или Леший — не жить им дольше одного дня, поскольку Василиса лечит только людей. Змею Горынычу или Коту-Баюну лекарства Василисы Премудрой тоже не помогут, но и вреда не принесут. Также Василису ночью не трогает Кот-Баюн, поскольку за травами лечебными Василиса в Безжизненный Лес не ходит. Кроме того женские чары Царевны-Лягушки на Василису не действуют. Если ее пациента попытаются убить дважды, медицина окажется бессильна. Василиса не спасет и от магических атак, например от проклятия Лихом. Днем Василиса ведет себя как Красна Девица, и только мимолетный, слегка грустный взгляд может немножко намекнуть, что она лучший лекарь в Тридевятом царстве.



Разбойник


Разбойники, в отличие от всех предыдущих ролей, знают друг друга, поскольку живут в одном Логове, а также знают Лешего и Бабу-Ягу, поэтому могут действовать согласованно сразу с первого хода. Но только Главарь шайки выполняет действия по ночам и не голосует днем, пока остальные Разбойники старательно прикидываются Добрыми Молодцами и Красными Девицами. Если Главарь выбывает из игры по какой-либо причине, его место тут же занимает один из оставшихся Разбойников. В первую очередь, Разбойники стараются вывести из строя Ивана-Царевича, пока тот не собрал достаточно сил из Добрых Молодцев и Красных Девиц для активного противостояния Разбойникам днем.



Леший


Леший по ночам шпионит для Разбойников, сообщая им о найденных ролях в их Логове, но днем не голосует, поскольку не живет в деревне. Однако другие игроки могут проголосовать за Лешего и, таким образом, казнить его. Так как Леший выходец из болот, его не может соблазнить Царевна-Лягушка, а если и попытается, то Леший пометит ее дом, и жители деревни узнают, кто она такая на самом деле. Не стоит Лешему опасаться и чар Кощея, а вот Василиса может залечить его до смерти. Если Кот-Баюн попробует напасть на Лешего, то рискует лишиться своих железных когтей, и придется потом Коту усыплять жертв одним только мурчанием.



Баба-Яга


Баба-Яга так же работает вместе с Разбойниками, по ночам колдует: может либо наслать болезнь на других игроков, либо защитить кого-нибудь из союзников от нападения. Её колдовство даже сильнее проклятья Лиха. Днем Баба-Яга тоже активна: того, кто у нее под защитой, нельзя казнить даже большинством голосов. Однако запас волшебных кореньев для дневной защиты ограничен, так что Баба-Яга не может защитить кого-нибудь, включая себя, больше трех раз за игру. При этом днем Баба-Яга прикидывается обычной Красной Девицей и голосует со всеми вместе.



Змей-Горыныч


Змей-Горыныч по ночам летает над деревнями, лесами и болотами и занимается грабежом, раскрывая днем роль ограбленного. Днем Змей спит, поэтому не голосует, но его могут казнить большинством голосов. Змей очень опасен для всех, особенно для Разбойников и Ивана-Царевича. Змею без разницы, кого грабить, но если его раскроет Волк или Леший, он может стать ценным союзником. Если убить Змея ночью, можно, с некоторой вероятностью, получить весьма ценный предмет — Змеиную Шкуру, которая защитит ее обладателя один раз от физической атаки.



Лихо Одноглазое


Лихо Одноглазое ночью убивает всех, кто попадается ему на пути, а кого убить не может (Лешего, Кота-Баюна, или Змея Горыныча) — проклинает, так что любой, кто попробует общаться с проклятым этой же ночью, умрет в течение дня. Сам проклятый при этом тоже погибает, не погибает только Кот-Баюн, который просто ложится спать, чтобы набраться сил, пропуская ход следующей ночью. Спасти от проклятия Лиха может только Баба-Яга. Проклятие не действует и на того, кто победил Кота-Баюна: он, как и Кот, просто ложится спать с пропуском хода.



Царевна-Лягушка


Царевна-Лягушка не может победить в игре, зато может заработать очень много денег, соблазняя других игроков по ночам. Соблазненный при этом пропускает ход. Лягушка не может соблазнить Василису Премудрую, также ей стоит избегать Лешего, который ее сдаст всем на следующий день. Если Иван-Царевич или Главарь Разбойников найдут Лягушку, то могут пригласить на сторону мирных жителей или Разбойников, при этом Иван не приемлет отказа Лягушки, а вот Главарь не такой разборчивый. Но Царевна достаточно хитрая, может стать двойным агентом, ведь несмотря на то, что она в одиночку не может победить, — это отличный шанс набрать золота, ведь шансы дотянуть до конца игры сильно возрастают! Днем Царевна-Лягушка прикидывается Красной Девицей и голосует со всеми вместе.



Кощей Бессмертный


Кощей Бессмертный живет у себя замке. По ночам он ходит по окрестным деревням и зомбирует Добрых Молодцев и Красных Девиц, которые переходят к нему на службу и беспрекословно выполняют все поручения. Отказавшись выполнить приказ, к примеру голосовать днем по-другому, чем было сказано Кощеем, или писать сообщения днем в чате, если Кощей это запретил, Слуга Кощея гибнет. Таким образом, Кощей способен повлиять на результаты голосования днем, хоть сам лично не голосует. Если Кощея убьют, все его жертвы тоже погибают. Василиса может вылечить Слугу Кощея, который потом возвращается к своей исходной роли. У Змея-Горыныча и Волка врожденный иммунитет к зомбированию, так что Кощей при всем желании не может обратить их к себе на службу. Также Волк может выручить из беды Ивана или Василису, пожертвовав собой. Спасенные Волком приобретает Волчий иммунитет к зомбированию.



Кот-Баюн


Кот-Баюн живет в лесу, по ночам охотится. Днем спит у себя в дупле, поэтому в голосовании не участвует. Однако днем его могут казнить большинством голосов. Кот может атаковать двумя способами: мурчать — и тогда его жертва засыпает и не может ходить ночью, а также голосовать на следующий день, — либо убивать сразу железными когтями. Атака когтями не работает на Змее-Горыныче, а, атаковав Лешего, Кот и вовсе может остаться без когтей! Лихо не может проклясть Кота, который после проклятия просто будет спать одну ночь. Если кто осилит Кота-Баюна победить, от любой болезни и недуга, включая проклятие Лиха, исцелится. Эта Котова способность сохраняется за игроком до конца игры. Слуги Кощея не могут днем голосовать за Кота, но могут косвенно узнать, кто Кот, не сообщая об этом Кощею. Кот-Баюн не вступает в союзы с Иваном или Разбойниками, так что они для Кота — первостепенная цель.


Используемые технологии


Для написания игры я выбрал технологию бессерверных вычислений (serverless) на основе OpenFaaS, поскольку она достаточно простая для организации игры, и вместе с тем достаточно развитая, чтобы писать сложные игровые правила без излишних усложнений. Также я буду использовать кластер Kubernetes, поскольку этот способ развертывания приложений позволяет довольно просто и надежно получить быстрое развертывание, возможность легкого масштабирования. Для создания игровой логики можно обойтись только OpenFaaS, однако я также попробую сделать Сказочника в виде отдельного контейнера, чтобы сравнить сложность реализации. В качестве основного языка программирования для микросервисов и функций я выбрал Go, поскольку уже давно изучаю его в свободное время на замену Perl, а для взаимодействия пользователей с микросервисами и функциями будет использоваться js на основе некоего фреймворка. Об окончательном решении я расскажу в соответствующей статье цикла. Для общения функций между собой я выбрал NATS.io, поскольку уже сталкивался с нею ранее, и у нее достаточно легкая интеграция в Kubernetes.


Анонс


  • Введение
  • Установка окружения для разработки, разбиение задачи на функции
  • Работы над backend
  • Работы над frontend
  • Настройка CI\CD, организация тестирования
  • Запуск пробного сеанса игры
  • Итоги




К сожалению, не доступен сервер mySQL