(Pseudo) Random number allocator

Hi, I am trying to work out a way to have a module randomly assign one out of 760 numbers to participants, resulting with all of them having a different number (between 1 and 760). I've read certain discussions about random number generators (implementable via JavaScript), but would that also work (and still be random) if there are only a set number (760) of numbers to distribute?

What would you think be the best way to go about this?

16 Replies
Dave Cox

Hi Mick,

Yes, you can do what you are talking about, but it is a bit more complicated that just running the random number generator. Because you have 760 number that you want to assign, and each one can only be assigned once, this is similar to a really large card deck. What you need to do, is place all of these cards (numbers) in an array, and then shuffle the array. Then you can assign the cards from the deck in order of the stack, and the result will appear to be random, but with not duplicates. 

So, how do we pull this off?

First you need to put all of your cards into and array. For this discussion, I'm only going to work with 6, but you can assign as many as you want. Just continue to add them to the array.

var cards = [1, 2, 3, 4, 5, 6]; // Assign values to the array "cards"

Next we need a way to shuffle the array. That takes a function that can work on the shuffle. It will look like this:

function shuffle(array) {
 var currentIndex = array.length, temporaryValue, randomIndex;
 while (0 != currentIndex) { // Keep working until all elements are shuffled
  randomIndex = Math.floor(Math.random() * currentIndex);
  currentIndex -= 1;
  temporaryValue = array[currentIndex];
  array[randomIndex] = temporaryValue;
  }
 return array;
}

Now that we have a function to handle the shuffle, we just need to call in in our javascript:

cards = shuffle(cards); // shuffle the card stack

And let's display the results in the browser's console:

console.log(cards);

Now you need a loop to assign each of these back to a variable in storyline. 

Because that is whole lot of variables, It might be better to pull the values as you need it from the javascript array. If you assign all of your javascript to an external file, and make your array public in scope, javascript can remember all of these variables for you, and you can just pull each item as you need it with a javascript call. It really just depends on how you plan to use this.

I know this is a lot, but I have used this technique with some games that I've created, so I know that it does work.

Mark Shepherd

Outstanding work, Phil and Dave! :)

  • I've tried a simpler version of math.Floor that Phil has suggested, and while it works well, its only caveat is that it uses JavaScript, which not all browsers or systems support.
  • While it is VERY cumbersome, you COULD also built the card deck manually using Blank Slides and a single Variable Assignment Trigger (x=1, x=2, x=3) via a Question Bank and a Question Draw that pulls a slide randomly, thereby avoiding JavaScript and building the solution 100% inside of Storyline itself.
  • With some clever variations on this idea, you could use a smaller set of sub-groups to assign yourself a totalized number out of 750 or 760 (ie: three QB groups of ten slides to assign each number, from 0 to 9, with the second maxing out at 5 or 6 for the second digit), thereby saving you the laborious process of building a blank QB set of 700+ items.

Hope this helps,

-Mark

 

Phil Mayor

Mark I did think of the question bank idea and discounted it because of the number, like the idea of using small banks to generate large random numbers.

I didn't read the original post fully and reading again wonder if they want each participant who takes the course to get a completely random number, I don't think this can be done at all, although you could use javascript to send out to a google sheet and assign the number there.

 

Michael Hinze

Unless I am misreading Mick's requirements, having a Javascript that runs in a user's browser and generates a unique number is not enough, because it wouldn't generate a unique number for each of the 760 participants. As I see it, it needs to be a SERVER_SIDE script that generates (and stores) all unique numbers and a script in Storyline that queries the server to retrieve an unused number.

Mick Philipsen

Thanks very much to everyone thus far!

I do indeed want every participant to have a unique (and randomly assigned) number; I am creating a mandatory series of 4 modules being released with a week interval, with an overall quiz at the end. We are looking at a lottery style incentive, rewarding 500x Tier1 prizes, 150x T2, 100x T3, 25x T4 and 5x T5. I want to avoid any bias or possible influence on the outcome and want the result to be random (so not based on when you start or finish the modules and/or quiz).

Nick Shelton

I'd just assume you can use JavaScript, I mean, Storyline runs javascript to write the SWF to the page, or the Canvas if HTML5...so, I'm just assuming JS here.

