Feb 142012
 

I recently added some code to the Neil Rajah to set up levels that are biased towards combat (flatter regions, which would let the generator place more enemies, more health pickups), and others biased towards platforming (more ups and downs, more diamond pickups). The code was pretty simple, or so I thought:

public Element generateLevel(int level) {
rand.setSeed(level);

...

// After level 10, levels are either biased towards platforming or combat
if (level >= 10) {
float f = rand.nextFloat();
if (f ChanceUp = 0.05;
ChanceDown = 0.05;
ChanceHealth = 0.3;
} else if (f ChanceCoin += .2;
MaxTrapLength = 8;
}
}

Pretty straightforward. I seed the random number generator with the level number, so it always generates the same level every time. Then the second block of code picks a combat level (lower chance of height changes, higher chance of health), a platforming level, or a normal level, with about 30% probability each.

Well, this didn’t work. Some trace statements showed that rand.nextFloat() almost always generates something very close to 0.73, so all my levels were ending up as ‘normal’. This was a surprise to me. I had assumed that changing the seed would completely change the pattern of numbers generated, but it turns out that that’s not the case. So I wrote a little test program to see how this worked:

private void testRand() {
for (int i = 0; i < 10; i++) {
Random rand = new Random();
rand.setSeed(i);
String str = "seed " + i + ": ";
for (int j = 0; j < 50; j++) {
str += Double.toString(rand.nextDouble()) + ",";
}
Gdx.app.log("", str);
}
}

And here’s the output, graphed in Excel:

It looks pretty random, except for the first generated number, which is almost identical across all the seed values. Maybe others knew this about random number generators, but it surprised me. Notice how the numbers converge at the 10th sample as well.

The solution turned out to be fairly simple. Since Random.setSeed() takes a long, I just multiplied the seed by 1 billion. That produced this output:

That’s more ‘random looking’, if you ask me. So I’ve put this back into my level generator – the seed is now the level number, multiplied by a billion. It feels like the game now has more variety in the levels, but my judgment on that is probably biased, since I know what I just changed.

So if you’re using random numbers like I am, where you’re seeding it with a fixed value to generate ‘reproducible random data’, you might want to keep this in mind. if your seed values are close to each other, the first generated number will be almost identical across all your runs. It doesn’t seem to matter what the seed value is – if they’re close together, the first generated number from nextFloat() or nextDouble() will almost always be 0.73xxx. Kinda weird, if you ask me. If someone has an explanation for why it does this, I would love to hear it.

  2 Responses to “Noticed something interesting about the Java random number generator”

  1. I seed my random number generator with System.nanoTime(). This is a widely used trick and you should try this as well.

    • That would work for something while the game is running. This was for a level generator, so I needed repeatable results.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>