Необходим предсказуемый генератор случайных чисел


151

Я разработчик веб-игр, и у меня возникла проблема со случайными числами. Допустим, у игрока есть 20% шанс получить критический удар своим мечом. Это означает, что 1 из 5 попаданий должен быть критическим. Проблема в том, что я получил очень плохие результаты в реальной жизни - иногда игроки получают 3 крита в 5 попаданиях, иногда ни одного в 15 попаданиях. Сражения довольно короткие (3-10 попаданий), поэтому важно получить хорошее случайное распределение.

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

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


58
Вероятность примерно 3 критических и 2 некритических ударов составляет примерно 0,5%, а вероятность 15 некритических попаданий подряд - 3,5%, если предположить истинные случайные числа.
Никсуз

10
+1 к выше. Одной из характеристик случайных чисел является то, что вы получаете выбросы.
ConcernedOfTunbridgeWells

45
@Nixus: Нет, это примерно 5% шанс 3 критических и 2 некритических, вы забыли умножить на (5! / (3! * 2!)) = 10. При уровне уверенности 95% это статистически маловероятно, что 3 критических попадания произойдут за 5 ударов.
erikkallen

7
Сначала я подумал, что это глупый вопрос ... еще раз, я унижен ТАК.
SergioL

Ответы:


39

Я согласен с более ранними ответами, что реальная случайность в небольших сериях некоторых игр нежелательна - она ​​кажется слишком несправедливой для некоторых случаев использования.

Я написал простую реализацию типа Shuffle Bag в Ruby и провел некоторое тестирование. Реализация сделала это:

  • Если он все еще кажется справедливым или мы не достигли порога минимальных бросков, он возвращает справедливое попадание на основе нормальной вероятности.
  • Если наблюдаемая вероятность от прошлых бросков заставляет это казаться несправедливым, это возвращает "справедливо идущий" удар.

Это считается несправедливым на основе граничных вероятностей. Например, для вероятности 20% вы можете установить 10% в качестве нижней границы и 40% в качестве верхней границы.

Используя эти границы, я обнаружил, что при прогонах из 10 попаданий в 14,2% случаев истинная псевдослучайная реализация давала результаты, выходящие за эти границы . Приблизительно в 11% случаев 0 критических попаданий были забиты в 10 попытках. В 3,3% случаев 5 или более критических попаданий попадали из 10. Естественно, при использовании этого алгоритма (с минимальным количеством бросков 5) гораздо меньшее количество (0,03%) «честных» пробегов вышло за пределы , Даже если приведенная ниже реализация не подходит (конечно, можно делать более умные вещи), стоит отметить, что очень часто ваши пользователи будут чувствовать, что это несправедливо по отношению к реальному псевдослучайному решению.

Вот мясо моего FairishBagнаписано на Ruby. Полная реализация и быстрое моделирование Монте-Карло доступно здесь (суть) .

def fire!
  hit = if @rolls >= @min_rolls && observed_probability > @unfair_high
    false
  elsif @rolls >= @min_rolls && observed_probability < @unfair_low
    true
  else
    rand <= @probability
  end
  @hits += 1 if hit
  @rolls += 1
  return hit
end

def observed_probability
  @hits.to_f / @rolls
end

Обновление: использование этого метода увеличивает общую вероятность получения критического удара примерно до 22% с использованием указанных выше границ. Вы можете компенсировать это, установив его «реальную» вероятность чуть ниже. Вероятность 17,5% с честной модификацией дает наблюдаемую долгосрочную вероятность около 20% и сохраняет краткосрочные прогнозы на должном уровне.


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

Стив Рабин написал интересную статью о случайности в играх. Короче говоря, истинное «случайное» поведение на самом деле не кажется «случайным» для большинства людей, и исследования подтвердили это. Его статья называется «Отфильтрованная случайность для решений ИИ и игровой логики» и публикуется в «Мудрости программирования игр 2 AI» (2003). Вы должны проверить это, вероятно, будет полезно для вас.
Джефф Такер

@IanTerrell Было бы хорошо заявить, насколько велик размер выборки ваших тестов, то есть сколько битв для определения этих вероятностей.

