Как вы получаете текущее семя Random в С#?
В моей игре я собираюсь использовать случайные значения, чтобы выбрать вознаграждение, которое игрок получает от сундука. Проблема в том, что вы можете быстро сохранить и быстро загрузить, а это значит, что они могут продолжать перезагрузку, чтобы повторно рандомизировать, пока они не получат то, что они хотят. Есть ли способ получить текущее значение семени моего объекта Random
и, возможно, вернуться к той же точке при загрузке, чтобы они не могли злоупотреблять рандомизацией?
Ответы
Ответ 1
Не уверен в получении начального числа, но вы можете сохранить значение, которое вы даете объекту Random
. Помните, что есть два конструктора. Вторым является Random(Int32)
, поэтому, если вы сами задаете начальное число (достаточно простое значение - Environment.TickCount), вы можете сохранить это значение где-то перед тем, как передать его конструктору. Если вы еще не прочитали его, ознакомьтесь с документацией MSDN по адресу https://docs.microsoft.com/en-us/dotnet/api/system.random.
Ответ 2
Это невозможно.
Вместо этого вы можете сериализовать экземпляр Random
, используя двоичную сериализацию.
Random
[Serializable]
, и семя и внутреннее состояние будут сохраняться.
Обратите внимание, однако, что сохранение случайного семени позволяет вашим игрокам предсказать будущее, что очень полезно, если вы позволите сохранить битву.
Также обратите внимание, что пользователи могут сохранить, открыть сундук, загрузить, выполнить действие, которое генерирует случайное число, а затем получить другой предмет из сундука.
Ответ 3
В самом деле, Seed
не сохраняется, поскольку он не имеет отношения к алгоритму после инициализации. Одна из его производных mj
хранится в SeedArray
, но вы можете проверить, что использование Reflection для сравнения экземпляров Random
:
int subtraction = (Seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(Seed);
mj = MSEED - subtraction;
SeedArray[55]=mj;
Итак, все, что вам нужно сделать, это проверить последний элемент (индекс 55) в SeedArray
. Это единственное место Seed
.
[Перемещенный ответ из удаленного вопроса Как определить, имеет ли два случайных экземпляра одно и то же семя?]
Ответ 4
Это связано только с касательной, но в случае, если кто-то задается вопросом, почему Random
не имеет свойства, называемого Seed
, или метода, называемого GetSeed()
, я готов сделать ставку, что это, вероятно, связано с проблемы безопасности: хотите ли вы представить внутреннюю работу вашего генератора случайных чисел во внешний мир? Точно нет! В противном случае, некоторый клиентский код мог бы ткнуть, пока не получит значения, которые вы использовали, а затем делайте с ними неприятные и непреднамеренные вещи.
Ответ 5
Я бы просто использовал это в соответствии с MSDN: http://msdn.microsoft.com/en-us/library/ctssatww.aspx
Random(seed)
где seed - некоторое значение, которое я загрузил из хранилища.
Ответ 6
Вы можете рассчитать случайное вознаграждение как хэш-функцию:
- некоторое семя, которое назначается при запуске новой игры и сохраняется в сохраненных играх; и
- некоторое постоянное свойство сундука, которое инвариантно во всех играх (например, фиксированный идентификатор или его положение, если оно никогда не перемещается).
Этот метод имеет то преимущество, что данный сундук всегда будет давать ту же награду в данной игре, независимо от того, сколько раз вы сохраняете и воспроизводите, даже если сундуки открываются в разных порядках или запускаются другие "случайные" события в разных порядках. Также каждая награда за сундуки не зависит от других нагрузок сундуков, если свойство сундука, используемое в хеше, не зависит.
В следующем примере 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.
Ответ 7
К сожалению, в эталонной реализации от Microsoft значение семестра no arg ctor даже не сохраняется, не говоря уже о доступе к доступу:
http://referencesource.microsoft.com/#mscorlib/system/random.cs,bb77e610694e64ca
Однако, как вы можете видеть в ссылочной реализации, значение, которое вы можете передать (возможно, должно - я знаю, что знаю), как и они: Environment.TickCount
Итак, сохраните это для переменной, а затем передайте эту переменную в ctor, который принимает arg, и теперь вы знаете семя. Не после факта, но этого должно быть достаточно для любых ваших намерений.
Ответ 8
Я рекомендую вам создать случайное число и использовать его в качестве начального числа для вашего реального генератора случайных чисел. По этому методу у вас есть начальное число, которое на самом деле является случайным числом, и вы можете сохранить свой номер семени для дальнейшего использования.