惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
GbyAI
GbyAI
Y
Y Combinator Blog
Google DeepMind News
Google DeepMind News
小众软件
小众软件
The GitHub Blog
The GitHub Blog
阮一峰的网络日志
阮一峰的网络日志
J
Java Code Geeks
WordPress大学
WordPress大学
Microsoft Security Blog
Microsoft Security Blog
IT之家
IT之家
F
Fortinet All Blogs
博客园 - 【当耐特】
H
Hackread – Cybersecurity News, Data Breaches, AI and More
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
C
Cybersecurity and Infrastructure Security Agency CISA
L
LINUX DO - 热门话题
Spread Privacy
Spread Privacy
O
OpenAI News
V
V2EX
博客园 - 三生石上(FineUI控件)
AI
AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
Microsoft Azure Blog
Microsoft Azure Blog
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Jina AI
Jina AI
H
Help Net Security
L
LINUX DO - 最新话题
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tenable Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Cisco Talos Blog
Cisco Talos Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 叶小钗
V
Vulnerabilities – Threatpost
C
Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
酷 壳 – CoolShell
酷 壳 – CoolShell
Hacker News: Ask HN
Hacker News: Ask HN
S
Security @ Cisco Blogs
S
Securelist
T
The Blog of Author Tim Ferriss
Apple Machine Learning Research
Apple Machine Learning Research
美团技术团队
雷峰网
雷峰网
V2EX - 技术
V2EX - 技术

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Драматургия через математику: WFC + Entropy Bias
DyadichenkoG · 2026-04-22 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение11 мин

Охват и читатели1.9K

Как одна модификация формулы превращает генератор карт в дизайнера уровней

Всем привет! Меня зовут Григорий Дядиченко, и я технический продюсер. Играли в Hades? Там дизайнер уровней не бросает кубики. Он точно знает, где игрок поймает дыхание после погони, где встретит соблазн свернуть с пути, где сундук стоит под прицелом элитника, а где — просто в углу за колонной. В простой случайной генерации таких решений нет: карты рождаются «равномерными» и драматургически мёртвыми. Сегодня хочется поговорить о том, как одной модификацией в формуле Wave Function Collapse вернуть в генератор жизнь. Разберём Entropy Bias, Entropy Cascade, Tile Probability Bias и семантические слои. Если вам интересна тема процедурной генерации и немножко математики — добро пожаловать под кат.

WFC за три минуты

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

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

Вопрос собственно один: какую клетку коллапсировать следующей? И вот тут появляется энтропия Шеннона.

 H(c) = -sum( p(t) * log2(p(t)) )

где p(t) — вероятность того, что клетка станет тайлом t. Чем выше энтропия — тем больше неопределённость. Чем ниже — тем клетка «определённее»: осталось меньше вариантов.

WFC всегда коллапсирует клетку с минимальной энтропией. Ту, где выбор почти сделан, где противоречие вероятнее всего и решение дешевле проверить. По сути — жёсткий скелет алгоритма. Всё остальное (overlap model, simple-tiled, backtracking) — это детали реализации, сейчас они нас не интересуют.

Если хочется копнуть глубже, то вот хорошие ресурсы:

  • https://github.com/mxgmn/WaveFunctionCollapse — оригинал от Максима Гумина.

  • https://robertheaton.com/2018/12/17/wavefunction-collapse-algorithm/ — лучший пошаговый разбор, который я видел.

  • Shannon, C.E. (1948). A Mathematical Theory of Communication — корни энтропии, если захочется дойти до основ основ.

Проблема: WFC не знает, что он делает

Чтож, а теперь собственно проблема, ради которой вся статья и затевалась.

Правило минимальной энтропии — локальное. Алгоритм смотрит на одну клетку и её ближайших соседей через ограничения соседства. Он не знает, где эта клетка находится: в центре комнаты, у выхода, на границе безопасной зоны. Для WFC карта — однородный математический объект, в котором каждая позиция эквивалентна любой другой.

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

Две карты из одного генератора, с одним тайлсетом, с одними ограничениями.

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

Вторая. Игрок заходит — короткий коридор с одним мобом для разогрева. Развилка: влево — риск и сундук, вправо — безопасно, но длиннее. В центральной арене бой с несколькими волнами. Перед выходом — алтарь-выбор. Тоже валидный результат WFC. С тем же тайлсетом.

