From 1efa499461020ac175ba928a2fc15cbffab278bc Mon Sep 17 00:00:00 2001
From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com>
Date: Sun, 9 Jan 2022 23:33:54 +0200
Subject: [PATCH] Advance losers on report if BYE
---
.../tournament/DuringMatchActions.tsx | 4 +-
app/core/tournament/algorithms.ts | 33 ++++++++-----
app/services/tournament.ts | 49 +++++++++++++++----
app/utils/hooks.ts | 8 +--
app/validators/user.ts | 24 +++++----
5 files changed, 80 insertions(+), 38 deletions(-)
diff --git a/app/components/tournament/DuringMatchActions.tsx b/app/components/tournament/DuringMatchActions.tsx
index a26b93414..1ccd5873c 100644
--- a/app/components/tournament/DuringMatchActions.tsx
+++ b/app/components/tournament/DuringMatchActions.tsx
@@ -89,8 +89,8 @@ export function DuringMatchActions({
)}
- {roundInfos.map((info) => (
-
{info}
+ {roundInfos.map((info, i) => (
+
{info}
))}
diff --git a/app/core/tournament/algorithms.ts b/app/core/tournament/algorithms.ts
index 4bdcf2115..7a95f88a9 100644
--- a/app/core/tournament/algorithms.ts
+++ b/app/core/tournament/algorithms.ts
@@ -56,11 +56,14 @@ export function eliminationBracket(
!(upperTeam === "BYE" && lowerTeam === "BYE"),
"Unexpected both teams in the first round are BYEs"
);
- const firstRoundMatch = createMatch({
- upperTeam,
- lowerTeam,
- side: "winners",
- });
+ const firstRoundMatch = createMatch(
+ {
+ upperTeam,
+ lowerTeam,
+ side: "winners",
+ },
+ upperTeam === "BYE" || lowerTeam === "BYE"
+ );
matchesWQueue.push(firstRoundMatch);
matchesLQueue.push(firstRoundMatch);
@@ -123,9 +126,13 @@ export function eliminationBracket(
invariant(match1, "Unexpected no match1 in losers bracket");
invariant(match2, "Unexpected no match2 in losers bracket");
- const losersMatch = createMatch({
- side: "losers",
- });
+ const losersMatch = createMatch(
+ {
+ side: "losers",
+ },
+ // If the first match already has a bye then this losers match will also be skipped
+ match1.lowerTeam === "BYE" || match1.upperTeam === "BYE"
+ );
match1[
match1.side === "winners"
@@ -169,11 +176,11 @@ export function eliminationBracket(
return bracket;
- // TODO: also need to make match number 0 if loser bye
- function createMatch(args: Omit): Match {
- const number = [args.lowerTeam, args.upperTeam].includes("BYE")
- ? 0
- : matchNumber++;
+ function createMatch(
+ args: Omit,
+ willBeSkipped?: boolean
+ ): Match {
+ const number = willBeSkipped ? 0 : matchNumber++;
return {
id: uuidv4(),
number,
diff --git a/app/services/tournament.ts b/app/services/tournament.ts
index fb8264e38..20816b7e5 100644
--- a/app/services/tournament.ts
+++ b/app/services/tournament.ts
@@ -672,11 +672,14 @@ function resolveNewOrder({
newMatchId,
}: {
bracket: NonNullable;
- oldMatch: NonNullable;
+ oldMatch: { id: string };
newMatchId: string;
}): TeamOrder {
const allMatches = bracket.rounds.flat().flatMap((round) => {
- return round.matches;
+ return round.matches.map((match) => ({
+ ...match,
+ isWinners: round.position > 0,
+ }));
});
const newMatch = allMatches.find((m) => m.id === newMatchId);
@@ -688,7 +691,19 @@ function resolveNewOrder({
newMatchId
)
)
- .sort((a, b) => a.position - b.position);
+ .sort((a, b) => {
+ // first let's put teams from winners above teams from losers
+ // this might come to question if losers match is bye (so position 0)
+ // and would thus be above the winners bracket match if not for
+ // this condition
+ if (a.isWinners !== b.isWinners) {
+ return Number(b.isWinners) - Number(a.isWinners);
+ }
+
+ // otherwise if match number is smaller it
+ // should mean the match is above the other match.
+ return a.position - b.position;
+ });
invariant(
matchesThatLeadToNewMatch.length === 2,
`matchesThatLeadToNewMatch length was unexpected: ${matchesThatLeadToNewMatch.length}`
@@ -698,10 +713,6 @@ function resolveNewOrder({
"oldMatch not among matchesThatLeadToNewMatch"
);
- // if match number is smaller it should mean the match is above
- // the other match. thanks to sorting above 0 index should have
- // the smaller match number. Winner's bracket match should
- // always have the smaller number compared to loser's bracket match
if (matchesThatLeadToNewMatch[0].id === oldMatch.id) return "UPPER";
return "LOWER";
}
@@ -741,9 +752,29 @@ function newParticipantsForMatches({
}),
teamId: loserTeam.teamId,
});
- }
- // if match number === 0 let's advance
+ const losersMatch = bracket.rounds
+ .flatMap((round) => round.matches)
+ .find(({ id }) => id === match.loserDestinationMatchId);
+ invariant(losersMatch, "losersMatch undefined");
+
+ // if the match will have a BYE then we need to generate one more participant
+ if (losersMatch.position === 0) {
+ invariant(
+ losersMatch.winnerDestinationMatchId,
+ "losersMatch.winnerDestinationMatchId undefined"
+ );
+ result.push({
+ matchId: losersMatch.winnerDestinationMatchId,
+ order: resolveNewOrder({
+ bracket,
+ oldMatch: losersMatch,
+ newMatchId: losersMatch.winnerDestinationMatchId,
+ }),
+ teamId: loserTeam.teamId,
+ });
+ }
+ }
return result;
}
diff --git a/app/utils/hooks.ts b/app/utils/hooks.ts
index 003234e4f..f9f3b2e60 100644
--- a/app/utils/hooks.ts
+++ b/app/utils/hooks.ts
@@ -6,15 +6,15 @@ import { LoggedInUserSchema } from "~/validators/user";
export const useUser = () => {
const [root] = useMatches();
- const { user } = LoggedInUserSchema.parse(root.data);
- return user;
+ const parsed = LoggedInUserSchema.parse(root.data);
+ return parsed?.user;
};
export const useBaseURL = () => {
const [root] = useMatches();
- const { baseURL } = z.object({ baseURL: z.string() }).parse(root.data);
- return baseURL;
+ const parsed = z.object({ baseURL: z.string() }).nullish().parse(root.data);
+ return parsed?.baseURL;
};
// TODO: fix causes memory leak
diff --git a/app/validators/user.ts b/app/validators/user.ts
index 4fef82888..aeeee1a35 100644
--- a/app/validators/user.ts
+++ b/app/validators/user.ts
@@ -1,12 +1,16 @@
import { z } from "zod";
-export type LoggedInUser = z.infer["user"];
-export const LoggedInUserSchema = z.object({
- user: z
- .object({
- id: z.string(),
- discordId: z.string(),
- discordAvatar: z.string().nullable(),
- })
- .nullish(),
-});
+export type LoggedInUser = NonNullable<
+ z.infer
+>["user"];
+export const LoggedInUserSchema = z
+ .object({
+ user: z
+ .object({
+ id: z.string(),
+ discordId: z.string(),
+ discordAvatar: z.string().nullable(),
+ })
+ .nullish(),
+ })
+ .nullish();