Why does shuffling two different decks yield the same result? [duplicate] - c#

This question already has answers here:
Random String Generator Returning Same String [duplicate]
(30 answers)
Closed 8 years ago.
First off I have my "Deck" class here. I've just put in the some basic methods, for testing purposes. It's my first go at creating a "card" program.
public class Deck
{
private int deckCounter = 0;
private List<Card> deckSize = new List<Card>();
private List<Card> shuffledDeck = new List<Card>();
private Random random = new Random();
public Deck()
{
}
public void Build()
{
for (int i = 1; i < 5; i++)
{
for (int k = 1; k < 14; k++)
{
deckSize.Add(new Card(k.ToString(), i));
}
}
}
public void Add(Card card)
{
deckSize.Add(card);
deckCounter++;
}
public Card RemoveCard()
{
Card cardToRemove = deckSize.First();
deckSize.RemoveAt(0);
return cardToRemove;
}
public void ShowContainedCards()
{
int cardCount = 0;
foreach (Card c in deckSize)
{
Console.WriteLine(c.ReturnCardInfo());
cardCount++;
}
Console.WriteLine(cardCount);
}
public void Shuffle()
{
while (deckSize.Count != 0)
{
int i = random.Next(deckSize.Count);
shuffledDeck.Add(deckSize[i]);
deckSize.RemoveAt(i);
}
deckSize = shuffledDeck;
}
public bool IsEmpty()
{
if (deckSize.Any())
{
return false;
}
else return true;
}
public List<Card> GetCardList()
{
return deckSize;
}
}
Basicly, what I do is, this:
Deck deck1 = new Deck();
Deck deck2 = new Deck();
deck1.Build();
deck1.Shuffle();
deck2.Build();
deck2.Shuffle();
After that, I get the exact same shuffle, for deck1 and deck2. Why is that? Also, I'm a newb at this, if you couldn't tell :)

Use the same Random class instance in both deck instances:
Random random = new Random();
Deck deck1 = new Deck(random);
Deck deck2 = new Deck(random);
So, in the constructor:
public class Deck
{
private int deckCounter = 0;
private List<Card> deckSize = new List<Card>();
private List<Card> shuffledDeck = new List<Card>();
private Random random;
public Deck(Random random)
{
this.random = random;
}
The current problem with your code, is that the two instances of Random that are created are seeded the same. This causes them to produce the same results. Using the same instance of Random means the second shuffle will build on top of the seeded results of the first shuffle.

From the docs:
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.
The same docs also suggest a solution:
This problem can be avoided by using a single Random object to generate all random numbers.
Hence, one possible solution would be to make your random generator static, so all of your Deck instances share the same Random instance:
private static Random random = new Random();
That way, you would even avoid changing any part of the public interface of your Deck class.

Computers are inherently not random, so any random number generator will actually be using an algorithm to produce output that looks random. The thing with this is that there's always a starting point, and if you know where it' starting from, you can predict the outcome. Random number generators therefore have a "seed" which tells it where to start. The same seed will always give the same sequence of "random" numbers.
Both times, you're using new Random(), which uses the default seed. In some languages, you'd be advised to pass the current time as a seed, but C# does that for you. However, if you create two Random objects close together, they're likely to get the same time, which is what's happening here.
If you made your Random static, then all your random numbers would come from the same source, so the two decks would get successive random numbers, not the same ones in parallel.

Related

Two different random number generators giving the same answer?

static void Main(string[] args)
{
//random number gen
Console.WriteLine("Array Random Number:");
randomGenA();
Console.WriteLine("------------------");
//LIST: random movie picker...
Console.WriteLine("List Random Number:");
randomGenB();
Console.WriteLine("------------------");
Console.ReadLine();
}
static void randomGenA()
{
Random randomA = new Random();
int randomNumA = randomA.Next(51);
Console.WriteLine(randomNumA);
}
static void randomGenB()
{
Random randomB = new Random();
int randomNumB = randomB.Next(0,51);
Console.WriteLine(randomNum);
}
}
I wanted them both to produce two different random numbers but instead I keep getting the same random number from both of them. Why does it do this?
Declare a class level random and use it in your methods:
private static Random _random = new Random();
Your methods would look like:
static void randomGenA()
{
int randomNumA = _random.Next(51);
Console.WriteLine(randomNumA);
}
static void randomGenB()
{
int randomNumB = _random.Next(0,51);
Console.WriteLine(randomNum);
}
Check this out for further reading: http://www.dotnetperls.com/random
As per the documentation:
https://msdn.microsoft.com/en-us/library/system.random%28v=vs.110%29.aspx
Two Randoms with the same seed will provide the same sequence of numbers. Simply don't use the same seed. If you don't specify a seed, it uses the system time. Wait some time between the two instantiations and it will use two different system times.

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());