@ user677656: Это в самом деле, но это 100 тыс.
Иан Террелл

223

Это означает, что 1 из 5 попаданий должен быть критическим. Проблема в том, что я получил очень плохие результаты в реальной жизни - иногда игроки получают 3 крита в 5 попаданиях, иногда ни одного в 15 попаданиях.

Что вам нужно, так это сумка для случайного выбора . Это решает проблему истинной случайности, которая слишком случайна для игр.

Алгоритм примерно такой: вы кладете 1 критическое и 4 некритических попадания в сумку. Затем вы рандомизируете их порядок в сумке и выбираете их по одному. Когда сумка пуста, вы снова наполняете ее теми же значениями и рандомизируете. Таким образом, вы получите в среднем 1 критическое попадание за 5 попаданий, и самое большее 2 критических и 8 некритических попаданий подряд. Увеличьте количество предметов в сумке для большей случайности.

Вот пример реализации (на Java) и ее тестовых случаев, которые я написал некоторое время назад.


21
+1 за хорошую идею без критики. Масштабируйте сумку для более высокой степени случайности и для обработки различий в критических шансах между игроками (если переменная ofc)
TheMissingLINQ

16
Вы можете иметь сумку размером 10. Положите 1 удар, плюс 30% шанс секунды. Если критический шанс изменится, вы можете просто выбросить сумку и начать новую. Обратите внимание, что любая такая схема рискует тем, что если вы (или ваш оппонент) знаете вероятность критического удара и размер сумки, вы иногда можете точно знать, что вы не получите еще один критический удар для определенного количества бросков. Это может повлиять на тактику.
Стив Джессоп

3
Да ... в таком случае вы запускаете трюки, похожие на подсчет карт. Рискну ли я пиону или займусь большим убийством ... небольшой фиксированный набор потенциальных результатов может снизить риск потери и увеличить шанс быть «заигранным»
Мэтью Уайтед

8
Мне нравится идея shuffle bag, но я не думаю, что это соответствует духу игры, потому что вероятность критического удара в 20% (что означает, что вы не можете сделать ни одного в 10 попаданиях) больше не является вероятностью. Становится ровно 1 хит каждые 5 хитов. Более того, перемотка сумки при изменении вероятности критического попадания вызовет сбой в игре. Если мой критический удар был сделан, я наложу заклинание на себя, чтобы получить следующего критика раньше: p
Микаэль Карпантье,

2
@Jonathan: сделав сумку большого размера, которую вы ей даете, она фактически сводит на нет всю идею сумки: чтобы убедиться, что что-то происходит (критический результат достигнут) в пределах допустимого количества бросков. Создание сумки размером 50000 - это примерно то же самое, что использование генератора случайных чисел.
dstibbe

113

Вы неправильно понимаете, что означает случайное.

Что из этого является более случайным?

введите описание изображения здесь введите описание изображения здесь

В то время как второй график выглядит более равномерно распределенным, на самом деле более случайным является первый график. Человеческий разум часто видит шаблоны в случайном порядке, поэтому мы видим сгустки на первом графике как шаблоны, но это не так - они просто являются частью случайно выбранной выборки.


25
Хорошее объяснение Numb3rs!
RMAAlmeida

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

8
Вы можете измерить вероятность того, что указанное распределение является случайным.
ceejayoz


2
Чтобы быть справедливым, хотя OP, возможно, не использует правильные термины, он понимает, что генератор случайных чисел дает ему что-то больше похожее на первый график, когда он хочет что-то более похожее на второй график, потому что он кажется более «справедливым» для пользователя.
Кип

88

Учитывая поведение, которое вы просите, я думаю, что вы случайным образом выбираете не ту переменную.

Вместо того, чтобы рандомизировать, будет ли этот удар критическим, попробуйте рандомизировать количество ходов до следующего критического удара. Например, просто выбирайте число от 2 до 9 каждый раз, когда игрок получает критическое значение, а затем дайте ему его следующее критическое значение после того, как прошло много раундов. Вы также можете использовать методы игры в кости, чтобы приблизиться к нормальному распределению - например, вы получите свой следующий критический результат в ходах 2D4.

