ready for regionals
This commit is contained in:
@@ -270,15 +270,120 @@ async function populateKnockoutBracketInternal(tournamentId: string, groupConfig
|
||||
|
||||
const orderedTeamIds: string[] = [];
|
||||
const maxRank = groupConfig.advance_per_group;
|
||||
const numGroups = groupConfig.num_groups;
|
||||
|
||||
for (let rank = 1; rank <= maxRank; rank++) {
|
||||
const teamsAtRank = qualifiedTeams
|
||||
.filter(t => t.rank === rank)
|
||||
.sort((a, b) => a.groupOrder - b.groupOrder);
|
||||
orderedTeamIds.push(...teamsAtRank.map(t => t.teamId));
|
||||
const teamsByGroup: string[][] = [];
|
||||
for (let g = 0; g < numGroups; g++) {
|
||||
teamsByGroup[g] = [];
|
||||
}
|
||||
|
||||
logger.info('Ordered team IDs', { orderedTeamIds });
|
||||
for (const qualified of qualifiedTeams) {
|
||||
teamsByGroup[qualified.groupOrder][qualified.rank - 1] = qualified.teamId;
|
||||
}
|
||||
|
||||
const totalQualifiedTeams = numGroups * maxRank;
|
||||
for (let i = 0; i < totalQualifiedTeams / 2; i++) {
|
||||
const group1 = i % numGroups;
|
||||
const rankIndex1 = Math.floor(i / numGroups);
|
||||
|
||||
const group2 = (i + 1) % numGroups;
|
||||
const rankIndex2 = maxRank - 1 - rankIndex1;
|
||||
|
||||
const team1 = teamsByGroup[group1]?.[rankIndex1];
|
||||
const team2 = teamsByGroup[group2]?.[rankIndex2];
|
||||
|
||||
if (team1) orderedTeamIds.push(team1);
|
||||
if (team2) orderedTeamIds.push(team2);
|
||||
}
|
||||
|
||||
const knockoutTeamCount = orderedTeamIds.length;
|
||||
const nextPowerOf2 = Math.pow(2, Math.ceil(Math.log2(knockoutTeamCount)));
|
||||
const wildcardsNeeded = nextPowerOf2 - knockoutTeamCount;
|
||||
|
||||
if (wildcardsNeeded > 0) {
|
||||
logger.info('Wildcards needed', { knockoutTeamCount, nextPowerOf2, wildcardsNeeded });
|
||||
|
||||
const allNonQualifiedTeams: Array<{ teamId: string; wins: number; losses: number; cups_for: number; cups_against: number; cup_differential: number }> = [];
|
||||
const qualifiedTeamIds = new Set(qualifiedTeams.map(t => t.teamId));
|
||||
|
||||
for (const group of groups) {
|
||||
const groupMatches = await pbAdmin.getMatchesByGroup(group.id);
|
||||
const completedMatches = groupMatches.filter(m => m.status === "ended");
|
||||
|
||||
const standings = new Map<string, { teamId: string; wins: number; losses: number; cups_for: number; cups_against: number; cup_differential: number }>();
|
||||
|
||||
for (const team of group.teams || []) {
|
||||
const teamId = typeof team === 'string' ? team : team.id;
|
||||
|
||||
if (qualifiedTeamIds.has(teamId)) continue;
|
||||
|
||||
standings.set(teamId, {
|
||||
teamId,
|
||||
wins: 0,
|
||||
losses: 0,
|
||||
cups_for: 0,
|
||||
cups_against: 0,
|
||||
cup_differential: 0,
|
||||
});
|
||||
}
|
||||
|
||||
for (const match of completedMatches) {
|
||||
if (!match.home || !match.away) continue;
|
||||
|
||||
const homeStanding = standings.get(match.home.id);
|
||||
const awayStanding = standings.get(match.away.id);
|
||||
|
||||
if (homeStanding) {
|
||||
homeStanding.cups_for += match.home_cups;
|
||||
homeStanding.cups_against += match.away_cups;
|
||||
homeStanding.cup_differential = homeStanding.cups_for - homeStanding.cups_against;
|
||||
|
||||
if (match.home_cups > match.away_cups) {
|
||||
homeStanding.wins++;
|
||||
} else {
|
||||
homeStanding.losses++;
|
||||
}
|
||||
}
|
||||
|
||||
if (awayStanding) {
|
||||
awayStanding.cups_for += match.away_cups;
|
||||
awayStanding.cups_against += match.home_cups;
|
||||
awayStanding.cup_differential = awayStanding.cups_for - awayStanding.cups_against;
|
||||
|
||||
if (match.away_cups > match.home_cups) {
|
||||
awayStanding.wins++;
|
||||
} else {
|
||||
awayStanding.losses++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allNonQualifiedTeams.push(...Array.from(standings.values()));
|
||||
}
|
||||
|
||||
allNonQualifiedTeams.sort((a, b) => {
|
||||
if (b.wins !== a.wins) return b.wins - a.wins;
|
||||
if (b.cup_differential !== a.cup_differential) return b.cup_differential - a.cup_differential;
|
||||
if (b.cups_for !== a.cups_for) return b.cups_for - a.cups_for;
|
||||
return a.teamId.localeCompare(b.teamId);
|
||||
});
|
||||
|
||||
const wildcardTeams = allNonQualifiedTeams.slice(0, wildcardsNeeded);
|
||||
const wildcardTeamIds = wildcardTeams.map(t => t.teamId);
|
||||
|
||||
orderedTeamIds.push(...wildcardTeamIds);
|
||||
|
||||
logger.info('Added wildcard teams', {
|
||||
wildcardTeams: wildcardTeams.map(t => ({
|
||||
teamId: t.teamId,
|
||||
wins: t.wins,
|
||||
cupDiff: t.cup_differential,
|
||||
cupsFor: t.cups_for
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
logger.info('Ordered team IDs (with wildcards)', { orderedTeamIds, totalTeams: orderedTeamIds.length });
|
||||
|
||||
const tournament = await pbAdmin.getTournament(tournamentId);
|
||||
const knockoutMatches = (tournament.matches || [])
|
||||
|
||||
Reference in New Issue
Block a user