diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2026-09-25 20:19:43 +0200 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2026-09-25 21:00:13 +0200 |
| commit | bf09385a34f928e6c266d2f81337237955ee949b (patch) | |
| tree | 4a400b2864d0887bc34e931ca3e87646276c9a4e /src | |
| parent | 945f3bdceffed7d3bb20ee1849f5f166b3c467bc (diff) | |
| download | bycs-sol-bf09385a34f928e6c266d2f81337237955ee949b.tar.gz bycs-sol-bf09385a34f928e6c266d2f81337237955ee949b.zip | |
mass-graduation: keep student selection stable for 45 minutes
Diffstat (limited to 'src')
| -rw-r--r-- | src/mass-graduation.js | 16 | ||||
| -rw-r--r-- | src/utils-common.ts | 15 | ||||
| -rw-r--r-- | src/utils-mock.js | 1 | ||||
| -rw-r--r-- | src/utils-prod.js | 1 |
4 files changed, 30 insertions, 3 deletions
diff --git a/src/mass-graduation.js b/src/mass-graduation.js index 335ba16..3bce288 100644 --- a/src/mass-graduation.js +++ b/src/mass-graduation.js @@ -1,7 +1,6 @@ import { GraduationChange, submitGraduationChange } from "./graduation-ENV.ts"; import { fetchStudents } from "./student-ENV.ts"; - -import { getName } from "./utils-ENV.js"; +import { CourseLocalStorage, getName, splitmix32 } from "./utils-ENV.js"; let name; @@ -23,8 +22,19 @@ function toggle(btn, others) { // https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array function shuffleArray(array) { + var seed = JSON.parse(CourseLocalStorage.getItem("bycs-sol-mandatory-seed")); + if (seed === null || Date(seed.endOfLife) < Date()) { + seed = { + seed: (Math.random() * 2 ** 32) >>> 0, + // Keep the same seed for 45 minutes + endOfLife: new Date(new Date().getTime() + 45 * 60000), + }; + CourseLocalStorage.setItem("bycs-sol-mandatory-seed", JSON.stringify(seed)); + } + const rng = splitmix32(seed.seed); + for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); + const j = Math.floor(rng() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; diff --git a/src/utils-common.ts b/src/utils-common.ts index 8053043..153bbaa 100644 --- a/src/utils-common.ts +++ b/src/utils-common.ts @@ -33,3 +33,18 @@ export async function getUserIconUrl(userId: number): Promise<string> { return (userpicture as HTMLImageElement).src ?? ""; } + +// SplitMix32 implementation taken from: +// https://github.com/bryc/code/blob/master/jshash/PRNGs.md +// We only need a seeded PRNG to choose students to observe. +export function splitmix32(a: number) { + return function () { + a |= 0; + a = (a + 0x9e3779b9) | 0; + let t = a ^ (a >>> 16); + t = Math.imul(t, 0x21f0aaad); + t = t ^ (t >>> 15); + t = Math.imul(t, 0x735a2d97); + return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296; + }; +} diff --git a/src/utils-mock.js b/src/utils-mock.js index 563f685..4fb2b10 100644 --- a/src/utils-mock.js +++ b/src/utils-mock.js @@ -5,6 +5,7 @@ export { dateStringNow, datetimeStringNow, getUserIconUrl, + splitmix32, } from "./utils-common.ts"; export function isTeacher() { diff --git a/src/utils-prod.js b/src/utils-prod.js index b53f535..447a17a 100644 --- a/src/utils-prod.js +++ b/src/utils-prod.js @@ -4,6 +4,7 @@ export { dateStringNow, datetimeStringNow, getUserIconUrl, + splitmix32, } from "./utils-common.ts"; export function isTeacher() { |
