diff --git a/src/parsers/parsers.ts b/src/parsers/parsers.ts index 7e9e7de9..76a9d0db 100644 --- a/src/parsers/parsers.ts +++ b/src/parsers/parsers.ts @@ -47,6 +47,7 @@ import { AlgoZenithProblemParser } from './problem/AlgoZenithProblemParser'; import { AnarchyGolfProblemParser } from './problem/AnarchyGolfProblemParser'; import { AtCoderProblemParser } from './problem/AtCoderProblemParser'; import { BaekjoonOnlineJudgeProblemParser } from './problem/BaekjoonOnlineJudgeProblemParser'; +import { BAPSOJProblemParser } from './problem/BAPSOJProblemParser'; import { BeecrowdProblemParser } from './problem/BeecrowdProblemParser'; import { BloombergCodeConProblemParser } from './problem/BloombergCodeConProblemParser'; import { BUCTOJProblemParser } from './problem/BUCTOJProblemParser'; @@ -142,6 +143,8 @@ export const parsers: Parser[] = [ new BaekjoonOnlineJudgeProblemParser(), new BaekjoonOnlineJudgeContestParser(), + new BAPSOJProblemParser(), + new BeecrowdProblemParser(), new BeecrowdContestParser(), diff --git a/src/parsers/problem/BAPSOJProblemParser.ts b/src/parsers/problem/BAPSOJProblemParser.ts new file mode 100644 index 00000000..08269d78 --- /dev/null +++ b/src/parsers/problem/BAPSOJProblemParser.ts @@ -0,0 +1,122 @@ +import { Sendable } from '../../models/Sendable'; +import { TaskBuilder } from '../../models/TaskBuilder'; +import { Parser } from '../Parser'; + +/* eslint-disable @typescript-eslint/naming-convention */ +interface BAPSOJContestInfo { + id: number; + problem_set: { + id: number; + problem_id: number; + slug: string; + title: string; + is_visible: boolean; + submission_meta: { + unique_users_accepted: number; + unique_users_tried: number; + user_tried: number; + user_accepted: number; + has_user_accepted: boolean; + }; + problem_order_character: string; + problem_order: number; + }[]; + permissions: string[]; + role: string; + created_at: string; + updated_at: string; + slug: string; + title: string; + description: string; + contest_type: string; + standing_type: string; + starts_at: string; + ends_at: string; + duration: number; + contest_visibility: string; + is_frozen: boolean; + problem_point: string; + created_by: string; +} + +interface BAPSOJProblemInfo { + id: number; + created_by: string; + attachments: any[]; + problem_set: { + id: number; + created_at: string; + updated_at: string; + sample_input: string; + sample_output: string; + title: string; + problem: number; + }; + input_output_samples: { + id: number; + order_character: string; + created_at: string; + updated_at: string; + sample_input: string; + sample_output: string; + problem_order: number; + contest: number; + problem: number; + }[]; + created_at: string; + updated_at: string; + slug: string; + title: string; + description: string; + input_description: string; + output_description: string; + constraints: null; + note: string; + problem_type: string; + time_limit: number; + memory_limit: number; + cpu_limit: number; + output_limit: number; + source_limit: number; + exec_limit: number; + is_visible: boolean; + tags: string[] | null; +} +/* eslint-enable @typescript-eslint/naming-convention */ + +export class BAPSOJProblemParser extends Parser { + public getMatchPatterns(): string[] { + return ['http://bapsoj.org/contests/*/problems/*', 'https://bapsoj.org/contests/*/problems/*']; + } + + private async getProblemInfo(contest: string, problem: string): Promise { + const contestInfoAPIResponse = await this.fetch( + `https://api.bapsoj.org/api/judge/contests/${contest}/?format=json`, + { credentials: 'omit' }, + ); + const contestInfo = JSON.parse(contestInfoAPIResponse) as BAPSOJContestInfo; + const problemId = contestInfo.problem_set.find(p => p.problem_order_character === problem).problem_id; + const problemInfoAPIResponse = await this.fetch( + `https://api.bapsoj.org/api/judge/problems/${problemId}/?format=json`, + { credentials: 'omit' }, + ); + const problemInfo = JSON.parse(problemInfoAPIResponse) as BAPSOJProblemInfo; + return problemInfo; + } + + public async parse(url: string): Promise { + const task = new TaskBuilder('BAPS OJ').setUrl(url); + const [contest, , problem] = url.split('/').slice(-3); + const problemInfo = await this.getProblemInfo(contest, problem); + + task.setName(`${problem}. ${problemInfo.title}`); + task.setTimeLimit(problemInfo.time_limit); + task.setMemoryLimit(problemInfo.memory_limit); + + problemInfo.input_output_samples.forEach(sample => { + task.addTest(sample.sample_input, sample.sample_output); + }); + + return task.build(); + } +}