@xcpcio/core 0.58.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/contest.ts DELETED
@@ -1,351 +0,0 @@
1
- import type { BannerMode, Contest as IContest, Image, MedalPreset, StatusTimeDisplay } from "@xcpcio/types";
2
- import type { Awards } from "./award";
3
- import type { Problem, Problems } from "./problem";
4
-
5
- import { ContestState } from "@xcpcio/types";
6
- import { Award, MedalType } from "./award";
7
- import { ContestOptions, createContestOptions } from "./contest-options";
8
- import { Group } from "./group";
9
- import { createProblems, createProblemsByProblemIds } from "./problem";
10
- import { createDayJS, dayjs, getTimeDiff } from "./utils";
11
-
12
- export class Contest {
13
- id = "";
14
- name = "";
15
-
16
- startTime: dayjs.Dayjs;
17
- endTime: dayjs.Dayjs;
18
- freezeTime: dayjs.Dayjs;
19
-
20
- replayStartTime?: dayjs.Dayjs;
21
- replayEndTime?: dayjs.Dayjs;
22
- replayFreezeTime?: dayjs.Dayjs;
23
- replayNowTime?: dayjs.Dayjs;
24
- replayContestStartTimestamp?: number;
25
-
26
- totalDurationTimestamp: number;
27
- freezeDurationTimestamp: number;
28
- unFreezeDurationTimestamp: number;
29
-
30
- penalty: number;
31
-
32
- problems: Problems;
33
- problemsMap: Map<string, Problem>;
34
-
35
- statusTimeDisplay: StatusTimeDisplay;
36
-
37
- badge?: string;
38
- medal?: Record<string, Record<string, number>> | MedalPreset;
39
- awards?: Awards;
40
- organization?: string;
41
-
42
- group: Map<string, Group>;
43
- tag: Map<string, string>;
44
-
45
- logo?: Image;
46
- banner?: Image;
47
- bannerMode?: BannerMode;
48
- boardLink?: string;
49
-
50
- options: ContestOptions;
51
-
52
- constructor() {
53
- this.startTime = createDayJS();
54
- this.endTime = createDayJS();
55
- this.freezeTime = createDayJS();
56
-
57
- this.totalDurationTimestamp = 0;
58
- this.freezeDurationTimestamp = 0;
59
- this.unFreezeDurationTimestamp = 0;
60
-
61
- // 20 mins
62
- this.penalty = 20 * 60;
63
-
64
- this.problems = [];
65
- this.problemsMap = new Map<string, Problem>();
66
-
67
- this.statusTimeDisplay = {
68
- correct: true,
69
- incorrect: true,
70
- pending: true,
71
- };
72
-
73
- this.group = new Map<string, Group>();
74
- this.tag = new Map<string, string>();
75
-
76
- this.options = new ContestOptions();
77
- }
78
-
79
- getStartTime() {
80
- return this.replayStartTime ?? this.startTime;
81
- }
82
-
83
- getEndTime() {
84
- return this.replayEndTime ?? this.endTime;
85
- }
86
-
87
- getFreezeTime() {
88
- return this.replayFreezeTime ?? this.freezeTime;
89
- }
90
-
91
- getContestDuration(timeFormat = "HH:mm:ss"): string {
92
- return dayjs.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
93
- }
94
-
95
- getContestState(nowTime?: Date): ContestState {
96
- const now = createDayJS(nowTime);
97
-
98
- if (now.isBefore(this.getStartTime())) {
99
- return ContestState.PENDING;
100
- }
101
-
102
- if (now.isSameOrAfter(this.getEndTime())) {
103
- return ContestState.FINISHED;
104
- }
105
-
106
- if (now.isSameOrAfter(this.getFreezeTime())) {
107
- return ContestState.FROZEN;
108
- }
109
-
110
- return ContestState.RUNNING;
111
- }
112
-
113
- getContestPendingTime(nowTime?: Date): string {
114
- let baseTime = createDayJS(nowTime);
115
- if (baseTime.isAfter(this.getStartTime())) {
116
- baseTime = this.getStartTime();
117
- }
118
-
119
- return getTimeDiff(Math.floor(dayjs.duration(this.getStartTime().diff(baseTime)).asSeconds()));
120
- }
121
-
122
- getContestElapsedTime(nowTime?: Date): string {
123
- let baseTime = createDayJS(nowTime);
124
- if (baseTime.isAfter(this.getEndTime())) {
125
- baseTime = this.getEndTime();
126
- }
127
-
128
- if (baseTime.isBefore(this.getStartTime())) {
129
- baseTime = this.getStartTime();
130
- }
131
-
132
- return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.getStartTime())).asSeconds()));
133
- }
134
-
135
- getContestRemainingTime(nowTime?: Date): string {
136
- let baseTime = createDayJS(nowTime);
137
- if (baseTime.isAfter(this.getEndTime())) {
138
- baseTime = this.getEndTime();
139
- }
140
-
141
- if (baseTime.isBefore(this.getStartTime())) {
142
- baseTime = this.getStartTime();
143
- }
144
-
145
- return getTimeDiff(Math.floor(dayjs.duration(this.getEndTime().diff(baseTime)).asSeconds()));
146
- }
147
-
148
- getContestProgressRatio(nowTime?: Date): number {
149
- const baseTime = createDayJS(nowTime);
150
-
151
- if (this.getStartTime().isSameOrAfter(baseTime)) {
152
- return 0;
153
- }
154
-
155
- if (this.getEndTime().isSameOrBefore(baseTime)) {
156
- return 100;
157
- }
158
-
159
- const total = this.getEndTime().diff(this.getStartTime(), "s");
160
- const pass = baseTime.diff(this.getStartTime(), "s");
161
-
162
- return Math.round((pass * 100) / total);
163
- }
164
-
165
- isEnableAwards(group: string): boolean {
166
- if (!this.awards) {
167
- return false;
168
- }
169
-
170
- if (!this.awards.has(group)) {
171
- return false;
172
- }
173
-
174
- return true;
175
- }
176
-
177
- resetReplayTime() {
178
- this.replayStartTime = undefined;
179
- this.replayEndTime = undefined;
180
- this.replayFreezeTime = undefined;
181
- this.replayNowTime = undefined;
182
- this.replayContestStartTimestamp = undefined;
183
- }
184
-
185
- setReplayTime(replayStartTimestamp: number) {
186
- if (replayStartTimestamp === 0) {
187
- this.resetReplayTime();
188
- return;
189
- }
190
-
191
- const replayStartTime = createDayJS(replayStartTimestamp);
192
- const diff = replayStartTime.diff(this.startTime, "s");
193
-
194
- this.replayStartTime = this.startTime.add(diff, "s");
195
- this.replayEndTime = this.endTime.add(diff, "s");
196
- this.replayFreezeTime = this.freezeTime.add(diff, "s");
197
- this.replayNowTime = createDayJS();
198
- this.replayContestStartTimestamp = this.replayNowTime.diff(this.replayStartTime, "s");
199
- }
200
- }
201
-
202
- export function createContest(contestJSON: IContest): Contest {
203
- const c = new Contest();
204
-
205
- c.name = contestJSON.contest_name;
206
-
207
- c.startTime = createDayJS(contestJSON.start_time);
208
- c.endTime = createDayJS(contestJSON.end_time);
209
-
210
- c.totalDurationTimestamp = c.endTime.unix() - c.startTime.unix();
211
-
212
- {
213
- // default value
214
- c.freezeTime = c.endTime;
215
- c.freezeDurationTimestamp = 0;
216
-
217
- if (contestJSON.frozen_time !== undefined && contestJSON.frozen_time != null) {
218
- const frozenTime = Number(contestJSON.frozen_time);
219
-
220
- c.freezeTime = createDayJS(c.endTime.unix() - frozenTime);
221
- c.freezeDurationTimestamp = frozenTime;
222
- }
223
-
224
- if (contestJSON.freeze_time !== undefined && contestJSON.freeze_time !== null) {
225
- c.freezeTime = createDayJS(contestJSON.freeze_time);
226
- c.freezeDurationTimestamp = c.endTime.unix() - c.freezeTime.unix();
227
- }
228
-
229
- c.unFreezeDurationTimestamp = c.totalDurationTimestamp - c.freezeDurationTimestamp;
230
- }
231
-
232
- c.penalty = contestJSON.penalty;
233
-
234
- {
235
- if (contestJSON.problem_id !== undefined && contestJSON.problem_id !== null) {
236
- c.problems = createProblemsByProblemIds(contestJSON.problem_id, contestJSON.balloon_color);
237
- }
238
-
239
- if (contestJSON.problems !== undefined && contestJSON.problems !== null) {
240
- c.problems = createProblems(contestJSON.problems);
241
- }
242
-
243
- c.problemsMap = new Map(c.problems.map(p => [p.id, p]));
244
- }
245
-
246
- if (contestJSON.status_time_display !== undefined && contestJSON.status_time_display !== null) {
247
- c.statusTimeDisplay = {
248
- correct: Boolean(contestJSON.status_time_display.correct ?? false),
249
- incorrect: Boolean(contestJSON.status_time_display.incorrect ?? false),
250
- pending: Boolean(contestJSON.status_time_display.pending ?? false),
251
- };
252
- }
253
-
254
- c.badge = contestJSON.badge;
255
- c.medal = contestJSON.medal;
256
-
257
- (() => {
258
- if (contestJSON.medal === undefined || contestJSON.medal === null) {
259
- return;
260
- }
261
-
262
- c.awards = new Map<string, Award[]>();
263
-
264
- if (typeof contestJSON.medal === "string") {
265
- // eslint-disable-next-line no-empty
266
- {}
267
- } else {
268
- for (const k in contestJSON.medal) {
269
- const v = contestJSON.medal[k];
270
-
271
- {
272
- const award: Award[] = [];
273
-
274
- let rank = 1;
275
- const work = (key: string, medalType: MedalType) => {
276
- if (Object.keys(v).includes(key)) {
277
- const a = new Award();
278
- a.medalType = medalType;
279
- a.minRank = rank;
280
- rank += Number(v[key]);
281
- a.maxRank = rank - 1;
282
- award.push(a);
283
- }
284
- };
285
-
286
- work("gold", MedalType.GOLD);
287
- work("silver", MedalType.SILVER);
288
- work("bronze", MedalType.BRONZE);
289
-
290
- {
291
- const a = new Award();
292
- a.medalType = MedalType.HONORABLE;
293
- a.minRank = rank;
294
- a.maxRank = 0x3F3F3F3F;
295
- award.push(a);
296
- }
297
-
298
- c.awards.set(k, award);
299
- }
300
- }
301
- }
302
- })();
303
-
304
- c.organization = contestJSON.organization;
305
-
306
- {
307
- const g = new Group();
308
- g.names.set("en", "All");
309
- g.names.set("zh-CN", "所有队伍");
310
- g.isDefault = true;
311
-
312
- c.group.set("all", g);
313
- }
314
-
315
- for (const [k, v] of Object.entries(contestJSON?.group ?? {})) {
316
- let key = k;
317
-
318
- const g = new Group();
319
- g.names.set("zh-CN", v);
320
-
321
- if (k === "official") {
322
- g.names.set("en", "Official");
323
- }
324
-
325
- if (k === "unofficial") {
326
- g.names.set("en", "Unofficial");
327
- }
328
-
329
- if (k === "girl" || k === "girls") {
330
- g.names.set("en", "Girls");
331
- key = "girl";
332
- }
333
-
334
- c.group.set(key, g);
335
- }
336
-
337
- c.banner = contestJSON.banner;
338
- if (c.banner) {
339
- c.bannerMode = contestJSON.banner_mode ?? "ALL";
340
- }
341
-
342
- c.logo = contestJSON.logo;
343
- c.boardLink = contestJSON.board_link;
344
-
345
- if (contestJSON.options) {
346
- c.options = createContestOptions(contestJSON.options);
347
- }
348
-
349
- return c;
350
- }
351
- export { ContestOptions };
package/src/export/cf.ts DELETED
@@ -1,125 +0,0 @@
1
- import type { Rank } from "../rank";
2
-
3
- import { SubmissionStatus } from "@xcpcio/types";
4
-
5
- import {
6
- isAccepted,
7
- isNotCalculatedPenaltyStatus,
8
- isPending,
9
- } from "../submission-status";
10
-
11
- import dayjs from "../utils/dayjs";
12
-
13
- export class CodeforcesGymGhostDATConverter {
14
- constructor() {}
15
-
16
- public convert(rank: Rank): string {
17
- let res = "";
18
-
19
- res += `@contest "${rank.contest.name}"
20
- @contlen ${Math.floor(dayjs.duration(rank.contest.endTime.diff(rank.contest.startTime)).asMinutes())}
21
- @problems ${rank.contest.problems.length}
22
- @teams ${rank.teams.length + 100}
23
- @submissions ${rank.submissions.length}
24
- `;
25
-
26
- rank.contest.problems.forEach((p) => {
27
- res += `@p ${p.label},${p.label},20,0\n`;
28
- });
29
-
30
- let teamIndex = 1;
31
- const teamIdMap = new Map<string, number>();
32
- const submissionsIdMap = new Map<string, Map<string, number>>();
33
-
34
- rank.teams.forEach((team) => {
35
- let name = team.name;
36
-
37
- if (team.organization) {
38
- name = `${team.organization} - ${name}`;
39
- }
40
-
41
- if (team.members) {
42
- name = `${name} - ${team.membersToString}`;
43
- }
44
-
45
- res += `@t ${teamIndex},0,1,"${name}"\n`;
46
- teamIdMap.set(team.id, teamIndex);
47
- teamIndex++;
48
-
49
- {
50
- const mp = new Map<string, number>();
51
- rank.contest.problems.forEach((p) => {
52
- mp.set(p.id, 0);
53
- });
54
- submissionsIdMap.set(team.id, mp);
55
- }
56
- });
57
-
58
- for (let i = 0; i < 100; i++) {
59
- res += `@t ${teamIndex},0,1,"Пополнить команду"\n`;
60
- teamIndex++;
61
- }
62
-
63
- rank.getSubmissions().forEach((submission) => {
64
- const teamId = submission.teamId;
65
- const problemId = submission.problemId;
66
- const problem = rank.contest.problemsMap.get(problemId);
67
- const teamIndex = teamIdMap.get(teamId);
68
-
69
- if (!problem) {
70
- return;
71
- }
72
-
73
- if (!teamIndex) {
74
- return;
75
- }
76
-
77
- const status = this.submissionStatusToCodeforcesGymDatStatus(submission.status);
78
- submissionsIdMap.get(teamId)!.set(problemId, submissionsIdMap.get(teamId)!.get(problemId)! + 1);
79
-
80
- res += `@s ${teamIndex},${problem.label},${submissionsIdMap.get(teamId)?.get(problemId)},${submission.timestampToSecond},${status}\n`;
81
- });
82
-
83
- return res;
84
- }
85
-
86
- private submissionStatusToCodeforcesGymDatStatus(status: SubmissionStatus): string {
87
- if (isAccepted(status)) {
88
- return "OK";
89
- }
90
-
91
- if (status === SubmissionStatus.WRONG_ANSWER) {
92
- return "WA";
93
- }
94
-
95
- if (status === SubmissionStatus.TIME_LIMIT_EXCEEDED) {
96
- return "TL";
97
- }
98
-
99
- if (status === SubmissionStatus.MEMORY_LIMIT_EXCEEDED) {
100
- return "ML";
101
- }
102
-
103
- if (status === SubmissionStatus.OUTPUT_LIMIT_EXCEEDED) {
104
- return "IL";
105
- }
106
-
107
- if (status === SubmissionStatus.PRESENTATION_ERROR) {
108
- return "PE";
109
- }
110
-
111
- if (status === SubmissionStatus.RUNTIME_ERROR) {
112
- return "RT";
113
- }
114
-
115
- if (status === SubmissionStatus.COMPILATION_ERROR || isNotCalculatedPenaltyStatus(status)) {
116
- return "CE";
117
- }
118
-
119
- if (isPending(status)) {
120
- return "PD";
121
- }
122
-
123
- return "RJ";
124
- }
125
- }