From bf931e70c0d1b6727b502f6f3cad9d188c4f8799 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Sat, 27 Jun 2026 07:58:38 -0500 Subject: [PATCH] third place fix --- lib/resolve-bracket.ts | 13 ++++++++++--- lib/third-place-security.ts | 39 ++++++++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/lib/resolve-bracket.ts b/lib/resolve-bracket.ts index 67d50b3..dd60e07 100644 --- a/lib/resolve-bracket.ts +++ b/lib/resolve-bracket.ts @@ -86,9 +86,16 @@ function resolveR32Slot( // 2. Der Slot ist in allen noch möglichen Konstellationen stabil // (Enumeration aller Annex-C-Kombinationen) // 3. Das konkrete Team ist bekannt (Gruppe fertig) - const fix = annexResolved - && thirdSlotIsSecure(winnerGroup, matches, teams) - && row?.qualifies === true; + const secure = thirdSlotIsSecure(winnerGroup, matches, teams); + console.log("[FIX-3RD]", "winnerGroup:", winnerGroup, + "| assignedThird:", assignment?.[winnerGroup], + "| annexResolved:", annexResolved, + "| thirdSlotIsSecure:", secure, + "| row.group:", row?.group, + "| row.qualifies:", row?.qualifies, + "| row.teamId:", row?.teamId, + "| team:", row?.teamId ? teams.find(t => t.id === row.teamId)?.name : "null"); + const fix = annexResolved && secure && row?.qualifies === true; const provisional = !fix; const prefix = provisional ? "aktuell " : ""; return { diff --git a/lib/third-place-security.ts b/lib/third-place-security.ts index c9efbbe..7003676 100644 --- a/lib/third-place-security.ts +++ b/lib/third-place-security.ts @@ -207,17 +207,31 @@ export function thirdSlotIsSecure( else contested.add(g); } - // 3. Wenn weniger als 8 lockedIn sind, aber alle contested stabil → früh raus - if (lockedIn.size >= 8) { - // Mehr als 8 Gruppen garantiert qualifiziert → Annex C kann nicht eindeutig sein - // (es gibt mehr als eine Auswahl von 8 aus den lockedIn) - // Prüfe: sind ALLE 8er-Teilmengen aus lockedIn identisch bezüglich dieses Slots? - // Das ist komplex; im Zweifel konservativ: false + // 3. lockedIn >= 8: wenn genau 8 → Zuordnung EINDEUTIG (nur eine Kombination). + // Wenn > 8 → mehrdeutig (versch. 8er-Teilmengen möglich) → konservativ false. + if (lockedIn.size > 8) { + console.log("[3RD-SECURE] false: >8 lockedIn | wg:", winnerGroup, "| lockedIn:", [...lockedIn].join(",")); return false; } + // Genau 8 lockedIn → nur eine mögliche Kombination → Annex C ist determiniert. + // Direkt prüfen, da Enumeration entfällt. + if (lockedIn.size === 8) { + const qGroups = [...lockedIn]; + const assignment = resolveAnnexC(qGroups); + if (!assignment) { console.log("[3RD-SECURE] false: no annex with 8 locked | wg:", winnerGroup); return false; } + const assignedGroup = assignment[winnerGroup]; + if (!assignedGroup) { console.log("[3RD-SECURE] false: no assignedGroup (8 locked) | wg:", winnerGroup); return false; } + const stableState = states.get(assignedGroup); + if (!stableState) return false; + const result = stableState.finished && stableState.third != null && stableState.possibleTeamIds.size === 1; + console.log("[3RD-SECURE] final (8 locked):", result, "| wg:", winnerGroup, "| stableGroup:", assignedGroup, "| finished:", stableState.finished, "| hasThird:", !!stableState.third, "| uniqueTeam:", stableState.possibleTeamIds.size); + return result; + } + if (lockedIn.size + contested.size < 8) { // Nicht genug Gruppen, um 8 Dritte zu füllen → Annex C nicht auflösbar + console.log("[3RD-SECURE] false: <8 possible | wg:", winnerGroup, "| lockedIn:", lockedIn.size, "| contested:", contested.size); return false; } @@ -229,7 +243,7 @@ export function thirdSlotIsSecure( // Begrenzung der Kombinationszahl const combos = combinations(contestedArr.length, need); - if (combos > 200) return false; // zu viele Kombinationen → nichts stabil + if (combos > 200) { console.log("[3RD-SECURE] false: >200 combos | wg:", winnerGroup); return false; } let stableGroup: GroupId | null = null; @@ -249,20 +263,23 @@ export function thirdSlotIsSecure( if (!assignment) continue; const assignedGroup = assignment[winnerGroup]; - if (!assignedGroup) return false; + if (!assignedGroup) { console.log("[3RD-SECURE] false: no assignedGroup | wg:", winnerGroup); return false; } if (stableGroup === null) { stableGroup = assignedGroup; } else if (stableGroup !== assignedGroup) { - return false; // Slot fällt in verschiedenen Kombinationen auf verschiedene Gruppen + console.log("[3RD-SECURE] false: unstable slot | wg:", winnerGroup, "| groups:", stableGroup, "vs", assignedGroup); + return false; } } // 5. Slot ist stabil → prüfe, ob die Quellgruppe selbst bereits feststeht - if (stableGroup === null) return false; + if (stableGroup === null) { console.log("[3RD-SECURE] false: stableGroup=null | wg:", winnerGroup); return false; } const stableState = states.get(stableGroup); if (!stableState) return false; - return stableState.finished && stableState.third != null && stableState.possibleTeamIds.size === 1; + const result = stableState.finished && stableState.third != null && stableState.possibleTeamIds.size === 1; + console.log("[3RD-SECURE] final:", result, "| wg:", winnerGroup, "| stableGroup:", stableGroup, "| finished:", stableState.finished, "| hasThird:", !!stableState.third, "| uniqueTeam:", stableState.possibleTeamIds.size); + return result; } // Berechnet C(n, k) — die Anzahl der Kombinationen.