mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-24 23:12:24 -05:00
Use a utility function for random number picking
This commit is contained in:
parent
b29f07636d
commit
43faf2a64d
2 changed files with 59 additions and 5 deletions
|
@ -403,13 +403,17 @@ class Scratch3LooksBlocks {
|
||||||
} else if (requestedBackdrop === 'previous backdrop') {
|
} else if (requestedBackdrop === 'previous backdrop') {
|
||||||
stage.setCostume(stage.currentCostume - 1);
|
stage.setCostume(stage.currentCostume - 1);
|
||||||
} else if (requestedBackdrop === 'random backdrop') {
|
} else if (requestedBackdrop === 'random backdrop') {
|
||||||
// Don't pick the current backdrop, so that the block
|
|
||||||
// will always have an observable effect.
|
|
||||||
const numCostumes = stage.getCostumes().length;
|
const numCostumes = stage.getCostumes().length;
|
||||||
if (numCostumes > 1) {
|
if (numCostumes > 1) {
|
||||||
let selectedIndex = Math.floor(Math.random() * (numCostumes - 1));
|
// Don't pick the current backdrop, so that the block
|
||||||
if (selectedIndex === stage.currentCostume) selectedIndex = numCostumes - 1;
|
// will always have an observable effect.
|
||||||
stage.setCostume(selectedIndex);
|
const lowerBound = 0;
|
||||||
|
const upperBound = numCostumes - 1;
|
||||||
|
const costumeToExclude = stage.currentCostume;
|
||||||
|
|
||||||
|
const nextCostume = MathUtil.inclusiveRandIntWithout(lowerBound, upperBound, costumeToExclude);
|
||||||
|
|
||||||
|
stage.setCostume(nextCostume);
|
||||||
}
|
}
|
||||||
// Try to cast the string to a number (and treat it as a costume index)
|
// Try to cast the string to a number (and treat it as a costume index)
|
||||||
// Pure whitespace should not be treated as a number
|
// Pure whitespace should not be treated as a number
|
||||||
|
|
|
@ -77,6 +77,56 @@ class MathUtil {
|
||||||
const sorted = elts.slice(0).sort((a, b) => a - b);
|
const sorted = elts.slice(0).sort((a, b) => a - b);
|
||||||
return elts.map(e => sorted.indexOf(e));
|
return elts.map(e => sorted.indexOf(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a random number given an inclusive range and a set
|
||||||
|
* of numbers that should be excluded.
|
||||||
|
* For instance, (1, 5, [2, 3]) will only pick 1, 4, or 5 (with equal
|
||||||
|
* probability)
|
||||||
|
*
|
||||||
|
* @param {number} lower - The lower bound (inlcusive)
|
||||||
|
* @param {number} upper - The upper bound (inclusive), such that lower <= upper
|
||||||
|
* @param {number} exclude - The numbers to exclude (MUST be in the range)
|
||||||
|
*/
|
||||||
|
static inclusiveRandIntWithout(lower, upper, excluded) {
|
||||||
|
/**
|
||||||
|
* By excluding a random integer, we are lowering the number
|
||||||
|
* of possible options by one.
|
||||||
|
*
|
||||||
|
* The algorithm is to pick a random integer in the range
|
||||||
|
* [lower, upper-1]. If we accidentally pick the exlcuded number,
|
||||||
|
* we will instead pikc "upper".
|
||||||
|
*
|
||||||
|
* So if C is excluded, and we are picking A..F then:
|
||||||
|
*
|
||||||
|
* A B C D E (no F)
|
||||||
|
* = = = = =
|
||||||
|
* A B F D E
|
||||||
|
*
|
||||||
|
* In the event that our excluded number isn't in the range, we will never pick it,
|
||||||
|
* and so we don't need to worry about remapping it to something else. For example,
|
||||||
|
* if we want to exclude 'F':
|
||||||
|
*
|
||||||
|
* A B C D E (no F)
|
||||||
|
* = = = = =
|
||||||
|
* A B C D E
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Note that 5 - 3 = 2, but there are 3 options (3, 4, 5).
|
||||||
|
// As a result, there isn't a need to subtract 1 as we've
|
||||||
|
// already got one less than the size of the range.
|
||||||
|
const possibleOptions = upper - lower;
|
||||||
|
|
||||||
|
const randInt = lower + Math.floor(Math.random() * possibleOptions);
|
||||||
|
if (randInt === excluded) {
|
||||||
|
// We've picked the excluded number.
|
||||||
|
return upper;
|
||||||
|
} else {
|
||||||
|
// We haven't picked the excluded number, so this
|
||||||
|
// value maps to itself.
|
||||||
|
return randInt;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = MathUtil;
|
module.exports = MathUtil;
|
||||||
|
|
Loading…
Reference in a new issue