Фибоначь врагов

от автора

Структуру, о которой ниже пойдёт речь, знали в древней Индии за тысячу лет до самого Фибоначчи и переоткрыли в 1988 году двое математиков, при этом весь граф целиком строится из строк, состоящих только из цифр 1 и 2, или если мы вычтем единицу, то получим 0/1 и бинарный вид.

Берём любую конечную строку из цифр 1 и 2, например такую «11212» и складываем цифры 1 + 1 + 2 + 1 + 2 = 7 и получаем ранг этой строки. Теперь простой вопрос: сколько существует строк заданного ранга? Строку такого же ранга можно получить двумя способами, либо дописав цифру 2 к строке ранга r-2, либо дописав цифру 1 к строке ранга r-1, и других вариантов нет, потому что других цифр в нашем алфавите из единиц и двоек нет.

ранг 0: “” → 1
ранг 1: 1 → 1
ранг 2: 11, 2 → 2
ранг 3: 111, 12, 21 → 3
ранг 4: 1111, 112, 121, 211, 22 → 5
ранг 5: … → 8

Заметили справа подозрительное 1, 1, 2, 3, 5, 8? Да… это последовательность Фибоначчи f® = f(r-1) + f(r-2), с небольшим условием что f(0) = 1 (пустая строка) и f(1) = 1 (единственная строка “1”), из-за этого вся последовательность сдвинута на одну позицию относительно канонических чисел Фибоначчи, и f® = F(r+1).

То же самое делали индийские стиховеды, с своих стихах — короткий слог занимает одну единицу длительности, длинный две, что позволяло красиво бить ритм и получать благозвучные конструкции в тексте, так что числа Фибоначчи в этом контексте старше самого Фибоначчи. Интересно что связывает стихи, Фибоначчи и дерево технологий в играх? Го под кат…


Красивая теория

Теперь берем получившиеся сочетания и пробуем сделать их графом, получается вот такая красивая структура.

ранг 4:   1111    112     121     211     22            │      │       │      │ │     ││            │      │       │      │ └──┐  ││ранг 3:    111 ────┼───────┼──────┘    21─┘│            │      12 ─────┼────────────┼──┘            │       │      │            │ранг 2:    11 ──────┼──────┼────────────┘            │       └────  2            │              │ранг 1:     \──────  1  ───/                     │ранг 0:             ""

Называется он граф Юнга-Фибоначчи и имеет вершину для каждой строки, включая пустую, а соседями строки s объявляются результаты четырёх операций:

  • вставить цифру 1 где-нибудь левее самой левой единицы, а если единиц в строке вообще нет, то в любое место.

  • заменить самую левую единицу на двойку.

  • удалить самую левую единицу.

  • заменить на единицу любую двойку, слева от которой нет ни одной единицы.

Эти операции разбиваются на две взаимно обратные пары: первая отменяется третьей, вторая отменяется четвёртой, поэтому граф можно считать неориентированным, но обычно его рисуют ориентированным, направляя каждое ребро от меньшего ранга к большему. Из этих же правил получаются интересные свойства строк: у строки 211 два непосредственных предшественника, 111 и 21, а у строки 22 тоже два, 12 и 21, а у строки 121 предшественник будет один.

Математики (Фомин и Стенли) эти свойства заметили и описали в своих работах:

  1. Граф связный, у любой непустой строки всегда есть операция, понижающая ранг, значит из любой вершины можно спуститься до пустой строки, а развернув путь получить дорогу из пустой строки куда угодно.

  2. Граф согласованый, длина любого направленного пути в точности равна разности рангов его концов (“коротких путей в обход” не существует).

  3. Для любых двух различных вершин u и v количество их общих непосредственных предшественников равно количеству их общих непосредственных последователей, и это число всегда либо ноль, либо единица.

  4. Исходящая степень любой вершины на единицу больше входящей, для каждой вершины по отдельности.

""     out=1  in=01      out=2  in=1     (вверх: 11, 2 | вниз: "")11     out=2  in=1     (вверх: 111, 21 | вниз: 1)2      out=2  in=1     (вверх: 12, 21 | вниз: 1)21     out=3  in=2     (вверх: 121, 211, 22 | вниз: 2, 11)22     out=3  in=2     (вверх: 122, 212, 221 | вниз: 12, 21)

Откуда берётся эта лишняя единица? Вставка единицы даёт столько вариантов, сколько есть позиций левее самой левой единицы, то есть количество ведущих двоек плюс один, а операция четыре, ведущая вниз, даёт на один вариант меньше. Замена самой левой единицы на двойку и удаление самой левой единицы дают по одному варианту каждая и взаимно компенсируются. Фомин назвал граф с таким набором свойств Y-графом, ну потому что действительно похоже на Y-ветвления. Стенли показал в своих работах доказал, что в любом ранге можно найти решетку сводящуюся к схеме ниже: 21, 22, 121, 211 и 221.

              221        (ранг 5)            /  |  \          22  121  211   (ранг 4)            \  |  /              21         (ранг 3)

Не устали еще? Теперь как это связано с играми…

Юнг, Фибоначчи и расстановка монстров

Всё, что написано выше, звучит как математика ради математики… не знаю зачем это нам давали в универе и даже писал пару лаборатоных на эту тему и наверное забыл бы совсем, видимо, чтобы я блеснул знаниями перед левел дизайнерами. И вот тут мы подбираемся к играм.

