The Problem with Random

For many games, randomness or RNG (random number generation) lies at the core of many important mechanics. Whether it’s a fight defining critical hit landed by one of your Pokémon, or determining whether the next tetrimino to grace the player’s well will be the coveted long bar, there is no doubt that balancing randomness in a game can deliver excitement and an engaging experience when balanced with care.

But what if random is not actually random? How would that affect the developers ability to balance their own game and ensure they are providing the desired experience to the player?

Recently, while developing Dicee!, a strategy game for the GB and GBC, I stumbled upon an issue which greatly impacts a developer’s ability to balance any kind of in-game RNG when developing their own game using GB Studio. In this article I’ll be showing you what’s going on under the hood of a set variable to random event, share some examples of just how skewed a random range can become in certain situations and offer a solution to address this problem.

To start, I’ll explain some of the mechanics of Dicee! In a game of Dicee!, the player rolls five d6 dice, attempting to score preset combinations over thirteen turns. The player can roll each of the five dice up to three times, with the option to lock any dice as they attempt to score a “full house” for 25 points, or try for the high scoring Dicee! (5 of the same number), for example.

A screenshot of the GameBoy game Dicee! showing the results of 5 dice rolls.
The game of Dicee! Given it’s a dice game, accurate RNG is essential!

Each roll of the dice uses the set variable to random event with a range of 1 to 6 to determine a d6 number and with up to 195 rolls of a dice per game, it’s easy to see how integral RNG is to the experience.

But what if I told you the set variable to random event with a range of 1 to 6 does not give as evenly distributed outcome as you would expect? This was in fact the case when I first released Dicee!

Story time!

So my wife had been playing Dicee! a lot. Every now and then she came to me and said she was getting more 1s and 2s in her rolls relative to the other numbers on the d6 and that the game was busted. I kept telling her, “Nah. No, no, it’s random. It’s picking a number from 1 to 6 at random each time the dice is rolled… You must be introducing some kind of bias.” She rolled her eyes and kept playing but eventually she became quite convinced that the dice were not random and the odds were stacked against her. So she started recording the numbers she was getting per game. Here are her findings for one game:

1s = 43
2s = 34
3s = 17
4s = 15
5s = 13
6s = 13

Well, the data doesn’t lie and although it’s a small pool of 135 rolls, it suggested something was definitely happening here. If random isn’t random, then I have a big problem on my hands. Some further testing needed to be done to get to the bottom of this if I was to make Dicee! actually enjoyable for my wife.

So I made a program to roll 1000 dice and display the results. Below is a typical outcome. The probabilities in Dicee! were definitely broken!

An image showing that GB Studio's randomization is generating more results of 1 and 2 than other values on a simulated six-sided dice.
The ones and twos are twice as likely to be rolled compared to other numbers on the D6…

Furthermore, this is the case for many other ranges larger than two. For example, here is the outcome for 1000 d3 rolls:

An image showing that GB Studio's randomization is generating more results of 1 than other values on a simulated three-sided dice.
Now rolling a 1 on a d3 is twice as likely as rolling any other number…

All of a sudden I could no longer trust that RNG in any game of mine was actually random. Off to GBS Discord I go to figure out what is happening here.

After much back and forth and many heads smarter than my own proposing reasons why randomly selecting a number from 1 to 6 in GBS can’t give you an evenly distributed outcome, we finally figured out how to resolve this issue. To make a long story short, because Game Boy and because math and because computer, randomly selecting a number from 1 to 8 and rerolling if 7 or 8, ended up giving me what I was looking for; a more or less even distribution of numbers across 1000 d6 rolls!

An image showing that GB Studio is distributing randomized results more evenly when simulating an eight sided dice.
Success!

It should be noted that a range of 2 will always be truly random. This script applies to any number that is greater than two, but not a multiple of eight. For example, you could use a random range of 8, 16 or 24 and so on and you will find a truly random distribution. How high your random range will go will depend on what your intended range is. If you have designed a boss to pick one of five attack patterns at random, then you would set your random range from 1 to 8 and the while expression to:

While $variable$ > 5, re-randomize 1 to 8

If you had eleven attack patterns, then you would want to set your random range from 1 to 16, and the while expression to:

While $variable$ > 11, re-randomize 1 to 16

To summarize, this is what I have learned and I think it’s important to know if you want to introduce RNG into your own games:

If you want to ensure you are getting a truly random value when using the set to random operation that is greater than 2 in GBS, make sure you do the following:

  1. Set the random range to a multiple of 8
  2. Use a ‘while’ loop to re-randomize if your intended range is not multiple of 8 or else!

That is the main take away from this. Well, that and also, listen to your wife.

Thanks to Rulz, Gearfo, Proximity Sound, Toxa and bbbbbr for helping me resolve this issue in the GBS Discord server. If you want to check out Dicee! for yourself, you can find it here.

Liked it? Take a second to support GB Studio Central on Patreon!
Become a patron at Patreon!