C# For Loop being temperamental - c#

For some reason, the loop only prints 1-3 circles to the panel unless the MessageBox.Show is called. it should print the number of circles the user input into the textbox. I don't understand why that MessageBox being called matters, why the loop decides not to do more than a few circles if the Box is not called. it should do the full number of loops around asked.
private void button2_Click(object sender, EventArgs e)
{
if (NumberCirclesText.Text != "" && Convert.ToInt32(NumberCirclesText.Text) < 100)
for (int x = 0; x < Convert.ToInt32(NumberCirclesText.Text); x++)
{
int y = x + 1;
Random myrandom = new Random();
int xcoord;
int ycoord;
ycoord = myrandom.Next(DrawSpace.Width);
xcoord = myrandom.Next(DrawSpace.Height);
int r = myrandom.Next(255);
SolidBrush mybrush = new SolidBrush(Color.FromArgb(myrandom.Next(255), myrandom.Next(255), myrandom.Next(255)));
System.Drawing.Graphics graphics = DrawSpace.CreateGraphics();
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(ycoord, xcoord, 30, 30);
graphics.DrawEllipse(System.Drawing.Pens.Transparent, rectangle);
graphics.FillEllipse(mybrush, rectangle);
//MessageBox.Show("There are " + y + " circles on the panel.");
NoOfCircles.Text = y.ToString();
}
}

The message box is a red-herring: it's the fact the message box causes a non-trivial delay that things work. You're creating a new Random object each iteration, but each iteration is so fast, the objects will produce the same "random" sequence. With the same "random" inputs, the circles appear (mostly) overlapped.
The simple fix, then, is to just declare and create the Random object outside the loop.