Я полагаю, что эта техника также используется в RPG, в которых есть случайные столкновения и в потустороннем мире - вы случайным образом выбираете счетчик шагов, и после стольких шагов вы получаете удар снова. Это кажется намного более справедливым, потому что вы почти никогда не будете поражены двумя встречами подряд - если это случится хотя бы один раз, игроки становятся раздражительными.


Я думаю, что это отличное решение, но как насчет 80% шансов?
Мыслитель

Мне также нравится время от времени использовать многомерные случайные генераторы. Шанс ударить + Шанс к власти + Шанс к критическому. Точно так же, как бросать несколько разных кубиков в D & D
Мэтью Уайтед

Мне нравится эта идея, и вы абсолютно правы в отношении счетчика шагов, который, например, использовался в финальной фантазии очень долгое время
Эд Джеймс,

Одна проблема с этим состоит в том, что это работает, только если вероятность критического удара примерно постоянна между попаданиями. Предположим, что в середине битвы игрок разыгрывает заклинание, которое удваивает вероятность критического удара. Тогда как вы регулируете количество оборотов?
Alex319

+1 Очень хорошо, также легко обрабатывает меньше вероятностей попадания, чем 20%.
Алиса Перселл

53

Сначала определите «правильное» распределение. Случайные числа, ну, в общем, случайные - результаты, которые вы видите, полностью согласуются с (псевдо) случайностью.

Продолжая это, я предполагаю, что вам нужно ощущение "справедливости", поэтому пользователь не может пройти 100 ходов без успеха. Если так, я бы отслеживал количество сбоев с момента последнего успеха и оценивал полученный результат. Давайте предположим, что вы хотите, чтобы 1 из 5 бросков «преуспел». Таким образом, вы случайным образом генерируете число от 1 до 5, и если это 5, отлично.

Если нет, запишите ошибку и в следующий раз сгенерируйте число от 1 до 5, но добавьте, скажем, floor (numFailures / 2). Так что на этот раз у них снова есть шанс 1 к 5. Если они терпят неудачу, в следующий раз интервал выигрыша 4 и 5; 2 из 5 шансов на успех. При таком выборе после 8 неудач они обязательно преуспеют.


На этой ноте ... будет ли диапазон случайных чисел влиять на распределение ... например, выбор Random r = new Random (); r.Next (1,5) против r.Next (1, 1000000)% 200000
Эойн Кэмпбелл

23
+1 за то, что видел проблему, стоящую за запросом, вместо того, чтобы сказать оператору, что он неправильно понимает.
Борис Калленс

4
Обратите внимание, что если вы сделаете это, то их общая доля успеха будет больше, чем 1 к 5. Обходным путем является (например) случайным образом выбрать 20 различных чисел из диапазона 1..100 и предопределить, что они будут быть их критиками. Хотя это намного больше бухгалтерии.
Стив Джессоп

«будет больше, чем 1 в 5», - я имею в виду, в конечном итоге.
Стив Джессоп

Вы можете немного уменьшить начальную вероятность, чтобы общая пропорция была уменьшена до 1/5. Я не понял, насколько вы должны уменьшить его, но все идет непрерывно, поэтому должен быть правильный ответ.
Стив Джессоп

35

Как насчет замены mt_rand () на что-то подобное?

Комикс XKCD (RFC 1149.5 определяет 4 как стандартное случайное число, проверенное IEEE.)

(RFC 1149.5 определяет 4 как стандартное случайное число, проверенное IEEE.)

Из XKCD .


Хорошо, но решит ли это проблему распределения случайных чисел в ОП? ;-)
Арджан Эйнбу

