In this blog, we are going to take a look at the random number functions in Legato and create a real world, usable Legato script to aid in that daily, ever present quandary of what to order for lunch.
Random Number Generators
Pseudo-random number generators are the standard in programming. Legato’s Random function takes the single random number generator used by all of your Legato scripts and gets an integer return value between 0 and 0x7FFF (32,767). This random number is generated by an algorithm that returns a sequence of apparently non-related numbers each time it is called. To get a number between zero and a whole integer, you would find the modulus of the return value and the maximum value that you want to be returned (exclusive). For example, if you wanted a random number between 0 and 10, the equation would look like this:
result = Random() % 11;
It works by using a seed, which you can change by calling the SeedRandom SDK function and passing it an integer. If you were to use the same seed, the first time you call the Random function you will get the same result.
SeedRandom(1);
int out;
out = Random();
AddMessage("%d", out);
When you run this script you will always get the following output in the log:
41
For GoFiler, all scripts in the same GoFiler session share the same generator and seed state, which is created the first time you run any script in a GoFiler session by using the current system time as a seed. I use the SeedRandom function in the example below to show how to use it, but for a script like this it is not necessary to do so.
A Real Life Example
One problem that we commonly run into here at Novaworks is trying to decide where we want to eat lunch on Friday afternoons. Given everyone’s different favorites, we decided that the easiest thing to do would be to get together a list of local restaurants and pick a name out of a hat. Or, you know, use Legato.
So we went ahead and compiled a CSV list with a few columns: restaurant name, a veto column, what cuisine the restaurant is, and how many times we’ve ordered from that restaurant. We then placed the CSV file in the same folder as the script file.
And finally here is our example script:
#define RESTAURANT 0
#define RESTAURANT_USE 1
#define RESTAURANT_ORIG 1
#define RESTAURANT_CUISINE 2
#define RESTAURANT_VISITED 3
string restaurants[][]; /* The restaurants we're choosing from */
string input[][]; /* The csv as an array */
int choice; /* The restaurant we're going to */
int rn; /* The number of restaurants to choose from */
int size; /* The size of the input array */
int count; /* Counter */
int visits; /* How many times we've gone to a place */
int main() {
//Seed random number generator. Not necessary but used as example.
SeedRandom(GetTickCount());
//Get the CSV file and place it in a 2 dimensional array
input = CSVReadTable(GetScriptFolder() + "\\restaurants.csv");
//Get how many rows there are (restaurants)
size = ArrayGetAxisDepth(input);
//Check to see if an array exists
if (size == 0) {
AddMessage("File not found or improperly formatted.");
return;
}
//Set the current number of restaurants to be used
rn = 0;
//Start a loop to go through every row in the CSV
for (count = 0; count < size; count++) {
//Check if the restaurant is to be used this week
if (input[count][RESTAURANT_USE] == "TRUE") {
//Add the restaurant name to the use list
restaurants[rn][RESTAURANT] = input[count][RESTAURANT];
//Keep track of positions in the input array to reference back
restaurants[rn][RESTAURANT_ORIG] = FormatString("%d", count);
//Increase current restaurant position
rn++;
}
}
//Random number between 0 and the number of restaurants
choice = Random() % rn;
//Get the number of visits to the restaurant chosen
visits = TextToInteger(input[TextToInteger(restaurants[choice][RESTAURANT_ORIG])][RESTAURANT_VISITED]);
//Increment the number of visits
visits++;
//Store the number back in the input array
input[TextToInteger(restaurants[choice][RESTAURANT_ORIG])][RESTAURANT_VISITED] = FormatString("%d", visits);
//Inform the user what the chosen restaurant is
AddMessage(FormatString("Food this week is: %s", restaurants[choice][RESTAURANT]));
//Write the input array back to the CSV file
CSVWriteTable(input, GetScriptFolder() + "\\restaurants.csv");
return ERROR_NONE;
}
First we get the CSV file and store it in a 2 dimensional string array.
input = CSVReadTable(GetScriptFolder() + "\\restaurants.csv");
We get the array depth to find out how many rows are in the CSV file. This allows us to know the total number of restaurants in the file so we can iterate through them and figure out how many of those are available for us to pick.
size = ArrayGetAxisDepth(input);
To figure out what restaurants are in the pool from which we can pick, we run through the input array. We check each for the RESTAURANT_USE value, and if that value is set to TRUE we place the name and original position into the restaurants array.
for (count = 0; count count++) {
if (input[count][RESTAURANT_USE] == "TRUE") {
restaurants[rn][RESTAURANT] = input[count][RESTAURANT];
restaurants[rn][RESTAURANT_ORIG] = FormatString("%d", count);
rn++;
}
}
We then find a random number between 0 and the size of the restaurant array, which we’ve been storing in the rn variable.
choice = Random() % rn;
The next thing we do is get the number of times we’ve visited the restaurant from the input array, increment it, and store it back into the array. This gets confusing as we’re storing all of our values in string arrays, but we want to treat times visited as an integer. To make things more complicated, we have to use the original value from the restaurant array to figure out the position in the input array of our restaurant.
visits = TextToInteger(input[TextToInteger(restaurants[choice][RESTAURANT_ORIG])][RESTAURANT_VISITED]);
visits is our integer of how many times we’ve visited a restaurant. We get this value by getting the string value out of the input array and transforming it into an integer. This allows us to use the value to specify a position in an array. We then add one to the number of visits, and we store the new value of visits into the input array by turning it back into a string.
visits++;
input[TextToInteger(restaurants[choice][RESTAURANT_ORIG])][RESTAURANT_VISITED] = FormatString("%d", visits);
Finally we store the CSV data back into the original file.
CSVWriteTable(input, GetScriptFolder() + "\\restaurants.csv");
Boxing Up the Pizza
There’s plenty of applications for Legato in everyday activities. There’s also plenty of ways to keep improving our script. For example, we didn’t even touch the possibility of limiting our restaurant choice by cuisine, and we could randomly choose which cuisine to select first before randomly selecting a restaurant within that cuisine, for example. Random numbers can make simple decisions quickly and Legato provides easy ways to access and use them.
Joshua Kwiatkowski is a developer at Novaworks, primarily working on Novaworks’ cloud-based solution, GoFiler Online. He is a graduate of the Rochester Institute of Technology with a Bachelor of Science degree in Game Design and Development. He has been with the company since 2013. |
Additional Resources
Novaworks’ Legato Resources
Legato Script Developers LinkedIn Group
Primer: An Introduction to Legato