Random and Seed, Generates same value? - c#

I'm developing a small XNA GAME,
for (int birdCount = 0; birdCount < 20; birdCount++)
{
Bird bird = new Bird();
bird.AddSpriteSheet(bird.CurrentState, birdSheet);
BIRDS.Add(bird);
}
The code above runs at Load function, BIRDS is the List where all Bird's are held.
The bird constructor customize the bird randomly. If I run the code breakPoint by breakPoint the random function generates different values, but if i do not stop the code and leave program running all random values become same so that all of birds become same.
How can i solve this problem ?
the code for random and seeds:
private void randomize()
{
Random seedRandom = new Random();
Random random = new Random(seedRandom.Next(100));
Random random2 = new Random(seedRandom.Next(150));
this.CurrentFrame = random.Next(0, this.textures[CurrentState].TotalFrameNumber - 1);
float scaleFactor = (float)random2.Next(50, 150) / 100;
this.Scale = new Vector2(scaleFactor, scaleFactor);
// more codes ...
this.Speed = new Vector2(2f * Scale.X, 0);
this.Acceleration = Vector2.Zero;
}

Chances are you are repeatedly creating a new Random object in your code - instead create the Random object once only (i.e. by making it static or passing it as a parameter)
Since the Random default constructor uses the current time as initial seed and all instances of Random with the same seed create the same sequence of numbers creating new Random objects in fast order might produce the same exact sequence of numbers. This sounds like what you are seeing.

Related

How to create 2 Random objects in 2 consecutive lines of code with different seeds?

I want to make 2 different Random objects in 2 consecutive lines of code. The parameterless constructer of the Random class is like this:
public Random()
: this(Environment.TickCount) {
}
It uses Environment.TickCount as the seed. TickCount represents the amount of time that has passed since the OS is switched on, right?
I tried the following:
Random r1 = new Random ();
Random r2 = new Random ();
And I found out that the 2 Random objects had the same seed because their Next methods return the same number each time. I was surprised by how fast a line of code can be executed. Then I tried:
long tick1 = Environment.TickCount;
for (int i = 0 ; i < 100000 ; i++) {
}
long tick2 = Environment.TickCount;
Console.WriteLine (tick2 - tick1);
And I get 0. So I iterated 100000 times and still, not even 1 millisecond has passed?
I just want to ask how can I create 2 different Random objects or is there another way to generate random numbers?
Base on #PankajMishra's answer, try this one:
//Function to get random number
private static readonly Random getrandom = new Random();
private static readonly object syncLock = new object();
public static int GetRandomNumber(int min, int max)
{
lock(syncLock) { // synchronize
return getrandom.Next(min, max);
}
}
lock block is effective when you use it in a multi-threading program, if you sure just one thread use it, so you can prevent lock to increase your code performance.
To me, it seems like an XY problem, because you don't need two separate Random instances - you can use the same one to generate all your random number, can't you? Just call Next again and that's it:
var rnd = new Random();
int firstRandomInt = rnd.Next();
int secondRandomInt = rnd.Next();
However, you really need 2 Random instances, you can use the first one to seed the second one:
var rnd = new Random();
var rnd2 = new Random(rnd.Next());

How can I ensure that same random numbers are not selected every time in C#?

I'm writing a trivia game player app in C#, where the user must pick 5 randomly selected trivia questions from a set of 20 available questions.
I use this code to generate an index that the app will use to fetch the questions:
private void GenerateRandomNumbers(int RandomIndex)
{
Random rand = new Random();
HashSet<int> check = new HashSet<int>();
for (int i = 1; i < RandomIndex; i++)
{
int curValue = rand.Next(1, RandomIndex);
while (check.Contains(curValue))
{
curValue = rand.Next(1, RandomIndex);
}
ChosenQuestions.Add(Questions[curValue]);
check.Add(curValue);
}
check.Clear();
}
The problem is that when the user plays the game a second time (by clicking the "PLAY AGAIN" button) and the above code is executed again, it keeps picking the same random numbers, though they are not necessarily in the same order. this causes the same trivia questions to be chosen every time. I want a fresh new set of totally random numbers every time the above code executes. How can I modify the code to accomplish this?
NOTE: I did copy this code from somewhere else here on Stack Overflow, so it's not my own original code.
Assuming RandomIndex is the number of values to pick. You want this:
rand.Next(1, RandomIndex);
to be
rand.Next(0, Questions.Length);
There is an off by one error in the loop as well. Let's just fix the whole thing:
private void GenerateRandomNumbers(int RandomIndex)
{
Random rand = new Random();
HashSet<int> check = new HashSet<int>();
for (int i = 0; i < RandomIndex; i++)
{
int curValue = rand.Next(0, Questions.Length);
while (check.Contains(curValue))
{
curValue = rand.Next(0, Questions.Length);
}
ChosenQuestions.Add(Questions[curValue]);
check.Add(curValue);
}
}
Also, if you call this in a tight loop, you will get the same values picked repeatedly. This because Random chooses a seed based on the system clock which only upadates every 15 ms or so.
I think that a shuffle would be better approach rather than checking whether indexes have already been picked.
You could seed RNG with different seeds
Random rand = new Random(newSeed);
Seed could be taken from current time, for example
Try using just one global Random object, and not creating a new Random() every time the user plays. This will ensure that isntead of initializing a new seed every time, the numbers will be a sequence created by one seed. This will make them closer to real randomness.