азница — в том, чего WFC не моделирует: темп, ожидание, направление. Дизайнер уровней оперирует понятиями «дальше от входа», «ближе к боссу», «в зоне риска», «после безопасной паузы». Алгоритм — только соседством. Если у дизайнера в голове лежит карта напряжения, то у алгоритма ничего похожего нет. Он равномерен.

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

Значит, алгоритму нужно дать понятие пространства. Не декоративно, не поверх. В ядро формулы. Чем и займёмся.

Модификация: Entropy Bias

Было:

select = argmin[ H(c) + noise(c) ]H(c) = -sum( p(t) * log2(p(t)) )

Стало:

select = argmin[ H(c) · f(W(x,y)) + noise(c) ]

Одно умножение, один новый множитель. Смотрите внимательно — в этой строке по сути всё содержание статьи.

W(x,y) — это семантический вес. Скалярное поле в диапазоне [0.0, 1.0], определённое на той же сетке, что и карта. Для каждой клетки (x, y) — одно число, которое говорит: насколько эта клетка важна для общей структуры. W = 1.0 — ключевая зона (босс-арена, стартовый хаб, ядро награды). W = 0.0 — проходная клетка, наполнитель.

f — монотонно убывающая функция: чем больше вес, тем меньше f. Простейший вариант:

f(W) = 1.0 - beta * W

где beta ∈ [0, 1] — сила смещения. При beta = 0 получаем классический WFC. При beta → 1 семантический вес полностью доминирует над энтропией.

Что происходит с правилом выбора? Была argmin H(c), стала argmin H(c) * f(W). Для клеток с высоким W множитель f маленький — итоговое значение падает — клетка с большей вероятностью попадает в минимум — коллапсирует раньше. Клетки с низким W, наоборот, отодвигаются в конец очереди.

И здесь собственно ключевое наблюдение: мы поменяли не порядок, а топологию.

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

Но WFC — алгоритм с propagation. Как только клетка коллапсирует, через правила соседства её состояние сужает варианты у соседей, соседей соседей и так далее. Клетка, севшая первой, становится источником ограничений, которые волной расходятся по сетке. Те клетки, что сядут позже, уже не выбирают из полного атласа тайлов — они выбирают из того, что им «оставили» предшественники.

Значит, решая «кто коллапсирует первым», вы на самом деле решаете, кто кому родитель в графе зависимостей. Поле W — это карта источников: вот здесь рождаются решения, отсюда информация течёт наружу. Это описывает не положение в очереди, а структуру связей: кто кого определяет, в каком направлении расходятся фронты ограничений, где встречаются волны от двух разных источников и спорят за пограничные клетки. Именно это я и называю топологией.

Представьте дождь на рельефе. Если просто перемешать порядок падения капель — ничего не изменится, вода всё равно соберётся туда же. А вот сама форма рельефа (где пики, где низины) определяет всю структуру потоков: где образуются реки, куда стекает с какого склона, где собираются озёра. Классический WFC — плоская плита, капли падают хаотично, карта пропитывается равномерно. Поле W в Entropy Bias — это и есть рельеф: задаёт, откуда информация стекает в какие области, какие зоны оказываются «вверх по течению», а какие пассивно принимают то, что к ним пришло.

Entropy Cascade

Давайте посмотрим, что происходит дальше. Когда клетка с высоким весом коллапсирует, включается propagation. Её состояние зафиксировано — у соседей сужается множество допустимых тайлов — у них падает энтропия. В следующей итерации argmin с большой вероятностью выберет одного из этих соседей: их энтропия упала, а их W тоже, скорее всего, немаленький (поле W обычно гладкое — ключевые зоны не выглядят как одинокий пиксель).

Соседи коллапсируют — propagation идёт дальше — их соседи садятся вторым кольцом. В общем, получается волна: расходящиеся из «горячих» зон концентрические фронты коллапса. Я это называю Entropy Cascade.

Следствие: структура карты определяется не правилами тайлов, а формой поля W. Если W имеет один пик в центре — карта строится от центра наружу. Два пика — две зоны роста, которые встречаются посередине и спорят за пограничные клетки. Длинный гребень — карта строится полосой. Круг — кольцо с "неважной" серединой, которая заполнится последней и, скорее всего, непредсказуемо.

В классическом WFC порядок коллапса практически случаен: минимальная энтропия ломается шумом, и структура карты — это эмерджентный результат локальных ограничений. В WFC + Entropy Bias порядок коллапса задан полем W, и через него — задана топология распространения информации по карте.

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

Generated Image

