Current time: 23.03.2024, 10:35 Hello There, Guest! (LoginRegister)
Language: english | russian  

Post Reply 
Threaded Mode | Linear Mode
Случайность как фактор нейтрализации тактики
Author Message
Berserker Offline
Administrators

Posts: 16449
Post: #1

   Когда речь заходит о роли случая в игре, мнения аудитории обычно расходятся. Одни утверждают, что всё «хорошо весьма» и генератор случайных чисел (ГСЧ) нисколько не портит игру, другие с горечью рассказывают, как очередное выпадение морали защитникам замка предрешило исход часовой битвы.

   А между тем, в чём-то правы и те, и другие. Первые правы в том, что ряд игровых моментов хорошо сбалансирован, то есть случай в них загнан в предсказуемые рамки. Но правы и другие, винящие козни ГСЧ в разбитой об стенку со злости клавиатуре. Например известно, что наши китайские коллеги любят очень сложные карты. В боях на таких картах без выпадения целой комбинации бонусов победить просто невозможно. И наоборот. Победа зависит от чётко выстроенного и исполняемого по шагам плана, который может нарушить любой двойной ход противника. Стоит ли говорить, что закон подлости в нужный момент проявляет себя на все 100%. Что мы имеем в итоге? Злость, досаду, потерю интереса.

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

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

   Другой проблемой является качество генератора, а вернее качество последовательности чисел, которую он выдаёт. Предполагается, что последовательность будет иметь равномерное распределение. То есть на 1000 сгенерированных значений от 1..10 должно прийтись в среднем по 100 каждого. Положим, приблизительно так и будет. Значит генератор подходит для боевого применения? Не спешите.
   
   Большинство игровых событий требует небольшой длины последовательности. Например, если дерево знаний даёт в 20% случаев повышение, то не стоит всерьёз надеяться, что игроку дадут возможность посетить 1000 деревьев. На карте будет расположено от силы 10 объектов данного типа. А значит к генератору предъявляются повышенные требования. И здесь мы сталкиваемся с проблемами. Оказывается, на небольших последовательностях значения могут скакать абсолютно произвольным образом. Например 4 дерева из 5-и окажутся удачливыми. Или наоборот, все 5 бесполезными. Представьте себе разочарование игрока, пробившегося с потерями в зону с тремя такими объектами и ушедшего ни с чем после значительной потери времени.
   
   Но даже если генератор имеет схожее с равномерным распределение на небольших по размерам последовательностях, это отнюдь не гарантирует того математического ожидания, которое будет искать игрок. Дело в том, что один и тот же генератор с одним и тем же состоянием используется одновременно для всех игровых событий. Это значит, что если мы генерируем числа от 1..5 и нам жизненно важно получить 5 хотя бы за десять генераций, мы можем не получить требуемое значение вообще. Всё потому, что после каждой нашей генерации работают другие события, например расчёт урона для отрядов в бою, где указанная пятёрка, возможно, не раз выпадала, но когда ход вновь возвращается нашему событию, генератор снова отплёвывается повтором. Поэтому драколич с шансом блока в 20% в битвах нередко блокирует 4-5 ударов подряд! Автор не раз лично был свидетелем этого явления и смеялся в голос. Даже шутка такая родилась, об абсолютной защите драколичей.

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

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

N - (number) - длина последовательности.
D - (distance) - разбежка или расстояние между максимальным и минимальным значением.
A - (average distribution) - математическое ожидание. Значение, к которому стремится среднее, рассчитанное по последовательности. Для равномерного распределения вычисляется как (Макс - Мин) / 2. Если измеряется в %, то это % от разбежки.
Quote:Мин...Мин + A * D...Макс

NA - произведение начальных A и N. Показывает ресурс, который идеальный генератор должен распределить по последовательности. Например, если имеется A = 20% и N = 10, то NA = 200%. Каждое новое генерируемое значение — это минимальное + некоторый бонус, который берётся из общего хранилища. NA * D показывает предполагаемую сумму всех бонусов для каждого значения.

M - количество оставшихся членов последовательности (<= N).

   Под хаотичностью события мы будем подразумевать его минимальные и максимальные отклонения от математического ожидания. Так, для диапазона 50..80 математическое ожидание A = (80 + 50) / 2 = 65. Возможные отклонения: ±15. 15 — это 23% от среднего. Значит хаотичность: -23%..+23%.
   
   Посмотрим, какую хаотичность предлагают разработчики игр для самого важного параметра в бою — урона. В Эадоре урон монстров задаётся одним числом (A), а конкретное значение при ударе рассчитывается как 0.75 * А .. 1,25 * А. Иначе говоря, хаотичность: ±25%. Запомним это значение. Оно вносит достаточно разнообразие в бой, позволяя случаться событием, вроде «успел добить жирного монстра» или «выжил с 1 жизнью», в то же время предоставляя игроку возможность оценки рисков и планирования.
   
   Проверим наиболее популярные разбросы урона в Героях 3.
   2-3, 4-6, 10-15 и т.д. Хаотичность: ±20%. Предсказуемость хорошая. Благословение не критично, проклятие не смертельно.
   1-2, 2-4, 10-20, 20-40 и т.д.. Хаотичность: ±33%. Имеют значительную зависимость от ГСЧ. Благословения и проклятья играют существенную роль. Критические успехи и провалы приводят к изменению оперативных планов.
   1-3, 3-8, 20-45. Хаотичность ±40%..50%. Практически выводит ситуацию из под контроля игрока. Урон скачет непредсказуемо. Невезенье или везенье всего в нескольких ходах может сыграть решающую роль в бою. Благословения и проклятья (артефакты для них) критичны.
   1..100. Хаотичность: ±100%. Классический пример полного разгула Случая. Палатка лечит на 5, 17, 13? Ценный монстр погибает? Утешьтесь, в среднем могла вылечить 150 единиц здоровья! Чтобы добиться этого среднего понадобится весь бой. Но жизнь палатки скоротечна, а нужда в ней возникает локальная. Так что вариантов у вас не много. Наилучший — не надеяться на неё вообще.
   
   Стоит отдельно рассмотреть довольно популярные двоичные генерации или генерации по принципу «всё сработало» и «всё не сработало». Они порой вносят гораздо больше хаоса в партию, чем расчёт урона. Например, 5% шанс блокировать магию противника. Хаотичность: -100%..+1900(!)%. Иначе говоря, ожидается срабатывание блока только в одном из двадцати случаев. Большей частью времени польза от эффекта нулевая (-100% от среднего). То есть бой идёт как будто способности нет. Но время от времени (в неподходящее) срабатывает блок, которого никто не ждал в виду некритичного шанса.
   
   20% двоичное событие имеет хаотичность: -100%..+400%. Стоит ли говорить, что если требуется использовать накопленную ману в нужный момент для важного заклинания (ослепление последнего отряда, взрыв и т.д), предугадать наступление этого самого правильного момента нельзя. И наивен тот, кто думает, что в случае двойного запаса маны и стабильности плана с расчётом на одну неудачу, из двух подряд попыток колдовать хоть одна, да пройдёт. Может не пройти.
   
   А ведь на самом деле игрока-тактика вполне устроило бы гарантированное или предсказуемое уменьшение эффекта заклинания, при котором само заклинание всё-таки действует. И защитнику не пришлось бы трястись, ожидая чудодейственного выпадения двадцатки, когда можно было бы весь бой игнорировать часть наносимого магического урона, справедливо осознавая, какие у соперника шансы убить ваш ценный отряд заклинанием.

   Не менее печально известен и воговский блок в 50%, берущий своё начало из блока минотавров в Героях 4. Несмотря на значение 35%, минотавры умудрялись блокировать порой целые серии ударов, так что бой с ними был нервным и долгим, с нередкими перезагрузками. Чтобы уж наверняка не оставить тактике шанса, воговские командиры могут учить пятидесятипроцентный блок. Если задача командира выжить, то это самое сильное умение в игре. И 50% там только на словах. Визуально блок срабатывает гораздо чаще (причины указаны выше), так что в критические моменты Ваш командир может пережить и по три летальных удара. С другой стороны, если отряды противника тоже обладают подобной способностью, приготовьтесь к абсолютному цирку, учитывая, что блок может полностью нивелировать действия ваших заклинаний.

   С учётом вышесказанного рекомендации следующие. Практически везде заменять двоичные генераторы на диапазонные (1), для каждого события использовать свой генератор, чтобы гарантировать чистоту последовательности (2) и использовать алгоритмы-надстройки над базовым ГСЧ для обеспечения выбранных характеристик последовательности (N, A, характер распределения) (3).

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

Code:
function CreateBalance50Obj (MinN, MaxN: integer): {O} TErmArr; stdcall;
Функция создаёт генератор с гарантированным равномерным (A=50%) распределением. Аргументы: минимальная и максимальная длина последовательности, в рамках которой математическое ожидание будет равно 50%. Рекомендуется использовать значения в интервалах 7-14 для событий, имеющих среднюю и большую важность для игрока и 17-24 для длительных явлений с малой или средней значимостью.

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

Пример. Пусть диапазон урона: 50..100. N = 10, A = 50%, NA = 500%. M = 10.
Выпадает 100. Теперь NA = 400%, M = 9, A = 400%/9 = 44.44%. Это значит что в оставшейся последовательности из девяти чисел среднее значение будет уже не Мин + 0.5 * Разбежка, а Мин + 0,44 * Разбежка. конкретно во второй генерации диапазон урона (реальный) будет 50..94.

Code:
function CreateCrit10Obj (MinN, MaxN: integer; A: single): TErmArr; stdcall;
Создаёт генератор с неравномерным распределением. Гарантируется переход состояния между последовательностями (если остался накопленный эффект несправедливой удачей/неудачей) и то, что максимальное отклонение от А не превысит Max (верхняя граница генерируемых значений). Практически для каждой генерации в 90% случаев генерируется значение в нижней (для A <= 50%) или верхней (для A > 50%), части диапазона, что описывается как «обычное» значение. Обычное значение варьируется около заданного A. В 10% случаев происходит критическая удача(провал) и генерируется значение из альтернативного диапазона.

Аргумент A - дробное число (e) 0.0..1.0. Для равномерного распределения 0.5 (что бессмысленно, так как для равномерного есть генератор выше).

Code:
procedure DestroyObj (hObj: TErmArr); stdcall;
Удаляет генератор. Генераторы сохраняются в файлах сохранения, так что временные генераторы нужно удалять, а о постоянных не заботиться. Аргумент - объект-генератор.

Code:
function GenerateBalance50Val (hObj: TErmArr; aMin, aMax: integer): integer; stdcall;
Аргументы: генератор Баланс-50, минимальное и максимальное значения.
Генерирует случайное число в указанном диапазоне. Гарантирует равномерное распределение.

Code:
function GenerateBinary50Val (hObj: TErmArr; Chance: single): integer; stdcall;
Аргументы: генератор Баланс-50, шанс успеха (вещественное число, e). Отрицательный шанс означает невозможность события вовсе. Шанс > 100% не гарантирует успех события, если генератор находится в пессимистичном состоянии (ранее везло).
Генерирует двоичное значение (1 или 0), где 1 - событие произошло, 0 - не произошло. Гарантирует равномерное распределение для NA кратным 100% и переход состояния между последовательностями в противном случае.

Code:
function GenerateCrit10Val (hObj: TErmArr; aMin, aMax: integer): integer; stdcall;
Аргументы: генератор Крит-10, минимальное и максимальное значения.

ВАЖНО! Между генерациями диапазоны значений могут быть произвольными. Генераторы гарантируют математические ожидания (A) в %-х значениях, так что если 20..40 дало 20, а потом 40..80 дало 80, то для генератора всё отлично. Сперва выпало минимальное значение (0%), затем максимальное (100%). Баланс соблюдён (50%).


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
06.12.2013 00:58
Find all posts by this user Quote this message in a reply
AKuHAK Offline

Posts: 116
Post: #2

Хорошая статья )) много букв. Хочу добавить, что очень напрягает именно отсутствие зависимости от предыдущих ходов. Ну например, что после двух подряд удач вероятность третьей не уменьшается. Ну к примеру luck^1+[количество удачных срабатываний]-[количество несработавших моментов]*luck/(1-luck) в пределах стека - хотя он и несколько неудачен.
06.12.2013 14:49
Find all posts by this user Quote this message in a reply
gamecreator Offline

Posts: 7107
Post: #3

(06.12.2013 14:49)AKuHAK Wrote:  Хочу добавить, что очень напрягает именно отсутствие зависимости от предыдущих ходов.
Должна ли она там быть? Для удачи, например, это будет нереалистично.


When all gods have burnt to ashes in eternity of sorrow,
Demons gonna tear your soul because there is no tomorrow.
06.12.2013 15:19
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16449
Post: #4

Quote:много букв.
Писать и редактировать вообще долго Sm

Кстати, оригинальная удача даёт 50% бонус к базовому урону, поэтому и не выглядит такой дисбалансной. Ведь 30% может дать нападение и до 300% преимущество в параметре «атака». А вот в Battle Heroes кажется удача получше, в полтора раза итоговый урон умножает.

Quote:Для удачи, например, это будет нереалистично.
Достаточно иметь длину последовательности 15-25 (когда заканчивается, выбирается случайно из этого диапазона новая длина), чтобы игрок не мог держать в голове и предсказывать бонусы. И в то же время удача будет действовать гарантированно столько, сколько написано в её описании.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
06.12.2013 16:04
Find all posts by this user Quote this message in a reply
fireman Offline
Forum Moderators

Posts: 1426
Post: #5

На счёт влияния удачи при мораль\удачи советую посмотреть на реализацию в героях 6. Там даже при их выпадание это не даст такой уж бонус.


Новости по WoG 3.59, ХотА и другим модам.
07.12.2013 02:51
Find all posts by this user Quote this message in a reply
GrayFace Offline
Forum Moderators

Posts: 1233
Post: #6

(06.12.2013 00:58)Berserker Wrote:     У программных ГСЧ есть немало проблем. [...]
   Другой проблемой является качество генератора, а вернее качество последовательности чисел, которую он выдаёт.