На самом деле, нет; Он просит неслучайный ГСЧ, для которого он мог бы использовать эту функцию; но то, что он действительно хочет, лучше объяснить текущим главным ответом ( stackoverflow.com/questions/910215/910224#910224 )
Колин Пикард

28
Это более случайно, чем хочет ОП
Чагдаш Текин

-1, потому что RFC1149 не имеет секции 5 (и альтернативно, нет 1149.5); +1 за честную случайность.
Greyfade

34

Надеюсь, эта статья поможет вам: http://web.archive.org/web/20090103063439/http://www.gamedev.net:80/reference/design/features/randomness/

Этот метод генерации «случайных чисел» распространен в играх RPG / MMORPG.

Проблема, которую он решает, заключается в следующем (извлечение):

Паучий клинок у тебя в горле. Это бьет, и вы скучаете. Это ударяет снова, и ты снова скучаешь. И снова и снова, пока от тебя ничего не останется ударить. Вы мертвы, и над трупом злорадствует двухтонный паукообразный. Невозможно? Нет. Невероятно? Да. Но при наличии достаточного количества игроков и времени, невероятное становится почти наверняка. Дело не в том, что лезвие паука было твердым, это была просто неудача. Как расстраивает. Этого достаточно, чтобы игрок захотел выйти из игры.


1
Я слышал вариант по этому поводу: «Событие« один на миллион »случается 6000 раз в мире».
ceejayoz

19

То, что вы хотите, это не случайные числа, а числа, которые кажутся человеку случайными. Другие уже предложили отдельные алгоритмы, которые могут вам помочь, например, Shuffle Bad.

Для хорошего подробного и всестороннего анализа этой области см. Мудрость программирования игр AI 2 . Вся книга достойна прочтения любым разработчиком игры, идея «на первый взгляд случайных чисел» рассматривается в главе:

Отфильтрованная случайность для решений AI и игровой логики :

Аннотация: Традиционная мудрость предполагает, что чем лучше генератор случайных чисел, тем более непредсказуемой будет ваша игра. Однако, согласно исследованиям психологии, истинная случайность в краткосрочной перспективе часто выглядит совершенно неслучайно для людей. В этой статье показано, как сделать случайные решения AI и игровую логику более случайными для игроков, сохраняя при этом сильную статистическую случайность.

Вы также можете найти другую интересную главу:

Статистика случайных чисел

Аннотация: случайные числа наиболее интенсивно используются искусственным интеллектом и играми в целом. Игнорировать их потенциал - значит делать игру предсказуемой и скучной. Неправильное их использование может быть столь же вредным, как и полное их игнорирование. Понимание того, как генерируются случайные числа, их ограничения и возможности, может устранить многие трудности при их использовании в вашей игре. Эта статья предлагает понимание случайных чисел, их генерации и методов, чтобы отделить хорошие от плохих.


8

Конечно, у любого поколения случайных чисел есть шанс произвести такие прогоны? Вы не получите достаточно большой набор образцов в 3-10 рулонах, чтобы увидеть соответствующий процент.

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


8

Лучшее решение может быть игра-тестирование с несколькими различных не случайными схемами и выбрать тот , который делает игрок счастливых.

Вы также можете попробовать политику отмены для того же номера в данной схватке, например, если игрок бросает в 1свой первый ход, принять его. Чтобы получить другой, 1им нужно бросить 2 1с подряд. Чтобы получить треть, 1им нужно 3 подряд, до бесконечности.


7

К сожалению, то, что вы просите, - это генератор неслучайных чисел, потому что вы хотите, чтобы предыдущие результаты были приняты во внимание при определении следующего числа. Боюсь, это не так, как работают генераторы случайных чисел.

Если вы хотите, чтобы 1 из каждых 5 попаданий была критической, просто выберите число от 1 до 5 и скажите, что это попадание будет критическим.


1
он хочет, чтобы игра была дружественной к случайным, если вы используете строго случайные числа, сгенерированные в некоторых случаях, у вас получаются «случайные по-корейски» результаты. Это случайные результаты, которые заставляют игроков слишком часто злиться и разочаровываться (спросите любого игрока линии 2);)
Хуан Течера

Следовательно, если первый удар является критическим, то следующие четыре не будут. Звучит так, будто это то, чего хочет ОП, но когда вы произносите это так, звучит отсталый. Вы получите мой UV для этого.
Belgariontheking

-1 вы, кажется, путаете «случайное» с «без памяти» - en.wikipedia.org/wiki/Memorylessness
Алиса Перселл,

