Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/lib/types/contest_table_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ export const TESSOKU_SECTIONS = {
CHALLENGES: 'challenges',
} as const;

export const JOI_SECOND_QUAL_ROUND_SECTIONS = {
'2020Onwards': '2020Onwards',
from2006To2019: 'from2006To2019',
} as const;

export const JOI_FINAL_ROUND_SECTIONS = {
semiFinal: 'semiFinal',
} as const;

/**
* Represents a two-dimensional table of contest results.
*
Expand Down
133 changes: 133 additions & 0 deletions src/lib/utils/contest_table_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
type ContestTableDisplayConfig,
type ProviderKey,
TESSOKU_SECTIONS,
JOI_SECOND_QUAL_ROUND_SECTIONS,
JOI_FINAL_ROUND_SECTIONS,
} from '$lib/types/contest_table_provider';
import { ContestType } from '$lib/types/contest';
import type { TaskResults, TaskResult } from '$lib/types/task';
Expand Down Expand Up @@ -834,6 +836,126 @@ export class JOIFirstQualRoundProvider extends ContestTableProviderBase {
}
}

const regexForJoiSecondQualRound = /^(joi)(\d{4})(yo2)$/i;

export class JOISecondQualRound2020OnwardsProvider extends ContestTableProviderBase {
constructor(contestType: ContestType) {
super(contestType, JOI_SECOND_QUAL_ROUND_SECTIONS['2020Onwards']);
}

protected setFilterCondition(): (taskResult: TaskResult) => boolean {
return (taskResult: TaskResult) => {
if (classifyContest(taskResult.contest_id) !== this.contestType) {
return false;
}

return regexForJoiSecondQualRound.test(taskResult.contest_id);
};
}

getMetadata(): ContestTableMetaData {
return {
title: 'JOI 二次予選',
abbreviationName: 'joiSecondQualRound2020Onwards',
};
}

getDisplayConfig(): ContestTableDisplayConfig {
return {
isShownHeader: true,
isShownRoundLabel: true,
isShownTaskIndex: false,
tableBodyCellsWidth: 'w-1/2 xs:w-1/3 sm:w-1/4 md:w-1/5 px-1 py-1',
roundLabelWidth: 'xl:w-28',
};
}

getContestRoundLabel(contestId: string): string {
const contestNameLabel = getContestNameLabel(contestId);
return contestNameLabel.replace('JOI 二次予選 ', '');
}
}

const regexForJoiQualRound = /^(joi)(\d{4})(yo)$/i;

export class JOIQualRoundFrom2006To2019Provider extends ContestTableProviderBase {
constructor(contestType: ContestType) {
super(contestType, JOI_SECOND_QUAL_ROUND_SECTIONS.from2006To2019);
}

protected setFilterCondition(): (taskResult: TaskResult) => boolean {
return (taskResult: TaskResult) => {
if (classifyContest(taskResult.contest_id) !== this.contestType) {
return false;
}

return regexForJoiQualRound.test(taskResult.contest_id);
};
}

getMetadata(): ContestTableMetaData {
return {
title: 'JOI 予選',
abbreviationName: 'joiQualRoundFrom2006To2019',
};
}

getDisplayConfig(): ContestTableDisplayConfig {
return {
isShownHeader: true,
isShownRoundLabel: true,
isShownTaskIndex: false,
tableBodyCellsWidth: 'w-1/2 xs:w-1/3 sm:w-1/4 md:w-1/5 lg:w-1/6 px-1 py-1',
roundLabelWidth: 'xl:w-28',
};
}

getContestRoundLabel(contestId: string): string {
const contestNameLabel = getContestNameLabel(contestId);
return contestNameLabel.replace('JOI 予選 ', '');
}
}

const regexForJoiSemiFinalRound = /^(joi)(\d{4})(ho)$/i;

export class JOISemiFinalRoundProvider extends ContestTableProviderBase {
constructor(contestType: ContestType) {
super(contestType, JOI_FINAL_ROUND_SECTIONS.semiFinal);
}

protected setFilterCondition(): (taskResult: TaskResult) => boolean {
return (taskResult: TaskResult) => {
if (classifyContest(taskResult.contest_id) !== this.contestType) {
return false;
}

return regexForJoiSemiFinalRound.test(taskResult.contest_id);
};
}

getMetadata(): ContestTableMetaData {
return {
title: 'JOI 本選',
abbreviationName: 'joiSemiFinalRound',
};
}

getDisplayConfig(): ContestTableDisplayConfig {
return {
isShownHeader: true,
isShownRoundLabel: true,
isShownTaskIndex: false,
tableBodyCellsWidth: 'w-1/2 xs:w-1/3 sm:w-1/4 md:w-1/5 px-1 py-1',
roundLabelWidth: 'xl:w-28',
};
}

getContestRoundLabel(contestId: string): string {
const contestNameLabel = getContestNameLabel(contestId);
return contestNameLabel.replace('JOI 本選 ', '');
}
}

/**
* A class that manages individual provider groups
* Manages multiple ContestTableProviders as a single group,
Expand Down Expand Up @@ -1104,6 +1226,16 @@ export const prepareContestProviderPresets = () => {
buttonLabel: 'JOI 一次予選',
ariaLabel: 'Filter JOI First Qualifying Round',
}).addProvider(new JOIFirstQualRoundProvider(ContestType.JOI)),

JOISecondQualAndSemiFinalRound: () =>
new ContestTableProviderGroup(`JOI 二次予選・予選・本選`, {
buttonLabel: 'JOI 二次予選・予選・本選',
ariaLabel: 'Filter JOI Second Qual Round',
}).addProviders(
new JOISecondQualRound2020OnwardsProvider(ContestType.JOI),
new JOIQualRoundFrom2006To2019Provider(ContestType.JOI),
new JOISemiFinalRoundProvider(ContestType.JOI),
),
};
};

Expand All @@ -1125,6 +1257,7 @@ export const contestTableProviderGroups = {
dps: prepareContestProviderPresets().dps(), // Dynamic Programming (DP) Contests
aclPractice: prepareContestProviderPresets().AclPractice(),
joiFirstQualRound: prepareContestProviderPresets().JOIFirstQualRound(),
joiSecondQualAndSemiFinalRound: prepareContestProviderPresets().JOISecondQualAndSemiFinalRound(),
};

export type ContestTableProviderGroups = keyof typeof contestTableProviderGroups;
Loading
Loading