You could script something up using a simple backend like Firebase.

Firebase (now owned by google) has a FREE "Spark" package that allows for 100 simultaneous connections...this would likely be enough for your needs, unless you expect all 760 people to access your tool at once.

You create endpoints, like "https://[PROJECT_ID].firebaseio-demo.com/numbers/" - that endpoint could simply be an array of assigned numbers (NoSQL). You're array could start full, and then pop off a random number based on the length of the array and then use that info to populate another endpoint like "https://[PROJECT_ID].firebaseio-demo.com/used_numbers/".

If you wanted you're used number could even be something like [ {id:1,name:"name of person"}, {id:45,name: "name of person"} ];

It'd take a little bit of JS wizardy, but the nice thing about firebase is that if you take advantage of the synchronous nature of it, you wouldn't have to worry about "race" conditions, where two people could potentially get the same number if assessing nearly simultaneously.

Best of luck!

- Nick (@nick_shelton | nickdoesstuff.com )

Mark Shepherd

Hi Mick:

One thing I have noticed about using the Storyline Quiz-based approach is that it isn't really as "random" as I might like. 

I often see the same numbers and values drawn from the Quiz Engine, using my
so-called "random" Quiz Draw in SL2, so my only other option to make that work better is to put some kind of randomizing element within the static Quiz Slides, or go back to JavaScript. :/

Dave Cox

When I created my games, I noticed that the random generator in Storyline was initialized only once. That's when the project first starts running. (At least in Storyline 2.) So my game worked fine on the first run, but if the game was restarted without reloading the module, then the sequence was always the same as the first time the game was run.

To get around this issue, I had to use Javascript's random() function.

Mark Shepherd

Hi Phil:

It's possible, at least in theory, to create multiple unique random values using the Quiz Slide technique, however, there needs to be multiple distinct draws in order to generate these kinds of numbers.

I'm currently working on testing a few working prototypes of this using different approaches, to see how much I can leverage my existing project's design model.  

As you say, there are limits as to how far this can go (can be tested) using SL 2's Preview Mode.  

I will no doubt need to try this on-line using something like SCORM Cloud to see how well these methods work in the real world. ;)

Noreen Beckinsale

I'm using Storyline 360 and need to generate a random unique number 16 times - at first I tried using question banks as that seemed to be an obvious choice but I get occasional duplicates. So might need to go down the JavaScript route - did anyone have a solution to this? Was also thinking of maybe using variables to store past numbers then comparing and forcing a new number to be generated if there is a match - but that sounds complicated and not sure if it will work

OWEN HOLT

Use 16 variables(V1, V2, etc) that correspond to a number (1 through 16), 1 control variable to display your random number, and the following JavaScript:


//call the StoryLine player
var player=GetPlayer();

//create a JavaScript variable for each corresponding SL variable
var nv1=player.GetVar("V1");
var nv2=player.GetVar("V2");
var nv3=player.GetVar("V3");
var nv4=player.GetVar("V4");
var nv5=player.GetVar("V5");
var nv6=player.GetVar("V6");
var nv7=player.GetVar("V7");
var nv8=player.GetVar("V8");
var nv9=player.GetVar("V9");
var nv10=player.GetVar("V10");
var nv11=player.GetVar("V11");
var nv12=player.GetVar("V12");
var nv13=player.GetVar("V13");
var nv14=player.GetVar("V14");
var nv15=player.GetVar("V15");
var nv16=player.GetVar("V16");

//create an array with your variables
var myArray = [nv1, nv2, nv3, nv4, nv5, nv6, nv7, nv8, nv9, nv10, nv11, nv12, nv13, nv14, nv15, nv16];

//filter out variables with a zero value and place remaining values in a new array
var filtered1 = myArray.filter(function(x) {return x>0;});

//Pick a random number from the new array and send it to your control variable in SL
var myNumber = filtered1[Math.floor(Math.random() * filtered1.length)];
player.SetVar("ControlNumber",myNumber);

//set the corresponding variable of the random number to zero in SL
var myVariable = "V" + myNumber;
player.SetVar(myVariable, "0");