Skip to content

Commit

Permalink
feat: show why the team is invited or striked out
Browse files Browse the repository at this point in the history
  • Loading branch information
shiftpsh committed Nov 24, 2024
1 parent 5cc97f0 commit b960fa2
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 23 deletions.
39 changes: 29 additions & 10 deletions app/2025/components/MergedScoreboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,22 @@ import {
TableBody,
TableContainer,
TableHead,
Tooltip,
Typo,
} from "@solved-ac/ui-react";
import { IconAlertCircle } from "@tabler/icons-react";
import { institutionRegionMap } from "../data/institution";
import {
ChampionshipTeamLike,
TeamRankInCombinedScoreboardStatus,
} from "../data/types";
import MergedScoreboardTooltip from "./MergedScoreboardTooltip";

const isTeamInvited = (status: TeamRankInCombinedScoreboardStatus) =>
status === TeamRankInCombinedScoreboardStatus.D2 ||
status === TeamRankInCombinedScoreboardStatus.D3_3 ||
status === TeamRankInCombinedScoreboardStatus.D5 ||
status === TeamRankInCombinedScoreboardStatus.D4_4;

interface Props {
teams: ChampionshipTeamLike[];
Expand All @@ -35,6 +44,7 @@ const RegionScoreboard = ({ teams }: Props) => {
<col style={{ minWidth: "6em" }} />
<col style={{ minWidth: "6em" }} />
<col />
<col style={{ minWidth: "2em" }} />
</colgroup>
<TableHead>
<Row>
Expand All @@ -43,6 +53,7 @@ const RegionScoreboard = ({ teams }: Props) => {
<Cell>Site</Cell>
<Cell>Region</Cell>
<Cell>Team</Cell>
<Cell>?</Cell>
</Row>
</TableHead>
<TableBody>
Expand All @@ -62,21 +73,20 @@ const RegionScoreboard = ({ teams }: Props) => {
<Typo tabular>{team.rank === -1 ? "-" : team.rank}</Typo>
</Cell>
<Cell style={{ textAlign: "right" }}>
<Typo
tabular
description={
team.status === TeamRankInCombinedScoreboardStatus.D2 ||
team.status === TeamRankInCombinedScoreboardStatus.D5
}
>
{team.status === TeamRankInCombinedScoreboardStatus.D2 ||
team.status === TeamRankInCombinedScoreboardStatus.D5
<Typo tabular description={isTeamInvited(team.status)}>
{isTeamInvited(team.status)
? "invited"
: team.assignedValue.toFixed(4)}
</Typo>
</Cell>
<Cell>
{team.fromSite} <Typo description>#{team.rankInSite}</Typo>
{team.fromSite}
{team.rankInSite !== 0 && (
<>
{" "}
<Typo description>#{team.rankInSite}</Typo>
</>
)}
</Cell>
<Cell>
<Region
Expand Down Expand Up @@ -113,6 +123,15 @@ const RegionScoreboard = ({ teams }: Props) => {
{shortenInstitutionName(team.institution)}
</Typo>
</Cell>
<Cell>
{team.status !== TeamRankInCombinedScoreboardStatus.NONE && (
<>
<Tooltip title={<MergedScoreboardTooltip team={team} />}>
<IconAlertCircle />
</Tooltip>
</>
)}
</Cell>
</Row>
);
})}
Expand Down
54 changes: 54 additions & 0 deletions app/2025/components/MergedScoreboardTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use client";

import { shortenInstitutionName } from "@/utils/institution";
import {
ChampionshipTeamLike,
TeamRankInCombinedScoreboardStatus,
} from "../data/types";
import { institutionRegionMap } from "../data/institution";

interface Props {
team: ChampionshipTeamLike;
}

const MergedScoreboardTooltip = ({ team }: Props) => {
const { status } = team;
if (status === TeamRankInCombinedScoreboardStatus.NONE) return null;
if (status === TeamRankInCombinedScoreboardStatus.D2) {
return (
<>
In top 2 teams of the South Pacific Independent Regional Contest (see
D2)
</>
);
}
if (status === TeamRankInCombinedScoreboardStatus.D3_3) {
return <>Won the regional st {team.fromSite} site (see D3 (3))</>;
}
if (status === TeamRankInCombinedScoreboardStatus.D4_2_1) {
return <>Second instance of a single team (see D4 (2))</>;
}
if (status === TeamRankInCombinedScoreboardStatus.D4_2_2) {
return (
<>
4th or later instance of {shortenInstitutionName(team.institution)} (see
D4 (2))
</>
);
}
if (status === TeamRankInCombinedScoreboardStatus.D4_3) {
return (
<>
Lowest value from region {institutionRegionMap.get(team.institution)}{" "}
(see D4 (3))
</>
);
}
if (status === TeamRankInCombinedScoreboardStatus.D5) {
return <>Wildcard team (see D5)</>;
}

return null;
};

export default MergedScoreboardTooltip;
41 changes: 29 additions & 12 deletions app/2025/data/championship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ export const combineRegions = (regions: Region[]) => {
fromSite: region.site,
rankInSite: t.recalculatedRank,
rankInRegion: -1,
assignedValue: (t.recalculatedRank - 1) / region.score,
assignedValue: Math.max(0, (t.recalculatedRank - 1) / region.score),
sortKey: (t.recalculatedRank - 1) / region.score,
status: TeamRankInCombinedScoreboardStatus.NONE,
status:
t.recalculatedRank === 0
? TeamRankInCombinedScoreboardStatus.D3_3
: TeamRankInCombinedScoreboardStatus.NONE,
} satisfies ChampionshipTeamLike)
)
)
Expand All @@ -72,24 +75,32 @@ export const combineRegions = (regions: Region[]) => {
instituteCountMap.set(team.institution, instituteCount + 1);
});

