How do you get the current seed of Random in C#? - c#

In my game I'm going to use random values to pick the reward the player gets from a chest. The problem is that you can quick save and quick load and that means they can keep reloading to re-randomize until they get what they want. Is there some way that I could get the current seed value of my Random object and possibly return to that same point when they load so that they couldn't abuse the randomization?

This is not possible.
Instead, you can serialize the Random instance using binary serialization.
Random is [Serializable], and the seed and internal state will persist.
Note, however, that saving the random seed allows your players to predict the future, which is very useful if you allow saving in battle.
Also note that users can still save, open the chest, load, perform an action that generates a random number, then get a different item from the chest.

Not sure on getting the seed, but you could save the value you give to the Random object. Remember, there are two constructors. The second is Random(Int32), so if you set the seed yourself (an easy enough value is Environment.TickCount), you could store that value somewhere before you pass it to the constructor. If you haven't read it yet, check out the MSDN documentation at https://learn.microsoft.com/en-us/dotnet/api/system.random.

Indeed, the Seed isn't stored as it is not relevant for the algorithm after initialization. One of its derivatives, mj, is stored in the SeedArray though, you can check that using Reflection to compare both Random instances:
int subtraction = (Seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(Seed);
mj = MSEED - subtraction;
SeedArray[55]=mj;
So all you have to do is to check the last element (index 55) in the SeedArray. This is the only place Seed is used.
[Moved answer from deleted question How to determine if two Random instances have the same seed?]

You can calculate the random reward as a hash function of:
some seed that is assigned when you begin a new game, and is persisted in saved games; and
some constant property of a chest that is invariant across all games (e.g. a fixed ID, or its position if it never moves).
This method has the advantage that a given chest will always yield the same reward in a given game, no matter how many times you save and replay, even if chests are opened in different orders, or other 'random' events are triggered in different orders. Also each chest's reward is independent of other chests' rewards, so long as the chest's property used in the hash is independent.
In the following example GetRewardId generates a reward ID as a hash of the game seed XORed with the x coordinate of a chest. It uses Random to perform the hash, by using the hash input as the Random object's seed, and taking the first randomly generated number as the output.
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);
If many of your chests are likely to be aligned in sace, you may want to choose a different property, or use additional dimensions, by XORing with the y and/or z coordinates too.

I'd probably just use this as per MSDN: http://msdn.microsoft.com/en-us/library/ctssatww.aspx
Random(seed)
where seed is some value I've loaded from storage.

This is only related on a tangent, but in case anyone is wondering why Random doesn't have a property called Seed or a method called GetSeed(), I'm willing to wager that it's likely due to security concerns: Would you want to expose the inner workings of your "random" number generator to the outside world? Absolutely not! Otherwise, some client code could poke around until it got the values you were using and then do nasty and unintended things with them.

Unfortunately, in the reference implementation from Microsoft, the no arg ctor's seed value is not even saved, let alone exposed for access:
http://referencesource.microsoft.com/#mscorlib/system/random.cs,bb77e610694e64ca
However, as you can also see in the reference implementation, the value you can pass in (probably should -- I know I do), just like they do, is: Environment.TickCount
So save that to a variable, then pass that variable in to the ctor that takes an arg and you now know the seed. Not after the fact, but this should be sufficient for whatever your intent is.

I recommend you to generate a random number and use it as a seed number to your real random number generator. By this method you have a seed number that is actually a random number and you can save your seed number for further using.

Related

Why I failed to set seed to UnityEngine.Random

