From 5594ecb8f6a84a75f4b33b2e12b300d0986e01d4 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sat, 9 Apr 2022 16:23:00 +0300 Subject: [PATCH] Bracket starts with 11 teams / DE Closes #811 --- app/core/tournament/bracket.test.ts | 38 ++++++++++++++++++++++++++--- app/core/tournament/bracket.ts | 32 +++++++++++++++--------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/app/core/tournament/bracket.test.ts b/app/core/tournament/bracket.test.ts index dd1289af9..789c1ca8b 100644 --- a/app/core/tournament/bracket.test.ts +++ b/app/core/tournament/bracket.test.ts @@ -87,7 +87,7 @@ TournamentRoundsForDB("Generates rounds correctly", () => { .map(String) .map((id) => ({ id })), }); - const roundsCounted = countRounds(bracket); + const roundsCounted = countRounds(bracket, false); let max = -Infinity; let min = Infinity; const uniqueParticipants = new Set(); @@ -149,9 +149,9 @@ TournamentRoundsForDB( ); TournamentRoundsForDB("Advances bye to right spot", () => { - const { mapList } = testTournamentData("DE", 24); - const TEAM_COUNT = 7; + const { mapList } = testTournamentData("DE", TEAM_COUNT); + const bracketForDb = tournamentRoundsForDB({ mapList, bracketType: "SE", @@ -178,6 +178,38 @@ TournamentRoundsForDB("Advances bye to right spot", () => { assert.equal(teamOrder, "UPPER"); }); +TournamentRoundsForDB( + "Has matching match for each loser destination match id", + () => { + const TEAM_COUNT = 11; + const { mapList } = testTournamentData("DE", 11); + + const bracketForDb = tournamentRoundsForDB({ + mapList, + bracketType: "DE", + participantsSeeded: new Array(TEAM_COUNT) + .fill(null) + .map((_, i) => i + 1) + .map(String) + .map((id) => ({ id })), + }); + + const matches = bracketForDb.flatMap((round) => round.matches); + const losers = matches + .filter((match) => !match.loserDestinationMatchId) + .flatMap((match) => match.id ?? []); + const loserDestinationMatchIds = matches.flatMap( + (match) => match.loserDestinationMatchId ?? [] + ); + + for (const id of loserDestinationMatchIds) { + if (!losers.includes(id)) { + throw new Error(`No matching losers match found for id: ${id}`); + } + } + } +); + CountBracketRounds.run(); RoundNames.run(); TournamentRoundsForDB.run(); diff --git a/app/core/tournament/bracket.ts b/app/core/tournament/bracket.ts index 29ebcb30c..2d7ad29bb 100644 --- a/app/core/tournament/bracket.ts +++ b/app/core/tournament/bracket.ts @@ -155,7 +155,10 @@ export function getRoundNameByPositions( return result; } -export function countRounds(bracket: Bracket): EliminationBracket { +export function countRounds( + bracket: Bracket, + skipFirstRoundLosersIfNotPlayed = true +): EliminationBracket { const isDE = bracket.losers.length > 0; let winners = isDE ? 2 : 0; @@ -198,7 +201,11 @@ export function countRounds(bracket: Bracket): EliminationBracket { } // First round of losers is not played if certain amount of byes - if (matchesWithByes && matchesWithByes >= matchesWithOpponent) { + if ( + skipFirstRoundLosersIfNotPlayed && + matchesWithByes && + matchesWithByes >= matchesWithOpponent + ) { losers--; } @@ -274,8 +281,9 @@ export function tournamentRoundsForDB({ for (const [roundI, round] of side.entries()) { const position = isWinners ? roundI + 1 : -(roundI + 1); const stagesRaw = mapList[isWinners ? "winners" : "losers"][roundI]; - invariant(stagesRaw, "stagesRaw is undefined"); - const stages = stagesRaw.map((stage, i) => ({ + // can be undefined if it's about unplayed first round of losers, + // we don't need to add any stages for that round + const stages = (stagesRaw ?? []).map((stage, i) => ({ position: i + 1, stageId: stage.id, })); @@ -323,7 +331,7 @@ export function tournamentRoundsForDB({ } function groupMatchesByRound(bracket: Bracket): EliminationBracket { - const { winners, losers } = countRounds(bracket); + const { winners, losers } = countRounds(bracket, false); const result: EliminationBracket = { winners: new Array(winners).fill(null).map(() => []), @@ -354,7 +362,8 @@ function groupMatchesByRound(bracket: Bracket): EliminationBracket { search(match.winnerDestinationMatch, side, depth + 1); matchesIncluded.add(match.id); - result[side][depth - 1]?.push(match); + invariant(result[side][depth - 1], "No rounds array for the match"); + result[side][depth - 1].push(match); } } @@ -368,11 +377,10 @@ function advanceByes( ["upperTeam" | "lowerTeam", number][] >(); for (const round of result.winners[0]) { - const winnerDestinationMatch = round.winnerDestinationMatch; - invariant(winnerDestinationMatch, "winnerDestinationmatch is undefined"); + invariant(round.winnerDestinationMatch, "!round.winnerDestinationMatch"); const teamsForSecondRoundArr = - teamsForSecondRound.get(winnerDestinationMatch.number) ?? []; + teamsForSecondRound.get(round.winnerDestinationMatch.number) ?? []; let changed = false; if ( round.upperTeam && @@ -380,7 +388,7 @@ function advanceByes( round.lowerTeam === "BYE" ) { teamsForSecondRoundArr.push([ - resolveSide(round, winnerDestinationMatch, result), + resolveSide(round, round.winnerDestinationMatch, result), round.upperTeam, ]); changed = true; @@ -390,7 +398,7 @@ function advanceByes( round.upperTeam === "BYE" ) { teamsForSecondRoundArr.push([ - resolveSide(round, winnerDestinationMatch, result), + resolveSide(round, round.winnerDestinationMatch, result), round.lowerTeam, ]); changed = true; @@ -398,7 +406,7 @@ function advanceByes( if (changed) { teamsForSecondRound.set( - winnerDestinationMatch.number, + round.winnerDestinationMatch.number, teamsForSecondRoundArr ); }