// D4-3: smallest value for each region
// D4-3: smallest value for each region (they are removed)
const regionsSet = new Set<string>();
teams.forEach((team) => {
if (team.status === TeamRankInCombinedScoreboardStatus.D4_2_1) return;
if (team.status === TeamRankInCombinedScoreboardStatus.D4_2_2) return;
if (
team.status === TeamRankInCombinedScoreboardStatus.D4_2_1 ||
team.status === TeamRankInCombinedScoreboardStatus.D4_2_2
) {
return;
}
if (team.status === TeamRankInCombinedScoreboardStatus.D3_3) {
team.sortKey = -1000;
return;
}
const teamRegion = institutionRegionMap.get(team.institution);
if (!teamRegion) return;
if (regionsSet.has(teamRegion)) return;
regionsSet.add(teamRegion);
team.status = TeamRankInCombinedScoreboardStatus.D4_3;
team.sortKey = 0;
team.sortKey = -500;
});

// D2: Two top teams of the South Pacific Independent Regional Contest
teams.push({
teamId: -1,
assignedValue: 0,
sortKey: 0,
sortKey: -1000,
status: TeamRankInCombinedScoreboardStatus.D2,
rank: null,
fromSite: "SP Finals",
Expand All @@ -101,7 +112,7 @@ export const combineRegions = (regions: Region[]) => {
teams.push({
teamId: -1,
assignedValue: 0,
sortKey: 0,
sortKey: -1000,
status: TeamRankInCombinedScoreboardStatus.D2,
rank: null,
fromSite: "SP Finals",
Expand All @@ -115,11 +126,11 @@ export const combineRegions = (regions: Region[]) => {
teams.push({
teamId: -1,
assignedValue: 0,
sortKey: 0,
sortKey: -1000,
status: TeamRankInCombinedScoreboardStatus.D5,
rank: null,
fromSite: "Wildcard",
rankInSite: 1,
rankInSite: 0,
rankInRegion: -1,
institution: "Wildcard",
teamName: "Wildcard",
Expand All @@ -133,18 +144,21 @@ export const combineRegions = (regions: Region[]) => {

let rank = 1;
let rowCount = 1;
let prvScore = 0;
let prvScore: number | null = null;
const regionRank = new Map<string, number>();
const regionRowCount = new Map<string, number>();
const regionPrvScore = new Map<string, number>();
teams.forEach((team) => {
if (
team.status === TeamRankInCombinedScoreboardStatus.NONE ||
team.status === TeamRankInCombinedScoreboardStatus.D3_3 ||
team.status === TeamRankInCombinedScoreboardStatus.D4_3 ||
team.status === TeamRankInCombinedScoreboardStatus.D2 ||
team.status === TeamRankInCombinedScoreboardStatus.D5
) {
if (team.sortKey !== prvScore) {
if (prvScore === null) {
prvScore = team.sortKey;
} else if (team.sortKey !== prvScore) {
rank += rowCount;
rowCount = 1;
prvScore = team.sortKey;
Expand All @@ -153,6 +167,9 @@ export const combineRegions = (regions: Region[]) => {
}
team.rank = rank;
}
if (team.status === TeamRankInCombinedScoreboardStatus.D3_3) {
team.rankInRegion = -1;
}

if (
team.status === TeamRankInCombinedScoreboardStatus.NONE ||
Expand Down
5 changes: 4 additions & 1 deletion app/2025/data/regionScoreboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ export const filterRegionalTeams = <T extends TeamInStandingsLike>(
institutionOccurCount.set(x.institution, institutionCount + 1);
});

let recaulculatedRank = 1;
// (D4-3): we have to remove #1s from each region,
// but since we want to include them in the displayed teams list,
// we'll just consider the rank as 0
let recaulculatedRank = 0;
ret.forEach((x) => {
if (x.status === TeamRankStatus.NONE) {
x.recalculatedRank = recaulculatedRank++;
Expand Down
2 changes: 2 additions & 0 deletions app/2025/data/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export type Region = RegionBase &
export enum TeamRankInCombinedScoreboardStatus {
NONE = "none",
D2 = "South Pacific Independent Regional Contest",
D3_3 = "winner universities",
D4_2_1 = "second instance of a single team",
D4_2_2 = "fourth or later instances of teams of a single university",
D4_3 = "smallest value from each Asia Pacific country",
Expand All @@ -114,6 +115,7 @@ export interface ChampionshipTeamLike {
assignedValue: number;
sortKey: number;
status: TeamRankInCombinedScoreboardStatus;
statusMetadata?: string;
rank: number | null;
fromSite: string;
rankInSite: number | null;
Expand Down

0 comments on commit b960fa2

Please sign in to comment.