Необходим предсказуемый генератор случайных чисел - PullRequest
151 голосов
/ 26 мая 2009

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

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

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

Ответы [ 37 ]

3 голосов
/ 26 мая 2009

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

<code>
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;

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

2 голосов
/ 26 мая 2009

OP

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

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

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

listOfFollowingAttacks = {Хит, Хит, Хит, Хит, Мисс, Крит};

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

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

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

2 голосов
/ 27 июля 2009

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

2 голосов
/ 28 мая 2009

alt text

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

2 голосов
/ 28 мая 2009

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

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

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

0 голосов
/ 26 мая 2009

Для генераторов случайных чисел C ++ используйте rand или boost :: random

Всякий раз, когда игрок получает удар, вы просто проверяете, нет ли случайного числа в [0; 1] меньше 0,2. Это означает, что кто-то не может получить критических ударов в 15, но это невероятно.

Это даст вам натуральные случайные числа в соответствии с законами биномиального распределения (p = 0,2)

0 голосов
/ 10 июня 2009

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

0 голосов
/ 31 мая 2009

Проблема с bozo sort , в том, что у него есть потенциал, который можно использовать вечно.

0 голосов
/ 29 мая 2009

Я также пытался решить эту проблему. Лучшее, что я мог придумать, - это динамическое изменение вероятностей, если числа основаны на том, как часто они появлялись в ближайшем прошлом. Что-то вроде (для игры в кости, в matlab):

probabilities = [1 1 1 1 1 1];
unrandomness = 1;
while true
    cumprob = cumsum(probabilities) ./ sum(probabilities);
    roll = find(cumprob >= rand, 1)
    probabilities = probabilities + unrandomness;
    probabilities(roll) = probabilities(roll) - 6*unrandomness;
    if min(probabilities) < 0
        probabilities = probabilities - min(probabilities);
    end
end

Извините за отсутствие отступов. Параметр неслучайности может быть отрегулирован по желанию. Истинный случайный вывод (unrandomness = 0):

2 3 1 1 4 1 3 3 4 5 1 5 5 2 6 1 1 1 6 1 1 3 5 6 6 1 4 2 4 6 3 6 5 1 1 6 2 5 6 4 3 5 2 4 6 5 5 5 4 4 3 4 1 2

unrandomness = 1:

3 2 4 5 6 2 6 2 4 1 5 5 1 6 4 3 1 4 2 1 3 2 6 5 3 6 5 3 1 4 1 6 5 3 4 2 1 6 5 4 1 4 3 1 6 6 5 4 3 1 5 2 3 2

Выглядит лучше, я думаю. Особенно, если вы строите промежутки между числами.

0 голосов
/ 28 мая 2009

Так и должно быть, скорее всего, вам не следует ожидать критического удара 1 раз в 5 сражений ... попробуйте с монетой или кубиком и убедитесь сами Но это только я. GB

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...