How do random numbers from the random object work?

if I have this:
(I already declared the variables)
random1 = new Random();
Console.WriteLine(random1.Next(1, 100));
Console.WriteLine(random1.Next(1, 100));
When I have that, it'll generate a different number for every time I call console.writeline, so this would generate ex. 10, 55 and if you do it again 20,60 so basically random numbers each time, good.
But when I add this:
random2 = new Random();
Console.WriteLine(random1.Next(1, 100));
Console.WriteLine(random1.Next(1, 100));
Console.WriteLine(random2.Next(1, 100));
Console.WriteLine(random2.Next(1, 100));
Random1 will generate the same numbers as random! So it will be ex. 5,54,5,54 and if i do it again 70,34,70,34. But it's random2 is a new object so why is it generating the same numbers as random1??
Another example:
If I have class like this
class RandomNumber
{
Random random = new Random();
public int getrandomnumber { get { return random.Next(1, 5); } }
}
After doing this
randomnumberobject = new RandomNumber();
randomnumberobject2 = new RandomNumber();
Console.WriteLine(randomnumberobject.getrandomnumber);
Console.WriteLine(randomnumberobject2.getrandomnumber);
They'll generate a random number, but both of them will generate the exact same random number. So first time i'd get this 5,5 second time this 3,3 and so on.
But if I change the class to this
class RandomNumber
{
Random random;
public int getrandomnumber { get { return random.Next(1, 5); } }
public RandomNumber(Random random) { this.random = random; }
}
And do this instead
random = new Random();
randomnumberobject = new RandomNumber(random);
randomnumberobject2 = new RandomNumber(random);
Console.WriteLine(randomnumberobject.getrandomnumber);
Console.WriteLine(randomnumberobject2.getrandomnumber);
Suddenly, they both generate different random numbers! So why does this happen? What's the reason? Keep in mind, I'm still kind of a beginner.
What you see is "by design" - i.e. it happens because of how the class is implemented... the algorithm it uses needs a "seed" (kind of a starting state) which in this case is based on the clock... as documented on MSDN:
The random number generation starts from a seed value. If the same
seed is used repeatedly, the same series of numbers is generated. One
way to produce different sequences is to make the seed value
time-dependent, thereby producing a different series with each new
instance of Random. By default, the parameterless constructor of the
Random class uses the system clock to generate its seed value, while
its parameterized constructor can take an Int32 value based on the
number of ticks in the current time. However, because the clock has
finite resolution, using the parameterless constructor to create
different Random objects in close succession creates random number
generators that produce identical sequences of random numbers. The
following example illustrates that two Random objects that are
instantiated in close succession generate an identical series of
random numbers.
This means basically that if two Random objects are created at nearly the same time using the parameterless constructor they will produce the same sequence of random numbers since they have been initialized with the same "starting state" based on the clock.
Random number generation works based on a seed value in most of the programming languages. This seed is usually taken from a current time value. So if you declare the two Random objects close to each other, most likely they will obtain the same seed from the CLR. That's why they will generate the same numbers.
When you use the same instance, the first two numbers will already come from the random sequence, so the next two won't be the same.
Use the explicit seed in such situations (the constructor of Random which is overloaded with an int value).
Because you are reseeding each time in the last example, if you don't reseed random object will pull from the same pool of random numbers each time.
var random1 = new Random(DateTime.Now.Millisecond);
Console.WriteLine(random1.Next(1, 100));
Console.WriteLine(random1.Next(1, 100));
Console.WriteLine(random1.Next(1, 100));
Console.WriteLine(random1.Next(1, 100));
var random2 = new Random(DateTime.Now.Millisecond);
Console.WriteLine(random2.Next(1, 100));
Console.WriteLine(random2.Next(1, 100));

XNA Randomly chosen Texture always picks same texture