TL;DR Version: just put the line Random myrandom = new Random(); before the loop.
To understand the cause of this you first need to understand how computers generate random numbers:
Since a computer is not a very random machine, it cannot generate true random numbers, it can only generate pseudo-random numbers - numbers that seem random. The way computers do this is when given a starting value (called a seed), they apply some first-grade maths to it, and get a pseudo-random number. When asked to generate another number, they simply apply the actions they did to the starting value to the previously generated number.
Now that you know how computers generate numbers that look like they are random, you may have one question - Where does the starting value come from?
Well, since when given the same starting value the computer will generate the same sequence of random numbers, we need some value that constantly changes. What changes any second? Time! Computers use the amount of milliseconds since epoch (usually January 1st, 1970) as their seed to generate random numbers.
In .NET (which includes C#), the way to tell the computer to use the time to generate a random sequence, is by creating a new Random object, Random myrandom = new Random();
To get the next number in the sequence, you call myrandom.Next();.
Since your code loops and creates a new Random object every iteration, and since every iteration is fast enough so the time does not change, each new Random object has the same seed, and so when you're asking it for a random number it gives you the first in its sequence. Because the seed of all the Random objects is the same, the first random number each one generates will be identical.
Now after you've understood the problem, the solution:
In order to get different random numbers each time you can do one of the following:
Either have each new Random object have a different seed, which means
at least a millisecond has to pass before the for loop repeats.
Or just use one Random object (its seed is the time when the for loop
starts) and every time you want a random number just ask the same
object for the next number in the sequence.
Since the first approach requires you to slow down your loop, which is stupid unless you don't have another option, choose the second solution, which is to declare the Random object outside the loop.

Related

Unity3d generate multiple random numbers

I am currently attempting to generate two random (whole) numbers at once for a game I am making. I am trying to randomly generate a start and end tile. When I do this though, my two randomly generated numbers are always the same. I understand this is probably just because they are being called calculated to close together, but I can't find any information that works on how to get two different random numbers. my code is quite simple (in c#):
float startTile = Mathf.Ceil(Random.Range(1.0f, 8.0f));
float endTile = Mathf.Ceil(Random.Range(1.0f, 8.0f));
Thank you in advance!
Edit
This was marked as a duplicate question, where the answer for the old question was:
Random rand = new Random();
int t = rand.next(x,x2);
Unless I'm doing something incorrect, I am unable to even use the rand.Next(x,x1) function within unity.
The actual code:
private void SpawnStartandEndTiles()
{
Random rand = new Random();
int t = rand.N //<Next is not an option
//Other misc. Code that uses the random numbers
}
Please let me know if I am just not getting something with how the Random function works.
Thanks so much.
First of all don't use System.Random because using most classes in System namespace (*) drastically increase the size of your game. Instead use UnityEngine.Random
Random numbers are always generated using a seed. Given a specific seed the sequence of random numbers are always the same. You can say computed random is never really random.
By setting the Random.seed to a value depending on the time makes Random.Range to generate numbers close to real random.
For example:
Random.seed = System.DateTime.Now.Millisecond;
//...
float startTile = Mathf.Ceil(Random.Range(1.0f, 8.0f));
float endTile = Mathf.Ceil(Random.Range(1.0f, 8.0f));
(*) These are in mscorlib.dll and therefore does not have any impact on the size of game
System.Collection.*
System.Collection.Generic.*
System.IO.*

What is the refresh rate of the random() method in C# [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
I am going to generate 100 random numbers in a for loop. The only problem is that since the random() method is timer-based, it will generate the same numbers 3-4 times in a row.
I can solve this problem by including a threat.sleep() method in my loop. Therefor i want to know the exact refresh rate of the random() method so that i can match the threat.sleep() method and not get delayed more than necessary.
Here is my code:
for (int i; i <= 100; i += 1)
{
Random rndNum = new Random();
Console.WriteLine(rndNum.Next(1, 100));
Thread.Sleep(X); //I want to know the best value of X (as less delay as possible)
}
Thanks a bunch
/HamMan4Ever
I've never heard or read that the Random class is timer-based. You may have heard that it is seeded by the system time, but after that each call to Next will return a randomish number typically different from the previous. Typically when you see non-random data coming from a Random, it's because you're creating a new random on each iteration through a loop, as you are in the code you shared. Since each is seeded from the system clock and you're creating several very quickly, you see repeated patterns. Create your Random outside the loop to make this problem go away.
It is equal to the refresh rate of the system clock as it uses the time as a seed. But for your job, you should keep the Random instance outside the loop.
Random rndNum = new Random();
for (int i; i <= 100; i += 1)
{
Console.WriteLine(rndNum.Next(1, 100));
}
Since it uses the time as a seed, it uses it only ones and will generate random numbers even if you call it multiple times at the same time as long as you use the same instance.

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.

Random numbers for dice game [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
random string generation - two generated one after another give same results
I am writing a simple dice game for windows phone 7, that involves rolling two dice at the same time. Here is my Dice Roll Code:
private int DiceRoll()
{
int result;
Random rnd = new Random();
result = rnd.Next(1, 7);
return result;
}
I then have this code that rolls the dice when a button is clicked:
private void roll_Click(object sender, RoutedEventArgs e)
{
roll1 = DiceRoll();
roll2 = DiceRoll();}
My problem is that both die get the same result.
Any idea how I can get a rolling algorithm that will usually return different results, but occasionally return the same?
The default seed for Random is based on the current time. To quote the documentation,
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.
That is exactly what you should do: create one instance of Random and use it to generate all your random numbers.
You need to keep one Random object around and reuse it; every time you create a new Random object, you effectively reset the sequence of numbers to begin in the same place. Store the Random object as a member variable someplace. You'll also want to seed it with a different value each time you run the program -- for example, a value based on the system clock time.
The clear majority of 'random number' tools I've seen fail badly if you allocate two or more random objects in a single application. You're allocating a new Random object for every invocation, and each time they are going to be seeded with something pretty weak, and maybe even identical seeds.
So, generate a single Random object and use it over the life of your application.

random string generation - two generated one after another give same results

I have a simple piece of code:
public string GenerateRandomString()
{
string randomString = string.Empty;
Random r = new Random();
for (int i = 0; i < length; i++)
randomString += chars[r.Next(chars.Length)];
return randomString;
}
If i call this function to generate two strings, one after another, they are identical... but if i debug through the two lines where the strings are generated - the results are different.
does anyone know why is it happening?
This is happening, because the calls happen very close to each other (during the same milli-second), then the Random constructor will seed the Random object with the same value (it uses date & time by default).
So, there are two solutions, actually.
1. Provide your own seed value, that would be unique each time you construct the Random object.
2. Always use the same Random object - only construct it once.
Personally, I would use the second approach. It can be done by making the Random object static, or making it a member of the class.
The above answers are correct. I would suggest the following changes to your code though:
1) I would suggest using a StringBuilder instead of appending to the string all the time. Strings are immutable, so this is creating a new string each time you add to it. If you have never used StringBuilder, look it up. It is very useful for this sort of work.
2) You can make your method easier to reuse if you pass the length into the method itself. You could probably pass the chars array in as well, but I've left that out.
3) Use the same random object each time, as suggested above.
public string GenerateRandomString(int length)
{
StringBuilder randomString = new StringBuilder(length);
for (int i = 0; i < length; i++)
randomString.Append(chars[(int)(_RandomObj.Next(chars.Length))].ToString());
return randomString.ToString();
}
It's because you're creating two random objects at the same time. This is giving it the same seed, so you're going to get the same numbers.
When you debug it, there's time between the creation of the random objects which allow them to get different seeds.
The default constructor for Random (the one you're using) seeds the generator with a value based on the current time. If the time in milliseconds doesn't change between the first and second call of the function, it would use the same random seed.
My suggestion is to use a static Random object and only initialize it once.
Since the Random generator is tied with the system clock you are probably displaying the same results with that time period. There are several ways to correct. If you are using loops place the Random rnd = new Random(); outside of the loop.
Place the Random rnd = new Random(); line where you declare your variables and use the same variable throughout your program (rnd for this example).
This will work in most cases.

Categories

Resources