Randomly choose the pupil you had in mind all along

Russell Eveleigh
Mar 7 · 5 min read

I recently rediscovered my first adventure in pure JavaScript: a not-so-random random name chooser.

Nothing beats the analogue method of picking names from a hat. Somehow though, having the computer make the choice adds an element of magic and authenticity in the eyes of the pupils.

Years ago my first attempt at creating a random name chooser used ActionScript in Adobe Flash to select a key frame at random and so display a pupil’s picture in the corner of my PowerPoint. I’d ask a question, tap a picture of dice and we’d all watch as each pupil’s face would briefly flash up before settling on a photo with an audible bloop! It was all very Pavlovian. You know: computer goes bloop, 27 pupils sigh with relief and one sinks into their chair, mortified.

Photo by Brett Jordan on Unsplash

When I realised that ActionSctipt was syntactically similar to JavaScript, I thought it was about time I explored this famous web language, and created a new, less threatening, text only name spinner, building in some extra tricks in the process.

Improving the hat

In JavaScript a random number between 0 and 27 is generated like this:

Math.floor(Math.random() * 28);

A random number between 0 and 1 is multiplied by 28, then rounded down to produce an integer between 0 and 27. This can be used to randomly select a pupil from an array.

In class I have found random name choosing — when truly random — to present two main problems. Actually, the same problem twice. It feels as though the same pupils get chosen too frequently, which irritates the unchosen, and too frequently the selected name belongs to a pupil not fit to answer the question, which irritates me.

Given a class size of 28, any pupil has a 3.6% chance of being chosen each time, so it is tempting to think it won’t take long for all names to be chosen. In fact, the chance of everybody being selected before there is a repeat is 1 in 108,713,644,516. Furthermore, over 28 selections there is a 96% chance that a name will come up twice in a row and a 3% chance of a name occurring three times in a row. These ‘glitches’ disrupt the flow of a lesson and lead to talk about fairness instead of the learning point.

I wanted to find a way to avoid names repeating too frequently, so I created a script that stored an array of previously selected names. The length of this array was kept to 1/3 of the group size, such that a name would not be called again for at least 10 turns (rounded up) in a class of 28 pupils, a name would not be called for at least 5 turns in a subgroup of 15 pupils etc. When the script calls a name that has been called on the previous occasions, it gives up and runs again until a “unique” name is found:

//Randomly choose a name (but not too random).
var selectName = function (x) {
var ability = document.getElementsByClassName(x);

if (ability.length > 1) {
//Start by assuming it ia unique name.
var unique = true;
past.length = Math.ceil(ability.length * 0.33);

//Set the number of previously selected names to a
third of the size of all in that category.

//Randomly choose a number between 0 and number
names at chosen skill level
num = Math.floor(Math.random() * ability.length);

//Use that number to select a name
var chosenName = ability[num].innerHTML;
//Compare it to recently chosen.
for (i = 0; i < past.length; i++) {

//If there is a match...
if (past[i] == chosenName) {
unique = false;

//...stop and try again.
selectName(x);
break;
}
}

//If it is a unique name...
if (unique === true) {
document.getElementById("chosen").innerHTML = chosenName;

//...Add that name
to chosen name div, and add it to the first
position of the list of recently chosen names.
past.unshift(chosenName);

//... set opacity of foreground
foreFadeO = 0.75;

//... set chosen display to block.
chosenDisplay = "block";

//... call function to reveal name.
foreFade(foreFadeO, chosenDisplay);
sound("drip");
}

} else {
selectName("content");
}
};
Photo by American Heritage Chocolate on Unsplash

A great real world solution is to have different coloured named lolly pop sticks from which to draw. Clever. But, what if you don’t want little Timmy to know you’ve asked him because he is in yellow group? I wanted to find a way to allow the teacher to select a name from a subgroup.

Pupil names are added using the addGroup() function and are stored in a local storage variable on the user’s machine, this way the names are remembered when the page is reloaded. Initially, names receive an ability value of “two” which is combined into an object later in the script.

var addGroup = function () {
title = gn.value.toUpperCase();
names = n.value;
textSplit = names.split(/\n/);
localStorage.setItem("title" + cc, title);
localStorage.setItem("names" + cc, textSplit);
skillLevel = [];
for (j = 0; j < textSplit.length; j++) {
skillLevel[j] = "two";
}
localStorage.setItem("skillLevel" + cc, skillLevel);
as.style.display = "none";
cd.style.display = "none";
csect.style.display = "block";
location.reload();
};

Elsewhere, the teacher can assign each pupil to group one, two or three. Then when drawing a name, they hit the corresponding number on the keyboard to preselect a subgroup from which a name is randomly drawn. A listener on the window detects the key press, triggers a quick flash of five possible names from the whole set, then the preselected name appears. Cleverer.

//Listen for keypresses
window.addEventListener("keypress", function (e) {
if (!lastOne && foreFadeO === 0 && !menuDisplay) {
var keycode = e.keyCode;
//If enter is pressed choose any name.
if (keycode == 13) {
flashNames("content");
//If one is pressed choose name from "one" class.
} else if (keycode == 49) {
flashNames("one");
//If one is pressed choose name from "two" class.
} else if (keycode == 50) {
flashNames("two");
//If one is pressed choose name from "three" class.
} else if (keycode == 51) {
flashNames("three");
//If esc is pressed clear name.
} else if (keycode == 27) {
alert("escape");
foreFadeO = 0;
chosenDisplay = "none";
foreFade(foreFadeO, chosenDisplay, true);
}
}
}, false);

So, if I wanted to ask a straight forward question such as “How old was Queen Victoria when she died?” I would hit 1 on my keyboard, saving a higher order question like “Explain what you think was the biggest change to occur during the reign of Queen Victoria?” for another group.

I knew that I had to get to grips with closure — of JavaScript functions that is. During this project there were too many times when I got stuck as to why certain functions were called several times in a row, despite there being only one apparent trigger. All over the place I bodged my way around this by forcing the page to reload using location.reload() to clear and reset variables. I sensed this was not right and that knowing more about function closures and AJAX would probably help. Still, the whole thing continues to work a treat and the pupils never suspect a thing.

https://reveleigh.com/tools/random-name-chooser/

Geek Culture

Proud to geek out. Follow to join our +1M monthly readers.