Skip to content

Commit

Permalink
seedrandom's second argument is always deterministic
Browse files Browse the repository at this point in the history
The expression evaluated inside the `seedrandom` function is
always deterministic, given the seed.

This means that values generate with `seedrandom` aren't saved to the
suepend data.

This commit also adds some unit tests for seedrandom in exams.
  • Loading branch information
christianp committed Dec 19, 2024
1 parent 28ed84e commit 6a98c8b
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 131 deletions.
6 changes: 5 additions & 1 deletion runtime/scripts/jme-builtins.js
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,11 @@ newBuiltin('seedrandom', ['?', '?'], '?', null, {
return result;
}
});
Numbas.jme.lazyOps.push('seedrandom');
jme.lazyOps.push('seedrandom');
jme.isDeterministicOps['seedrandom'] = function(expr,scope) {
// The second argument is always deterministic.
return jme.isDeterministic(expr.args[0], scope);
}

newBuiltin('mod', [TNum,TNum], TNum, math.mod );
newBuiltin('max', [TNum,TNum], TNum, math.max );
Expand Down
11 changes: 11 additions & 0 deletions runtime/scripts/jme.js
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,9 @@ var jme = Numbas.jme = /** @lends Numbas.jme */ {
// a function application is deterministic if its definition is marked as not random,
// and all of its arguments are deterministic
var op = jme.normaliseName(expr.tok.name, scope);
if(isDeterministicOps[op]) {
return isDeterministicOps[op](expr,scope);
}
var fns = scope.getFunction(op);
if(!fns || fns.length==0) {
return false;
Expand Down Expand Up @@ -4230,6 +4233,14 @@ var substituteTreeOps = jme.substituteTreeOps = {};
*/
var findvarsOps = jme.findvarsOps = {}

/** Custom isDeterministic behaviour for specific functions.
*
* @memberof Numbas.jme
* @enum {Numbas.jme.isDeterministic}
* @see Numbas.jme.isDeterministic
*/
var isDeterministicOps = jme.isDeterministicOps = {};

/** Find all variables used in given syntax tree.
*
* @memberof Numbas.jme
Expand Down
17 changes: 16 additions & 1 deletion tests/jme-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -9662,6 +9662,9 @@ var jme = Numbas.jme = /** @lends Numbas.jme */ {
// a function application is deterministic if its definition is marked as not random,
// and all of its arguments are deterministic
var op = jme.normaliseName(expr.tok.name, scope);
if(isDeterministicOps[op]) {
return isDeterministicOps[op](expr,scope);
}
var fns = scope.getFunction(op);
if(!fns || fns.length==0) {
return false;
Expand Down Expand Up @@ -13000,6 +13003,14 @@ var substituteTreeOps = jme.substituteTreeOps = {};
*/
var findvarsOps = jme.findvarsOps = {}

/** Custom isDeterministic behaviour for specific functions.
*
* @memberof Numbas.jme
* @enum {Numbas.jme.isDeterministic}
* @see Numbas.jme.isDeterministic
*/
var isDeterministicOps = jme.isDeterministicOps = {};

/** Find all variables used in given syntax tree.
*
* @memberof Numbas.jme
Expand Down Expand Up @@ -15167,7 +15178,11 @@ newBuiltin('seedrandom', ['?', '?'], '?', null, {
return result;
}
});
Numbas.jme.lazyOps.push('seedrandom');
jme.lazyOps.push('seedrandom');
jme.isDeterministicOps['seedrandom'] = function(expr,scope) {
// The second argument is always deterministic.
return jme.isDeterministic(expr.args[0], scope);
}

newBuiltin('mod', [TNum,TNum], TNum, math.mod );
newBuiltin('max', [TNum,TNum], TNum, math.max );
Expand Down
Loading

0 comments on commit 6a98c8b

Please sign in to comment.