Saturday 13 August 2011

Using math.random in Corona SDK


During my very first steps with Corona SDK (and Lua) I have tried to use the math.random method.
From my experience it wasn’t as simple as I thought, so I think it is worth a blog post.
Don’t get me wrong, using the math.random is not a big issue at all, but there are some details better known first.

When using the method you may notice that each time you’ll restart the application, you’lI get the exact same sequence of numbers back from it.
This is not a bug or a problem, it is a feature :)
So why do we get the same sequence and how to “solve” it out?

Let’s start with the why:
The math.random does not have any magic in it, it is an algorithm – a function.
As the same as with any other function, the expectation is to get the exact same B whenever you send the exact same A, and the math.random in not an exception to this rule.

So How to solve the “problem”:
The random algorithm needs a seed.
Different seeds will create different sequences; same seeds will create the same ones.
If you call the math.random without setting a seed first, the function will use the exact same default seed (and will create the exact same sequence).
So before calling math.random() you’ll need to set up a seed using math.randomseed().
math.randomseed(1) and math.randomseed(2) will produce different results after calling math.random().
In order to have a different and unique seed each time you start the application you can use the system's time as the seed: math.randomseed( os.time() ).

So far so good – but it is not all :)

There is also a bug with Lua.
Under some conditions the first number that returned back from math.random could be the exact number, each time you start.
To work around this issue you’ll have to call math.random couple of times before making a use to the returned result.

Bottom line: If you want to use math.random in Corona SDK (and in Lua in general) and to get a different sequence each time, set the random seed as the system’s current time, and call the random method twice before using it J.
Add the following lines to the head of your code:

math.randomseed(os.time())
math.random()
math.random()


C# (my main development language) is not very different in a sense that the concept of random and seeds is the same.
But Microsoft did our work easier. The default constructor of the random method will use the system's time as the seed, so you don't necessarily have to know anything about seeds (for good and bad). For more details check the MSDN page.
Arguably (and can really argue both sides) corona could have add the three lines of code from above to the framework, so it will bypass the Lua bug and use the system time as default.
It will make the development easier for new developers (the same decision Microsoft took with C#), but will produce unexpected result for Lua developers (and that’s why I can understand why they maybe should leave it as it).

This issue causes some pains to new Corona/Lua developers as you can understand from this forum thread.

Feel free to share your thoughts :)


2 comments:

  1. Sounds like you need to wrapper the math.random function yourself. Whenever it's called it looks at a static bool to see whether it's been initialized yet, if not, it seeds and calls math.random an extra time.

    ReplyDelete
  2. Hi Chris,
    Wrapping is not a bad idea as calling local function is faster than calling math.random anyway.
    more info at "Lua: Best Practices" at:
    http://developer.anscamobile.com/content/performance-and-optimization
    Thanks for your comment.

    ReplyDelete