From 2332456ef2a1f1b6f6caffa8c070ce6467c7f082 Mon Sep 17 00:00:00 2001 From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com> Date: Fri, 17 Dec 2021 18:57:51 +0200 Subject: [PATCH] Generate bracket reset --- app/core/tournament/algorithms.test.ts | 13 +++++++------ app/core/tournament/algorithms.ts | 19 +++++++++++------- app/core/tournament/bracket.test.ts | 27 ++++++++++++++++++++++---- app/core/tournament/bracket.ts | 21 ++++++++++++++------ 4 files changed, 57 insertions(+), 23 deletions(-) diff --git a/app/core/tournament/algorithms.test.ts b/app/core/tournament/algorithms.test.ts index a1ef11103..4590c0aeb 100644 --- a/app/core/tournament/algorithms.test.ts +++ b/app/core/tournament/algorithms.test.ts @@ -1,9 +1,10 @@ import { suite } from "uvu"; import * as assert from "uvu/assert"; -import type { Match, TeamIdentifier } from "./bracket"; import { eliminationBracket, fillParticipantsWithNullTillPowerOfTwo, + Match, + TeamIdentifier, } from "./algorithms"; const AmountOfTeams = suite("Amount of teams"); @@ -21,29 +22,29 @@ AmountOfTeams("Generates right amount of rounds (16 participants - SE)", () => { AmountOfTeams("Generates right amount of rounds (16 participants - DE)", () => { const bracket16 = eliminationBracket(16, "DE"); - assert.equal(removeMatchesWithByes(bracket16.winners).length, 16); // not incl reset + assert.equal(removeMatchesWithByes(bracket16.winners).length, 17); assert.equal(removeMatchesWithByes(bracket16.losers).length, 14); }); AmountOfTeams("Generates right amount of rounds (15 participants - DE)", () => { const bracket15 = eliminationBracket(15, "DE"); - assert.equal(removeMatchesWithByes(bracket15.winners).length, 15); // not incl reset + assert.equal(removeMatchesWithByes(bracket15.winners).length, 16); assert.equal(removeMatchesWithByes(bracket15.losers).length, 14); // one bye }); AmountOfTeams("Generates right amount of rounds (17 participants - DE)", () => { const bracket17 = eliminationBracket(17, "DE"); - assert.equal(removeMatchesWithByes(bracket17.winners).length, 17); // not incl reset + assert.equal(removeMatchesWithByes(bracket17.winners).length, 18); assert.equal(removeMatchesWithByes(bracket17.losers).length, 30); - assert.equal(removeMatchesWithByes(bracket17.winners).length, 17); // not incl reset + assert.equal(removeMatchesWithByes(bracket17.winners).length, 18); assert.equal(removeMatchesWithByes(bracket17.losers).length, 30); }); AmountOfTeams("Same amount of rounds as next power of two", () => { const bracket17 = eliminationBracket(17, "DE"); const bracket32 = eliminationBracket(32, "DE"); - assert.equal(bracket17.winners.length, bracket32.winners.length); // not incl reset + assert.equal(bracket17.winners.length, bracket32.winners.length); assert.equal(bracket17.losers.length, bracket32.losers.length); }); diff --git a/app/core/tournament/algorithms.ts b/app/core/tournament/algorithms.ts index f57c02923..bf26ae9ed 100644 --- a/app/core/tournament/algorithms.ts +++ b/app/core/tournament/algorithms.ts @@ -132,13 +132,18 @@ export function eliminationBracket( invariant(match1, "Unexpected no match1 in final match"); invariant(match2, "Unexpected no match2 in final match"); - // Add final match - bracket.winners.push( - createMatch({ - match1, - match2, - }) - ); + // Add final match and bracket reset + const grandFinals = createMatch({ + match1, + match2, + }); + bracket.winners.push(grandFinals); + + const bracketReset = createMatch({ + match1: grandFinals, + match2: grandFinals, + }); + bracket.winners.push(bracketReset); return bracket; } diff --git a/app/core/tournament/bracket.test.ts b/app/core/tournament/bracket.test.ts index 1b725724e..0c6c84e62 100644 --- a/app/core/tournament/bracket.test.ts +++ b/app/core/tournament/bracket.test.ts @@ -1,29 +1,48 @@ import { suite } from "uvu"; import * as assert from "uvu/assert"; import { eliminationBracket } from "./algorithms"; -import { countRounds } from "./bracket"; +import { countRounds, getRoundNames } from "./bracket"; const CountBracketRounds = suite("countRounds()"); +const RoundNames = suite("getRoundNames()"); CountBracketRounds("Counts bracket (DE - 38)", () => { const bracket = eliminationBracket(38, "DE"); const count = countRounds(bracket); - assert.equal(count, { winners: 7, losers: 9 }); + assert.equal(count, { winners: 8, losers: 9 }); }); CountBracketRounds("Counts bracket (DE - 10)", () => { const bracket = eliminationBracket(10, "DE"); const count = countRounds(bracket); - assert.equal(count, { winners: 5, losers: 5 }); + assert.equal(count, { winners: 6, losers: 5 }); }); CountBracketRounds("Counts bracket (DE - 16)", () => { const bracket = eliminationBracket(16, "DE"); const count = countRounds(bracket); - assert.equal(count, { winners: 5, losers: 6 }); + assert.equal(count, { winners: 6, losers: 6 }); +}); + +RoundNames("No bracket reset round for SE", () => { + const bracketSE = getRoundNames(eliminationBracket(16, "SE")); + const bracketDE = getRoundNames(eliminationBracket(16, "DE")); + + let hasBR = false; + for (const round of bracketDE.winners) { + if (round === "Bracket Reset") hasBR = true; + } + assert.ok(hasBR); + + hasBR = false; + for (const round of bracketSE.winners) { + if (round === "Bracket Reset") hasBR = true; + } + assert.not.ok(hasBR); }); CountBracketRounds.run(); +RoundNames.run(); diff --git a/app/core/tournament/bracket.ts b/app/core/tournament/bracket.ts index 2fd6481ad..a1814c0f2 100644 --- a/app/core/tournament/bracket.ts +++ b/app/core/tournament/bracket.ts @@ -54,6 +54,7 @@ export function participantCountToRoundsInfo({ const WINNERS_DEFAULT = 5; const WINNERS_FIRST_TWO_DEFAULT = 3; const GRAND_FINALS_DEFAULT = 7; +const GRAND_FINALS_RESET_DEFAULT = 7; const LOSERS_DEFAULT = 3; const LOSERS_FINALS_DEFAULT = 5; @@ -67,9 +68,13 @@ export function getRoundsDefaultBestOf( return { winners: new Array(winnersRoundCount).fill(null).map((_, i) => { + const isSE = losersRoundCount === 0; if (i === 0) return WINNERS_FIRST_TWO_DEFAULT; if (i === 1) return WINNERS_FIRST_TWO_DEFAULT; - if (i === winnersRoundCount - 1) return GRAND_FINALS_DEFAULT; + if (i === winnersRoundCount - 2 + Number(isSE)) { + return GRAND_FINALS_DEFAULT; + } + if (i === winnersRoundCount - 1) return GRAND_FINALS_RESET_DEFAULT; return WINNERS_DEFAULT; }), losers: new Array(losersRoundCount) @@ -80,15 +85,19 @@ export function getRoundsDefaultBestOf( }; } -function getRoundNames(bracket: Bracket): EliminationBracket { +export function getRoundNames(bracket: Bracket): EliminationBracket { const { winners: winnersRoundCount, losers: losersRoundCount } = countRounds(bracket); return { winners: new Array(winnersRoundCount).fill(null).map((_, i) => { - if (i === winnersRoundCount - 3) return "Winners' Semifinals"; - if (i === winnersRoundCount - 2) return "Winners' Finals"; - if (i === winnersRoundCount - 1) return "Grand Finals"; + const isSE = bracket.losers.length === 0; + if (i === winnersRoundCount - 4 + Number(isSE)) { + return "Winners' Semifinals"; + } + if (i === winnersRoundCount - 3 + Number(isSE)) return "Winners' Finals"; + if (i === winnersRoundCount - 2 + Number(isSE)) return "Grand Finals"; + if (!isSE && i === winnersRoundCount - 1) return "Bracket Reset"; return `Winners' Round ${i + 1}`; }), losers: new Array(losersRoundCount) @@ -100,7 +109,7 @@ function getRoundNames(bracket: Bracket): EliminationBracket { } export function countRounds(bracket: Bracket): EliminationBracket { - let winners = 1; + let winners = 2; for (let i = bracket.participantsWithByesCount; i > 1; i /= 2) { winners++;