3

So I am trying to learn some C#, currently on a short course on An Introduction to Programming. I have a question in my text book which is giving me pretty much simular results to this post Same random numbers from instantiated class

I have tried to follow the solution but get the same results every time, the task is to Roll two dice and display their numbers using 2 instances of a class. But like the post above the "dice" role the same number. If I call the same instance of the class twice and out put the values to separate labels I get completely different values like i want. here is the class:

namespace CH10_Ex10._5
{
public class ThrowDice
{

    public ThrowDice()
    {

    }

    private Random newRandom = new Random(); 

    private int x;

    public void Throw()
    {

        x = newRandom.Next(1, 7);


    }

    public int value
    {
        get
        {
            return x;
        }
    }
}
}

and here is my main form:

namespace CH10_Ex10._5
{
public partial class Form1 : Form
{
    ThrowDice Die1;
    ThrowDice Die2;

    public Form1()
    {
        InitializeComponent();
        Die1 = new ThrowDice();
        Die2 = new ThrowDice();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Die1.Throw();
        dieOneLabel.Text = Convert.ToString(Die1.value);
        Die2.Throw();


        dieTwoLabel.Text = Convert.ToString(Die2.value);
    }
}
}

I have tried to find an answer with out opening a new post so i am sorry if this have been answered before. I am very green at this.

My understanding is that if i declare objects with new, then i am creating separate instances of the class and therefore when i call those objects they should run independently/separately, but use the same rules which are specified in my class. I have tried to debug and as i step through the code i see the 2 separate calls to the class and what it looks like is the call 1 generates a random number eg 6 and call 2 seems to generate 6 as well.

thanks in advance

Community
  • 1
  • 1
user3510945
  • 113
  • 1
  • 10

3 Answers3

3

The problem is that the random instance will be initialized with the current time since you're using the default constructor. Since that happens on two instances very quick they get the same seed here:

public Form1()
{
    InitializeComponent();
    Die1 = new ThrowDice();
    Die2 = new ThrowDice();
}

You could make it static:

private static Random newRandom = new Random(); 

Random constructor:

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.

However, Random is not thread safe. So you should have a look at this answer.

This is also really worth reading: C# in Depth: Random numbers which suggests to use ThreadLocal<T> which is new in .NET 4 instead of static with lock.

Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
1

You can fix this using same random instance in both instances.For example you can add a constructor like this:

private Random newRandom;
public ThrowDice(Random rnd)
{
    newRandom = rnd;
    x = newRandom.Next(1, 7);
}

Then:

Random rnd = new Random;
public Form1()
{
    InitializeComponent();

    Die1 = new ThrowDice(rnd);
    Die2 = new ThrowDice(rnd);
}
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
-1

What i usually use :

private Random newRandom = new Random(Guid.NewGuid().GetHashCode());
pmaltais
  • 1
  • 1
  • I am not sure what his question is, but I don't think this answers it. – Popo Apr 08 '14 at 14:00
  • His problem is that he's using the same seed since the instantiation is too close. If he adds Guid.NewGuid().GetHashCode() to his random declaration, he will get different seed each time. That way, his dice roll will be different ... well ... not always identical :P – pmaltais Apr 08 '14 at 14:43