7

mt_rand () основана на реализации Mersenne Twister , что означает, что она дает одно из лучших случайных распределений, которое вы можете получить.

Очевидно, что вы хотите совсем не случайность, поэтому вы должны начать с точного указания того, что вы хотите. Вы, вероятно, поймете, что у вас противоречивые ожидания - что результаты должны быть действительно случайными и не предсказуемыми, но в то же время они не должны демонстрировать локальные отклонения от заявленной вероятности - но тогда это становится предсказуемым. Если вы установили максимум 10 не-критов подряд, то вы просто сказали игрокам: «Если у вас было 9 не-критов подряд, следующий будет критическим со 100% уверенностью» - вы можете ну вообще не заморачивайся случайностью.


6

При таком небольшом количестве тестов вы должны ожидать такие результаты:

Истинная случайность предсказуема только при огромном размере набора, так что вполне возможно бросить монету и получить головы 3 раза подряд, однако после нескольких миллионов подбрасываний вы получите примерно 50-50.


7
Хотя есть шанс, что после нескольких миллионов бросков вы все равно увидите только одну сторону медали. Хотя, если это когда-нибудь случится, вы, вероятно, сидите слишком близко к бесконечной невероятной езде: P
Грант Питерс

ха-ха, да, но шанс настолько невероятно низок, что законы математики говорят, что вы должны видеть равномерное распределение.
Эд Джеймс

6

Я вижу много ответов, предлагающих отследить ранее сгенерированные числа или перемешать все возможные значения.

Лично я не согласен, что 3 крита подряд это плохо. Также я не согласен, что 15 не критов подряд это плохо.

Я бы решил эту проблему, изменив шанс крита сам после каждого номера. Пример (чтобы продемонстрировать идею):

int base_chance = 20;
int current_chance = base_chance;

int hit = generate_random_number(0, 100) + 1; // anything from 1 to 100
if(hit < current_chance)//Or whatever method you use to check
{
    //crit!
    if(current_chance > base_chance)
        current_chance = base_chance; // reset the chance.
    else
        current_chance *= 0.8; // decrease the crit chance for the NEXT hit.
}
else
{
    //no crit.
    if(current_chance < base_chance)
        current_chance = base_chance; // reset the chance.
    else
        current_chance *= 1.1; // increase the crit chance for the NEXT hit.
    //raise the current_chance
}

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

Просто добавляю мои 2 цента ...


Мне нравится такой подход. Я бы, наверное, сделал это по-другому. Начните с меньшего шанса и доведите до максимума 20% + некоторый дополнительный процент, пока он не достигнет цели, и снова сбросьте до некоторого небольшого количества.
Мэтью

5

Несколько лучших ответов - отличные объяснения, поэтому я просто сосредоточусь на алгоритме, который дает вам контроль над вероятностью «плохих полос», но никогда не становится детерминированным. Вот что я думаю тебе следует сделать:

Вместо указания p , параметра распределения Бернулли, которое является вашей вероятностью критического удара, укажите a и b , параметры бета-распределения, «сопряженный априор» распределения Бернулли. Вы должны отслеживать A и B , количество критических и некритических попаданий на данный момент.

Теперь, чтобы указать а и б , убедитесь, что a / (a ​​+ b) = p, шанс критического удара. Важно то, что (a + b) количественно определяет, насколько близко вы хотите, чтобы A / (A + B) было к p в целом.

Вы делаете свою выборку так:

пусть p(x)будет функцией плотности вероятности бета-распределения. Он доступен во многих местах, но вы можете найти его в GSL как gsl_ran_beta_pdf.

S = A+B+1
p_1 = p((A+1)/S)
p_2 = p(A/S)

Выберите критическое попадание путем выборки из распределения Бернулли с вероятностью p_1 / (p_1 + p_2)

Если вы обнаружите, что у случайных чисел слишком много «плохих полос», увеличьте a и b , но в пределе, когда a и b уходят в бесконечность, вы будете использовать ранее описанный подход с мешочками.

