@xcpcio/core 0.13.0 → 0.15.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/dist/index.cjs +410 -223
- package/dist/index.d.ts +55 -38
- package/dist/index.mjs +394 -223
- package/package.json +4 -2
- package/src/award.ts +16 -5
- package/src/contest.ts +12 -0
- package/src/export/cf.ts +120 -0
- package/src/export/general-excel.ts +184 -0
- package/src/export/index.ts +2 -0
- package/src/index.ts +1 -1
- package/src/problem.ts +8 -0
- package/src/team.ts +2 -0
- package/src/export.ts +0 -116
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SubmissionStatus, ContestState } from '@xcpcio/types';
|
|
1
2
|
import dayjs from 'dayjs';
|
|
2
3
|
export { default as dayjs } from 'dayjs';
|
|
3
4
|
import duration from 'dayjs/plugin/duration';
|
|
@@ -8,30 +9,125 @@ import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
|
|
|
8
9
|
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
|
|
9
10
|
import minMax from 'dayjs/plugin/minMax';
|
|
10
11
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
11
|
-
import { ContestState, SubmissionStatus } from '@xcpcio/types';
|
|
12
12
|
import _ from 'lodash';
|
|
13
|
+
import * as XLSX from 'xlsx-js-style';
|
|
14
|
+
import stringWidth from 'string-width';
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
MedalType2[MedalType2["BRONZE"] = 3] = "BRONZE";
|
|
19
|
-
MedalType2[MedalType2["HONORABLE"] = 4] = "HONORABLE";
|
|
20
|
-
return MedalType2;
|
|
21
|
-
})(MedalType || {});
|
|
22
|
-
class Award {
|
|
23
|
-
constructor() {
|
|
24
|
-
this.medalType = 0 /* UNKNOWN */;
|
|
25
|
-
this.minRank = 0;
|
|
26
|
-
this.maxRank = 0;
|
|
16
|
+
function stringToSubmissionStatus(status) {
|
|
17
|
+
status = status.toUpperCase().replace(" ", "_");
|
|
18
|
+
if (["OK", "AC", SubmissionStatus.ACCEPTED.toString()].includes(status)) {
|
|
19
|
+
return SubmissionStatus.ACCEPTED;
|
|
27
20
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
function calcDict(attemptedNum, solvedNum) {
|
|
31
|
-
if (solvedNum === 0) {
|
|
32
|
-
return 0;
|
|
21
|
+
if ([SubmissionStatus.CORRECT.toString()].includes(status)) {
|
|
22
|
+
return SubmissionStatus.ACCEPTED;
|
|
33
23
|
}
|
|
34
|
-
|
|
24
|
+
if ([SubmissionStatus.PARTIALLY_CORRECT.toString()].includes(status)) {
|
|
25
|
+
return SubmissionStatus.PARTIALLY_CORRECT;
|
|
26
|
+
}
|
|
27
|
+
if (["WA", SubmissionStatus.WRONG_ANSWER.toString()].includes(status)) {
|
|
28
|
+
return SubmissionStatus.WRONG_ANSWER;
|
|
29
|
+
}
|
|
30
|
+
if (["RJ", "INCORRECT", SubmissionStatus.REJECTED.toString()].includes(status)) {
|
|
31
|
+
return SubmissionStatus.REJECTED;
|
|
32
|
+
}
|
|
33
|
+
if (["PD", SubmissionStatus.PENDING.toString()].includes(status)) {
|
|
34
|
+
return SubmissionStatus.PENDING;
|
|
35
|
+
}
|
|
36
|
+
if ([SubmissionStatus.WAITING.toString()].includes(status)) {
|
|
37
|
+
return SubmissionStatus.WAITING;
|
|
38
|
+
}
|
|
39
|
+
if ([SubmissionStatus.JUDGING.toString()].includes(status)) {
|
|
40
|
+
return SubmissionStatus.JUDGING;
|
|
41
|
+
}
|
|
42
|
+
if ([SubmissionStatus.FROZEN.toString()].includes(status)) {
|
|
43
|
+
return SubmissionStatus.FROZEN;
|
|
44
|
+
}
|
|
45
|
+
if (["CE", SubmissionStatus.COMPILATION_ERROR.toString()].includes(status)) {
|
|
46
|
+
return SubmissionStatus.COMPILATION_ERROR;
|
|
47
|
+
}
|
|
48
|
+
if (["PE", SubmissionStatus.PRESENTATION_ERROR.toString()].includes(status)) {
|
|
49
|
+
return SubmissionStatus.PRESENTATION_ERROR;
|
|
50
|
+
}
|
|
51
|
+
if (["TL", "TLE", SubmissionStatus.TIME_LIMIT_EXCEEDED.toString()].includes(status)) {
|
|
52
|
+
return SubmissionStatus.TIME_LIMIT_EXCEEDED;
|
|
53
|
+
}
|
|
54
|
+
if (["ML", "MLE", SubmissionStatus.MEMORY_LIMIT_EXCEEDED.toString()].includes(status)) {
|
|
55
|
+
return SubmissionStatus.MEMORY_LIMIT_EXCEEDED;
|
|
56
|
+
}
|
|
57
|
+
if (["OL", "OLE", SubmissionStatus.OUTPUT_LIMIT_EXCEEDED.toString()].includes(status)) {
|
|
58
|
+
return SubmissionStatus.OUTPUT_LIMIT_EXCEEDED;
|
|
59
|
+
}
|
|
60
|
+
if (["IL", "ILE", SubmissionStatus.IDLENESS_LIMIT_EXCEEDED.toString()].includes(status)) {
|
|
61
|
+
return SubmissionStatus.IDLENESS_LIMIT_EXCEEDED;
|
|
62
|
+
}
|
|
63
|
+
if (["RT", "RE", "RTE", SubmissionStatus.RUNTIME_ERROR.toString()].includes(status)) {
|
|
64
|
+
return SubmissionStatus.RUNTIME_ERROR;
|
|
65
|
+
}
|
|
66
|
+
if (["JE", SubmissionStatus.JUDGEMENT_FAILED.toString()].includes(status)) {
|
|
67
|
+
return SubmissionStatus.JUDGEMENT_FAILED;
|
|
68
|
+
}
|
|
69
|
+
if (["SE", SubmissionStatus.SYSTEM_ERROR.toString()].includes(status)) {
|
|
70
|
+
return SubmissionStatus.SYSTEM_ERROR;
|
|
71
|
+
}
|
|
72
|
+
if ([SubmissionStatus.HACKED.toString()].includes(status)) {
|
|
73
|
+
return SubmissionStatus.HACKED;
|
|
74
|
+
}
|
|
75
|
+
if ([SubmissionStatus.CONFIGURATION_ERROR.toString()].includes(status)) {
|
|
76
|
+
return SubmissionStatus.CONFIGURATION_ERROR;
|
|
77
|
+
}
|
|
78
|
+
if ([SubmissionStatus.CANCELED.toString()].includes(status)) {
|
|
79
|
+
return SubmissionStatus.CANCELED;
|
|
80
|
+
}
|
|
81
|
+
if ([SubmissionStatus.SKIPPED.toString()].includes(status)) {
|
|
82
|
+
return SubmissionStatus.SKIPPED;
|
|
83
|
+
}
|
|
84
|
+
if ([SubmissionStatus.SECURITY_VIOLATED.toString()].includes(status)) {
|
|
85
|
+
return SubmissionStatus.SECURITY_VIOLATED;
|
|
86
|
+
}
|
|
87
|
+
if ([SubmissionStatus.DENIAL_OF_JUDGEMENT.toString()].includes(status)) {
|
|
88
|
+
return SubmissionStatus.DENIAL_OF_JUDGEMENT;
|
|
89
|
+
}
|
|
90
|
+
return SubmissionStatus.UNKNOWN;
|
|
91
|
+
}
|
|
92
|
+
function isAccepted(status) {
|
|
93
|
+
const acceptedArray = [SubmissionStatus.ACCEPTED, SubmissionStatus.CORRECT];
|
|
94
|
+
return acceptedArray.includes(status);
|
|
95
|
+
}
|
|
96
|
+
function isRejected(status) {
|
|
97
|
+
const rejectArray = [
|
|
98
|
+
SubmissionStatus.RUNTIME_ERROR,
|
|
99
|
+
SubmissionStatus.TIME_LIMIT_EXCEEDED,
|
|
100
|
+
SubmissionStatus.MEMORY_LIMIT_EXCEEDED,
|
|
101
|
+
SubmissionStatus.OUTPUT_LIMIT_EXCEEDED,
|
|
102
|
+
SubmissionStatus.IDLENESS_LIMIT_EXCEEDED,
|
|
103
|
+
SubmissionStatus.WRONG_ANSWER,
|
|
104
|
+
SubmissionStatus.REJECTED,
|
|
105
|
+
SubmissionStatus.JUDGEMENT_FAILED,
|
|
106
|
+
SubmissionStatus.HACKED
|
|
107
|
+
];
|
|
108
|
+
return rejectArray.includes(status);
|
|
109
|
+
}
|
|
110
|
+
function isPending(status) {
|
|
111
|
+
const pendingArray = [
|
|
112
|
+
SubmissionStatus.PENDING,
|
|
113
|
+
SubmissionStatus.WAITING,
|
|
114
|
+
SubmissionStatus.JUDGING,
|
|
115
|
+
SubmissionStatus.FROZEN
|
|
116
|
+
];
|
|
117
|
+
return pendingArray.includes(status);
|
|
118
|
+
}
|
|
119
|
+
function isNotCalculatedPenaltyStatus(status) {
|
|
120
|
+
const isNotCalculatedPenaltyArray = [
|
|
121
|
+
SubmissionStatus.COMPILATION_ERROR,
|
|
122
|
+
SubmissionStatus.PRESENTATION_ERROR,
|
|
123
|
+
SubmissionStatus.CONFIGURATION_ERROR,
|
|
124
|
+
SubmissionStatus.SYSTEM_ERROR,
|
|
125
|
+
SubmissionStatus.CANCELED,
|
|
126
|
+
SubmissionStatus.SKIPPED,
|
|
127
|
+
SubmissionStatus.UNKNOWN,
|
|
128
|
+
SubmissionStatus.UNDEFINED
|
|
129
|
+
];
|
|
130
|
+
return isNotCalculatedPenaltyArray.includes(status);
|
|
35
131
|
}
|
|
36
132
|
|
|
37
133
|
dayjs.extend(duration);
|
|
@@ -70,6 +166,267 @@ function getTimeDiff(seconds) {
|
|
|
70
166
|
return [two(h), two(m), two(s)].join(":");
|
|
71
167
|
}
|
|
72
168
|
|
|
169
|
+
class CodeforcesGymGhostDATConverter {
|
|
170
|
+
constructor() {
|
|
171
|
+
}
|
|
172
|
+
convert(rank) {
|
|
173
|
+
let res = "";
|
|
174
|
+
res += `@contest "${rank.contest.name}"
|
|
175
|
+
@contlen ${Math.floor(dayjs.duration(rank.contest.endTime.diff(rank.contest.startTime)).asMinutes())}
|
|
176
|
+
@problems ${rank.contest.problems.length}
|
|
177
|
+
@teams ${rank.teams.length + 100}
|
|
178
|
+
@submissions ${rank.submissions.length}
|
|
179
|
+
`;
|
|
180
|
+
rank.contest.problems.forEach((p) => {
|
|
181
|
+
res += `@p ${p.label},${p.label},20,0
|
|
182
|
+
`;
|
|
183
|
+
});
|
|
184
|
+
let teamIndex = 1;
|
|
185
|
+
const teamIdMap = /* @__PURE__ */ new Map();
|
|
186
|
+
const submissionsIdMap = /* @__PURE__ */ new Map();
|
|
187
|
+
rank.teams.forEach((team) => {
|
|
188
|
+
let name = team.name;
|
|
189
|
+
if (team.organization) {
|
|
190
|
+
name = `${team.organization} - ${name}`;
|
|
191
|
+
}
|
|
192
|
+
if (team.members) {
|
|
193
|
+
name = `${name} - ${team.membersToString}`;
|
|
194
|
+
}
|
|
195
|
+
res += `@t ${teamIndex},0,1,${name}
|
|
196
|
+
`;
|
|
197
|
+
teamIdMap.set(team.id, teamIndex);
|
|
198
|
+
teamIndex++;
|
|
199
|
+
{
|
|
200
|
+
const mp = /* @__PURE__ */ new Map();
|
|
201
|
+
rank.contest.problems.forEach((p) => {
|
|
202
|
+
mp.set(p.id, 0);
|
|
203
|
+
});
|
|
204
|
+
submissionsIdMap.set(team.id, mp);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
for (let i = 0; i < 100; i++) {
|
|
208
|
+
res += `@t ${teamIndex},0,1,\u041F\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043A\u043E\u043C\u0430\u043D\u0434\u0443
|
|
209
|
+
`;
|
|
210
|
+
teamIndex++;
|
|
211
|
+
}
|
|
212
|
+
rank.getSubmissions().forEach((submission) => {
|
|
213
|
+
const teamId = submission.teamId;
|
|
214
|
+
const problemId = submission.problemId;
|
|
215
|
+
const problem = rank.contest.problemsMap.get(problemId);
|
|
216
|
+
if (!problem) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const status = this.submissionStatusToCodeforcesGymDatStatus(submission.status);
|
|
220
|
+
submissionsIdMap.get(teamId).set(problemId, submissionsIdMap.get(teamId).get(problemId) + 1);
|
|
221
|
+
res += `@s ${teamIdMap.get(teamId)},${problem.label},${submissionsIdMap.get(teamId)?.get(problemId)},${submission.timestamp},${status}
|
|
222
|
+
`;
|
|
223
|
+
});
|
|
224
|
+
return res;
|
|
225
|
+
}
|
|
226
|
+
submissionStatusToCodeforcesGymDatStatus(status) {
|
|
227
|
+
if (isAccepted(status)) {
|
|
228
|
+
return "OK";
|
|
229
|
+
}
|
|
230
|
+
if (status === SubmissionStatus.WRONG_ANSWER) {
|
|
231
|
+
return "WA";
|
|
232
|
+
}
|
|
233
|
+
if (status === SubmissionStatus.TIME_LIMIT_EXCEEDED) {
|
|
234
|
+
return "TL";
|
|
235
|
+
}
|
|
236
|
+
if (status === SubmissionStatus.MEMORY_LIMIT_EXCEEDED) {
|
|
237
|
+
return "ML";
|
|
238
|
+
}
|
|
239
|
+
if (status === SubmissionStatus.OUTPUT_LIMIT_EXCEEDED) {
|
|
240
|
+
return "IL";
|
|
241
|
+
}
|
|
242
|
+
if (status === SubmissionStatus.PRESENTATION_ERROR) {
|
|
243
|
+
return "PE";
|
|
244
|
+
}
|
|
245
|
+
if (status === SubmissionStatus.RUNTIME_ERROR) {
|
|
246
|
+
return "RT";
|
|
247
|
+
}
|
|
248
|
+
if (status === SubmissionStatus.COMPILATION_ERROR || isNotCalculatedPenaltyStatus(status)) {
|
|
249
|
+
return "CE";
|
|
250
|
+
}
|
|
251
|
+
if (isPending(status)) {
|
|
252
|
+
return "PD";
|
|
253
|
+
}
|
|
254
|
+
return "RJ";
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
var MedalType = /* @__PURE__ */ ((MedalType2) => {
|
|
259
|
+
MedalType2["UNKNOWN"] = "Unknown";
|
|
260
|
+
MedalType2["GOLD"] = "Gold";
|
|
261
|
+
MedalType2["SILVER"] = "Silver";
|
|
262
|
+
MedalType2["BRONZE"] = "Bronze";
|
|
263
|
+
MedalType2["HONORABLE"] = "Honorable";
|
|
264
|
+
return MedalType2;
|
|
265
|
+
})(MedalType || {});
|
|
266
|
+
class Award {
|
|
267
|
+
constructor() {
|
|
268
|
+
this.medalType = "Unknown" /* UNKNOWN */;
|
|
269
|
+
this.minRank = 0;
|
|
270
|
+
this.maxRank = 0;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function isValidMedalType(medal) {
|
|
274
|
+
const validMedalType = [
|
|
275
|
+
"Gold" /* GOLD */,
|
|
276
|
+
"Silver" /* SILVER */,
|
|
277
|
+
"Bronze" /* BRONZE */,
|
|
278
|
+
"Honorable" /* HONORABLE */
|
|
279
|
+
];
|
|
280
|
+
return validMedalType.includes(medal);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
class GeneralExcelConverter {
|
|
284
|
+
constructor() {
|
|
285
|
+
}
|
|
286
|
+
convert(oriRank) {
|
|
287
|
+
const rank = _.cloneDeep(oriRank);
|
|
288
|
+
rank.options.disableFilterTeamsByGroup();
|
|
289
|
+
rank.options.disableFilterSubmissionByTimestamp();
|
|
290
|
+
const workbook = XLSX.utils.book_new();
|
|
291
|
+
for (const [k, v] of rank.contest.group) {
|
|
292
|
+
rank.options.setGroup(k);
|
|
293
|
+
rank.buildRank();
|
|
294
|
+
const sheet = this.convertToSheet(rank);
|
|
295
|
+
XLSX.utils.book_append_sheet(workbook, sheet, v.names.get(v.defaultLang));
|
|
296
|
+
}
|
|
297
|
+
return workbook;
|
|
298
|
+
}
|
|
299
|
+
convertAndWrite(rank, filename) {
|
|
300
|
+
return XLSX.writeFile(
|
|
301
|
+
this.convert(rank),
|
|
302
|
+
filename,
|
|
303
|
+
{
|
|
304
|
+
compression: true
|
|
305
|
+
}
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
convertToSheet(rank) {
|
|
309
|
+
const aoa = this.convertToAoa(rank);
|
|
310
|
+
const sheet = XLSX.utils.aoa_to_sheet(aoa);
|
|
311
|
+
const cols = [];
|
|
312
|
+
const head = aoa[1];
|
|
313
|
+
for (let j = 0; j < head.length; j++) {
|
|
314
|
+
let wch = 10;
|
|
315
|
+
for (let i = 1; i < aoa.length; i++) {
|
|
316
|
+
wch = Math.max(wch, stringWidth(aoa[i][j]) + 2);
|
|
317
|
+
}
|
|
318
|
+
cols.push({
|
|
319
|
+
wch
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
sheet["!cols"] = cols;
|
|
323
|
+
{
|
|
324
|
+
const mergeRange = { s: { r: 0, c: 0 }, e: { r: 0, c: head.length - 1 } };
|
|
325
|
+
const merges = [{ s: mergeRange.s, e: mergeRange.e }];
|
|
326
|
+
sheet["!merges"] = merges;
|
|
327
|
+
}
|
|
328
|
+
const font = {
|
|
329
|
+
name: "Arial Unicode MS",
|
|
330
|
+
bold: false,
|
|
331
|
+
italic: false,
|
|
332
|
+
sz: 12
|
|
333
|
+
};
|
|
334
|
+
const borderStyle = {
|
|
335
|
+
style: "thin"
|
|
336
|
+
};
|
|
337
|
+
const cellStyle = {
|
|
338
|
+
alignment: {
|
|
339
|
+
vertical: "center",
|
|
340
|
+
horizontal: "center"
|
|
341
|
+
},
|
|
342
|
+
border: {
|
|
343
|
+
top: borderStyle,
|
|
344
|
+
bottom: borderStyle,
|
|
345
|
+
left: borderStyle,
|
|
346
|
+
right: borderStyle
|
|
347
|
+
},
|
|
348
|
+
font
|
|
349
|
+
};
|
|
350
|
+
for (let i = 1; i < aoa.length; i++) {
|
|
351
|
+
for (let j = 0; j < aoa[i].length; j++) {
|
|
352
|
+
const cellAddress = XLSX.utils.encode_cell({ r: i, c: j });
|
|
353
|
+
const cell = sheet[cellAddress];
|
|
354
|
+
cell.s = cellStyle;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
{
|
|
358
|
+
const cellAddress = XLSX.utils.encode_cell({ r: 0, c: 0 });
|
|
359
|
+
const cell = sheet[cellAddress];
|
|
360
|
+
const titleStyle = _.cloneDeep(cellStyle);
|
|
361
|
+
titleStyle.font.sz = 28;
|
|
362
|
+
titleStyle.font.bold = true;
|
|
363
|
+
cell.s = titleStyle;
|
|
364
|
+
}
|
|
365
|
+
return sheet;
|
|
366
|
+
}
|
|
367
|
+
convertToAoa(rank) {
|
|
368
|
+
const aoa = [];
|
|
369
|
+
const enableAwards = rank.contest.isEnableAwards(rank.options.group);
|
|
370
|
+
{
|
|
371
|
+
aoa.push([rank.contest.name]);
|
|
372
|
+
}
|
|
373
|
+
{
|
|
374
|
+
const head = [];
|
|
375
|
+
head.push("Rank");
|
|
376
|
+
if (rank.contest.organization) {
|
|
377
|
+
head.push(`${rank.contest.organization} Rank`);
|
|
378
|
+
head.push(rank.contest.organization);
|
|
379
|
+
}
|
|
380
|
+
head.push("Name", "Solved", "Penalty", ...rank.contest.problems.map((p) => p.label), "Dict");
|
|
381
|
+
if (enableAwards) {
|
|
382
|
+
head.push("Medal");
|
|
383
|
+
}
|
|
384
|
+
aoa.push(head);
|
|
385
|
+
}
|
|
386
|
+
for (const team of rank.teams) {
|
|
387
|
+
const arr = [];
|
|
388
|
+
arr.push(team.rank.toString());
|
|
389
|
+
if (team.organization) {
|
|
390
|
+
if (team.organizationRank !== -1) {
|
|
391
|
+
arr.push(team.organizationRank.toString());
|
|
392
|
+
} else {
|
|
393
|
+
arr.push("");
|
|
394
|
+
}
|
|
395
|
+
arr.push(team.organization);
|
|
396
|
+
}
|
|
397
|
+
arr.push(team.name, team.solvedProblemNum.toString(), team.penaltyToMinute.toString());
|
|
398
|
+
for (const p of team.problemStatistics) {
|
|
399
|
+
if (p.isUnSubmitted) {
|
|
400
|
+
arr.push("-");
|
|
401
|
+
}
|
|
402
|
+
if (p.isSolved) {
|
|
403
|
+
arr.push(`+${p.totalCount}(${p.solvedTimestampToMinute})`);
|
|
404
|
+
}
|
|
405
|
+
if (p.isWrongAnswer) {
|
|
406
|
+
arr.push(`-${p.failedCount}`);
|
|
407
|
+
}
|
|
408
|
+
if (p.isPending) {
|
|
409
|
+
arr.push(`? ${p.failedCount} + ${p.pendingCount}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
arr.push(`${team.dict}%`);
|
|
413
|
+
if (enableAwards) {
|
|
414
|
+
const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
|
|
415
|
+
arr.push(medals.join(", "));
|
|
416
|
+
}
|
|
417
|
+
aoa.push(arr);
|
|
418
|
+
}
|
|
419
|
+
return aoa;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function calcDict(attemptedNum, solvedNum) {
|
|
424
|
+
if (solvedNum === 0) {
|
|
425
|
+
return 0;
|
|
426
|
+
}
|
|
427
|
+
return Math.floor((attemptedNum - solvedNum) * 100 / attemptedNum);
|
|
428
|
+
}
|
|
429
|
+
|
|
73
430
|
class ProblemStatistics {
|
|
74
431
|
constructor() {
|
|
75
432
|
this.acceptedNum = 0;
|
|
@@ -175,6 +532,12 @@ class TeamProblemStatistics {
|
|
|
175
532
|
}
|
|
176
533
|
return Math.floor(this.solvedTimestamp / 60) * 60 + this.failedCount * this.contestPenalty;
|
|
177
534
|
}
|
|
535
|
+
get penaltyToMinute() {
|
|
536
|
+
return Math.floor(this.penalty / 60);
|
|
537
|
+
}
|
|
538
|
+
get solvedTimestampToMinute() {
|
|
539
|
+
return Math.floor(this.solvedTimestamp / 60);
|
|
540
|
+
}
|
|
178
541
|
}
|
|
179
542
|
|
|
180
543
|
class Group {
|
|
@@ -260,6 +623,15 @@ class Contest {
|
|
|
260
623
|
const pass = baseTime.diff(this.startTime, "s");
|
|
261
624
|
return Math.round(pass * 100 / total);
|
|
262
625
|
}
|
|
626
|
+
isEnableAwards(group) {
|
|
627
|
+
if (!this.awards) {
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
if (!this.awards.has(group)) {
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
return true;
|
|
634
|
+
}
|
|
263
635
|
}
|
|
264
636
|
function createContest(contestJSON) {
|
|
265
637
|
const c = new Contest();
|
|
@@ -424,208 +796,6 @@ function createContestIndexList(contestListJSON) {
|
|
|
424
796
|
return contestIndexList;
|
|
425
797
|
}
|
|
426
798
|
|
|
427
|
-
function stringToSubmissionStatus(status) {
|
|
428
|
-
status = status.toUpperCase().replace(" ", "_");
|
|
429
|
-
if (["OK", "AC", SubmissionStatus.ACCEPTED.toString()].includes(status)) {
|
|
430
|
-
return SubmissionStatus.ACCEPTED;
|
|
431
|
-
}
|
|
432
|
-
if ([SubmissionStatus.CORRECT.toString()].includes(status)) {
|
|
433
|
-
return SubmissionStatus.ACCEPTED;
|
|
434
|
-
}
|
|
435
|
-
if ([SubmissionStatus.PARTIALLY_CORRECT.toString()].includes(status)) {
|
|
436
|
-
return SubmissionStatus.PARTIALLY_CORRECT;
|
|
437
|
-
}
|
|
438
|
-
if (["WA", SubmissionStatus.WRONG_ANSWER.toString()].includes(status)) {
|
|
439
|
-
return SubmissionStatus.WRONG_ANSWER;
|
|
440
|
-
}
|
|
441
|
-
if (["RJ", "INCORRECT", SubmissionStatus.REJECTED.toString()].includes(status)) {
|
|
442
|
-
return SubmissionStatus.REJECTED;
|
|
443
|
-
}
|
|
444
|
-
if (["PD", SubmissionStatus.PENDING.toString()].includes(status)) {
|
|
445
|
-
return SubmissionStatus.PENDING;
|
|
446
|
-
}
|
|
447
|
-
if ([SubmissionStatus.WAITING.toString()].includes(status)) {
|
|
448
|
-
return SubmissionStatus.WAITING;
|
|
449
|
-
}
|
|
450
|
-
if ([SubmissionStatus.JUDGING.toString()].includes(status)) {
|
|
451
|
-
return SubmissionStatus.JUDGING;
|
|
452
|
-
}
|
|
453
|
-
if ([SubmissionStatus.FROZEN.toString()].includes(status)) {
|
|
454
|
-
return SubmissionStatus.FROZEN;
|
|
455
|
-
}
|
|
456
|
-
if (["CE", SubmissionStatus.COMPILATION_ERROR.toString()].includes(status)) {
|
|
457
|
-
return SubmissionStatus.COMPILATION_ERROR;
|
|
458
|
-
}
|
|
459
|
-
if (["PE", SubmissionStatus.PRESENTATION_ERROR.toString()].includes(status)) {
|
|
460
|
-
return SubmissionStatus.PRESENTATION_ERROR;
|
|
461
|
-
}
|
|
462
|
-
if (["TL", "TLE", SubmissionStatus.TIME_LIMIT_EXCEEDED.toString()].includes(status)) {
|
|
463
|
-
return SubmissionStatus.TIME_LIMIT_EXCEEDED;
|
|
464
|
-
}
|
|
465
|
-
if (["ML", "MLE", SubmissionStatus.MEMORY_LIMIT_EXCEEDED.toString()].includes(status)) {
|
|
466
|
-
return SubmissionStatus.MEMORY_LIMIT_EXCEEDED;
|
|
467
|
-
}
|
|
468
|
-
if (["OL", "OLE", SubmissionStatus.OUTPUT_LIMIT_EXCEEDED.toString()].includes(status)) {
|
|
469
|
-
return SubmissionStatus.OUTPUT_LIMIT_EXCEEDED;
|
|
470
|
-
}
|
|
471
|
-
if (["IL", "ILE", SubmissionStatus.IDLENESS_LIMIT_EXCEEDED.toString()].includes(status)) {
|
|
472
|
-
return SubmissionStatus.IDLENESS_LIMIT_EXCEEDED;
|
|
473
|
-
}
|
|
474
|
-
if (["RT", "RE", "RTE", SubmissionStatus.RUNTIME_ERROR.toString()].includes(status)) {
|
|
475
|
-
return SubmissionStatus.RUNTIME_ERROR;
|
|
476
|
-
}
|
|
477
|
-
if (["JE", SubmissionStatus.JUDGEMENT_FAILED.toString()].includes(status)) {
|
|
478
|
-
return SubmissionStatus.JUDGEMENT_FAILED;
|
|
479
|
-
}
|
|
480
|
-
if (["SE", SubmissionStatus.SYSTEM_ERROR.toString()].includes(status)) {
|
|
481
|
-
return SubmissionStatus.SYSTEM_ERROR;
|
|
482
|
-
}
|
|
483
|
-
if ([SubmissionStatus.HACKED.toString()].includes(status)) {
|
|
484
|
-
return SubmissionStatus.HACKED;
|
|
485
|
-
}
|
|
486
|
-
if ([SubmissionStatus.CONFIGURATION_ERROR.toString()].includes(status)) {
|
|
487
|
-
return SubmissionStatus.CONFIGURATION_ERROR;
|
|
488
|
-
}
|
|
489
|
-
if ([SubmissionStatus.CANCELED.toString()].includes(status)) {
|
|
490
|
-
return SubmissionStatus.CANCELED;
|
|
491
|
-
}
|
|
492
|
-
if ([SubmissionStatus.SKIPPED.toString()].includes(status)) {
|
|
493
|
-
return SubmissionStatus.SKIPPED;
|
|
494
|
-
}
|
|
495
|
-
if ([SubmissionStatus.SECURITY_VIOLATED.toString()].includes(status)) {
|
|
496
|
-
return SubmissionStatus.SECURITY_VIOLATED;
|
|
497
|
-
}
|
|
498
|
-
if ([SubmissionStatus.DENIAL_OF_JUDGEMENT.toString()].includes(status)) {
|
|
499
|
-
return SubmissionStatus.DENIAL_OF_JUDGEMENT;
|
|
500
|
-
}
|
|
501
|
-
return SubmissionStatus.UNKNOWN;
|
|
502
|
-
}
|
|
503
|
-
function isAccepted(status) {
|
|
504
|
-
const acceptedArray = [SubmissionStatus.ACCEPTED, SubmissionStatus.CORRECT];
|
|
505
|
-
return acceptedArray.includes(status);
|
|
506
|
-
}
|
|
507
|
-
function isRejected(status) {
|
|
508
|
-
const rejectArray = [
|
|
509
|
-
SubmissionStatus.RUNTIME_ERROR,
|
|
510
|
-
SubmissionStatus.TIME_LIMIT_EXCEEDED,
|
|
511
|
-
SubmissionStatus.MEMORY_LIMIT_EXCEEDED,
|
|
512
|
-
SubmissionStatus.OUTPUT_LIMIT_EXCEEDED,
|
|
513
|
-
SubmissionStatus.IDLENESS_LIMIT_EXCEEDED,
|
|
514
|
-
SubmissionStatus.WRONG_ANSWER,
|
|
515
|
-
SubmissionStatus.REJECTED,
|
|
516
|
-
SubmissionStatus.JUDGEMENT_FAILED,
|
|
517
|
-
SubmissionStatus.HACKED
|
|
518
|
-
];
|
|
519
|
-
return rejectArray.includes(status);
|
|
520
|
-
}
|
|
521
|
-
function isPending(status) {
|
|
522
|
-
const pendingArray = [
|
|
523
|
-
SubmissionStatus.PENDING,
|
|
524
|
-
SubmissionStatus.WAITING,
|
|
525
|
-
SubmissionStatus.JUDGING,
|
|
526
|
-
SubmissionStatus.FROZEN
|
|
527
|
-
];
|
|
528
|
-
return pendingArray.includes(status);
|
|
529
|
-
}
|
|
530
|
-
function isNotCalculatedPenaltyStatus(status) {
|
|
531
|
-
const isNotCalculatedPenaltyArray = [
|
|
532
|
-
SubmissionStatus.COMPILATION_ERROR,
|
|
533
|
-
SubmissionStatus.PRESENTATION_ERROR,
|
|
534
|
-
SubmissionStatus.CONFIGURATION_ERROR,
|
|
535
|
-
SubmissionStatus.SYSTEM_ERROR,
|
|
536
|
-
SubmissionStatus.CANCELED,
|
|
537
|
-
SubmissionStatus.SKIPPED,
|
|
538
|
-
SubmissionStatus.UNKNOWN,
|
|
539
|
-
SubmissionStatus.UNDEFINED
|
|
540
|
-
];
|
|
541
|
-
return isNotCalculatedPenaltyArray.includes(status);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
function submissionStatusToCodeforcesGymDatStatus(status) {
|
|
545
|
-
if (isAccepted(status)) {
|
|
546
|
-
return "OK";
|
|
547
|
-
}
|
|
548
|
-
if (status === SubmissionStatus.WRONG_ANSWER) {
|
|
549
|
-
return "WA";
|
|
550
|
-
}
|
|
551
|
-
if (status === SubmissionStatus.TIME_LIMIT_EXCEEDED) {
|
|
552
|
-
return "TL";
|
|
553
|
-
}
|
|
554
|
-
if (status === SubmissionStatus.MEMORY_LIMIT_EXCEEDED) {
|
|
555
|
-
return "ML";
|
|
556
|
-
}
|
|
557
|
-
if (status === SubmissionStatus.OUTPUT_LIMIT_EXCEEDED) {
|
|
558
|
-
return "IL";
|
|
559
|
-
}
|
|
560
|
-
if (status === SubmissionStatus.PRESENTATION_ERROR) {
|
|
561
|
-
return "PE";
|
|
562
|
-
}
|
|
563
|
-
if (status === SubmissionStatus.RUNTIME_ERROR) {
|
|
564
|
-
return "RT";
|
|
565
|
-
}
|
|
566
|
-
if (status === SubmissionStatus.COMPILATION_ERROR || isNotCalculatedPenaltyStatus(status)) {
|
|
567
|
-
return "CE";
|
|
568
|
-
}
|
|
569
|
-
if (isPending(status)) {
|
|
570
|
-
return "PD";
|
|
571
|
-
}
|
|
572
|
-
return "RJ";
|
|
573
|
-
}
|
|
574
|
-
function rankToCodeforcesGymDAT(rank) {
|
|
575
|
-
let res = "";
|
|
576
|
-
res += `@contest "${rank.contest.name}"
|
|
577
|
-
@contlen ${Math.floor(dayjs.duration(rank.contest.endTime.diff(rank.contest.startTime)).asMinutes())}
|
|
578
|
-
@problems ${rank.contest.problems.length}
|
|
579
|
-
@teams ${rank.teams.length + 100}
|
|
580
|
-
@submissions ${rank.submissions.length}
|
|
581
|
-
`;
|
|
582
|
-
rank.contest.problems.forEach((p) => {
|
|
583
|
-
res += `@p ${p.label},${p.label},20,0
|
|
584
|
-
`;
|
|
585
|
-
});
|
|
586
|
-
let teamIndex = 1;
|
|
587
|
-
const teamIdMap = /* @__PURE__ */ new Map();
|
|
588
|
-
const submissionsIdMap = /* @__PURE__ */ new Map();
|
|
589
|
-
rank.teams.forEach((team) => {
|
|
590
|
-
let name = team.name;
|
|
591
|
-
if (team.organization) {
|
|
592
|
-
name = `${team.organization} - ${name}`;
|
|
593
|
-
}
|
|
594
|
-
if (team.members) {
|
|
595
|
-
name = `${name} - ${team.membersToString}`;
|
|
596
|
-
}
|
|
597
|
-
res += `@t ${teamIndex},0,1,${name}
|
|
598
|
-
`;
|
|
599
|
-
teamIdMap.set(team.id, teamIndex);
|
|
600
|
-
teamIndex++;
|
|
601
|
-
{
|
|
602
|
-
const mp = /* @__PURE__ */ new Map();
|
|
603
|
-
rank.contest.problems.forEach((p) => {
|
|
604
|
-
mp.set(p.id, 0);
|
|
605
|
-
});
|
|
606
|
-
submissionsIdMap.set(team.id, mp);
|
|
607
|
-
}
|
|
608
|
-
});
|
|
609
|
-
for (let i = 0; i < 100; i++) {
|
|
610
|
-
res += `@t ${teamIndex},0,1,\u041F\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043A\u043E\u043C\u0430\u043D\u0434\u0443
|
|
611
|
-
`;
|
|
612
|
-
teamIndex++;
|
|
613
|
-
}
|
|
614
|
-
rank.getSubmissions().forEach((submission) => {
|
|
615
|
-
const teamId = submission.teamId;
|
|
616
|
-
const problemId = submission.problemId;
|
|
617
|
-
const problem = rank.contest.problemsMap.get(problemId);
|
|
618
|
-
if (!problem) {
|
|
619
|
-
return;
|
|
620
|
-
}
|
|
621
|
-
const status = submissionStatusToCodeforcesGymDatStatus(submission.status);
|
|
622
|
-
submissionsIdMap.get(teamId).set(problemId, submissionsIdMap.get(teamId).get(problemId) + 1);
|
|
623
|
-
res += `@s ${teamIdMap.get(teamId)},${problem.label},${submissionsIdMap.get(teamId)?.get(problemId)},${submission.timestamp},${status}
|
|
624
|
-
`;
|
|
625
|
-
});
|
|
626
|
-
return res;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
799
|
function getImageSource(image) {
|
|
630
800
|
if (image?.url) {
|
|
631
801
|
return image.url;
|
|
@@ -688,6 +858,7 @@ class Team {
|
|
|
688
858
|
this.problemStatisticsMap = /* @__PURE__ */ new Map();
|
|
689
859
|
this.submissions = [];
|
|
690
860
|
this.placeChartPoints = [];
|
|
861
|
+
this.awards = [];
|
|
691
862
|
}
|
|
692
863
|
get penaltyToMinute() {
|
|
693
864
|
return Math.floor(this.penalty / 60);
|
|
@@ -1227,4 +1398,4 @@ class Resolver extends Rank {
|
|
|
1227
1398
|
}
|
|
1228
1399
|
}
|
|
1229
1400
|
|
|
1230
|
-
export { Award, Contest, ContestIndex, ContestIndexConfig, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected,
|
|
1401
|
+
export { Award, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcpcio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "XCPCIO Core",
|
|
5
5
|
"author": "Dup4 <lyuzhi.pan@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"dayjs": "^1.11.8",
|
|
44
44
|
"lodash": "^4.17.21",
|
|
45
|
-
"
|
|
45
|
+
"string-width": "^6.1.0",
|
|
46
|
+
"xlsx-js-style": "^1.2.0",
|
|
47
|
+
"@xcpcio/types": "0.15.0"
|
|
46
48
|
},
|
|
47
49
|
"devDependencies": {
|
|
48
50
|
"@babel/types": "^7.22.4",
|