I'm trying to set my own seed to UnityEngine.Random (not System.Random)
but it seems that it doesn't work.
here are my code and output
void Start()
{
UnityEngine.Random.InitState(114514);
Debug.Log(UnityEngine.Random.seed);
var a = UnityEngine.Random.Range(0f,1f);
Debug.Log(UnityEngine.Random.seed);
var b = UnityEngine.Random.value;
Debug.Log(UnityEngine.Random.seed);
var c = UnityEngine.Random.value;
Debug.Log(UnityEngine.Random.seed);
}
output:
114514
-101807786
-1953724440
-628832631
why every time I call Random.value or Random.range, it seems that the seed will change to another?
Random number engines are implemented in a way that they calculate a pseudo-random number from the seed given. On top of that, they calculate the seed for the next iteration. From that next seed, the next random number and the third seed will be caluclated. Since we want the second (and all following) iterations to yield results different from the first one, the seed needs to change and can not remain the same.
Calculating a seudo-random number by using a specific seed will allways result in the exact same result. And since the new seed is calculated as pseudo-random as well, the sequence of seeds (and outputs) will allways remain the same. Assigning a seed makes sure that you start this sequence at a defined point and not the default one. If you would start your programm with the seed -101807786, the output would be
-1953724440
-628832631
followed by one more seed (which is the next one in the sequence).
Now, there are different implementations of random number engines which may expose different propertys called seed. The UnityEngine.Random happens to exose the current seed under the name seed while other engines may expose the initial, user defined seed under the name seed.

How Pseudorandom number generator gets "first" seed number?

