[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Random numbers for different dice

Posted on 2010-01-01
21
Medium Priority
?
569 Views
Last Modified: 2013-12-17
The code below create and roll 3 dices and write their values to a console output. I get random number (between 1 and 6) each time the program is run however for some reason that number is the same for dice1,dice2 and dice 3
using System;

class Die
{
    protected int rollValue;
    public int RollValue
    {
        get
        {
            return rollValue;
        }
    }

    public void Roll()
    {
        rollValue = new Random().Next(1, 6);
    }
}

class Program
{
    static void Main()
    {
        Die dice1 = new Die();
        dice1.Roll();
        Console.WriteLine(dice1.RollValue);

        Die dice2 = new Die();
        dice2.Roll();
        Console.WriteLine(dice2.RollValue);

        Die dice3 = new Die();
        dice3.Roll();
        Console.WriteLine(dice3.RollValue);
    }
}

Open in new window

0
Comment
Question by:a_anis3000
  • 10
  • 6
  • 3
  • +1
21 Comments
 
LVL 30

Expert Comment

by:Reza Rad
ID: 26158081
problem is in fast process rate
try this:

Die dice1 = new Die();
            dice1.Roll();
            Console.WriteLine(dice1.RollValue);
            System.Threading.Thread.Sleep(1000);
            dice1.Dispose();
            
            Die dice2 = new Die();
            dice2.Roll();
            Console.WriteLine(dice2.RollValue);
            System.Threading.Thread.Sleep(1000);

            Die dice3 = new Die();
            dice3.Roll();
            Console.WriteLine(dice3.RollValue);
            System.Threading.Thread.Sleep(1000);

Open in new window

0
 
LVL 30

Expert Comment

by:Reza Rad
ID: 26158085
sorry , try this code
previous has a dispose which is not correct here

Die dice1 = new Die();
            dice1.Roll();
            Console.WriteLine(dice1.RollValue);
            System.Threading.Thread.Sleep(1000);
            dice1.Dispose();
            
            Die dice2 = new Die();
            dice2.Roll();
            Console.WriteLine(dice2.RollValue);
            System.Threading.Thread.Sleep(1000);

            Die dice3 = new Die();
            dice3.Roll();
            Console.WriteLine(dice3.RollValue);
            System.Threading.Thread.Sleep(1000);

Open in new window

0
 
LVL 30

Assisted Solution

by:Reza Rad
Reza Rad earned 980 total points
ID: 26158087
this is without dispose()

Die dice1 = new Die();
            dice1.Roll();
            Console.WriteLine(dice1.RollValue);
            System.Threading.Thread.Sleep(1000);
            
            Die dice2 = new Die();
            dice2.Roll();
            Console.WriteLine(dice2.RollValue);
            System.Threading.Thread.Sleep(1000);

            Die dice3 = new Die();
            dice3.Roll();
            Console.WriteLine(dice3.RollValue);
            System.Threading.Thread.Sleep(1000);

Open in new window

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 30

Assisted Solution

by:Reza Rad
Reza Rad earned 980 total points
ID: 26158097
you can use this code too:

static void Main(string[] args)
        {
            Random rnd = new Random();
            Console.WriteLine(rnd.Next(1, 6));
            
            Console.WriteLine(rnd.Next(1, 6));
            
            Console.WriteLine(rnd.Next(1, 6));
            
            
        }

Open in new window

0
 

Author Comment

by:a_anis3000
ID: 26158115
>>System.Threading.Thread.Sleep(1000);<<
Interesting not only each dice got its a different number now, but also this line of code slowed the speed at witch the output is printed to the console.

Thanks it works now, I am curious to know how this line of code works.

0
 
LVL 8

Accepted Solution

by:
Jon500 earned 520 total points
ID: 26158126
Sorry, my solution is perhaps more direct.

Just create a Random object first, then use .Next when you need it.

For example, add my code below existing rollValue declaration:

protected int rollValue;
private Random random = new Random(555);

Then, use this as your Roll function:

    public void Roll()
    {
        rollValue = random.Next(1, 6);
    }

The reason your code failed is that you were re-seeding the Random() function with each request.

Regards,
Jon500
0
 
LVL 30

Expert Comment

by:Reza Rad
ID: 26158141
that line will wait 1000 miliseconds
but try my last code , that is better and faster
0
 
LVL 30

Expert Comment

by:Reza Rad
ID: 26158166
I mean this code:

static void Main(string[] args)
        {
            Random rnd = new Random();
            Console.WriteLine(rnd.Next(1, 6));
            
            Console.WriteLine(rnd.Next(1, 6));
            
            Console.WriteLine(rnd.Next(1, 6));
            
            
        }

Open in new window

0
 
LVL 8

Expert Comment

by:Jon500
ID: 26158174
@raza: Please enlighten me as to why this would be a timing issue. I ran without Sleep() with no problems. This is a single-threaded app, no?
0
 
LVL 30

Expert Comment

by:Reza Rad
ID: 26158201
@Jon500:
try this code:

            Console.WriteLine(new Random().Next(1, 6));
           
            Console.WriteLine(new Random().Next(1, 6));
           
            Console.WriteLine(new Random().Next(1, 6));

result is same:
like :
4
4
4
or
1
1
1

but with this:


            Random rnd = new Random();
            Console.WriteLine(rnd.Next(1, 6));
           
            Console.WriteLine(rnd.Next(1, 6));
           
            Console.WriteLine(rnd.Next(1, 6));
           
results are not same

reason is in first code , new instances of Random created each time (in fact 3 times) and because of fast response. all of them points to on memory space, then the results are same.
but in second only one instance created and Next function called 3 times. no conflict will happen in this manner.
the second is good practice with Random class.

0
 
LVL 8

Expert Comment

by:Jon500
ID: 26158214
Thank you but I did understand that. I now see that you had proposed two solutions. It was your first (the one that used "Sleep") that I was wondering about... But I see that you decided not to use Sleep() in your second solution.

Regards,
Jon500
0
 
LVL 30

Expert Comment

by:Reza Rad
ID: 26158235
Yes, you right
I first suggest using Sleep, and you know that sleep is not good programming method.
so I used another method in second suggestion.


Regards,

0
 
LVL 8

Expert Comment

by:Jon500
ID: 26158242
Thanks Raza. You deserve all the points. Our messages crossed and I only got involved after seeing that you might be "asleep [Sleep()] at the wheel". :)