Generated Image

Выбор функции f

Форма f(W) — это важный дизайнерский выбор, а не формальность. Давайте разберём пару рабочих вариантов.

Линейная.

f(W) = 1.0 - beta * W

Гладкая. Даёт плавное смещение. Разумный стартовый выбор: легко дебажить, легко крутить beta.

Пороговая.

f(W) = 1.0if ..W < threshold..epsilon..otherwise

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

Экспоненциальная.

f(W) = exp(-k * W)

Нелинейная. Мелкие различия в W почти не влияют, крупные — драматически. Усиливает контраст между ключевыми и проходными клетками.

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

Что происходит с noise

noise(c) в исходной формуле — небольшой случайный член, который разрывает ничьи между клетками с одинаковой энтропией. После модификации он нужен в той же роли, но его амплитуду приходится подбирать аккуратно. Если H(c) f(W) превратилось в маленькое число (оба множителя меньше единицы), а noise остался прежнего размера — шум перекроет сигнал, клетки начнут выбираться случайно, смещение исчезнет. По сути, нужно масштабировать шум долей от среднего H f по сетке, а не оставлять абсолютную константу. Мелочь, но если её забыть — удивитесь, почему вся модификация не работает.

Что это меняет для дизайнера

В классическом WFC вы контролируете карту через атлас: какие тайлы существуют, какие соседства разрешены. Это низкоуровневый контроль — вроде задания грамматики для языка, на котором потом говорит алгоритм. Вы не можете сказать «здесь должен быть тяжёлый момент», вы можете сказать только «этот тайл может стоять рядом с вот этим».

Entropy Bias добавляет отдельный уровень управления поверх грамматики: где в картинной плоскости должен быть тяжёлый момент. Этот уровень не конфликтует с ограничениями — он работает в полностью валидном подмножестве. Его проще рисовать: одна тепловая карта, кисть, слайдеры. И собственно, это и есть тот интерфейс, которого всегда не хватало дизайнеру уровней в процедурной генерации.

Второй рычаг: Tile Probability Bias

Entropy Bias решает, когда клетка коллапсирует. Остаётся вопрос, чем клетка становится, когда очередь дошла.

В классическом WFC выбор тайла внутри клетки — это взвешенный случайный выбор из оставшихся вариантов, где веса p(t) берутся из частот тайлов в обучающем атласе. Если сундук встречается в атласе в 2% случаев — примерно в 2% клеток, где он допустим, он и выпадет. Банально.

Модификация:

p'(t, c) = p(t) · g(t, W(x,y))

Вероятность тайла теперь зависит не только от атласа, но и от места. g — функция, заданная для каждого тайла отдельно: для одних растёт с W, для других падает, для третьих не меняется.

Пример: перки. Как в каком-нибудь Diablo или Hades. В атласе есть тайлы общих, редких и легендарных перков. В ванильном WFC они выпадают со своими частотами — легендарный, условно, с 5%, где попало. С Tile Probability Bias:

g(common, W_e)    = 1.0 - W_eg(rare, W_e)      = constg(legendary, W_e) = W_e

где W_e(x,y) — близость к выходу уровня: высокая в конце, низкая в начале. Чем дальше игрок прошёл — тем выше tier доступного перка.

Это уже не геометрия. Это нарратив: «чем дольше держался, тем лучше награда». Закодирован прямо в вероятностную функцию. Правил вида «легендарный не может стоять рядом со входом» — нет. Есть скалярное поле и модуляция частоты. Собственно и всё.

Entropy Bias двигает скелет карты. Tile Probability Bias — наполняет уже сложившийся скелет. Они ортогональны: можно включить один без другого. Вместе — карты, где и структура, и содержание подчинены одной дизайн идее.

Семантические слои

Одно поле W — неудобно на практике. Когда хочется одновременно «награда в центре, боссы на границах» и «выход далеко от входа, безопасные зоны на пути», кодировать всё в одну скалярную функцию — значит получить кашу, которую невозможно дебажить. Так что давайте разложим на слои.

  • W_d(x,y)danger: где появляются враги и ловушки

  • W_r(x,y)reward: где падают перки, сундуки, алтари

  • W_e(x,y)exit: направленность к выходу уровня

  • W_n(x,y)narrative: специальные зоны (босс-арена, safe room, триггер катсцены)

Каждый слой — это отдельное скалярное поле. Отдельно рисуется, отдельно дебажится, отдельно влияет на соответствующий тип тайлов через g(t, W_i).