I tried to understand better random number generating process, in particular pseudorandom number generation in .NET (actually MONO), and I am after reading these articles: MSDN Random, wikipedia Random number generation.
So I think I get it (.NET uses modified version of Donald E. Knuth's subtractive random number generator algorithm).
The only thing that stays unclear to me is how this algorithm gets its first seed number. I tried to find info, but didn't.
Does it takes from pseudorandom number generator too? It doesnt make sense, does it? First seed needs to be somehow random too, couse if not first random number in every instance of .NET application would be the same. If so, quessing next results from applications like games would be quite easy (if the author of application didn't modify the number after generation). So I am quessing the first seed number, I mean first input to the generator must be taken from something unique for machine or current application process, but I am just quessing.
So my question is: If my thinking process is correct (if not please correct me), how generator gets its first input for given algorithm?
From the Reference Random Class
public Random()
: this(Environment.TickCount) {
}
public Random(int Seed) {
///....
}
It's calculated based on your input or the Tick count
The default seed value is derived from the system clock
source Random() constructor
So separate instances get different random values. However if you create multiple instances of this class quickly, they may end up using the same clock-tick as seed - and thus generate the same sequence.
The Random class has a constructor that takes either no or one parameter of type int. Thus you can set the initial seed by your own.
If you do not provide a parameter than as the documentations says a time-dependent value is used as seed. The default values is the number of ticks (see source) that have elapsed since the system started up.
System.Random uses Environment.TickCount as the seed in its parameterless constructor, as per .NET source.

Quickly generating random numbers in C#

I'm creating a program which creates several panels with randomly determined colors which will be incremented/decremented by some random constant every 20 milliseconds or so to create a smooth, undulating color. For this, I've just been using the Next(int) method of the Random class. For a single instance, this works perfectly--every time I run the program, I get different colors changing at different rates. The problem comes when I try to create multiple panels--most, if not all, come out looking and behaving identically to each other, implying that all of the randomly generated numbers were identical. I'm assuming that this is a result of generating all of the pseudorandom numbers in rapid succession, causing all of them to be based on the same seed.
Is there a better way than using the Random class to generate random integers in rapid succession to ensure that they're not identical? If there isn't any way already built into C#, is there any straightforward way to develop a pseudorandom number generator (bearing in mind that this is my first foray into using C#)?
Do not use multiple instances of the Random Class using the default constructor. If they all are initialized within the same time slice they will all have the same seed and will all generate the same sequence of random numbers, use the constructor that you can pass in a seed and pass a different seed to each instance.
Random rand0, rand1, rand2;
void init()
{
int baseSeed = (int) DateTime.Now.Ticks;
rand0 = new Random(baseSeed);
rand1 = new Random(baseSeed + 1);
rand2 = new Random(baseSeed + 2);
}
Also you only need one object per thread, use the same Random object for all of the panels if they are all on the same thread.
Random is fine if you don't need cryptographically secure random numbers - but chances are you're creating a new instance every time you need a number, rather than using one instance throughout.
When you create a new instance of Random it will take "the current time" as the seed - so if you create two in quick succession, you'll end up with two instances with the same seed and therefore the same numbers (when you use the same calls).
It's generally better to use a single instance of Random - or rather, one per thread, as it's not thread-safe.
See my article on the topic for various approaches.
If you have multiple instances of the Random class that are producing identical series of random numbers, then you must be creating each instance using the same seed. For example:
The most likely explanation for that is that you are creating them all like this:
var rng = new Random();
and creating each instance at the same point in time. This constructor uses the current time to seed the RNG and if you create them all at the same point in time, they will all be seeded with the same time.
Solve the problem by creating each instance with a different seed. Or create a single RNG and share it between all panels.
I prefer RNGCryptoServiceProvider. It is roughly as fast as Random and tends to produce more unique values in my informal testing. You also avoid any undesirable behaviors pertaining to seeding (such as others are describing).
However, you can't guarantee uniqueness (otherwise it wouldn't be random). You can use a database if you need to permanently track unique values (which it doesn't sound like you wish to do) or a Dictionary where the random value is the key if you just care about generating a set of unique numbers in memory. If the key already exists, you reject the value and generate another one.
using System.Security.Cryptography;
...
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
byte[] bytes = new byte[8];
crypto.GetBytes( bytes );
long value = BitConverter.ToInt64( bytes, 0 );
As mentioned above, you can use a single instance of the random class. However, if for some reason this isn't desirable (i.e. you want to run multiple threads and don't want any contention), then you can use multiple instances as long as you initialize the seed for each generator to a random or pseudo-randomly generated seed.
For this initial seed generation, you will need to use the same Random generator.

Creating a true random [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why does it appear that my random number generator isn't random in C#?
How can I generate truly (not pseudo) random numbers with C#?
I've created a dice game where the dice is based on a percentile, 1-100.
public static void Roll()
{
Random rand = new Random((int)DateTime.Now.Ticks);
return rand.Next(1, 100);
}
But I don't feel like it's a real random based on current time.
If I do
for (int i = 0; i < 5; i++)
{
Console.WriteLine("#" + i + " " + Roll());
}
They would all be the same values, because the DateTime.Now.Ticks didn't change, it seeded the same number.
I was thinking I could generate a new random seed if the seed was the same due to the current time, but it doesn't feel like an honest "re-roll"
What should I do to try and replicate a close to real/honest dice roll? Should I use the RNGCryptoServiceProvider class to generate rolls instead?
DateTime.Now.Ticks only has a resolution of approximately 16ms, so if you create a Random with that overload multiple times within a 16ms "slot" they will all be seeded with the same value and therefore you will get the same sequence.
Initialize your Random outside your loop so that a single Random sequence is produced, rather than creating it each time within the loop which could result in Randoms being seeded with the same value and so produce the same sequence.
Update
My previous point that the default constructor initialized Random with CPU ticks was incorrect, the default constructor actually uses Environment.TickCount which is:
A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started.
Which still has a low resolution. If you make multiple instances of Random in quick succession, they can easily be created within the same time slot and therefore have the same seed value, and create the same sequence. Create a single instance of Random and use that.
Update
Further to your comments, if you wish to generate a random sequence across multiple threads, please see the following Jon Skeet article which discusses a thread-safe wrapper:
https://codeblog.jonskeet.uk/2009/11/04/revisiting-randomness
Pseudo-random number generators like Random should only be seeded once, so:
private static Random _rand = new Random();
public static int Roll()
{
return _rand.Next(1, 100);
}
(Note I made the return value int rather than void; the Roll function as quoted in the question results in a syntax error.)
But your title says "Creating a true random". Random won't do that for you, it's a pseudo-random number generator, meaning it's deterministic, just hard to predict if you don't know the seed. Usually that's good enough for most purposes, but if you need real randomness, you need an entropy source. http://random.org is one popular one.
You should create your Random class only once outside your Roll function and seed it with a unique value.
You are recreating your Random each time you call Roll which causes the 'not random numbers'.
Should I use the RNGCryptoServiceProvider class to generate rolls instead?
If this is a serious game with money at stake then: Yes.
I'm assuming that you are calling the Roll() method so quickly that Now.Ticks is the same?
The simplest way to get around this would be rather than to create a new Random() instance each time you call Roll() create a static variable to hold a single instance of Random().
The usual way to use random number generators is to seed them once, save them and call on them repeatedly throughout your programme. As long as you seed from a suitable value at the start, you should get acceptable randomness - assuming the generator you're using is using a function returning things which are suitably random for your purposes. So, save your Random instance outside the Roll() function, seed it the first time it's used, then just call Next() on it each time you need another number.
When you get right down to it, there's no such thing as true random number generation on a computer, only pseudorandom sequences based on a seed. However, humans are terrible at identifying randomness, so it's usually okay.

Designing a custom Random class

I know C# has the Random class and probably a few classes in LINQ to do this, but if I was to write my own code to randomly select an item from a collection without using any built in .NET objects, how would this be done?
I can't seem to nail the logic required for this - how would I tell the system when to stop an iteration and select the current value - at random?
EDIT: This is a hypothetical question. This is not related to a production coding matter. I am just curious.
Selecting a random element from a collection can be done as follows.
Random r = new Random();
int randomIndex = r.Next(0, myCollection.Size -1);
var randomCollectionItem = myCollection[randomIndex];
Unless you have a VERY good reason, writing your own random generator is not necessary.
My advice to you is DON'T DO IT. Whatever reason you think you may have for not wanting to use the built-in library, I am pretty sure you misunderstood something. Please go back to the drawing board.
All of the advice above is technically accurate, but is kind of like giving a chemistry textbook to someone who wants to refine his own oil to use in his car.
There are many pseudo-random number generators. They aren't truly random, but they come at different quality, distinguished by their statistical and sequential properties and what purpose they are applicable for.
It very much depends on "how random you need it". If it just needs to "look random to a human", simple generators look like that:
rnd = seed; // some starting value
rnd = (a * rnd + b) % c; // next value
...
For well chosen values of a, b, and cthese generators are ok for simple statistical tests. A detailed discussion and common values for these you find here.
One interesting approach is to collect as much "external" data as possible - like time between keypresses, mouse movements, duration of disk reads etc. -, and use an algorithm that accumulates randomness while discarding dependency. That is mathematically tricky though (IIRC not long ago a critical attack surfaced based on one of these not being as random as thought).
Only a very few special applications use a truly random external hardware source - anything between a open-imput amplifier and radioactive decay.
You need to use a seed, something semi random provided by the computer itself.
Maybe use very fine resolution time and use the last couple microseconds when the method is called. That should be random enough to generate anything from 00 to 99, you can then go from there.
It sounds like your problem isn't in calculating a random number, but in how to use that random number to select an item from a list. Assuming you can create a random number somehow, all you need to do is use it as the argument to the list's indexer.
int index = customRandomGenerator.Next();
var selection = items[index];
Assuming that your presupposition about having to iterate through the list is correct (or the collection doesn't have an indexer) then you could do:
int index = customRandomGenerator.Next();
Item selection = null;
for (int i = 0; i < items.Length; i++)
{
if (i == index)
{
selection = items[i];
break;
}
}
The only true "cryptographically strong" random number generator in the .Net Framework is in System.Cryptography.RandomNumberGenerator - run this through Reflector to see what is does? Looking at your problem you would need a to know the Count of the collection otherwise you may never retrieve an item - you would need to specify a start and end value to draw random numbers from - the Random class would work best - pop it through Reflector.
Well, I never thought about implementing that myself as it seems like reinventing the wheel but you may have a look on this wikipedia article, hope it helps you do what you want
Random Number Generator

Categories

Resources