Как вы получаете текущее семя Random в C#?
в моей игре я собираюсь использовать случайные значения, чтобы забрать награду Игрок получает из груди. Проблема в том, что вы можете быстро сохранить и быстро загрузить, а это значит, что они могут продолжать перезагружать, чтобы повторно рандомизировать, пока не получат то, что хотят. Есть ли способ, которым я мог бы получить текущее значение семени моего Random
объект и, возможно, вернуться к той же точке, когда они загружаются, чтобы они не могли злоупотреблять рандомизацией?
8 ответов
Это невозможно.
вместо этого вы можете сериализовать Random
экземпляра с использованием двоичной сериализации.Random
is [Serializable]
, и семя, и внутреннее состояние будет сохраняться.
обратите внимание, однако, что сохранение случайного семени позволяет вашим игрокам предсказывать будущее, что очень полезно, если вы позволяете экономить в бою.
также обратите внимание, что пользователи могут сохранять, открывать сундук, загружать, выполнять действие, которое генерирует случайное число, а затем получить другой предмет из сундука.
Это только по касательной, но если кому-то интересно, почему Random
не имеет свойства под названием Seed
или метод, называемый GetSeed()
, Я готов поспорить, что это, вероятно, связано с проблемами безопасности: вы хотели бы подвергнуть внутреннюю работу вашего генератора случайных чисел внешнему миру? Абсолютно нет! В противном случае, какой-нибудь клиентский код мог бы копаться, пока не получит значения, которые вы использовали, а затем делать с ними неприятные и непреднамеренные вещи.
действительно,Seed
нет как это не актуально для алгоритм после инициализации. Одно из его производных,mj
, хранится в SeedArray
хотя, вы можете проверить это, используя отражение для сравнения обоих Random
случаях:
int subtraction = (Seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(Seed);
mj = MSEED - subtraction;
SeedArray[55]=mj;
поэтому все, что вам нужно сделать, это проверить последний элемент (индекс 55) в SeedArray
. Это единственное место есть.
[перемещен ответ из удаленного вопроса как определить, если два Случайные экземпляры имеют одно и то же семя?]
Я бы, вероятно, просто использовал это в соответствии с MSDN:http://msdn.microsoft.com/en-us/library/ctssatww.aspx
Random(seed)
где seed-некоторое значение, которое я загрузил из хранилища.
вы можете рассчитать случайное вознаграждение как хэш-функцию:
- некоторое семя, которое назначается, когда вы начинаете новая игры и сохраняется в спас и
- некоторое постоянное свойство сундука, которое инвариантно во всех играх (например, фиксированный идентификатор или его положение, если он никогда не движется).
этот метод имеет то преимущество, что данный сундук всегда будет давать одинаковую награду в данной игре, независимо от того, как много раз вы сохраняете и воспроизводите, даже если сундуки открываются в разных ордерах или другие "случайные" события запускаются в разных ордерах. Кроме того, вознаграждение каждого сундука не зависит от вознаграждения других сундуков, если свойство сундука, используемое в хэше, независимо.
в следующем примере GetRewardId
генерирует идентификатор награды как хэш игрового семени, XORed с координатой X сундука. Он использует Random
чтобы выполнить хэш, используя хэш-вход в качестве Random
объекта семя, и принимая первое случайно сгенерированное число в качестве выхода.
private static int GetRewardId(int seed, float coord, int numRewards)
{
int tempSeed = BitConverter.ToInt32(BitConverter.GetBytes(coord), 0) ^ seed;
return new Random(tempSeed).Next(numRewards);
}
int seed = new Random().Next();
int numDifferentRewards = 5;
float xCoordinate = chest.Position.X;
int rewardId = GetRewardId(seed, xCoordinate, numDifferentRewards);
если многие из ваших сундуков, вероятно, будут выровнены в sace, вы можете выбрать другое свойство или использовать дополнительные размеры, XORing с координатами y и/или z тоже.
к сожалению, в ссылочной реализации от Microsoft начальное значение no arg ctor даже не сохраняется, не говоря уже о доступе: http://referencesource.microsoft.com/#mscorlib/system/random.cs,bb77e610694e64ca
однако, как вы также можете видеть в ссылочной реализации, значение, которое вы можете передать (вероятно, должно - я знаю, что делаю), так же, как и они, это: Environment.TickCount
поэтому сохраните это в переменной, а затем передайте эту переменную в конструктор, который принимает аргумент и теперь вы знаете, семян. Не после факта, но этого должно быть достаточно для любых ваших намерений.
Я рекомендую вам сгенерировать случайное число и использовать его в качестве начального числа для вашего генератора реальных случайных чисел. С помощью этого метода у вас есть номер семени, который на самом деле является случайным числом, и вы можете сохранить номер семени для дальнейшего использования.