Randomizers¶
Randomization makes each student see different numbers in a question while keeping the question solvable. These are the randomizer macros the question engine actually exposes.
These are not PHP functions
Question control code looks like PHP but runs through the engine's own
interpreter against a fixed allowlist. The core randomizers are below (the allowlist also has
jointrandfrom($list1, $list2, …), which picks the same random position from each list, and
nonzerodiffrrands).
PHP's own shuffle(), array_rand() and mt_rand() are not — and
neither are the randint / pickone / pickunique names that earlier
versions of this page described. They never existed.
Random numbers¶
rand($min, $max)¶
A random integer from $min to $max, inclusive.
$a = rand(2, 9) // integer from 2 to 9
$n = rand(-5, 5) // integer from -5 to 5
nonzerorand($min, $max)¶
The same, but never returns 0. Use this instead of a retry loop when zero is the only value you need to exclude.
$a = nonzerorand(-5, 5) // never 0
rrand($min, $max, $step)¶
A random value from $min to $max in increments of $step. This is how you get decimals — rand only ever returns integers.
$rate = rrand(0.01, 0.15, 0.01) // 0.01, 0.02, … 0.15
$price = rrand(5, 20, 0.25) // 5, 5.25, 5.5, … 20
All three arguments are required; rrand errors if $step is missing or not positive. nonzerorrand($min, $max, $step) is the never-zero form.
rands($min, $max, $n, $ord)¶
An array of $n random integers. Values may repeat.
$ord orders the result: 'def' (default, the order drawn), 'inc' ascending, 'dec' descending.
$vals = rands(1, 6, 3) // e.g. 4, 4, 1
$sorted = rands(1, 20, 4, 'inc') // e.g. 3, 7, 7, 18
rrands($min, $max, $step, $n, $ord) is the stepped form, and nonzerorands / nonzerorrands the never-zero forms.
diffrands($min, $max, $n, $ord)¶
An array of $n distinct random integers — the macro to reach for instead of a do/while retry loop.
$two = diffrands(1, 9, 2) // two different integers, e.g. 3, 8
nonzerodiffrands($min, $max, $n, $ord) additionally excludes zero. diffrrands is the stepped form.
Picking from a list¶
randfrom($list)¶
One element chosen at random. Takes exactly one argument — a list, not a series of values.
$sign = randfrom(array(1, -1))
$word = randfrom(array("increasing", "decreasing"))
$coeff = randfrom(array(2, 3, 5, 7))
A comma-separated string works too, since randfrom runs a non-array argument through listtoarray first:
$word = randfrom("increasing,decreasing")
randsfrom($list, $n, $ord)¶
An array of $n picks from the list, with repetition.
$rolls = randsfrom(array(1,2,3,4,5,6), 3) // may repeat, e.g. 2, 5, 2
diffrandsfrom($list, $n, $ord)¶
An array of $n distinct picks from the list — the macro that does what the old pickunique claimed to.
$choices = diffrandsfrom(array(1,2,3,4,5,6), 3) // never repeats, e.g. 4, 1, 6
Shuffling¶
singleshuffle($array)¶
Returns the array in a random order.
It returns a new array — it does not shuffle in place
PHP's shuffle() modifies its argument. singleshuffle does not, so a bare
singleshuffle($options) statement has no effect. Assign the result.
$options = array("increasing", "decreasing", "constant", "undefined")
$options = singleshuffle($options)
An optional second argument truncates the result, which is a compact way to draw a random subset:
$three = singleshuffle($options, 3) // 3 of them, shuffled
jointshuffle($array1, $array2)¶
Shuffles two equal-length arrays the same way, so paired entries stay together. It does not update an index you stored before the shuffle, so recompute it afterwards. A multiple-choice question does not need it: the engine already shuffles $questions and grades against the unshuffled index.
$opts = array("3", "5", "7", "9")
$fb = array("no", "no", "yes", "no")
$opts,$fb = jointshuffle($opts, $fb)
$correct = arrayfindindex("yes", $fb) // where "7" landed
It errors if the two arrays are different lengths.
Names and places¶
The engine also ships randomizers for realistic word problems:
| Macro | Returns |
|---|---|
randname(), randnames($n, $gender) |
person names |
randmalename(), randfemalename() |
a name of that gender |
randmalenames($n), randfemalenames($n) |
arrays of names (a single string when $n is 1 — true of every plural macro in this table) |
randnamewpronouns($g) |
a name together with matching pronouns |
randcity($country), randcities($n, $country) |
city names; $country is "USA" (default) or "Canada" only — anything else returns "" |
randstate($country), randstates($n, $country) |
state names (provinces/territories for "Canada"); same "USA"/"Canada" restriction |
randcountry(), randcountries($n) |
country names |
randpythag($min, $max) |
a Pythagorean triple |
randnamewpronouns($g) returns a six-element array — name, then the subject, object, possessive-determiner, possessive-pronoun and reflexive forms — so generated prose agrees with the name drawn:
$name,$sub,$obj,$posdet,$pospro,$refl = randnamewpronouns()
Pass 'neutral' for they/them:
$name,$sub,$obj,$posdet,$pospro,$refl = randnamewpronouns('neutral')
Avoiding degenerate values¶
Prefer the macro that already excludes the bad case over a retry loop:
$a = nonzerorand(-5, 5) // not: a loop re-drawing until $a != 0
$a,$b = diffrands(1, 9, 2) // not: a loop re-drawing until $b != $a
Where no macro covers the condition, a postfix where guards the assignment. It re-draws that one value until the condition holds, up to 200 attempts, and takes an optional else { fallback } for when it never does:
$b = rand(-6, 6)
$c = rand(-9, 9) where ($b^2 - 4*$c >= 0)
^ is exponentiation here — the interpreter rewrites a^b to safepow(a, b). If a
line combines both postfix forms, where must come before if.
Seeding and reproducibility¶
Every student gets their own seed, and the same seed always regenerates the same values — that is what lets an instructor reopen a student's attempt and see the exact numbers they were graded on.
The seed is engine state, not a variable you can read: $seed is on the interpreter's disallowed list and referencing it fails the question with Eeek.. unallowed var. Use setseed if a question needs to control randomization explicitly.
A full randomized setup¶
// Two distinct nonzero integers
$a,$b = diffrandsfrom(array(-5,-4,-3,-2,2,3,4,5), 2)
$product = $a * $b // c, the constant term
$bcoef = -($a + $b) // b, the coefficient of x: (x - a)(x - b) = x^2 - (a + b)x + ab
Question text:
<p>Find a quadratic with roots `$a` and `$b`.</p>
<p>Write it in the form `x^2 + bx + c`.</p>