Skip to content

Be Careful with Random Numbers in .NET

[private void ColorWindowButton_Click(object sender, RoutedEventArgs e)
{
// todo fix this, crashes if window previously closed
_colorView.Show();
}[

I’m working on a little game for some friends that involves rolling five dice on a board and came across an interesting little problem, which I’ll illustrate with a very small dummy program. Here we have a simple die class for creating individual die objects:

using System;

namespace DiceRoller
{
    class Die
    {
        public int Face { get; private set; }

        private const int maxRoll = 6;
        private Random ran = new Random();

        // Constructor
        public Die()
        {
            Roll();
        }

        // Roll the die
        public int Roll()
        {
            Face = ran.Next(maxRoll) + 1;
            return Face;
        }
    }
}

And a small console program that will instantiate 5 dice and roll all five of them, 5 times.

using System;

namespace DiceRoller
{
    class Program
    {
        static void Main(string[] args)
        {
            Die[] dice = { new Die(),
                           new Die(),
                           new Die(),
                           new Die(),
                           new Die()
                         };

            for (int j = 0; j < 5; j++)
            {
                for (int i = 0; i < dice.Length; i++)
                {
                    Console.Write(dice[i].Roll());
                }
                Console.WriteLine("\n");
            }

            Console.ReadLine();
        }
    }
}

And here is the output.
Output

Whoa! Not very random. The default .NET random number generator appears to be using the system time to generate the random numbers. Because our calls to ran.Next() are so close together, we’re getting mostly the same result. There are a couple of ways to fix this. One option is to tell the thread to stop executing for some time before the roll, by using Thread.Sleep(10) at the start of the Roll() method. This works, but it’s ugly.

A better solution is to make the Random object in the Die class a static member. This way, every die will share the same Random, and so each time ran.Next() is called it iterates the random number on the same object. This solution is perfect. You only need to change one line in the Die class:

private static Random ran = new Random();

And the result:
Output

Perfect! In this case it was easy to see the problem and very simple to fix, but the moral of the story is, be careful with the RNG if you’re using it for anything non-trivial, especially when you’re generating multiple numbers from different instances of Random.


Post a Comment

Your email is never published nor shared.