Если вы реализуете это, пожалуйста, дайте мне знать, как это происходит!


5

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

например

int GetRand(int nSize)
{
    return 1 + (::rand() % nSize);
}
int GetDice()
{
    static int nPrevious=-1;
    while (1) {
        int nValue = GetRand(6);
        // only allow repeat 5% of the time
        if (nValue==nPrevious && GetRand(100)<95)
            continue;
        nPrevious = nValue;
        return nValue;
    }
}

Этот код отклоняет повторяющиеся значения в 95% случаев, делая повторения маловероятными, но не невозможными. Статистически это немного некрасиво, но, вероятно, даст желаемые результаты. Конечно, это не помешает распространению типа "5 4 5 4 5". Вы можете стать хитрее и отказаться от второго (скажем) 60% времени, а третьего - от 30%.

Я не рекомендую это как хороший дизайн игры. Просто предлагая, как достичь того, что вы хотите.


Некоторые значения в моей игре, такие как критическое попадание, не могут иметь вероятности более 50%, поэтому я вообще блокирую повторение, но это снижает вероятность события на несколько процентов.
Мыслитель

4

Не совсем понятно, чего ты хочешь. Можно создать функцию так, чтобы первые 5 раз, когда вы ее вызывали, она возвращала числа 1-5 в случайном порядке.

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

В качестве альтернативы, вы можете продолжать использовать свой текущий подход и предположить, что ваши текущие результаты связаны с плохим генератором случайных чисел. Обратите внимание, что ничего не может быть не так с вашими текущими номерами. Случайные значения являются случайными. иногда вы получаете 2, 3 или 8 одинаковых значений подряд. Потому что они случайные. Хороший генератор случайных чисел просто гарантирует, что в среднем все числа будут возвращаться одинаково часто.

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

Кроме того, вы можете вспомнить последние N значений, возвращаемых вашей случайной функцией, и взвесить результат по ним. (простой пример: «для каждого появления нового результата есть 50% -й шанс, что мы должны отбросить значение и получить новое»)

Если бы мне пришлось угадывать, я бы сказал, что придерживаться «фактической» случайности - ваш лучший выбор. Убедитесь, что вы используете хороший генератор случайных чисел, а затем продолжайте в том же духе, что и сейчас.


На самом деле, функция, которую он использует, такая же, как у лучшего ГСЧ в библиотеке наддува.
Майкл Боргвардт

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

4

Вы можете создать список, содержащий числа от 1 до 5, и отсортировать их по случайности. Затем просто просмотрите список, который вы создали. У вас есть гарантия того, что вы наберете каждый номер хотя бы один раз ... Когда вы закончите с первыми 5, просто создайте еще 5 номеров ...


4

Я рекомендую прогрессивную процентную систему, которую использует Blizzard: http://www.shacknews.com/onearticle.x/57886

Обычно вы бросаете ГСЧ, а затем сравниваете его со значением, чтобы определить, успешен он или нет. Это может выглядеть так:

if ( randNumber <= .2 ) {
   //Critical
} else {
   //Normal
}

Все, что вам нужно сделать, это добавить прогрессивное увеличение базового шанса ...

if (randNumber <= .2 + progressiveChance ) {
   progressiveChance = 0;
   //Critical
} else {
   progressiveChance += CHANCE_MODIFIER;
   //Normal hit
}

Если вам нужно, чтобы он был более модным, его легко добавить еще. Вы можете ограничить сумму, которую может получить прогрессивный шанс, чтобы избежать 100% критического шанса или сбросить его при определенных событиях. Вы также можете увеличивать прогрессивный шанс в меньших количествах при каждом повышении, например, прогрессивный шанс + = (1 - прогрессивный шанс) * МАСШТАБ, где МАСШТАБ <1.


4

Ну, если вы немного в математике, вы можете попробовать экспоненциальное распределение

