Most of us have dealt with generating random numbers at some point in our app development. In this tutorial, we’ll look at the core syntax for generating random numbers. Later, we’ll walk through a “dice rolling” mechanism for more advanced use cases.

### Seeding the Generator

One of the most common mistakes in requesting random numbers is failing to **seed** the random number generator. Outside of some very high-tech, math-intensive, complex methods, most computers/devices generate **pseudo-random** numbers. As such, we must **seed** the random number generator with a value to start the generation. If we seed the generator with the same value, we’ll get the same pattern of random numbers. This can be useful in some cases, but in most cases we’ll want **different** numbers. To achieve this, we can add this line to our `main.lua`

file:

1 |
math.randomseed( os.time() ) |

Since os.time() returns a different value each time we run the app, this call will seed the random number generator with a fairly random starting value. Conveniently, we only need to do this once, typically near the top of our main code.

With that out of the way, let’s look at the math.random() function which has three “modes”:

`value = math.random()`

— returns a floating point number between 0 and 1.`value = math.random( maxVal )`

— returns an integer between 1 and`maxVal`

.`value = math.random( startVal, maxVal )`

— returns an integer between`startVal`

and`maxVal`

.

The first mode is the way most programming languages work, but since most people don’t really need floating point numbers between 0 and 1, we’ve traditionally needed to multiply this number by the maximum value. For instance, if we want a number between 1 and 10, the C code would look like this:

1 |
int number = int( rand() * 10 ) + 1 |

Fortunately, Lua provides a convenience method to help with this, in the form of the 2nd structure above. Simply pass in the maximum value to get a number between 1 and `maxVal`

.

1 |
local number = math.random( 10 ) |

In the instances where the range should **not** start at 1, Lua offers the 3rd structure. For instance, if we want to spawn an enemy in the middle third of the screen, this code would be useful to generate its **x** position:

1 |
local number = math.random( 100, 220 ) |

### Roll the Dice!

The above functions are useful, but what if we need something more complex? In many games, for instance **Dungeons & Dragons**™ and similar role-playing games, players need to roll **three** 6-sided dice to determine their character’s strength. In this example, character strength values range in the 3-18 range, but only a few players would roll for a strength of 3 or 18. Most characters would end up in the range of 10 to 11. Many board games like **Monopoly**™ use two 6-sided dice, so rolling a summed total of 2 or 12 is rare, while sums between 6 and 8 are more common. In statistics, this is referred to as a **bell curve**. However, the standard random number generator generates a flat line of numbers where each has an equal probability to be selected. As a result, dice rolling needs can get quite complex. Additionally, some games feature many varieties of dice in addition to the traditional 6-sided version — there are dice with 4 sides, 8 sides, 10, 12, 20, and even 30!

Sometimes we’ll also need to add or subtract “modifiers” to the results. These gaming systems use a fairly common “language” for specifying the dice and modifiers. For instance, consider:

`3d6`

— Generate a number by rolling three 6-sided dice, then add them up.`2d8+3`

— Generate a number by rolling two 8-sided dice, add them up, and then add 3 to the total.

Rolling physical dice may be fun, but how can this be accomplished in Corona SDK? First, we should establish the “language” of the dice. In this tutorial, we’ll use a variant of the Myth-Weavers system. In this system, we start with the **number of dice**, then we write the letter `d`

, followed by the **number of sides** to the dice. This is followed by an optional `+`

or `−`

and a number that gets added or subtracted. To make it a bit more functional, this system also supports the idea of keeping some dice results while discarding others. In the role-playing example, since most heroes need better stats than normal humans, their character stats are rolled using four 6-sided dice, but only the highest 3 dice results are kept and added together. This dice string would be represented as `4d6^3`

. Now let’s inspect the Lua code:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
local function rollDice( dicePattern ) -- Dice pattern 3d6+3k3 -- First number : number of dice -- d : required string -- Second number : sides to the dice -- +/- : optional modifier -- ^/k : optional string; '^' keeps the high values, 'k' keeps the low values -- Third number : number of dice to keep, i.e. 4d6^3 keeps the best three numbers local dice = {} local random = math.random local total = 0 -- Parse the string local count, sides, sign, modifier, keepHiLo, keep = string.match( dicePattern, "(%d+)[dD](%d+)([%+%-]*)(%d*)([%^k]*)(%d*)" ) modifier = tonumber(modifier) keep = tonumber(keep) if ( modifier == nil ) then modifier = 0 end if ( sign == "-" and modifier > 0 ) then modifier = modifier * -1 end for i = 1, count do dice[i] = random( sides ) end if ( keep ) then local function keepCompare( a, b ) return a > b end if ( keepHiLo == "k" ) then table.sort( dice ) else table.sort( dice, keepCompare ) end for i = 1, keep do total = total + dice[i] end else for i = 1, count do total = total + dice[i] end end total = total + modifier return total, dice end |

