Move hard conflict and oversized group detection from JS to server

This commit is contained in:
Ian Gulliver
2026-02-16 10:45:13 -08:00
parent 71e536f284
commit b71c4bfd3f
2 changed files with 122 additions and 85 deletions

View File

@@ -82,90 +82,8 @@ async function loadStudents() {
lastOveralls = allOveralls;
const mismatchList = constraintData.mismatches;
const studentName = {};
for (const s of students) studentName[s.id] = s.name;
const mustAdj = {};
for (const s of students) {
for (const [bId, eff] of Object.entries(allOveralls[s.id])) {
if (eff.kind === 'must') {
const a = s.id, b = parseInt(bId);
if (!mustAdj[a]) mustAdj[a] = [];
mustAdj[a].push(b);
if (!mustAdj[b]) mustAdj[b] = [];
mustAdj[b].push(a);
}
}
}
const ufParent = {};
for (const s of students) ufParent[s.id] = s.id;
const ufFind = (x) => {
if (ufParent[x] !== x) ufParent[x] = ufFind(ufParent[x]);
return ufParent[x];
};
for (const s of students) {
for (const [bId, eff] of Object.entries(allOveralls[s.id])) {
if (eff.kind === 'must') {
const ra = ufFind(s.id), rb = ufFind(parseInt(bId));
if (ra !== rb) ufParent[ra] = rb;
}
}
}
const findMustPath = (from, to) => {
if (from === to) return [from];
const visited = new Set([from]);
const queue = [[from]];
while (queue.length > 0) {
const path = queue.shift();
const curr = path[path.length - 1];
for (const next of (mustAdj[curr] || [])) {
if (next === to) return [...path, next];
if (!visited.has(next)) {
visited.add(next);
queue.push([...path, next]);
}
}
}
return null;
};
const hardConflictList = [];
for (const s of students) {
for (const [bId, eff] of Object.entries(allOveralls[s.id])) {
if (eff.kind !== 'must_not') continue;
const b = parseInt(bId);
if (ufFind(s.id) !== ufFind(b)) continue;
const path = findMustPath(b, s.id);
if (!path) continue;
const chain = [];
for (let i = 0; i < path.length - 1; i++) {
const x = path[i], y = path[i + 1];
if (allOveralls[x]?.[y]?.kind === 'must') {
chain.push({ from: studentName[x], to: studentName[y], kind: 'must' });
} else {
chain.push({ from: studentName[y], to: studentName[x], kind: 'must' });
}
}
chain.push({ from: s.name, to: studentName[b], kind: 'must_not' });
hardConflictList.push(chain);
}
}
const mustGroups = {};
for (const s of students) {
const root = ufFind(s.id);
if (!mustGroups[root]) mustGroups[root] = [];
mustGroups[root].push(s.name);
}
const oversizedGroups = [];
for (const members of Object.values(mustGroups)) {
if (members.length > trip.room_size) {
oversizedGroups.push(members);
}
}
const hardConflictList = constraintData.hard_conflicts;
const oversizedGroups = constraintData.oversized_groups;
const conflictsEl = document.getElementById('conflicts');
const conflictsWasOpen = conflictsEl.querySelector('wa-details')?.open;