Итоговый вес для Entropy Bias — взвешенная сумма:

W(x,y) = sum( alpha_i * W_i(x,y) )

где alpha_i — дизайнерские коэффициенты: «на этом уровне важнее динамика награды, alpha_r = 0.5», «а тут важен путь, alpha_e = 0.7».

По сути, эта декомпозиция — это интерфейс. Дизайнер уровней рисует четыре понятных карты вместо одной непонятной. Карта опасности — кисть. Карта награды — кисть. Карта выхода — градиент от старта к концу. Карта нарратива — точки интереса. Алгоритм собирает.

Чтож, давайте посмотрим на три сценария, где слои работают вместе.

Награда за риск

W_d и W_r оба высокие в центре. Ядро карты одновременно — зона опасности и зона награды. Алгоритм коллапсирует это ядро первым (суммарный W большой) — туда попадают тайлы, совместимые одновременно с элитным врагом и с хорошим сундуком. Propagation от ядра задаёт коридоры: они «знают», что ведут в опасную зону. К моменту, когда периферия коллапсирует, она уже адаптирована под это ядро — стены, ограничение видимости, узкие проходы.

Эффект для игрока: подходя к центру, вы чувствуете нарастание давления. Находите элитника — и сразу видите сундук с легендаркой за его спиной. Выбор: рискнуть или уйти. Карта рассказала эту историю без единого скрипта. По сути, классическая связка «риск — награда» из World of Warcraft или любой рогалик-игры, но сгенерированная автоматически.

Путь наименьшего сопротивления ведёт не к выходу

W_e направлен в одну сторону — это «правильная» дорога к выходу. Но W_d вдоль этой дороги высокий: там мобы, препятствия, узкие места. Параллельно — более открытый коридор с низким W_d, но уводящий в тупик или длинный обход.

Игрок интуитивно выбирает лёгкий путь. Через пять минут понимает, что ушёл не туда. Возвращается. Это не баг, это дизайн: карта создаёт ощущение выбора и его цены. В WFC без Entropy Bias такое случается редко и случайно. С Entropy Bias — стабильно, и интенсивность настраивается контрастом полей.

Тайная комната

W_r имеет локальный пик в углу, далеко от старта и выхода. W_n низкий везде, кроме этого пика. В поле W образуется «остров»: клетки с высоким весом, окружённые низким.

Алгоритм коллапсирует остров одним из первых (высокий W → низкий f → коллапс). Через propagation остров формирует маленькую замкнутую зону с лучшей наградой уровня. От него фронт коллапса слабый (вес падает резко), и соседство с остальной картой определяется обычным WFC — как пойдёт. Часто комната оказывается за стеной, за секретным проходом, за непроходимой на первый взгляд преградой. Её надо найти. Найдёте — забираете лучший перк уровня. Как в Skyrim, только без ручной расстановки.

И собственно разница с «ручным» размещением тайника: он не фиксирован в координатах. Он фиксирован в отношении — как аномалия поля W. Где конкретно он окажется на карте — решает алгоритм через propagation. Каждый прогон даёт новое размещение, но свойство «далеко, тяжело найти, хорошо платит» сохраняется.

Это и есть то, ради чего вся модификация: инвариант дизайна сохраняется, конкретная реализация варьируется от прогона к прогону. Дизайнер задаёт идею, а не результат.

Интерактивное демо

По сути, всё это удобнее один раз увидеть, чем прочитать. Я собрал интерактивное демо: вы рисуете три тепловые карты (danger, reward, exit). Алгоритм выдаёт уровень в реальном времени. Меняете кисть — перегенерируете. Видно, как форма поля W проявляется в геометрии карты и какие сценарии получаются из каких комбинаций слоёв.

Итого

Собственно, что мы получили. Классический WFC коллапсирует карту по локальной энтропии — структура эмерджентна и драматургически равномерна. Добавили f(W(x,y)) в формулу выбора клетки — получили Entropy Bias: ключевые зоны коллапсируют первыми, от них расходятся волны Entropy Cascade, и топология карты перестаёт быть случайной. Добавили g(t, W(x,y)) в вероятность тайлов — получили Tile Probability Bias: наполнение карты тоже зависит от места. Разбили W на семантические слои — получили интерфейс, который понимает дизайнер уровней. В канале просили что-то сложное — получайте. Если половина слов не совсем понятна в этом абзаце — это нормально.

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

Источники, из которых собиралась картина: