Онлайн-справочник по самым часто задаваемым вопросам из темы "Как сделать?" на форуме QSP.su

20.3. Как сделать шанс на выпадение определённой вещи?

В: Как сделать шанс на выпадение определённой вещи? Например 25 процентный шанс на то, что в сундуке окажется золотая чаша?

О:

В самом простом виде, когда мы имеем дело с одним конкретным предметом и приблизительно знаем шансы его выпадения, можно сделать весьма простой алгоритм:

! задаём шанс выпадения предмета (якобы в процентах) — предел от 1 до ...
chance=25
! теперь выбрасываем случайное число от 1 до 100
bones=rand(1,100)
! проверяем попало ли выпавшее число в заданный нами предел
if bones<=chance:
! если выпавшее число меньше либо равно заданному
    
! получаем предмет
    addobj "Золотая чаша"
    "Вы нашли в сундуке золотую чашу."
else
! в противном случае ничего не получаем
    "Вы ничего не нашли в сундуке."
end

Чуть более сложной задачей становится выбор из нескольких вариантов предметов. Эта задача осложняется тем, что начинающие авторы продолжают применять подход с процентным значением шансов к большому набору предметов:

Золотая чаша - 25%
Кувшин - 25%
Вострый меч — 50%
Убольшающее зелье — 25%

Если сложить все процентные значения в этом случае, мы получаем 125% на все предметы, но такого не может быть.

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

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

Вострый меч — 50
Убольшающее зелье — 25

Теперь мы знаем, что это не проценты, а коэффициенты соотношений шанса выпадения. Делим 50 на 25, и понимаем, что Вострый меч должен выпадать вдвое чаще, чем Убольшающее зелье. При условии, что хоть один предмет должен выпасть обязательно, составляем следующий алгоритм:

! максимальное значение случайного числа (складывается из коэффициентов)
bones_max=50+25
! определяем отрезок для меча (от 1 до 50)
chance_sword=50
! определяем отрезок для зелья (от 51 до 75)
chance_potion=75
! выбрасываем случайное число от 1 до bones_max
bones=rand(1,bones_max)
! теперь используя сложное условие проверяем отрезки
if bones<=chance_sword:
! если мы уложились в отрезок для меча
    
! получаем меч
    addobj "Вострый меч"
elseif bones<=chance_potion:
! иначе если мы уложились в отрезок для зелья
    
! получаем зелье
    addobj "Убольшающее зелье"
end

Теперь можно составить алгоритм для случая с четырьмя предметами. Он не будет сильно отличаться от предыдущего:

! максимальное значение числа
bones_max=50+25+25+25
! отрезок меча (1-50)
chance_sword=50
! отрезок зелья (51-75)
chance_potion=75
! отрезок кувшина (76-100)
chance_jug=100
! отрезок чаши (101-125)
chance_cup=125
! выбрасываем число
bones=rand(1,bones_max)
! получаем выпавший предмет
if bones<=chance_sword:
    addobj "Вострый меч"
elseif bones<=chance_potion:
    addobj "Убольшающее зелье"
elseif bones<=chance_jug:
    addobj "Кувшин"
elseif bones<=chance_cup:
    addobj "Золотая чаша"
end

Что если мы хотим, чтобы в принципе предмет мог выпасть с 50% вероятностью, но между собой они делили шансы выпадения по-прежнему? Просто увеличиваем максимальное значение числа вдвое:

! максимальное значение числа
bones_max=(50+25+25+25)*2
! отрезок меча (1-50)
chance_sword=50
! отрезок зелья (51-75)
chance_potion=75
! отрезок кувшина (76-100)
chance_jug=100
! отрезок чаши (101-125)
chance_cup=125
! выбрасываем число
bones=rand(1,bones_max)
! получаем выпавший предмет
if bones<=chance_sword:
    addobj "Вострый меч"
elseif bones<=chance_potion:
    addobj "Убольшающее зелье"
elseif bones<=chance_jug:
    addobj "Кувшин"
elseif bones<=chance_cup:
    addobj "Золотая чаша"
else
! или ничего не получаем
    "Вы ничего не нашли"
end

Конечно же данное решение не является универсальным, и для более универсального решения рамок обычного F.A.Q не хватит, но в большинстве случаев для написания сносной системы случайного выпадения предметов хватает и данного решения. Главное помнить, что выбирая между разными предметами мы уже работаем не с чистой вероятностью выпадения, а с тем, насколько чаще один предмет выпадает по отношению к другим предметам.