The random name project


Names in a hat

Truthfully, 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.

Click here for the random name chooser.

Usually I add pupil photos to a movie clip in Flash and then use minimal ActionScript to randomly select a keyframe and thus a pupil picture. This year however, I thought I would use HTML, CSS and JavaScript to tackle the problem, building some extra tricks into the process at the same time too.

In JavaScript, a random number is generated like this:

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

This generates a random number between 0 and 1, multiplies this by 28 then rounds this down to produce an integer between 0 and 27 (the first name in the list is held at position 0).

Improving the hat

In class I have found random name choosing - when truly random - to present two main problems. Actually, the same problem twice. It seems 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 0.36% chance of being chosen each time, so it is tempting to think it won't take long for all names to be chosen. Wrong! 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 - events that respectively cause minor disruption and a minor riot.

Ok, no one really cares, but these glitches do disrupt the flow of a lesson. Go on, see for yourself. See how many names go unpicked after 28 selections.

Key: unpicked, picked once, picked twice, picked three times or more.

Bob
Steve
Harry
Lucy
Clare
Stephanie
Kelly
Keith
Paul
Michael
Jessica
Edith
Vanessa
Jane
Thomas
William
Fred
Alice
Jo
Agatha
Cynthia
John
Daniel
Graham
Arthur
Hazel
Joan
Jade

.........................................

Avoiding repetition

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 [math]\frac{1}{3}[/math] 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");
    }
};

Coloured lolly pop sticks 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.

Closure issues

I know that I have got to get to grips with closure - of JavaScript functions that is. During this project there were too many times when I got too 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 sense this is not right and that knowing more about function closures and AJAX would probably help. Still, the whole thing works a treat and the pupils never suspect a thing.

Check out my not so random random name chooser.