Дизайнеры в двух шутерах двух разных студий расставляют врагов на уровне по этому самому графу. Сами дизайнеры не знали что они применяют диаграмму Хассе (и частный случай её граф Юнга-Фибоначчи), думаю они и слов-то таких не знали, просто в процессе настройки и тестирования уровней выяснилось, что вываливать врагов на игрока кучей неинтересно и быстро надоедает, а лучше разбивать уровень на сегменты, и размещать там врагов по некоей секретной формуле.

Менять врагов сразу на «много» тоже снижает интерес, поэтому раскладка в секретной формуле описывала добавление одного простого врага к тому числу, что было в текущей точке спавна, если игрок пошел в одну сторону, и схлопывание двух слабых врагов в одного более сильного — если пошел в другую. Ничего не напоминает?

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

Ранг строки, то есть сумма её цифр, оказывается бюджетом сегмента, и вся кривая напряжения по уровню превращается в последовательность рангов, которую дизайнер задаёт через размещение врагов в точках спавна.

Никакой попытки свести бандита и монстра, который прёт в лоб, к общей шкале стоимости не делалось, потому что такая шкала начинает врать, а расширение алфавита {1,2} новыми буквами ломало схему и снижало интерес у фокус-групп, т.е. все должно работать в пределах одного типа врагов. Хотите другой тип врагов? Делайте ему свою фибоюнговину и расставляйте по уровню. Формально это естественное поведение такого алгоритма, и эта единичка для врага любого типа просто двигает сложность, но…

Но это дает дизайнеру возможнось размещать врагов в любом месте уровня, опираясь на данные из предыдущих стычек и точек спавна, не переставляя заново всё, что стоит дальше по коридору. Еще это дает правильный прогресс сложности, такой граф градуирован и длина любого пути равна разности рангов, а обходных путей не существует, что было доказано математиками. Значит переход между двумя соседними сегментами кривой всегда раскладывается в известное число «добавил-убрал врага», и дизайнер если следует правилам не может случайно перепрыгнуть ступеньку слоужности.

И наконец становится возможно уровень сложности нормально посчитать не привлекая санитаров. Дизайнер описывает верхнюю раскладку и точку схождения, а всё промежуточное вычисляется на простом питоновском скрипте. И сложная боевая система уровня становится числами раскладки бюджета с врагами, позволяя сделать три разных прохождения одной стычки, одинаковым по сложности и разным по ощущению.

Фибоначчи, Юнг и деревья навыков

Работая уже в другой студии, над другим проектом в совершенно другом жанре я обнаружил, что дизайнер дерева технологий использует подозрительно похожую схему для настройки цены развития. Оговорюсь, что это не то отображение дерева технологий или развития персонажа в игре, которое вы видите на экране. Это такой лист с деревом технологий, нарисованным лесенкой что у вас как игрока получилась сбалансированная карта развития персонажа, и более-менее стабильные билды или сборки или равносильные рассы. А если такую лесенку не нарисуете зараенее, то у вас получатся возможно интересные особенности у каждой рассы или билда, но сбалансировать их станет сложно и придется вводить дополнительные элементы или механики.

Ветка A  ■ ■ ■ ■ □ □Ветка B  ■ ■ ■ □ □Ветка C  ■ ■ □ □Ветка D  ■ □Состояние = (4, 3, 2, 1), ранг 10.Закрашенное всегда образует лесенку, невозрастающую сверху вниз.

Решетка юнга позволяется разложить технологии в сетку, где строка это ветка развития, а столбец глубина внутри неё. Дальше мы вводим правило, что клетку (мощную технологию) можно взять, только если уже взяты клетка слева и клетка сверху. Множество допустимых состояний исследования при таком правиле в точности совпадает с множеством диаграмм Юнга, помещающихся в эту сетку. То есть вопросы “как сбалансировать две рассы” и “сколько ещё надо добавить, чтобы получить сбалансированные билды” теперь решаются арифметикой над массивом, без обхода графа зависимостей, к чему это я… Если у вас в игре две расы врагов, посчитать такие таблицы можно на бумаге, но в AoE2 сейчас около пятьдесяти рас, и у каждой свое дерево технологий, которые должны балансироваться с другими. Сбалансировать такое руками? Наверное можно…

Для баланса игры это хорошо, потому что не будет скрытых особеннстей, а для реиграбельности скорее плохо, потому что все пути получаются одинаковой длины в конечном счёте взаимозаменяемы, и тогда ощущение выбора приходится создавать другими средствами. Оговорюсь, что в виде кода эти таблицы (дерево технологий) ни в одном известном мне проекте так не генерируется. И в Age of Empires 2, и в Stellaris граф технологий сделан руками, причём Stellaris поверх него ещё и накидывает случайные технологии, что от решёточной детерминированности максимально далеко. Речь именно об инструментах и о том, как устроено пространство создания таких деревьев технлогий, а не о рантайме.

Зачем всё это

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

Но вся эта конструкция интересна как в ней вылезли числа Фибоначчи, правда они вылезают примерно везде, где что-то считается. Еще она интересна, что четыре простых правила могут порождают интересный дизайн уровня и боевки достаточный, чтобы не давать расслабляться игроку и при этом не ломать прогрессию сложности.

Дизайнеры уровней и дерева технологий пришли к этому методом проб и ошибок, хотя надо было всего лишь погрузиться в теорию частично упорядочных множеств и тразитивных сокращений с диаграммами Хассе. Но про Хассе они точно не знают, я спрашивал…

ссылка на оригинал статьи https://habr.com/ru/articles/1076886/