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?
Related
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.
I'm working on a neural networks project and I have 2 classes like this:
public class Net
{
// Net object is made of neurons
public List<Neuron> Neurons = new List<Neuron>();
// neurons are created in Net class constructor
public Net(int neuronCount, int neuronInputs)
{
for (int n = 0; n < neuronCount; n++)
{
Neurons.Add(new Neuron(n, neuronInputs));
}
}
}
public class Neuron
{
public int index; // neuron has index
public List<double> weights = new List<double>(); // and list of weights
// Neuron constructor is supposed to add random weights to new neuron
public Neuron(int neuronIndex, int neuronInputs)
{
Random rnd = new Random();
for (int i = 0; i < neuronInputs; i++)
{
this.index = neuronIndex;
this.weights.Add(rnd.NextDouble());
}
}
When I try to create network and display it's "contents":
Neuro.Net Network = new Neuro.Net(4, 4); // creating network with 4 neurons with 4 weights each
// dgv is a DataGridView for weights preview
dgv.Rows.Clear();
dgv.Columns.Clear();
// creating columns
foreach (Neuro.Neuron neuron in Network.Neurons)
{
dgv.Columns.Add("colN" + neuron.index, "N" + neuron.index);
}
dgv.Rows.Add(Network.Neurons[0].weights.Count());
for (int n = 0; n < Network.Neurons.Count(); n++)
{
for (int w = 0; w < Network.Neurons[n].weights.Count(); w++)
{
dgv.Rows[w].Cells[n].Value = Network.Neurons[n].weights[w];
}
}
When I run that code - I'm getting something like this (all weights are identical):
When I saw it - I tried to debug and find my mistake. However, when I put breakpoint in the neuron constructor - my network initializes as I want (weights are different):
I tried to use Debug and Release configurations - same results.
Can someone explain what is going on here?
Magic?
However, when I put breakpoint in neuron constructor - my network
initializes as I want (neurons are diffrent):
Presumably, the breakpoint introduces enough of a delay for Random() to be seeded with a different number. The delay can be caused by you pausing in the code (obviously) or even the non-matching evaluation of a conditional breakpoint (which slows execution slightly).
It would be better to have:
private static readonly Random _random = new Random();
And call _random.Next() without creating a new instance, such as:
public Neuron(int neuronIndex, int neuronInputs)
{
for (int i = 0; i < neuronInputs; i++)
{
this.index = neuronIndex;
this.weights.Add(_random.NextDouble());
}
}
The parameterless constructor of Random uses Environment.TickCount (hence the difference when a delay is introduced). You could also provide your own seed if you must create a new instance every time.
This behavior is documented here, specifically:
...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. [...] This problem can be avoided by creating a single
Random object rather than multiple ones.
Alternatively, you could use System.Security.Cryptography.RNGCryptoServiceProvider.
Random numbers are generated using current system time.
When you are debugging, you allow sometime between each generation. When you run, the code, it runs so fast that the seed is the same, thus, the generated randoms are equal.
Solution: declare a class member to contain the random instance and for every new random, call .Next() method.
private static rnd = new Random();
remove this line:
Random rnd = new Random();
and you are done
create a static instance of Random class.
since within constructor, Random is initialized each time, hence the possibility of similar numbers!
private static readonly Random rnd = new Random();
public Neuron(int neuronIndex, int neuronInputs)
{
private static readonly rnd = new Random();
for (int i = 0; i < neuronInputs; i++)
{
this.index = neuronIndex;
this.weights.Add(rnd.NextDouble());
}
}
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.
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);
My code is to generate random cordinates of lat and long within a bound:
Random lastLat = new Random();
Random lastLon = new Random();
for (int i = 0; i < 50; i++)
{
int lat = lastLat.Next(516400146, 630304598); //18.51640014679267 - 18.630304598192915
int lon = lastLon.Next(224464416, 341194152); //-72.34119415283203 - -72.2244644165039
SamplePostData d0 = new SamplePostData();
d0.Location = new Location(Convert.ToDouble("18." + lat), Convert.ToDouble("-72." + lon));
AddPushpin(d0);
}
My output looks like this:
http://img263.imageshack.us/img263/7504/capturerkv.png http://img263.imageshack.us/img263/7504/capturerkv.png
Is there something wrong with how my numbers are generated?
Jørn's answer gave the problem, but not the solution: just use a single instance of Random:
Random rng = new Random();
for (int i = 0; i < 50; i++)
{
int lat = rng.Next(516400146, 630304598);
int lon = rng.Next(224464416, 341194152);
SamplePostData d0 = new SamplePostData();
d0.Location = new Location(18d + lat / 1000000000d,
-72d - lon / 1000000000d);
AddPushpin(d0);
}
(I've changed the way of using the result, too - there's no need to convert to and from a string to achieve what you want. An alternative would be to call Random.NextDouble instead and multiply it by the size of the desired range, then add a base value.)
If you're calling routine multiple times, you should probably use a single instance of Random across those multiple calls. Beware though: Random in .NET is not thread-safe. Ideally you should have a single instance per thread. See my article on randomness for more details of how to handle Random.
You are initializing both of your Random instances without an explicit seed, causing them to return the same stream of pseudo-random numbers. What you are doing now, is equivalent of using DateTime.Now as the seed for both instances. As modern computers tend to execute code really fast, you end up with the same seed in both instances.
If you use a single Random instance for generating both lang and long you should see a much more "random" distribution.
You shouldn't use two different Random objects. Draw both latitude and longitude from the same Random.
Random random = new Random();
for (int i = 0; i < 50; i++)
{
int lat = random.Next(516400146, 630304598); //18.51640014679267 - 18.630304598192915
int lon = random.Next(224464416, 341194152); //-72.34119415283203 - -72.2244644165039
SamplePostData d0 = new SamplePostData();
d0.Location = new Location(Convert.ToDouble("18." + lat), Convert.ToDouble("-72." + lon));
AddPushpin(d0);
}
Your problem is you are creating two Random objects at the same time causing them to be seeded with almost the same Time seed.
Use just ONE object.