Слово "качество" и акцент на псевдослучайности ГСЧ тут не к месту. Идеальный физический ГСЧ - это тот, у которого все случайные значения независимы и распределены равномерно. Это тот идеал, к которому стремятся приблизить программные ГСЧ и этот идеал гарантирует "некачественные" в твоих терминах последовательности - такие, в которых блок может срабатывать по 5 раз подряд.

Ты делаешь интересную штуку. Из-за склонности мозга искать закономерности, он отказывается верить в честность по-настоящему честного с точки зрения теории вероятности генератора, я на себе это тоже прочувствовал. Наверное, всё будет хорошо, если для каждого числа использовать отдельный генератор со случайным seed'ом. Т.е.
1) Мораль и удача - это 2 независимых генератора с разными seed'ами.
2) Если бы в результате выпадения удачи, скажем, урон увеличивался на случайный процент от 1% до 100%, то нужны бы были опять 2 независимых генератора - 1 для шанса выпадения удачи и другой для урона, который она даёт.
3) И всё это *2 - т.к. 2 игрока.
Всё потому, что, из-за внесённой зависимости генерируемых чисел, нарушается равномерность распределения векторов. Т.е. если генерировать пары (X,Y) одним генератором, то я уверен, что они не будут равномерно распределены в квадрате.

Но мне больше понравился подход heroeswm (и возможно, Г5, с которых они всё скопировали) - у приведений там есть шанс блока 50%, но если приведение сделало блок 2 раза подряд, то 3й раз блок оно точно не сделает (аналогино, если 2 раза не сделало блок, то на 3й сделает точно). Это вносит элемент тактики.


Вся правда обо мне
17.12.2013 20:56
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16449
Post: #7

Quote:Слова "качество" и связь с программными ГСЧ тут не к месту.
Качество с точки зрения потребителя. А у потребителя область проверки качества ограничена небольшими выборками и небольшим числом опытов. Скажем, 5 выборок по 20 чисел. И все характеристики уже рассчитываются по ним самим человеком.

Quote:Ты делаешь интересную штуку. Наверное, всё будет хорошо, если для каждого числа использовать отдельный генератор со случайным seed'ом.
Абсолютно согласен. Сейчас так и есть, только используются объекты-надстройки для каждого случайного события.

Quote:Но мне больше понравился подход heroeswm (и возможно, Г5, с которых они всё скопировали) - у приведений там есть шанс блока 50%, но если приведение сделало блок 2 раза подряд, то 3й раз блок оно точно не сделает (аналогино, если 2 раза не сделало блок, то на 3й сделает точно). Это вносит тактичность в битвы.
Преследую точно такую же цель. В BalancedGenerator.era это делается легко ) N = 3, A = 50%. В среднем должно выпадать 1,5 раза из трёх генераций. Если выпало два, то третий будет всегда 0. При чём если первый раз не выпало, то во второй раз шансы реальные уже не 50%, а 75% (нужно распределить полтора выпадания по двум оставшимся генерациям).

А чтобы игрок не предсказывал идеально выпадания, исходя из истории генераций, длина выборки (N) выбирается при инициализации случайно из указанного диапазона. Например N=8..14.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
17.12.2013 21:10
Find all posts by this user Quote this message in a reply
GrayFace Offline
Forum Moderators

Posts: 1233
Post: #8

(17.12.2013 21:10)Berserker Wrote:  А чтобы игрок не предсказывал идеально выпадания, исходя из истории генераций, длина выборки (N) выбирается при инициализации случайно из указанного диапазона. Например N=8..14.
А я о том, что хорошо, когда игрок может идеально предсказывать выпадания и это чётко прописано в описании.
И твой пример с 3 числами тому подтверждение - игрок не может точно предсказать, но, если в курсе, как всё работает, будет ожидать, что если выпало много неудач, то должно повезти.
Всегда лучше делать чистое решение - либо никакой случайности, либо ограниченная по чётко описанному алгоритму, который можно просчитать в уме.


Вся правда обо мне
18.12.2013 19:35
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16449
Post: #9

Не согласен. Достаточно знать, что за 8-14 генераций будет либо указанный средний урон, либо ровно X% раз случится событие. При желании автора N - фиксировано. Например, всегда из 10 бросков 3 попадают. А вообще я противник двоичных событий (удача/нет). А для любых количественных генераций гарантия мат. ожидания — это вполне себе фактор баланса и тактики.

Если урон 50-100, то за десять ударов будет нанесено строго 750. Случайность есть локальная только.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
18.12.2013 20:15
Find all posts by this user Quote this message in a reply
« Next Oldest | Next Newest »
Post Reply 


Forum Jump:

Powered by MyBB Copyright © 2002-2024 MyBB Group