C# Random Image from Directory [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
Consider this method:
private static int GenerateRandomNumber(int seed, int max)
{
return new Random(seed).Next(max);
}
On my machine, executing this loop yields the same number through 1500 iterations:
for (int i = 0; i < 1501; i++)
{
int random = GenerateRandomNumber(100000000, 999999999);
Console.WriteLine(random.ToString());
Console.ReadKey();
}
I get 145156561, for every single iteration.
I don't have a pressing issue, I was just curious about this behavior because .Next(max) says "Returns a Non Negative random number less than the specified maximum. Perhaps I am not understanding something basic.
You're always seeding a new instance with the same seed, and then grabbing the first max. By using a Seed, you're guaranteeing the same results.
If you want to have a static, random number generation that does different results, you should rework this a bit. However, since Random is not threadsafe, it requires some synchronization when used statically. Something like:
private static Random random;
private static object syncObj = new object();
private static void InitRandomNumber(int seed)
{
random = new Random(seed);
}
private static int GenerateRandomNumber(int max)
{
lock(syncObj)
{
if (random == null)
random = new Random(); // Or exception...
return random.Next(max);
}
}
Dilbert has encountered the same problem back in 2001:
http://dilbert.com/strips/comic/2001-10-25/
Coincidence?
I don't think so.
And random.org agrees : http://www.random.org/analysis/
The problem is that you are creating a new Random instance with the same seed number each time. You should create a single Random instance (store it in a static if necessary) and simply call the next method on that same instance.
Random number generation is not truly random, see this Wikipedia entry for more details.
Salam to All,
Well it drove me crazy as well. The answer is simple. Change the seed before you generate random.
Example:
I want to generate random number between 1 to 10
Random rnd = new Random(DateTime.Now.Second);
int random_number = rnd.Next(10);
Put it inside a loop and run it three times. It will give out random numbers below 10.
Pseudo-random number generator usually work by choosing a seed, and then generating a deterministic sequence based on that seed. Choosing the same seed every time, you generate the same sequence.
There are "only" 2^32 different random sequences in .NET.
Not sure how the internals work.. check wiki for it, but it's very simple.
public class MathCalculations
{
private Random rnd = new Random();
public Int32 getRandom(Int32 iMin, Int32 iMax)
{
return rnd.Next(iMin, iMax);
}
}
public class Main
{
MathCalculations mathCalculations = new MathCalculations();
for (int i = 0; i < 6; i++)
{
getRandom(0,1000);
}
}
will generate Number1, Number2, Number3, Number4, Number5, Number6 (1 seed, 1 sequence of many numbers, random*not really, but approx.*)
if you however do this:
public class MathCalculations
{
public Int32 getRandom(Int32 iMin, Int32 iMax)
{
Random rnd = new Random();
return rnd.Next(iMin, iMax);
}
}
public class Main
{
MathCalculations mathCalculations = new MathCalculations();
for (int i = 0; i < 6; i++)
{
getRandom(0,1000);
}
}
You will now get Number1, Number1, Number1, Number1, Number1, Number1 (1 seed, 6 equal sequences of many numbers, always pick the same starting number from each equal sequence).. At some point Number1 will be different, because the seed changes over time.. but you need to wait some time for this, nonetheless, you never pick number2 from the sequence.
The reason is, each time you generate a new sequence with the same seed, hence the sequence is the same over and over again, and each time your random generated will pick the first number in it's sequence, which, with the same seed, is of course always the same.
Not sure if this is technically correct by the underlying methods of the random generator, but that's how it behaves.
In the event that anyone is looking for a "quick and dirty" "solution" (and I use that term with caution) then this will suffice for most.
int secondsSinceMidnight = Convert.ToInt32(DateTime.Now.Subtract(DateTime.Today).TotalSeconds);
Random rand = new Random(secondsSinceMidnight);
var usuallyRandomId = rand.Next();
Please note my use of usually random. I agree that the item marked as the answer is a more correct way of doing this.

Generate a random number if the number matched with the previous

I want to create a random number with a text in front of it, and I don't want the system displaying a number twice. So, this is that the way that I did it:
Random _rand = new Random();
private void RandomNumberGenerator()
{
int random = _rand.Next(10000);
string text = "TP0" + random;
if (random.Equals(random))
{
_rand.Next();
}
else
{
random = _rand.Next(10000);
}
MessageBox.Show(text);
}
I am not getting any displayed number twice (but I am not too sure, because I just close the program until it displayed the number 5 times (all of it are not the same number).
Is it possible from the above code to displaying a number twice with any chance?
Thank you.
EDITED to get rid of magic numbers and ensure sanity.
Random _rand = new Random();
HashSet<int> _taken = new HashSet<int>();
object _syncRoot = new object();
private int RandomNumberGenerator() {
lock (_syncRoot) {
const int MAX_NUMBER = 10000;
if (_taken.Count == MAX_NUMBER) {
throw new Exception("All possible numbers are already generated.");
}
int random = _rand.Next(MAX_NUMBER);
while (_taken.Contains(random)) {
random = (random + 1) % MAX_NUMBER;
}
_taken.Add(random);
return random;
}
}
Soner Gonul is correct, random.Equals(random) is always going to be true I think.
You could work around it (roughly) by having another int variable which will become whatever the last number generated was, then when the function goes into it's next cycle have it reference the new random number variable against the one stored in your second variable, which is the previous random number. That's one way of doing it, I can try define that a little clearer in a minute if you don't understand

Very weird - code (with Random) works different when I use breakpoint

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());
}
}

Categories