#### Deconstructing the Code

Let’s step through the code to see how it works:

1 2 3 4 |
local dice = {} local random = math.random local total = 0 |

Here, we create a table to hold the individual dice rolls. We also localize the `math.random()`

function for optimal performance and set the `total`

value to 0.

Next we need to parse the `dicePattern`

argument using string.match():

1 2 3 4 5 6 7 8 9 10 11 |
local count, sides, modifier, keepHiLo, keep = string.match( dicePattern, "(%d+)[dD](%d+)([%+%-]*)(%d*)([%^k]*)(%d*)" ) modifier = tonumber(modifier) keep = tonumber(keep) if ( modifier == nil ) then modifier = 0 end if ( sign == "-" and modifier > 0 ) then modifier = modifier * -1 end |

In Lua, `string.match()`

requires two parameters: the string we want to search through and a **pattern** of what to search for. All of the matches are returned to the variables on the left side of the `=`

sign. In this example, we search for a **number** (`(%d+)`

) followed by the letter `d`

(`[dD]`

). Note that we support both a lowercase `d`

and an uppercase `D`

as a minor fail-safe. Next, we look for the **sides to the dice **(`(%d+)`

). In Lua pattern matching, `%d`

indicates a single number while `%d+`

indicates any number with **1 or more** digits.

Next, we must search for the optional parts of the string. The next pattern set (`([%+%-]*)`

) looks for a `+`

or `−`

sign and stores the results in a variable named `sign`

. These are special symbols, so we need to **escape** them with a leading `%`

sign. By placing them within square brackets, Lua knows that either one is valid. Finally, the `*`

at the end indicates that **zero or more** matches are allowed, thus making it optional. The next pattern set (`(%d*)`

) captures an optional number for the value of the modifier. Following this, we search for either a carrot `^`

or the letter `k`

to determine the number of dice to keep out of the set. The carrot is another special symbol, so it needs to be escaped with a percent sign. Finally, we capture the count of dice to keep. In this match, we’ll actually get an empty string returned for `modifier`

and `keep`

. By converting that string to a number with `tonumber()`

, it will either return a number or `nil`

. If the modifier is `nil`

, make it 0. Then check the `sign`

variable and, if it’s a minus sign, multiply `modifier`

by -1.

Now let’s generate the rolls:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
for i = 1, count do dice[i] = random( sides ) end if ( keep ) then local function keepCompare( a, b ) return a > b end if ( keepHiLo == "k" ) then table.sort( dice ) else table.sort( dice, keepCompare ) end for i = 1, keep do total = total + dice[i] end else for i = 1, count do total = total + dice[i] end end total = total + modifier return total, dice |

The first `for`

loop loads the dice array with a number randomly generated from the number of specified sides to the dice. If we ask for `4d6`

, we’ll get an array of 4 numbers, each number ranging 1-6. Then, if `keep`

is specified, we’ll get the sum of the values, up to the `keep`

amount. To figure out which dice to keep, the array must be sorted using the `table.sort()`

function. By checking the value of the `keepHiLo`

value parsed from the string, we can sort the table from either low to high or vice-versa. Finally, we loop through the array of sorted numbers and only count those that we want to keep. Finally, to wrap up the function, we add the `modifier`

, return the total of the rolls, and also return the array of rolls in case we want the calling routine to display the values.

#### Making a Roll

With the function established, we can call the function using a valid dice string and then access the dice values after the call:

1 2 3 4 5 6 7 8 9 10 |
local result, rolls = rollDice( "3d6" ) for i = 1, #rolls do print( i, rolls[i] ) end print( result ) result, rolls = rollDice( "4d6+1^3" ) for i = 1, #rolls do print( i, rolls[i] ) end print( result ) |

### In Conclusion

Hopefully you have a clearer understanding of random number generation along with a function that you can use as an advanced dice rolling mechanism. Armed with this knowledge, you can implement ranges of random numbers that are not evenly distributed, allowing your app to easily support common, uncommon, and even rare events.

It is really such a great and easy to understand tutorial, thanks a lot for sharing this.

Thanks for the tutorial, nice one.

However everyone should keep in mind, that lua random number generation is… an utter crap.

I know that even when calling random function, if it returns ‘1’ 5 times in a row it is still considered random, but that means random generator does not behave properly.

A simple example from today: I need to generate 12 random numbers between 1 and 400. Most of the time I end up with at least 3 equal numbers in my list. Yes, I do use randomseed. Else I would end up with the same set of numbers every time.

Once we forgot to put the randomseed in our game… how cool it was to see that everytime players started the game they had exactly the same layout created.