Skip to content

Commit

Permalink
:docs: Improve PAST labels (#1526)
Browse files Browse the repository at this point in the history
  • Loading branch information
KATO-Hiro committed Nov 27, 2024
1 parent 8e33c51 commit 9f26fa4
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 48 deletions.
69 changes: 69 additions & 0 deletions src/lib/utils/contest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ export const getContestNameLabel = (contestId: string) => {
return 'TDPC';
}

if (contestId.startsWith('past')) {
return getPastContestLabel(PAST_TRANSLATIONS, contestId);
}

if (contestId === 'practice2') {
return 'ACL Practice';
}
Expand Down Expand Up @@ -338,6 +342,71 @@ export const getContestNameLabel = (contestId: string) => {
return contestId.toUpperCase();
};

/**
* A mapping of contest dates to their respective Japanese translations.
* Each key represents a date in the format 'YYYYMM', and the corresponding value
* is the Japanese translation indicating the contest number.
*
* Note:
* After the 15th contest, the URL includes the number of times the contest has been held
*
* See:
* https://atcoder.jp/contests/archive?ratedType=0&category=50
*
* Example:
* - '201912': ' 第 1 回' (The 1st contest in December 2019)
* - '202303': ' 第 14 回' (The 14th contest in March 2023)
*/
export const PAST_TRANSLATIONS = {
'201912': ' 第 1 回',
'202004': ' 第 2 回',
'202005': ' 第 3 回',
'202010': ' 第 4 回',
'202012': ' 第 5 回',
'202104': ' 第 6 回',
'202107': ' 第 7 回',
'202109': ' 第 8 回',
'202112': ' 第 9 回',
'202203': ' 第 10 回',
'202206': ' 第 11 回',
'202209': ' 第 12 回',
'202212': ' 第 13 回',
'202303': ' 第 14 回',
};

/**
* A regular expression to match strings that representing the 15th or later PAST contests.
* The string should start with "past" followed by exactly two digits and end with "-open".
* The matching is case-insensitive.
*
* Examples:
* - "past15-open" (matches)
* - "past16-open" (matches)
* - "past99-open" (matches)
* - "past1-open" (does not match)
*/
const regexForPast = /^past(\d{2})-open$/i;

export function getPastContestLabel(
translations: Readonly<ContestLabelTranslations>,
contestId: string,
): string {
let label = contestId;

Object.entries(translations).forEach(([abbrEnglish, japanese]) => {
label = label.replace(abbrEnglish, japanese);
});

if (label == contestId) {
label = label.replace(regexForPast, (_, round) => {
return `PAST 第 ${round} 回-open`;
});
}

// Remove suffix
return label.replace('-open', '').toUpperCase();
}

/**
* Generates a formatted contest label for AtCoder University contests.
*
Expand Down
24 changes: 12 additions & 12 deletions src/test/lib/utils/contest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,18 +366,6 @@ describe('Contest', () => {
});
});

// TODO(#issue): Skipped until notational inconsistencies are resolved.
// Current issues:
// 1. Contest names use inconsistent formats (e.g., "past201912-open" vs "past17-open")
// 2. Need to standardize naming conventions across all contests
describe.skip('when contest_id contains past', () => {
TestCasesForContestNameLabel.past.forEach(({ name, value }) => {
runTests(`${name}`, [value], ({ contestId, expected }: TestCaseForContestNameLabel) => {
expect(getContestNameLabel(contestId)).toEqual(expected);
});
});
});

describe('when contest_id is practice2 (ACL practice)', () => {
TestCasesForContestNameLabel.aclPractice.forEach(({ name, value }) => {
runTests(`${name}`, [value], ({ contestId, expected }: TestCaseForContestNameLabel) => {
Expand Down Expand Up @@ -446,6 +434,18 @@ describe('Contest', () => {
});
});

describe('when contest_id contains past', () => {
TestCasesForContestNameAndTaskIndex.past.forEach(({ name, value }) => {
runTests(
`${name}`,
[value],
({ contestId, taskTableIndex, expected }: TestCaseForContestNameAndTaskIndex) => {
expect(addContestNameToTaskIndex(contestId, taskTableIndex)).toEqual(expected);
},
);
});
});

describe('when contest_id is tessoku-book', () => {
TestCasesForContestNameAndTaskIndex.tessokuBook.forEach(({ name, value }) => {
runTests(
Expand Down
66 changes: 66 additions & 0 deletions src/test/lib/utils/test_cases/contest_name_and_task_index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { createTestCase, zip } from '../../common/test_helpers';
import {
getPastContestLabel,
getAtCoderUniversityContestLabel,
getAojContestLabel,
PAST_TRANSLATIONS,
AOJ_COURSES,
} from '$lib/utils/contest';

Expand Down Expand Up @@ -81,6 +83,70 @@ export const typical90 = [
}),
];

const generatePastTestCases = (
contestIds: string[],
taskIndices: string[],
): { name: string; value: TestCaseForContestNameAndTaskIndex }[] => {
return zip(contestIds, taskIndices).map(([contestId, taskIndex]) => {
const testCase = createTestCaseForContestNameAndTaskIndex(`PAST, ${contestId} ${taskIndex}`)({
contestId: `${contestId}`,
taskTableIndex: `${taskIndex}`,
expected: `${getPastContestLabel(PAST_TRANSLATIONS, contestId)} - ${taskIndex}`,
});

return testCase;
});
};

const PAST_TEST_DATA = {
// 1st
'past201912-open': {
contestId: 'past201904',
tasks: ['A', 'B', 'C', 'M', 'N', 'O'],
},
// 2nd
'past202004-open': {
contestId: 'past202004-open',
tasks: ['A', 'B', 'C', 'M', 'N', 'O'],
},
// 3rd
'past202005-open': {
contestId: 'past202005-open',
tasks: ['A', 'B', 'C', 'M', 'N', 'O'],
},
// 9th
'past202112-open': {
contestId: 'past202203-open',
tasks: ['A', 'B', 'C', 'M', 'N', 'O'],
},
// 10th
'past202203-open': {
contestId: 'past202203-open',
tasks: ['A', 'B', 'C', 'M', 'N', 'O'],
},
// 14th
'past202303-open': {
contestId: 'past202303-open',
tasks: ['A', 'B', 'C', 'M', 'N', 'O'],
},
'past15-open': {
contestId: 'past15-open',
tasks: ['A', 'B', 'C', 'M', 'N', 'O'],
},
'past16-open': {
contestId: 'past16-open',
tasks: ['A', 'B', 'C', 'M', 'N', 'O'],
},
'past17-open': {
contestId: 'past17-open',
tasks: ['A', 'B', 'C', 'M', 'N', 'O'],
},
};

export const past = Object.entries(PAST_TEST_DATA).flatMap(([contestId, tasks]) =>
generatePastTestCases(Array(tasks.tasks.length).fill(contestId), tasks.tasks),
);

export const tessokuBook = [
createTestCaseForContestNameAndTaskIndex('Tessoku Book, Task A01')({
contestId: 'tessoku-book',
Expand Down
36 changes: 0 additions & 36 deletions src/test/lib/utils/test_cases/contest_name_labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,42 +21,6 @@ export const tdpc = [
}),
];

// Note: Not yet implemented, because notational distortion needs to be corrected for each contest.
export const past = [
createTestCaseForContestNameLabel('PAST 17th')({
contestId: 'past17-open',
expected: '',
}),
createTestCaseForContestNameLabel('PAST 16th')({
contestId: 'past16-open',
expected: '',
}),
createTestCaseForContestNameLabel('PAST 15th')({
contestId: 'past15-open',
expected: '',
}),
createTestCaseForContestNameLabel('PAST 14th')({
contestId: 'past202303-open',
expected: '',
}),
createTestCaseForContestNameLabel('PAST 13th')({
contestId: 'past202212-open',
expected: '',
}),
createTestCaseForContestNameLabel('PAST 3rd')({
contestId: 'past202005-open',
expected: '',
}),
createTestCaseForContestNameLabel('PAST 2nd')({
contestId: 'past202004-open',
expected: '',
}),
createTestCaseForContestNameLabel('PAST 1st')({
contestId: 'past201912-open',
expected: '',
}),
];

export const aclPractice = [
createTestCaseForContestNameLabel('ACL Practice')({
contestId: 'practice2',
Expand Down

0 comments on commit 9f26fa4

Please sign in to comment.