Например, если лямбда = 0,5, ожидаемое значение равно 2 (прочитайте эту статью!), Это означает, что вы, скорее всего, будете нажимать / критические / что угодно в течение каждого второго хода (например, 50%, да?). Но с таким распределением вероятностей вы точно определите, что пропустили (или сделаете против чего-либо еще) на 0-м ходу (тот, в котором событие уже произошло, и поворот_счетчика был сброшен), с вероятностью 40% попасть в следующий ход, около 65% шанс сделать это 2-й (следующий после следующего) ход, около 80%, чтобы попасть 3-й и так далее.

Основная цель этого распределения состоит в том, что если у человека есть 50% -й шанс попадания, и он пропускает 3 раза подряд, он будет уверенно (ну, шанс более 80%, и он увеличивается с каждым следующим ходом). Это приводит к более «справедливым» результатам, сохраняя общую вероятность 50% без изменений.

Принимая ваш шанс крита 20%, у вас есть

  • 17% к критическому 1-му ходу
  • 32% к критическому второму ходу, если во всех предыдущих не было критического удара.
  • 45% к критическому третьему ходу, если не было критического удара во всех предыдущих.
  • 54% к 4-му ходу критического удара, если во всех предыдущих не было критического удара.
  • ...
  • 80% к критическому восьмому ходу, если во всех предыдущих не было критического удара.

По-прежнему около 0,2% (против этих 5%) шансов 3 крита + 2 не крита в 5 последовательных ходах. И есть вероятность 14% для 4 последовательных не критов, 5% из 5, 1,5% для 6, 0,3% для 7, 0,07% для 8 последовательных не критов. Бьюсь об заклад, его «более справедливо», чем 41%, 32%, 26%, 21% и 16%.

Надеюсь, тебе до сих пор не скучно до смерти.


это очень похоже на мое решение, за исключением того, что оно «запоминает» только время с момента последнего критического удара. В соответствии с этим решением строка из 4 критических попаданий совпадает со строкой из 1 критического попадания в отношении вероятностей на будущее. Таким образом, если критические попадания хороши, это решение ограничивает ваш риск снижения, но не ваш потенциал. Мое решение влияет на оба.
Нил Дж

Очевидно, что разные решения имеют свои преимущества. Этот фокус на поддержание чистоты случайности с научной точки зрения. Это не значит, что это как-то лучше, чем тасовать сумку или что-то еще. Это просто решение, которое стоит попробовать.
Мрак

3

Как насчет того, чтобы вероятность критического удара зависела от последних N атак. Одна простая схема - это некая цепочка Маркова: http://en.wikipedia.org/wiki/Markov_chain, но в любом случае код очень прост.


IF turns_since_last_critical < M THEN 
   critial = false
   turns_since_last_critical++;
ELSE
   critial = IsCritical(chance);
   IF Critial THEN
       turns_since_last_critica = 0;
   ELSE
       turns_since_last_critica++;
   END IF;
END IF;

Конечно, вы должны сделать свою математику, потому что вероятность критического удара ниже, чем вероятность критического, если вы знаете, что было достаточно ходов с момента последнего


Вы получаете большую часть эффекта, просто принимая во внимание последнюю атаку. Пусть P - наблюдаемая частота попаданий, R - частота попаданий после промаха и R / 2 - коэффициент попаданий после попадания. По определению, в любой момент у вас есть шанс попасть в P = P * R + (1-P) * (R / 2). Это означает, что P = R / (2-R)
MSalters

2

OP,

В значительной степени, если вы хотите, чтобы это было честно, это не будет случайным.

Проблема вашей игры - фактическая длина матча. Чем дольше совпадение, тем меньше случайности вы увидите (криты будут составлять 20%), и это приблизится к вашим предполагаемым значениям.

У вас есть два варианта, предварительно рассчитать атаки на основе предыдущих бросков. Который вы будете получать один крит каждые 5 атак (на основе ваших 20%), но вы можете сделать порядок, он происходит случайно.

listOfFollowingAttacks = {Hit, Hit, Hit, Miss, Crit};

Это шаблон, который вы хотите. Поэтому сделайте так, чтобы он выбирал случайным образом из этого списка, пока он не опустеет, а затем создайте его заново.

Это шаблон, который я создал для своей игры, и он работает достаточно хорошо для того, что я хочу.

