Пара к balance-100-levels.xlsx / .csv. Модель, веса, логика ступеней, мостик к экономике и
ограничения. Deliverable фазы 5. Контракт с прототипом: строки 1, 12, 23, 34, 45, 56, 67, 78, 89, 100
воспроизводят P1–P8 и difficulty_score десяти уровней прототипа (levels.json) в пределах ±0.15.
1. Формула difficulty_score
Сложность — взвешенная сумма нормированных параметров P1–P8 (не «слова длиннее»). Каждый
параметр нормируется в [0,1] по своему дизайн-диапазону, поэтому вес = максимальный вклад
этого параметра в очки сложности при полном размахе. В xlsx это формула в ячейке (лист Table,
колонка difficulty_score), ссылающаяся на веса на листе Model (B4–B12) и на P-ячейки своей строки:
score = FLOOR
+ w1 · (P1−1)/4 # words_count, диапазон 1..5
+ w2 · (P2−4)/4 # word_len_max, 4..8
+ w3 · (P3−1)/5 # zipf_band, 1..6
+ w4 · P4 # scramble_score, уже 0..1
+ w5 · (P5)/2 # trap_anagrams, 0..2
+ w6 · (P6−3)/11 # answer_letters, 3..14
+ w7 · enc(P7) # pun_type: direct=0, idiom=.33, homophone=.66, double-layer=1.0
+ w8 · (5−P8)/4 # cartoon_transparency инвертирован: 5=легко→0, 1=сложно→1
enc(P7) в Excel реализован вложенным IF по строковому значению pun_type.
Веса (лист Model) и почему такие
| Параметр | Вес (макс. вклад) | Доля от размаха | Обоснование (вклад ≈ влияние на время решения) |
|---|---|---|---|
| P1 words_count | 3.29 | 41 % | Число слов — грубый регулятор длины уровня: каждое новое слово — отдельный акт unscramble + удержание в памяти. Линейно множит работу → сильнейший драйвер медианного времени. |
| P4 scramble_score | 2.35 | 29 % | Разрушение биграмм — главный рычаг «залипания» скрэмбла (research §4 п.5; jumble-analysis). На 0–1 шкале с большим весом: переход 0.33→0.70 в одном слове кратно удлиняет поиск. |
| P2 word_len_max | 0.90 | 11 % | Длина слова растит пространство перестановок (факториально), но с потолком читаемости на 6"; вклад заметный, но вторичный к «сколько слов». |
| P7 pun_type | 0.60 | 7.5 % | Когнитивная сложность кульминации: direct → idiom → homophone → double-layer. Двухслойный каламбур требует «додумать» связь — но это разовый акт на уровень, поэтому вклад умеренный. |
| P5 trap_anagrams | 0.35 | 4.4 % | Ложная анаграмма в пуле уводит в тупик; штраф времени есть, но игрок обычно выкарабкивается — не доминирующий фактор. |
| P6 answer_letters | 0.33 | 4.1 % | Длина финального ответа; сильно коррелирует с P1/P2, поэтому во взвешенной сумме несёт свой небольшой остаточный вклад, чтобы не задваивать. |
| P3 zipf_band | 0.10 | 1.2 % | Редкость лексики. Мал по одной причине (см. §5, ограничения): в 10 якорях P3 почти монотонно растёт вместе с P4/P8, и линейная модель не может отделить его собственный вклад — он «поглощён» P4. Оставлен положительным (не ноль), чтобы редкая лексика всё же добавляла сложности. |
| P8 cartoon_transparency (инв.) | 0.10 | 1.2 % | Прозрачность карикатуры. Та же коллинеарность, что у P3: держим маленький положительный вклад, чтобы «намекающая» карикатура читалась как облегчение. |
FLOOR |
0.0765 | — | Пол шкалы (базовая когнитивная стоимость даже тривиального уровня). |
Калибровка весов. Веса не подобраны «на глаз»: это решение минимаксной задачи (LP), которая
минимизирует максимальную ошибку воспроизведения 10 якорей, при ограничениях (а) все веса ≥ 0
(отрицательный вклад параметра бессмысленен), (б) иерархия дизайна: w(P2) ограничен сверху, чтобы
длина слова не перевешивала «сколько слов» и «насколько зол скрэмбл». Достигнутый максимум ошибки по
якорям — 0.149 < 0.15. Файл-калибратор и проверка — build_balance.py / verify_balance.py.
Почему нормированная сумма, а не «сырые» веса из
levels-design.md. Рамочная формула из фазы 1
(0.9·P1 + … + 0.30·(6−P8)) была помечена как ориентировочная. При прямом применении она даёт
ошибку до 0.35 на краях (v1, v100 авторски заданы «круглыми» и не ложатся на чистую линейную
модель). Нормировка в[0,1]+ минимакс дают попадание в допуск и одновременно человекочитаемые
веса («сколько очков максимум даёт параметр»).
2. Кривая: тренд + пила + передышки + майлстоуны
- Тренд — сублинейный: значения P1–P8 интерполируются между якорями так, что ранний прирост
ощущается сильнее позднего (P1 берёт вторую… пятую единицу всё реже; P4 растёт с насыщением).
Средний score первой десятки ≈ 1.2, последней ≈ 6.2. - Пила — на непрерывном P4 наложена детерминированная осцилляция (
sawtooth): +спайк на каждом
10-м уровне, −передышка на уровне сразу после, плюс мягкие микро-волны в середине блока.
Амплитуда ~10–15 % локального размаха. В якорных точках осцилляция = 0 (значения запинены). - Передышки — после каждого milestone-спайка score падает (проверка
verify_balance.py[4b]
подтверждает дипы на 8 из 9 переходов «10-й → 11-й»). Блоки, которые в прототипе идут вниз
(v34→v45, v67→v78), интерполируются как гладкие спуски (staggering ступеней отключается на
нисходящих блоках, чтобы не появлялись артефактные зубцы). - Майлстоуны — колонка
notesна каждом 10-м уровне печатает «новинку» (расписание ниже).
Расписание новинок (колонка notes, каждый 10-й)
| Уровень | Новинка |
|---|---|
| 10 | первый полноценный 3-словный «разогрев», пик пилы скрэмбла |
| 20 | омофонный каламбур закрепляется как стандарт блока |
| 30 | подход к первому 2-словному ответу; появляются ловушки |
| 40 | 2-словные омофоны — рутина; P6 растёт до 9–10 |
| 50 | в ротацию входят идиомы; более длинные слова (P2=6) |
| 60 | устойчивые ловушки; омофоны при 12-буквенных ответах |
| 70 | двухслойные каламбуры — стандарт блока; P8 падает до 2 |
| 80 | 4-словные уровни ужесточаются; реже лексика (P3=5) |
| 90 | почти максимальный скрэмбл + двухслойность; подход к «экзамену» |
| 100 | ТОП-СПАЙК (экзамен): 5 слов, редчайшая лексика, самая косвенная карикатура (P8=1) |
3. Логика каждой ступени параметров
Ступени привязаны к якорям прототипа; между якорями значение держится и переключается один раз,
чтобы «новинка» ощущалась как событие. Фактические уровни переключения (из готового файла):
- words_count (P1): 1 → 2 (L7) → 3 (L40) → 4 (L62) → 5 (L95).
Онбординг (1–6) — одно слово, гарантированный успех. Второе слово приходит на L7 — это самый
заметный ранний скачок и он намеренно один (не стакается с другими ступенями). Пятое слово
приходит только на L95 — это «пятикратный» финальный вызов перед экзаменом. - word_len_max (P2): 4 → 5 (L31) → 6 (L49) → … растёт медленно и с откатами в блоках-передышках
(потолок читаемости на 6" — 6–7 букв, выше не идём). - zipf_band (P3): 1 → … → 6. Самый частый шаг (меняется ~9 раз): редкость лексики — плавный
фоновый регулятор, а не событие. На передышках откатывается в топ-банд (дыхание лёгкой лексикой). - scramble_score (P4): непрерывный, интерполируется + пила. Главный носитель «зубцов» кривой.
- trap_anagrams (P5): 0 → 1 (L31) … первая ловушка появляется на подходе к первому спайку
2-словных ответов — раньше её нет (онбординг без обманок, research §5). - answer_words (P6-компонент): 1 → 2 (L29). Первый двухсловный ответ — на подходе к майлстоуну 30.
- pun_type (P7): direct → idiom/homophone (L20) → … → double-layer. Категориальный, переключается
один раз за блок и поздно (ближе к концу блока), чтобы смена типа каламбура не совпадала со
ступенями P1/P6 и не давала двойной скачок. - cartoon_transparency (P8): 5 → … → 1. Прозрачность падает ступенями к финалу; на передышках
карикатура снова «подсказывает» (P8 выше) — визуальное облегчение.
4. Мостик к экономике подсказок и офферам
Кривая — не самоцель, а насос для мягкой валюты и (в полной игре) для мест офферов. free_hint_worth
(4→10 монет) растёт медленнее стоимости подсказки: по research доход за уровень намеренно держат
ниже цены хинта (2–4 монеты дохода против 25–100 за раскрытие буквы), чтобы копился управляемый
дефицит. Спайки на каждом 10-м уровне — это точки максимального target_hint_usage (до ~70 % на
топ-уровнях), то есть места, где игрок с наибольшей вероятностью тратит валюту, а неплатящий смотрит
rewarded-video: майлстоун-спайк = естественный слот для оффера/rewarded-ad, а передышка сразу
после — момент «победы даром», оберегающий ощущение честности. Так difficulty-кривая напрямую задаёт
ритм монетизации: пилообразная сложность порождает пилообразный спрос на подсказки, а майлстоуны
служят якорями для IAP-промо и наградной рекламы, не ломая уютного тона (никаких таймеров и штрафов).
5. Ограничения модели и что калибровал бы плейтестом
- Коллинеарность параметров. В 10 якорях P3 (редкость), P4 (скрэмбл) и P8 (прозрачность) растут
почти синхронно. Линейная модель не может честно разделить их индивидуальный вклад и «сваливает»
его в P4; поэтому веса P3 и P8 малы (1.2 %). На реальных данных (когда уровни варьируют эти
параметры независимо) веса надо пере-оценить регрессией по времени решения — сейчас они
дизайн-разумны, но статистически недоразделены. - Онбординговая нелинейность. Якоря v1=1.0 и v12=1.6 авторски «круглые» и задают более крутой
старт, чем предполагает линейный тренд по остальным 8 точкам. Отсюда остаточная ошибка ±0.149 именно
на краях. Это осознанный компромисс: не переобучать модель до отрицательных весов ради двух точек. target_solve_time_secиtarget_hint_usage_pct— гипотезы до данных. Время откалибровано так,
чтобы score-лестница легла на солв-тайм якоря прототипа (v1 ~25 с, v34 ~100 с, v100 ~195 с), но
реальная медиана зависит от аудитории, ввода (tap-to-place vs swipe) и качества карикатур. Первое,
что я мерил бы плейтестом: (1) фактическое медианное время по уровням → перекалиброватьa,bв
формуле времени и, если надо, веса; (2) точки массового отвала (churn) — не совпадают ли они со
спайками (тогда сгладить амплитуду пилы); (3) конверсия hint/rewarded-ad на майлстоунах — подтвердить
гипотезу «спайк = слот оффера».- Дискретность vs гладкость. Несколько межблоковых скачков (L7 «второе слово», L62, L95 «пятое
слово») велики (~0.9) — но они семантически осмысленны (появление новой единицы контента), а не
артефакт. Если плейтест покажет, что они выбивают, их можно распределить на 2 уровня.
6. Проверка (verify_balance.py)
python verify_balance.py открывает готовый xlsx (data_only=False) и проверяет:
[1] ровно 100 строк данных; [2] в колонке difficulty_score все 100 ячеек — формулы (начинаются
с =); [3] пересчёт формулы из P-ячеек воспроизводит 10 якорей в пределах ±0.15 и P1–P8 якорных
строк совпадают с прототипом; [4] тренд возрастает (early avg < late avg) и есть пила (дипы после
спайков). Текущий прогон: ALL CHECKS PASS, worst anchor err = 0.149.