Jump to content
  • Advertisement
Sign in to follow this  
Basse85

Random Numbers help

This topic is 2516 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello.
Im having some trouble with the random numbers in c#.
Im creating a basic random loot system that I will use in a text based dungeon crawler, but i need some help.

At the moment the system only supports three kinds of loot: weapon, armor and poitions. To determine what type of loot to create I generate a random number between 1-3 and use in a switchstatement to aply the loot.
I have created a Dice.cs class that handles all random numbers in form of different dice rolls (D12, D20...) and a LootProcessor.cs class that creates random loot.
I use a D3 to get the loot typ, but when I call it from the LootProcessor I never get the number "3".

Dice.cs
public static int RollD3()
{
Random D3 = new Random();
int d3Result = D3.Next(1, 4);
return d3Result;
}


LootProcessor.cs
static string LootType()
{
int lootNum;
lootNum = Dice.RollD3();
switch (lootNum)
{
case 1:
lootResult = weapon;
Output();
break;
case 2:
lootResult = armor;
Output();
break;
case 3:
lootResult = potion;
Output();
break;
default:
Output();
break;
}
return lootResult;
}


If I call the Dice.RollD3() from the program class I get values from 1-3 but when I call it from LootProcessor.cs it only generates from 1-2. I have done some testing and it never generated potions from loot class, only lots of weapons and armor.
Please help me understand this.

Thanks

Share this post


Link to post
Share on other sites
Advertisement
You generally shouldn't construct a new Random object every time you need a random number. You are supposed to have a Random object around where you call Next multiple times.

That being said, it's a bit weird that the first number out of a fresh Random object would never be a 3. If I were you, I would condense this to the simplest possible program that shows the problem (it should be like 20 lines of code) and post the complete program so others can try to reproduce the issue.

Share this post


Link to post
Share on other sites
The default .NET random number generator can occasionally cause these artifacts, especially for small numbers.

I've not seen the behavior where it would generate different results depending on callsite. Probably some trick caused by new Random() and the accuracy of your local clock.

Share this post


Link to post
Share on other sites

You generally shouldn't construct a new Random object every time you need a random number. You are supposed to have a Random object around where you call Next multiple times.


That helped.
Thank you alvaro

static Random D3 = new Random();
public static int RollD3()
{
int d3Result = D3.Next(1, 4);
return d3Result;
}

Share this post


Link to post
Share on other sites
[sup]Another quick suggestion.[/sup]

Randoms that small don't really seem to be that random. So what I would suggest is using a much larger number that is divisible by three. Then get a random with it as the max, then do a % on the number and add one. Should give you better randoms.

Share this post


Link to post
Share on other sites
I have been generating randoms in my game.

It seems to help to have one global static random object to use.

If you declare a new random it gets seeded, and in my case caused problems.

To really test out random number generation...

Open a console project and call the program.cs constructor to generate 30 randoms of 1,4 and console writeline (i) after every loop.

Run the console app without debugging, and you can see all of the random numbers which were generated.

Share this post


Link to post
Share on other sites

To really test out random number generation...

Open a console project and call the program.cs constructor to generate 30 randoms of 1,4 and console writeline (i) after every loop.

To really test out a random generator, you would want to be generating far more than 30 values. The first problem is that people are really bad at recognising random signals. People are biased towards interpreting repetition as non-random.

One key aspect of psuedo-random number generation is that all outputs should be reasonably likely, over a large number of invocations. That is, the generator should avoid bias in its output.

Here is a quick test program I threw together to demonstrate how you might test for such bias, using the default range function, and two simple implementations of such a function:



using System;

public class Test {

public static void Main(string [] args) {

if(args.Length != 2) {
Console.WriteLine("Usage: <number of digits> <number of iterations>");
return;
}

int n = int.Parse(args[0]);
int iterations = int.Parse(args[1]);

Random random = new Random();

int [] frequency;

Console.WriteLine("-------------------------------");
Console.WriteLine("Default random range generation");
Console.WriteLine("-------------------------------");

frequency = new int[n];
for(int i = 0 ; i < iterations ; ++i) {
int index = random.Next(0, n);
frequency[index]++;
}

for(int i = 0 ; i < n ; ++i) {
Console.WriteLine("Frequency of number " + i + ": " + (frequency * 100.0f / iterations) + "%");
}

Console.WriteLine("-------------------------------");
Console.WriteLine("Explicit use of low order bits");
Console.WriteLine("-------------------------------");

frequency = new int[n];
for(int i = 0 ; i < iterations ; ++i) {
int index = random.Next() % n;
frequency[index]++;
}

for(int i = 0 ; i < n ; ++i) {
Console.WriteLine("Frequency of number " + i + ": " + (frequency * 100.0f / iterations) + "%");
}

Console.WriteLine("-------------------------------");
Console.WriteLine("Casting next double to int");
Console.WriteLine("-------------------------------");

frequency = new int[n];
for(int i = 0 ; i < iterations ; ++i) {
int index = (int)(random.NextDouble() * n);
frequency[index]++;
}

for(int i = 0 ; i < n ; ++i) {
Console.WriteLine("Frequency of number " + i + ": " + (frequency * 100.0f / iterations) + "%");
}

}

}


Here is the output on my Linux machine (i.e. using mono, not Microsoft's implementation, YMMV):


user@host:~$ c# test.cs && ./test.exe 10 10000000
-------------------------------
Default random range generation
-------------------------------
Frequency of number 0: 9.99622%
Frequency of number 1: 9.99243%
Frequency of number 2: 10.00303%
Frequency of number 3: 10.02384%
Frequency of number 4: 9.98622%
Frequency of number 5: 9.9946%
Frequency of number 6: 10.00531%
Frequency of number 7: 10.00188%
Frequency of number 8: 10.00555%
Frequency of number 9: 9.99092%
-------------------------------
Explicit use of low order bits
-------------------------------
Frequency of number 0: 9.92869%
Frequency of number 1: 10.0747%
Frequency of number 2: 9.94714%
Frequency of number 3: 10.06481%
Frequency of number 4: 9.93947%
Frequency of number 5: 10.07618%
Frequency of number 6: 9.92547%
Frequency of number 7: 10.04247%
Frequency of number 8: 9.93499%
Frequency of number 9: 10.06608%
-------------------------------
Casting next double to int
-------------------------------
Frequency of number 0: 9.99552%
Frequency of number 1: 9.9953%
Frequency of number 2: 10.00841%
Frequency of number 3: 9.98883%
Frequency of number 4: 9.99405%
Frequency of number 5: 9.99853%
Frequency of number 6: 10.021%
Frequency of number 7: 10.01375%
Frequency of number 8: 9.99331%
Frequency of number 9: 9.9913%

Note that the middle block is far worse than the other two, it appears to be biased in favour of odd numbers. The middle block is, unfortunately, also the naive approach that many use when trying to generate random values in a given range.

Share this post


Link to post
Share on other sites
The problem with the non-randomness of low order bits doesn't exist in any decent PRNG, like say the Mersenne twister. It's unfortunate that a modern platform provides such a crappy pseudorandom number generator by default.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!