Рандом, вероятности и плейтест-данные

Учимся применять случайность осознанно и проверять баланс цифрами.

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

Зачем игре случайность

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

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

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

Input и output рандом

Дизайнеры различают два вида случайности.

  • Input random — случайность до решения игрока: раздача карт, расстановка уровня. Игрок видит ситуацию и адаптируется. Воспринимается как честный вызов.
  • Output random — случайность после решения: «попал я или промахнулся 85%». Когда тщательно спланированный ход срывает невезение, это фрустрирует.

XCOM печально известна output-рандомом: промах с 95% вызывает ярость. Into the Breach намеренно убрала почти весь output random — все последствия видны заранее, и проигрыш всегда «по вине игрока».

Тонкость в том, что граница между видами проводится по моменту решения, а не по моменту броска. Случайная раздача карт в Hearthstone — input: вы видите руку и строите план под неё. А вот «эффект, который с шансом 50% бьёт врага или вашего же героя» — output: вы приняли решение разыграть карту, и судьба хода зависит от монетки. Один и тот же генератор случайных чисел воспринимается совершенно по-разному в зависимости от того, успевает ли игрок отреагировать на результат. Поэтому опытные дизайнеры стараются «сдвигать» случайность к input-стороне: открывать игроку случайные факторы заранее, чтобы он мог встроить их в план.

Существуют и приёмы смягчения output-рандома без полного его удаления. Fire Emblem, например, во многих частях использует «двойной бросок» (true hit): показанные 80% на деле ближе к реальной частоте попаданий, чем честные 80%, потому что человек психологически ожидает от «80%» почти гарантированного успеха. Это сознательная подгонка математики под восприятие — игра врёт в пользу игрока, чтобы числа ощущались справедливо.

Как работает под капотом: считаем вероятности

Дизайнер обязан уметь оценивать вероятности. Простой пример — симуляция, проверяющая, как часто выпадает редкий лут с шансом 5%.

import random

hits = 0
trials = 100000
for _ in range(trials):
    if random.random() < 0.05:   # 5% шанс
        hits += 1

print("Выпало раз:", hits)
print("Доля:", round(hits / trials, 4))

Вывод:

Выпало раз: ~5000
Доля: ~0.05

Симуляция подтверждает: при 100 000 попыток доля сходится к заданным 5%. Это метод Монте-Карло — гонять случайность много раз и смотреть на средние. Так дизайнер проверяет, не получится ли, что игрок убьёт босса 200 раз и ни разу не увидит «редкую» награду (это бесит — отсюда системы «защиты от невезения», pity-механики).

Опасность хвостов: серии невезения

Средняя доля 5% звучит безобидно, но средние скрывают самое больное — хвосты распределения. Игрока ранит не среднее, а его личная неудачная серия. Посчитаем не только частоту дропа, но и самую длинную полосу невезения за множество попыток (используем фиксированный seed, чтобы результат был воспроизводим).

import random
random.seed(42)

drop_chance = 0.05
trials = 50000
max_dry = 0
dry = 0
got = 0
for _ in range(trials):
    if random.random() < drop_chance:
        got += 1
        if dry > max_dry:
            max_dry = dry
        dry = 0
    else:
        dry += 1

print("Дропов:", got)
print("Доля:", round(got / trials, 4))
print("Худшая серия невезения:", max_dry)

Вывод:

Дропов: 2476
Доля: 0.0495
Худшая серия невезения: 153

Вот в чём суть: средняя доля — честные 5%, но где-то в этих 50 000 попыток нашёлся несчастливец, которому пришлось убить босса 153 раза подряд без награды при «среднем ожидании» в 20 убийств. Для одного игрока это катастрофа — он напишет гневный отзыв «дроп сломан», хотя математика идеальна. Именно поэтому существуют pity-механики: гарантированная выдача после N неудач, постепенно растущий шанс с каждой попыткой (как в гача-играх) или «защита от дубликатов». Они срезают злой хвост распределения, оставляя среднюю частоту почти прежней. Дизайнер, который смотрит только на среднее и не считает хвосты, обрекает часть аудитории на ярость.

Чтение плейтест-данных

Реальный баланс читается по числам. Какие метрики смотрят:

МетрикаО чём говорит
Win rate персонажане доминирует ли / не слаб ли
Pick rateвыбирают ли его вообще
Точка отвала на уровнегде игроки массово бросают
Среднее время прохождениясовпадает ли с замыслом

Если у персонажа win rate 65% при высоком pick rate — он перекачан, нужен нерф. Если 30% — недокачан. Норма обычно около 50%.

Но цифры нужно читать с оговорками, иначе они обманут. Первая ловушка — связка win rate и pick rate. Сложный персонаж может иметь высокий win rate просто потому, что им играют только опытные фанаты; ослабить его — значит наказать новичков, которые и так им не берут. Поэтому метрики дробят по сегментам: отдельно для новичков, отдельно для топ-рейтинга. Персонаж, ломающий высокий уровень игры и бесполезный на низком, требует не тупого нерфа, а перепроектирования.

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

Частые ошибки

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

Output random без защиты. Долгие серии невезения без pity-механик разрушают доверие к игре — как показала симуляция, хвост в 153 неудачи реален даже при честных 5%.

Смотреть только на среднее. Среднее скрывает хвосты, а игрока ранит именно его личный хвост. Считать нужно и распределение, и крайние случаи.

Итог

  • Input random (до решения) ощущается честным; output random (после) часто фрустрирует, поэтому случайность сдвигают к input-стороне.
  • Вероятности проверяют симуляцией (Монте-Карло) и страхуют pity-механиками — особенно от злых хвостов распределения.
  • Баланс читается по плейтест-метрикам (win rate, pick rate, точки отвала), но цифры дробят по сегментам и дополняют наблюдением за живыми игроками.
Проверьте себя
1. Чем input random отличается от output random?
AНичем
BInput — случайность до решения игрока, output — после; output чаще фрустрирует
CInput быстрее считается
DOutput используется только в RPG
2. Что показывает метод Монте-Карло в балансе?
AТочную формулу выигрыша
BСреднее поведение случайной системы при многих прогонах
CЛучшую стратегию игрока
DОптимальную цену игры
3. О чём говорит win rate персонажа около 65% при высоком pick rate?
AПерсонаж недокачан
BПерсонаж перекачан и его, скорее всего, нужно ослабить
CИдеальный баланс
DДанные ошибочны