Happy new year,
Jon500
0
 
LVL 30

Expert Comment

by:Reza Rad
ID: 26158316
Glad to help Jon
Regards,
Happy new year to you
0
 
LVL 86

Assisted Solution

by:Mike Tomlinson
Mike Tomlinson earned 500 total points
ID: 26158372
The reason it fails is that when you create an instance of the Random() class it uses the current time as the seed.  If you create multiple instances in rapid succession then the same seed may be used.

See: http://msdn.microsoft.com/en-us/library/system.random.aspx

    "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."

    "This problem can be avoided by creating a single Random object rather than multiple ones."

    "To improve performance, create one Random object to generate many random numbers over time, instead of repeatedly creating a new Random objects to generate one random number."

So your answers of creating ONE instance of Random and moving it up to Class level scope are correct.  =)
0
 
LVL 8

Expert Comment

by:Jon500
ID: 26158409
Thanks Idle_Mind! Great knowledge to have and share.

Regards,
Jon500
0
 
LVL 30

Expert Comment

by:Reza Rad
ID: 26158837
Great @Idle_mind, thanks too
0
 

Author Comment

by:a_anis3000
ID: 26159039
Thanks for the feedback guys, I read the msdn article for the Random Class and now I got some idea why the randomization of my code didn't quite go as expected. Just one more thing, I don't quite understand what is meant by the "seed value" in the Random class
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26159166
The Random class produces "pseudo random" numbers based on a formula.  That formula requires a seed value to know where to begin.  If you used the same seed value every time then you would get the same sequence of random numbers out of the generator.  Most of the time we want a different seed so you just create an instance of Random and it will use the current time as the seed.  If you ran the app at exactly the same time every day then you would get the same sequence of random values.  Since this is pretty unlikely, using the time as a seed is usually good enough.

If you needed to be able to reproduce the same set of random numbers over and over again (possibly for some kind of testing?) then you could pass the same seed value to the Random constructor.
0
 
LVL 8

Expert Comment

by:Jon500
ID: 26164018
Just remember what the other guys had said, too: When seeding, my example used 555 just as an example seed. But it's better to use Random() without specifying a seed because Random() will use the system time as its seed value, virtually assuring a random set of numbers every time you restart your application.

Cheers,
Jon500
0
 

Author Comment

by:a_anis3000
ID: 26380439
Another alternate solution I found and would like to share is to make the Random object in the Die class static. i.e

private static Random random = new Random();
public void roll()
    {
        rollValue = random.Next(1, 7);        
    }


see attached code below for demonstration.Now each dice roll generates a perfectly random number


using System;

class Die
{
    private bool rolled = false;
    private int rollValue;
    public int RollValue
    {
        get
        {
            if (rolled)
                return rollValue;
            else
            {
                this.roll();
                return rollValue;
            }
        }        
    }

    private static Random random = new Random();
    public void roll()
    {
        rollValue = random.Next(1, 7);
        rolled = true;
    }
}

class Program
{
    public static void Main()
    {
        Die Dice1 = new Die();
        Die Dice2 = new Die();
        Die Dice3 = new Die();

        Console.WriteLine("Dice1 value: " + Dice1.RollValue);
        
        Dice2.roll();
        Console.WriteLine("Dice2 value: " + Dice2.RollValue);

        Dice3.roll();
        Console.WriteLine("Dice3 value: " + Dice3.RollValue);

        Dice3.roll();
        Console.WriteLine("Dice3 value: " + Dice3.RollValue);
    }
}

Open in new window

0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
This article shows how to deploy dynamic backgrounds to computers depending on the aspect ratio of display
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to use and create new code templates in NetBeans IDE 8.0 for Windows.
Suggested Courses

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question