ваш второй вариант - увеличить шанс критического удара, вы, вероятно, увидите более четное число в конце всех атак (при условии, что ваши матчи заканчиваются довольно быстро). Чем меньше вероятность, тем больше RNG вы получите.


2

Вы смотрите на линейное распределение, когда вы, вероятно, хотите нормальное распределение.

Если вы помните, еще в юности, играя в D & D, вас попросили бросить несколько n-сторонних кубиков, а затем суммировать результаты.

Например, бросание 4 х 6-сторонней матрицы отличается от бросания 1 х 24-сторонней игры в кости.


2

В City of Heroes на самом деле есть механик под названием «Разрушитель полос», который решает именно эту проблему. Это работает так, что после пропущенной строки длины, связанной с самой низкой вероятностью попадания в строку, следующая атака гарантированно будет попаданием. Например, если вы пропустите атаку с вероятностью попадания более 90%, то ваша следующая атака будет автоматически попадать, но если ваш шанс попадания будет ниже, чем 60%, вам понадобится несколько последовательных промахов, чтобы вызвать «полосатик» (I не знаю точных цифр)


2

альтернативный текст

это действительно предсказуемо ... но вы никогда не можете быть уверены.


Это должны быть мои обои для рабочего стола!

0

Как насчет взвешивания стоимости?

Например, если у вас есть шанс 20% на критическое попадание, сгенерируйте число от 1 до 5 с одним числом, представляющим критический удар, или число от 1 до 100 с 20 числами, являющимся критическим попаданием.

Но пока вы работаете со случайными или псевдослучайными числами, невозможно избежать результатов, которые вы видите в данный момент. Это природа случайности.


И почему это имеет значение? Существует абсолютно равный шанс получить критическое значение для обоих наборов чисел.
Самджудсон

Именно. Я просто представляю ему два варианта для его примера 20%. Хотя 100, вероятно, будет работать лучше, если вы имеете дело с целыми процентными процентами, поскольку вам нужно будет смоделировать только один «кубик», если вы хотите так думать об этом.
Томас Оуэнс

Варианты, которые вы представляете, это именно то, что он уже делает.
ceejayoz

2
Не за то, что он хочет. Ему нужен генератор не случайных чисел, даже если он думает, что это называется генератором случайных чисел.
ceejayoz

0

Реакция на: «Проблема в том, что я получил очень плохие результаты в реальной жизни - иногда игроки получают 3 крита в 5 попаданиях, иногда ни одного в 15 попаданиях».

У вас есть шанс где-то между 3 и 4% получить ничего в 15 попаданиях ...


Когда вы получаете 3500 игроков онлайн, сражающихся за 10000 битв в минуту, проблема, возникающая в 3% битв, является очень распространенной проблемой.
Мыслитель

С другой стороны, невезение, которое происходит в 3% сражений, все еще просто неудача.
MSalters

0

Я хотел бы предложить следующую «произвольно отсроченную ставку»:

  • Поддерживать два массива, один ( in-array) изначально заполнен значениями от 0 до n-1, другой ( out-array) пуст
  • Когда запрашивается результат:
    • вернуть случайное значение из всех определенных значений вin-array
    • переместить это значение из in-arrayвout-array
    • переместить один случайный (по всем элементам, включая неопределенный!) элемент out-arrayобратно вin-array

Это имеет свойство, что он будет «реагировать» медленнее, чем больше n . Например, если вам нужен шанс 20%, установка n на 5 и попадание в 0 «менее случайны», чем установка n в 10 и попадание в 0 или 1, а от 0 до 199 из 1000 будет почти неотличима от истинной случайности по небольшой выборке. Вам нужно будет настроить п вашего размера выборки.


0

Предварительно рассчитать случайный критический удар для каждого игрока.

// OBJECT
//...
// OnAttack()
//...
c_h = c_h -1;
if ( c_h == 0 ) {
 // Yes, critical hit!
 c_h = random(5) + 1 // for the next time
 // ...
}

0

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

Я работаю с Java, так что я не уверен, где можно найти что-то для C ++, которое дает вам случайные числа с нормальным распределением, но должно быть что-то там.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.