I made this code to load about 8 different textures to a list of objects with a texture property.
I have a folder with textures named "1.png, 2.png, 3.png,.......,46.png" and I want the 8 different objects to be loaded with randomly chosen textures.
DockedFruitsList = new List<Fruit>(8);
for (int i = 0; i < 8; i++)
{
Fruit temp = new Fruit();
temp = new Fruit();
temp.Position = AvailablePositions[i];
int random=(new Random().Next(0, 4600) % 46);
temp.Texture = Content.Load<Texture2D>(#"Fruits/" + random);
DockedFruitsList.Add(temp);
}
The thing is, despite the random always generates a different number, the result of draw is always the same texture, it changes from a run to another run, but it's always the same for all the 8 textures
spriteBatch.Begin();
for (int i = 0; i < DockedFruitsList.Count; i++)
{
spriteBatch.Draw(DockedFruitsList[i].Texture, DockedFruitsList[i].Position, Color.White);
}
spriteBatch.End();
Try this out:
for (int i = 0; i < 100; i++)
Console.WriteLine(new Random().Next(0, 10));
Odds are you'll get an output like this:
5
5
5
.
.
.
This is because the seed of the Random class is initialized with a time-based value. If you initialize many instances of the Random class near the same point in time, then they will all end up with the same seed, and so the values they will produce will all be the same.
What you really want to do is to create one Random instance and use that for all your random values. The values generated will have no relation to each other:
var r = new Random();
for (int i = 0; i < 100; i++)
Console.WriteLine(r.Next(0, 10));
Output:
2
8
0
.
.
.
From the msdn:
The random number generation starts from a seed value.
If the same seed is used repeatedly, the same series of numbers is generated.
By default, the parameterless constructor of the Random class uses the system clock to generate its seed value
System clock it uses only changes its value every few milliseconds, so if you call new Random() very quickly it'll get seeded with the same number, thus the calls to Next... will yield identical results.
Note that if you debugged it, stepping through the code gave the system clock time to advance, thus you won't get the error unless it runs through the loop without you breaking / stepping through.
Create the Random object once, and reuse it (note i'm now converting random to string and i've called a different method on random too):
var rand = new Random();
DockedFruitsList = new List<Fruit>(8);
for (int i = 0; i < 8; i++)
{
Fruit temp = new Fruit();
temp = new Fruit();
temp.Position = AvailablePositions[i];
int random=(rand.Next(46) + 1);
temp.Texture = Content.Load<Texture2D>(#"Fruits/" + random.ToString());
DockedFruitsList.Add(temp);
}
new Random().Next(0, 4600)
means you initialize the rng every time (maybe with the same seed?)
Move the new outside the method (static member or similar).
Random is seeded by the time(GetTickCount()), the time changes only every few milliseconds. So all instances of random created within that interval will return the same sequence. The correct thing is only creating a single instance of Random outside the loop.
DockedFruitsList = new List<Fruit>(8);
Random rand = new Random();
for (int i = 0; i < 8; i++)
{
Fruit temp = new Fruit();
temp = new Fruit();
temp.Position = AvailablePositions[i];
int random=(rand.Next(1, 46));
temp.Texture = Content.Load<Texture2D>(#"Fruits/" + random);
DockedFruitsList.Add(temp);
}
Check Revisiting randomness for more details.
There is also no reason to use rand.Next(0, 4600)%46. You can use rand.Next(0,46) directly.
Note that this code will still return duplicate entries. If you want to avoid that entirely you can use:
Random rand=new Random();
foreach(int randomFruid in Range(1,46).Shuffle(rand).Take(8))
{
...
}
With Shuffle from Is using Random and OrderBy a good shuffle algorithm?

Random number generator always picks the same value when run inside a loop

The problem with the code is, when I try to generate a number, if the spin is equal 1 it generates values inside range (1,2,3) if if try to use the loop to sum random values inside the same range the random number gerated is always the same while in loop,
example, if I run the loop with:
spind3 = 4 the values go from 4, 8, 12
spind3 = 5 the values go from 5, 10, 15
That means the first time the RandomNumber generates a value inside loop, it never change until the loop completes.
if (toggled3.Checked)
{
if (spind3.Value != 1)
{
for (int i = 1; i <= spind3.Value; i++)
{
diceCalc[1] += RandomNumber(1, 4);
}
}
else
diceCalc[1] = RandomNumber(1, 4);
}
You are probably creating a new Random object inside RandomNumber method. The default constructor for Random uses the system time as a seed. If you create multiple Random objects in a tight loop the time probably won't have changed between each call so they will all be initialized with the same seed.
To fix your code you should only create one Random object and reuse it.
From the documentation:
The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers. This problem can be avoided by using a single Random object to generate all random numbers. You can also work around it by modifying the seed value returned by the system clock and then explicitly providing this new seed value to the Random(Int32) constructor. For more information, see the Random(Int32) constructor.
The problem is that you are creating random generators too close in time. The random generator constructor uses the current time to seed the generator, and when you create them too close in time they will all be seeded using the same time.
Create one random generator and use in the loop:
Random rnd = new Random();
for (int i = 1; i <= spind3.Value; i++) {
diceCalc[1] += rnd.Next(1, 4);
}
You need to initialize your Random object, then call Next() inside your loop.
i.e.
if (toggled3.Checked)
{
// initialize your total and the random number generator
int diceTotal = 0;
Random rand = new Random();
for (int i = 0; i < spind3.Value; i++)
{
// add the next random number between 1 and 3
diceTotal += rand.Next(1, 4);
}
}
You can use Random(seed) constructor.
Random rand = new Random(Guid.NewGuid().GetHashCode());
One trick is to manually create the seed by adding DateTime.Now.Ticks to the variable i:
Random r = new Random((int)DateTime.Now.Ticks + i);

Categories