Dot Net
Random for .NET - Games and More
Random for .NET - Games and More
I started writing a brain games software which will be used for brain training and allow the user to take courses that will enhance and sharpen different abilities such as memory and attention. While writing Brain Games and testing my games I came across a disturbing phenomena: The .NET random (System.Random) is not really random. When I randomly set items similar ones appear next to each other and games look bad.
After searching the internet I came across the suggestion to use the RNGCryptoServiceProvider in order to generate random bytes. The examples found on StackOverFlow and other places seem to be good for a single bye only so I decided to publish the changes I made.
The code includes a RandomX class that uses the above crypto service provider. This code is much slower than the System.Random but it has much better results:
public class RandomX
{
static RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
public RandomX()
{
}
public int Next(int pMin, int pMax)
{
int normTo = pMax - pMin;
// Create a byte array to hold the random value.
byte[] randomNumber = new byte[4];
// Create a new instance of the RNGCryptoServiceProvider.
// Fill the array with a random value.
Gen.GetBytes(randomNumber);
// Convert the byte to an integer value to make the modulus operation easier.
int rand = (int)BitConverter.ToUInt32(randomNumber, 0);
// Return the random number mod the number
// of sides. The possible values are zero-
// based, so we add one.
return (Math.Abs(rand % normTo) + pMin);
}
}
As you can see the this class passed the tester that I wrote and the screenshot can be seen below:

I also added a tester class for this code:
class Program
{
static void Main(string[] args)
{
TestRandom6();
TestRandomMinNot0();
TestRandomLarge();
}
/// <summary>
/// Test with standard 6 value dice
/// </summary>
static void TestRandom6()
{
Console.WriteLine("Rolling standard dice:");
RandomX rnd = new RandomX();
int maxI = 6;
int maxLooop = 10000;
int[] histogram = new int[maxI];
int current;
for (int i = 0; i < maxLooop; i++)
{
current = rnd.Next(0, maxI);
histogram[current]++;
}
for (int i = 0; i < histogram.Length; i++)
{
Console.WriteLine("{0} = {1} - {2}%", i, histogram[i],
Math.Round((histogram[i] / (double)maxLooop) * 100, 2));
}
Console.WriteLine();
Console.ReadLine();
}
/// <summary>
/// A test where the minimum is not 0
/// </summary>
static void TestRandomMinNot0()
{
Console.WriteLine("Rolling a dice without 1 2 and 3:");
RandomX rnd = new RandomX();
int maxI = 6;
int maxLooop = 10000;
int[] histogram = new int[maxI];
int current;
for (int i = 0; i < maxLooop; i++)
{
current = rnd.Next(maxI/2, maxI);
histogram[current]++;
}
for (int i = 0; i < histogram.Length; i++)
{
Console.WriteLine("{0} = {1} - {2}", i, histogram[i],
Math.Round(histogram[i] / (double)maxLooop, 2));
}
Console.WriteLine();
Console.ReadLine();
}
/// <summary>
/// Test with standard 500 value array
/// </summary>
static void TestRandomLarge()
{
Console.WriteLine("Rolling 10000000 times a 99000 sided dice (takes a while):");
Console.WriteLine("This will print only the items that have values (histogram > 0)");
RandomX rnd = new RandomX();
int maxI = 99000;
int maxLooop = 10000000;
int[] histogram = new int[maxI];
int current;
for (int i = 0; i < maxLooop; i++)
{
current = rnd.Next(0, maxI);
histogram[current]++;
}
for (int i = 0; i < histogram.Length; i++)
{
if (histogram[i] > 0)
{
Console.WriteLine("{0} = {1} - {2}%", i, histogram[i],
Math.Round((histogram[i] / (double)maxLooop) * 100, 2));
}
}
Console.WriteLine();
Console.ReadLine();
}
}