third place fix und polymarket

This commit is contained in:
2026-06-27 14:03:11 -05:00
parent a721de5b23
commit 2b3cadfcb5
4 changed files with 361 additions and 43 deletions

View File

@@ -4,7 +4,7 @@ import {
ThirdAssignment, slotLabel,
} from "@/lib/bracket";
import { placeIsSecure } from "@/lib/secure-places";
import { thirdSlotIsSecure } from "@/lib/third-place-security";
import { thirdSlotIsSecure, securelyQualifiedThirdTeams } from "@/lib/third-place-security";
// Ein aufgelöster Teilnehmer einer K.o.-Begegnung.
export interface ResolvedSide {
@@ -58,6 +58,7 @@ function resolveR32Slot(
matches: Match[],
teams: Team[],
annexResolved: boolean,
secureTeamIds: Set<string>,
): { teamId: string | null; provisional: boolean; tooltip: string | null } {
const table = (g: GroupId) => tables.find((t) => t.group === g);
if (slot.type === "W") {
@@ -81,21 +82,14 @@ function resolveR32Slot(
const thirdGroup = assignment[winnerGroup];
if (thirdGroup) {
const row = thirds.find((r) => r.group === thirdGroup && r.qualifies);
// Fix nur, wenn ALLE drei Bedingungen erfüllt sind:
// Fix nur, wenn ALLE Bedingungen erfüllt sind:
// 1. Annex C aufgelöst (8 Dritte zuweisbar)
// 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 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;
// 3. Das konkrete Team ist sicher qualifiziert (kann nicht aus Top 8 fallen)
// 4. Die Gruppe hat alle Spiele gespielt (Team bekannt)
const slotStable = thirdSlotIsSecure(winnerGroup, matches, teams);
const teamSecure = row?.teamId ? secureTeamIds.has(row.teamId) : false;
const fix = annexResolved && slotStable && teamSecure && row?.qualifies === true;
const provisional = !fix;
const prefix = provisional ? "aktuell " : "";
return {
@@ -150,6 +144,7 @@ export function resolveBracket(
const losers = new Map<number, string | null>();
// Map: Match-Nummer -> ist das Spiel beendet (Sieger fix)?
const decided = new Map<number, boolean>();
const secureTeamIds = securelyQualifiedThirdTeams(matches, teams);
const r32: ResolvedTie[] = R32.map((rm: R32Match) => {
const feed = feedMatch(matches, rm.matchNumber);
@@ -158,8 +153,8 @@ export function resolveBracket(
// Für 3.-Platz-Slots: Gruppensieger ist die andere Seite (immer W)
const winnerGroup = (homeGroup ?? awayGroup) as GroupId | undefined;
const h = resolveR32Slot(rm.home, winnerGroup, tables, assignment, thirds, matches, teams, annexResolved);
const a = resolveR32Slot(rm.away, winnerGroup, tables, assignment, thirds, matches, teams, annexResolved);
const h = resolveR32Slot(rm.home, winnerGroup, tables, assignment, thirds, matches, teams, annexResolved, secureTeamIds);
const a = resolveR32Slot(rm.away, winnerGroup, tables, assignment, thirds, matches, teams, annexResolved, secureTeamIds);
const home = sideFrom(h.teamId, slotLabel(rm.home, assignment, winnerGroup), teams, feed, "home", h.provisional, h.tooltip);
const away = sideFrom(a.teamId, slotLabel(rm.away, assignment, winnerGroup), teams, feed, "away", a.provisional, a.tooltip);