From d836114025efccd2c4098e5537b7376998a74213 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Wed, 23 Sep 2026 20:53:49 +0200 Subject: mass-graduation: fix selection of mandatory graduations The previous algorithm did compare all graduations to the one with the most mandatory changes. However, the amount of mandatory changes can differ during normal operation by two. Therefore, the pool of candidates consists of graduations with one or two fewer mandatory changes than the maximum. This is fixed by selecting as many graduations from the group with the next fewest mandatory changes as possible. --- src/mass-graduation.js | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/mass-graduation.js b/src/mass-graduation.js index 46c4efe..69bbf07 100644 --- a/src/mass-graduation.js +++ b/src/mass-graduation.js @@ -33,27 +33,31 @@ function shuffleArray(array) { function chooseMandatory(graduations) { graduations.sort((g1, g2) => g1.mandatory - g2.mandatory); - // Get all graduations with smaller mandatory amount than the one with the highest amount - let mandatoryCandidates = graduations.filter( - (g) => g.mandatory < graduations[graduations.length - 1].mandatory, - ); - let rest; - - // All graduations have the same mandatory amount - if (mandatoryCandidates.length === 0) { - mandatoryCandidates = graduations; - rest = []; - } else { - rest = graduations.filter((g) => !mandatoryCandidates.includes(g)); + // Group the graduations according to the amount of mandatory changes + let mandatoryCandidateGroups = []; + let curGroup = []; + let mandatory = graduations[0].mandatory; + for (const g of graduations) { + if (g.mandatory === mandatory) { + curGroup.push(g); + } else { + // Start a new group + mandatoryCandidateGroups.push(curGroup); + curGroup = [g]; + mandatory = g.mandatory; + } } + // push the last group + mandatoryCandidateGroups.push(curGroup); + + // Choose from the group with the smallest amount of mandatory changes + const chosen = []; + for (const candidateGroup of mandatoryCandidateGroups) { + if (chosen.length === 5) break; - // Get a random list of possible indexes - const candidatesIdxs = shuffleArray([...Array(mandatoryCandidates.length).keys()]); - let chosen = candidatesIdxs.slice(0, 5).map((i) => mandatoryCandidates[i]); - if (chosen.length < 5) { - const missing = 5 - chosen.length; - const restIdxs = shuffleArray([...Array(rest.length).keys()]); - chosen = chosen.concat(restIdxs.slice(0, missing).map((i) => rest[i])); + // Get a random list of possible indexes + const candidatesIdxs = shuffleArray([...Array(candidateGroup.length).keys()]); + chosen.push(...candidatesIdxs.slice(0, 5 - chosen.length).map((i) => candidateGroup[i])); } return chosen; -- cgit v1.2.3