@xcpcio/core 0.4.0 → 0.4.2
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 +91 -88
- package/dist/index.d.ts +40 -33
- package/dist/index.mjs +91 -89
- package/package.json +2 -2
- package/src/contest-index.ts +11 -34
- package/src/contest.ts +13 -13
- package/src/index.ts +1 -0
- package/src/rank-statistics.ts +11 -0
- package/src/rank.ts +15 -0
package/dist/index.cjs
CHANGED
|
@@ -70,81 +70,6 @@ function getTimeDiff(seconds) {
|
|
|
70
70
|
return [two(h), two(m), two(s)].join(":");
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
class ContestIndexConfig {
|
|
74
|
-
constructor() {
|
|
75
|
-
this.contestName = "";
|
|
76
|
-
this.startTime = createDayJS();
|
|
77
|
-
this.endTime = createDayJS();
|
|
78
|
-
this.freezeTime = createDayJS();
|
|
79
|
-
this.totalDurationTimestamp = 0;
|
|
80
|
-
this.freezeDurationTimestamp = 0;
|
|
81
|
-
this.unFreezeDurationTimestamp = 0;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
class ContestIndex {
|
|
85
|
-
constructor() {
|
|
86
|
-
this.config = new ContestIndexConfig();
|
|
87
|
-
this.boardLink = "";
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
function createContestIndex(contestIndexJSON) {
|
|
91
|
-
const c = new ContestIndex();
|
|
92
|
-
const cc = c.config;
|
|
93
|
-
const cjc = contestIndexJSON.config;
|
|
94
|
-
cc.contestName = cjc.contest_name;
|
|
95
|
-
cc.startTime = createDayJS(cjc.start_time);
|
|
96
|
-
cc.endTime = createDayJS(cjc.end_time);
|
|
97
|
-
cc.totalDurationTimestamp = cc.endTime.unix() - cc.startTime.unix();
|
|
98
|
-
{
|
|
99
|
-
cc.freezeTime = cc.endTime;
|
|
100
|
-
cc.freezeDurationTimestamp = 0;
|
|
101
|
-
if (cjc.frozen_time !== void 0 && cjc.frozen_time != null) {
|
|
102
|
-
const frozenTime = Number(cjc.frozen_time);
|
|
103
|
-
cc.freezeTime = createDayJS(cc.endTime.unix() - frozenTime);
|
|
104
|
-
cc.freezeDurationTimestamp = frozenTime;
|
|
105
|
-
}
|
|
106
|
-
cc.unFreezeDurationTimestamp = cc.totalDurationTimestamp - cc.freezeDurationTimestamp;
|
|
107
|
-
}
|
|
108
|
-
cc.logo = cjc.logo;
|
|
109
|
-
c.boardLink = contestIndexJSON.board_link;
|
|
110
|
-
return c;
|
|
111
|
-
}
|
|
112
|
-
function createContestIndexList(contestListJSON) {
|
|
113
|
-
const contestIndexList = [];
|
|
114
|
-
const dfs = (contestList) => {
|
|
115
|
-
if (Object.prototype.hasOwnProperty.call(contestList, "config")) {
|
|
116
|
-
contestIndexList.push(createContestIndex(contestList));
|
|
117
|
-
} else {
|
|
118
|
-
for (const k in contestList) {
|
|
119
|
-
dfs(contestList[k]);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
dfs(contestListJSON);
|
|
124
|
-
contestIndexList.sort((a, b) => {
|
|
125
|
-
if (a.config.startTime.isBefore(b.config.startTime)) {
|
|
126
|
-
return 1;
|
|
127
|
-
}
|
|
128
|
-
if (a.config.startTime.isAfter(b.config.startTime)) {
|
|
129
|
-
return -1;
|
|
130
|
-
}
|
|
131
|
-
if (a.config.endTime.isBefore(b.config.endTime)) {
|
|
132
|
-
return 1;
|
|
133
|
-
}
|
|
134
|
-
if (a.config.endTime.isAfter(b.config.endTime)) {
|
|
135
|
-
return -1;
|
|
136
|
-
}
|
|
137
|
-
if (a.config.contestName < b.config.contestName) {
|
|
138
|
-
return 1;
|
|
139
|
-
}
|
|
140
|
-
if (a.config.contestName > b.config.contestName) {
|
|
141
|
-
return -1;
|
|
142
|
-
}
|
|
143
|
-
return 0;
|
|
144
|
-
});
|
|
145
|
-
return contestIndexList;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
73
|
class ProblemStatistics {
|
|
149
74
|
constructor() {
|
|
150
75
|
this.acceptedNum = 0;
|
|
@@ -272,8 +197,8 @@ class Contest {
|
|
|
272
197
|
getContestDuration(timeFormat = "HH:mm:ss") {
|
|
273
198
|
return dayjs__default.duration(this.endTime.diff(this.startTime)).format(timeFormat);
|
|
274
199
|
}
|
|
275
|
-
getContestState() {
|
|
276
|
-
const now = createDayJS();
|
|
200
|
+
getContestState(nowTime) {
|
|
201
|
+
const now = createDayJS(nowTime);
|
|
277
202
|
if (now.isBefore(this.startTime)) {
|
|
278
203
|
return types.ContestState.PENDING;
|
|
279
204
|
}
|
|
@@ -285,29 +210,29 @@ class Contest {
|
|
|
285
210
|
}
|
|
286
211
|
return types.ContestState.RUNNING;
|
|
287
212
|
}
|
|
288
|
-
getContestPendingTime() {
|
|
289
|
-
let baseTime = createDayJS();
|
|
213
|
+
getContestPendingTime(nowTime) {
|
|
214
|
+
let baseTime = createDayJS(nowTime);
|
|
290
215
|
if (baseTime.isAfter(this.startTime)) {
|
|
291
216
|
baseTime = this.startTime;
|
|
292
217
|
}
|
|
293
218
|
return getTimeDiff(Math.floor(dayjs__default.duration(this.startTime.diff(baseTime)).asSeconds()));
|
|
294
219
|
}
|
|
295
|
-
getContestRemainingTime(
|
|
296
|
-
let baseTime =
|
|
297
|
-
if (baseTime.isAfter(endTime)) {
|
|
298
|
-
baseTime = endTime;
|
|
220
|
+
getContestRemainingTime(nowTime) {
|
|
221
|
+
let baseTime = createDayJS(nowTime);
|
|
222
|
+
if (baseTime.isAfter(this.endTime)) {
|
|
223
|
+
baseTime = this.endTime;
|
|
299
224
|
}
|
|
300
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(endTime.diff(baseTime)).asSeconds()));
|
|
225
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(this.endTime.diff(baseTime)).asSeconds()));
|
|
301
226
|
}
|
|
302
|
-
getContestElapsedTime() {
|
|
303
|
-
let baseTime =
|
|
227
|
+
getContestElapsedTime(nowTime) {
|
|
228
|
+
let baseTime = createDayJS(nowTime);
|
|
304
229
|
if (baseTime.isAfter(this.endTime)) {
|
|
305
230
|
baseTime = this.endTime;
|
|
306
231
|
}
|
|
307
232
|
return getTimeDiff(Math.floor(dayjs__default.duration(baseTime.diff(this.startTime)).asSeconds()));
|
|
308
233
|
}
|
|
309
|
-
getContestProgressRatio() {
|
|
310
|
-
const baseTime =
|
|
234
|
+
getContestProgressRatio(nowTime) {
|
|
235
|
+
const baseTime = createDayJS(nowTime);
|
|
311
236
|
if (this.startTime.isSameOrAfter(baseTime)) {
|
|
312
237
|
return 0;
|
|
313
238
|
}
|
|
@@ -367,6 +292,66 @@ function createContest(contestJSON) {
|
|
|
367
292
|
return c;
|
|
368
293
|
}
|
|
369
294
|
|
|
295
|
+
class ContestIndexConfig {
|
|
296
|
+
constructor() {
|
|
297
|
+
this.contestName = "";
|
|
298
|
+
this.startTime = createDayJS();
|
|
299
|
+
this.endTime = createDayJS();
|
|
300
|
+
this.freezeTime = createDayJS();
|
|
301
|
+
this.totalDurationTimestamp = 0;
|
|
302
|
+
this.freezeDurationTimestamp = 0;
|
|
303
|
+
this.unFreezeDurationTimestamp = 0;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
class ContestIndex {
|
|
307
|
+
constructor() {
|
|
308
|
+
this.contest = new Contest();
|
|
309
|
+
this.boardLink = "";
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function createContestIndex(contestIndexJSON) {
|
|
313
|
+
const c = new ContestIndex();
|
|
314
|
+
const cjc = contestIndexJSON.config;
|
|
315
|
+
c.contest = createContest(cjc);
|
|
316
|
+
c.boardLink = contestIndexJSON.board_link;
|
|
317
|
+
return c;
|
|
318
|
+
}
|
|
319
|
+
function createContestIndexList(contestListJSON) {
|
|
320
|
+
const contestIndexList = [];
|
|
321
|
+
const dfs = (contestList) => {
|
|
322
|
+
if (Object.prototype.hasOwnProperty.call(contestList, "config")) {
|
|
323
|
+
contestIndexList.push(createContestIndex(contestList));
|
|
324
|
+
} else {
|
|
325
|
+
for (const k in contestList) {
|
|
326
|
+
dfs(contestList[k]);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
dfs(contestListJSON);
|
|
331
|
+
contestIndexList.sort((a, b) => {
|
|
332
|
+
if (a.contest.startTime.isBefore(b.contest.startTime)) {
|
|
333
|
+
return 1;
|
|
334
|
+
}
|
|
335
|
+
if (a.contest.startTime.isAfter(b.contest.startTime)) {
|
|
336
|
+
return -1;
|
|
337
|
+
}
|
|
338
|
+
if (a.contest.endTime.isBefore(b.contest.endTime)) {
|
|
339
|
+
return 1;
|
|
340
|
+
}
|
|
341
|
+
if (a.contest.endTime.isAfter(b.contest.endTime)) {
|
|
342
|
+
return -1;
|
|
343
|
+
}
|
|
344
|
+
if (a.contest.name < b.contest.name) {
|
|
345
|
+
return 1;
|
|
346
|
+
}
|
|
347
|
+
if (a.contest.name > b.contest.name) {
|
|
348
|
+
return -1;
|
|
349
|
+
}
|
|
350
|
+
return 0;
|
|
351
|
+
});
|
|
352
|
+
return contestIndexList;
|
|
353
|
+
}
|
|
354
|
+
|
|
370
355
|
function getImageSource(image) {
|
|
371
356
|
if (image?.url) {
|
|
372
357
|
return image.url;
|
|
@@ -377,6 +362,15 @@ function getImageSource(image) {
|
|
|
377
362
|
return "";
|
|
378
363
|
}
|
|
379
364
|
|
|
365
|
+
class RankStatistics {
|
|
366
|
+
constructor() {
|
|
367
|
+
this.teamSolvedNum = [];
|
|
368
|
+
}
|
|
369
|
+
reset() {
|
|
370
|
+
this.teamSolvedNum = [];
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
380
374
|
class Team {
|
|
381
375
|
constructor() {
|
|
382
376
|
this.id = "";
|
|
@@ -642,6 +636,7 @@ class Rank {
|
|
|
642
636
|
this.teamsMap = new Map(this.teams.map((t) => [t.id, t]));
|
|
643
637
|
this.submissions = ___default.cloneDeep(submissions).sort(Submission.compare);
|
|
644
638
|
this.submissionsMap = new Map(this.submissions.map((s) => [s.id, s]));
|
|
639
|
+
this.rankStatistics = new RankStatistics();
|
|
645
640
|
}
|
|
646
641
|
buildRank(options) {
|
|
647
642
|
(() => {
|
|
@@ -728,6 +723,13 @@ class Rank {
|
|
|
728
723
|
}
|
|
729
724
|
}
|
|
730
725
|
})();
|
|
726
|
+
(() => {
|
|
727
|
+
this.rankStatistics.reset();
|
|
728
|
+
this.rankStatistics.teamSolvedNum = Array(this.contest.problems.length + 1).fill(0);
|
|
729
|
+
for (const t of this.teams) {
|
|
730
|
+
this.rankStatistics.teamSolvedNum[t.solvedProblemNum]++;
|
|
731
|
+
}
|
|
732
|
+
})();
|
|
731
733
|
return this;
|
|
732
734
|
}
|
|
733
735
|
}
|
|
@@ -827,6 +829,7 @@ exports.ContestIndexConfig = ContestIndexConfig;
|
|
|
827
829
|
exports.Problem = Problem;
|
|
828
830
|
exports.ProblemStatistics = ProblemStatistics;
|
|
829
831
|
exports.Rank = Rank;
|
|
832
|
+
exports.RankStatistics = RankStatistics;
|
|
830
833
|
exports.Resolver = Resolver;
|
|
831
834
|
exports.Submission = Submission;
|
|
832
835
|
exports.Team = Team;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,32 +1,6 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
2
|
export { default as dayjs } from 'dayjs';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
declare class ContestIndexConfig {
|
|
6
|
-
contestName: string;
|
|
7
|
-
startTime: dayjs.Dayjs;
|
|
8
|
-
endTime: dayjs.Dayjs;
|
|
9
|
-
freezeTime: dayjs.Dayjs;
|
|
10
|
-
totalDurationTimestamp: number;
|
|
11
|
-
freezeDurationTimestamp: number;
|
|
12
|
-
unFreezeDurationTimestamp: number;
|
|
13
|
-
logo?: Image;
|
|
14
|
-
constructor();
|
|
15
|
-
}
|
|
16
|
-
declare class ContestIndex {
|
|
17
|
-
config: ContestIndexConfig;
|
|
18
|
-
boardLink: string;
|
|
19
|
-
constructor();
|
|
20
|
-
}
|
|
21
|
-
type ContestIndexList = Array<ContestIndex>;
|
|
22
|
-
declare function createContestIndex(contestIndexJSON: ContestIndex$1): ContestIndex;
|
|
23
|
-
declare function createContestIndexList(contestListJSON: any): ContestIndexList;
|
|
24
|
-
|
|
25
|
-
declare function calcDict(attemptedNum: number, solvedNum: number): number;
|
|
26
|
-
|
|
27
|
-
declare function createDayJS(time?: Date | string | number | undefined): dayjs.Dayjs;
|
|
28
|
-
declare function getTimestamp(time: number | dayjs.Dayjs): number;
|
|
29
|
-
declare function getTimeDiff(seconds: number): string;
|
|
3
|
+
import { SubmissionStatus, Submission as Submission$1, Submissions as Submissions$1, BalloonColor, Problem as Problem$1, Problems as Problems$1, StatusTimeDisplay, Image, ContestState, Contest as Contest$1, ContestIndex as ContestIndex$1, Team as Team$1, Teams as Teams$1 } from '@xcpcio/types';
|
|
30
4
|
|
|
31
5
|
declare class Submission {
|
|
32
6
|
id: string;
|
|
@@ -96,6 +70,12 @@ declare class TeamProblemStatistics {
|
|
|
96
70
|
get penalty(): number;
|
|
97
71
|
}
|
|
98
72
|
|
|
73
|
+
declare function calcDict(attemptedNum: number, solvedNum: number): number;
|
|
74
|
+
|
|
75
|
+
declare function createDayJS(time?: Date | string | number | undefined): dayjs.Dayjs;
|
|
76
|
+
declare function getTimestamp(time: number | dayjs.Dayjs): number;
|
|
77
|
+
declare function getTimeDiff(seconds: number): string;
|
|
78
|
+
|
|
99
79
|
declare class Contest {
|
|
100
80
|
name: string;
|
|
101
81
|
startTime: dayjs.Dayjs;
|
|
@@ -119,16 +99,42 @@ declare class Contest {
|
|
|
119
99
|
version: string;
|
|
120
100
|
constructor();
|
|
121
101
|
getContestDuration(timeFormat?: string): string;
|
|
122
|
-
getContestState(): ContestState;
|
|
123
|
-
getContestPendingTime(): string;
|
|
124
|
-
getContestRemainingTime(
|
|
125
|
-
getContestElapsedTime(): string;
|
|
126
|
-
getContestProgressRatio(): number;
|
|
102
|
+
getContestState(nowTime?: Date): ContestState;
|
|
103
|
+
getContestPendingTime(nowTime?: Date): string;
|
|
104
|
+
getContestRemainingTime(nowTime?: Date): string;
|
|
105
|
+
getContestElapsedTime(nowTime?: Date): string;
|
|
106
|
+
getContestProgressRatio(nowTime?: Date): number;
|
|
127
107
|
}
|
|
128
108
|
declare function createContest(contestJSON: Contest$1): Contest;
|
|
129
109
|
|
|
110
|
+
declare class ContestIndexConfig {
|
|
111
|
+
contestName: string;
|
|
112
|
+
startTime: dayjs.Dayjs;
|
|
113
|
+
endTime: dayjs.Dayjs;
|
|
114
|
+
freezeTime: dayjs.Dayjs;
|
|
115
|
+
totalDurationTimestamp: number;
|
|
116
|
+
freezeDurationTimestamp: number;
|
|
117
|
+
unFreezeDurationTimestamp: number;
|
|
118
|
+
logo?: Image;
|
|
119
|
+
constructor();
|
|
120
|
+
}
|
|
121
|
+
declare class ContestIndex {
|
|
122
|
+
contest: Contest;
|
|
123
|
+
boardLink: string;
|
|
124
|
+
constructor();
|
|
125
|
+
}
|
|
126
|
+
type ContestIndexList = Array<ContestIndex>;
|
|
127
|
+
declare function createContestIndex(contestIndexJSON: ContestIndex$1): ContestIndex;
|
|
128
|
+
declare function createContestIndexList(contestListJSON: any): ContestIndexList;
|
|
129
|
+
|
|
130
130
|
declare function getImageSource(image: Image): string;
|
|
131
131
|
|
|
132
|
+
declare class RankStatistics {
|
|
133
|
+
teamSolvedNum: Array<number>;
|
|
134
|
+
constructor();
|
|
135
|
+
reset(): void;
|
|
136
|
+
}
|
|
137
|
+
|
|
132
138
|
declare class Team {
|
|
133
139
|
id: string;
|
|
134
140
|
name: string;
|
|
@@ -161,6 +167,7 @@ declare class Rank {
|
|
|
161
167
|
teamsMap: Map<string, Team>;
|
|
162
168
|
submissions: Submissions;
|
|
163
169
|
submissionsMap: Map<string, Submission>;
|
|
170
|
+
rankStatistics: RankStatistics;
|
|
164
171
|
constructor(contest: Contest, teams: Teams, submissions: Submissions);
|
|
165
172
|
buildRank(options?: {
|
|
166
173
|
timestamp?: number;
|
|
@@ -191,4 +198,4 @@ declare function isRejected(status: SubmissionStatus): boolean;
|
|
|
191
198
|
declare function isPending(status: SubmissionStatus): boolean;
|
|
192
199
|
declare function isNotCalculatedPenaltyStatus(status: SubmissionStatus): boolean;
|
|
193
200
|
|
|
194
|
-
export { Contest, ContestIndex, ContestIndexConfig, ContestIndexList, Problem, ProblemStatistics, Problems, Rank, Resolver, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, stringToSubmissionStatus };
|
|
201
|
+
export { Contest, ContestIndex, ContestIndexConfig, ContestIndexList, Problem, ProblemStatistics, Problems, Rank, RankStatistics, Resolver, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, stringToSubmissionStatus };
|
package/dist/index.mjs
CHANGED
|
@@ -54,81 +54,6 @@ function getTimeDiff(seconds) {
|
|
|
54
54
|
return [two(h), two(m), two(s)].join(":");
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
class ContestIndexConfig {
|
|
58
|
-
constructor() {
|
|
59
|
-
this.contestName = "";
|
|
60
|
-
this.startTime = createDayJS();
|
|
61
|
-
this.endTime = createDayJS();
|
|
62
|
-
this.freezeTime = createDayJS();
|
|
63
|
-
this.totalDurationTimestamp = 0;
|
|
64
|
-
this.freezeDurationTimestamp = 0;
|
|
65
|
-
this.unFreezeDurationTimestamp = 0;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
class ContestIndex {
|
|
69
|
-
constructor() {
|
|
70
|
-
this.config = new ContestIndexConfig();
|
|
71
|
-
this.boardLink = "";
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function createContestIndex(contestIndexJSON) {
|
|
75
|
-
const c = new ContestIndex();
|
|
76
|
-
const cc = c.config;
|
|
77
|
-
const cjc = contestIndexJSON.config;
|
|
78
|
-
cc.contestName = cjc.contest_name;
|
|
79
|
-
cc.startTime = createDayJS(cjc.start_time);
|
|
80
|
-
cc.endTime = createDayJS(cjc.end_time);
|
|
81
|
-
cc.totalDurationTimestamp = cc.endTime.unix() - cc.startTime.unix();
|
|
82
|
-
{
|
|
83
|
-
cc.freezeTime = cc.endTime;
|
|
84
|
-
cc.freezeDurationTimestamp = 0;
|
|
85
|
-
if (cjc.frozen_time !== void 0 && cjc.frozen_time != null) {
|
|
86
|
-
const frozenTime = Number(cjc.frozen_time);
|
|
87
|
-
cc.freezeTime = createDayJS(cc.endTime.unix() - frozenTime);
|
|
88
|
-
cc.freezeDurationTimestamp = frozenTime;
|
|
89
|
-
}
|
|
90
|
-
cc.unFreezeDurationTimestamp = cc.totalDurationTimestamp - cc.freezeDurationTimestamp;
|
|
91
|
-
}
|
|
92
|
-
cc.logo = cjc.logo;
|
|
93
|
-
c.boardLink = contestIndexJSON.board_link;
|
|
94
|
-
return c;
|
|
95
|
-
}
|
|
96
|
-
function createContestIndexList(contestListJSON) {
|
|
97
|
-
const contestIndexList = [];
|
|
98
|
-
const dfs = (contestList) => {
|
|
99
|
-
if (Object.prototype.hasOwnProperty.call(contestList, "config")) {
|
|
100
|
-
contestIndexList.push(createContestIndex(contestList));
|
|
101
|
-
} else {
|
|
102
|
-
for (const k in contestList) {
|
|
103
|
-
dfs(contestList[k]);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
dfs(contestListJSON);
|
|
108
|
-
contestIndexList.sort((a, b) => {
|
|
109
|
-
if (a.config.startTime.isBefore(b.config.startTime)) {
|
|
110
|
-
return 1;
|
|
111
|
-
}
|
|
112
|
-
if (a.config.startTime.isAfter(b.config.startTime)) {
|
|
113
|
-
return -1;
|
|
114
|
-
}
|
|
115
|
-
if (a.config.endTime.isBefore(b.config.endTime)) {
|
|
116
|
-
return 1;
|
|
117
|
-
}
|
|
118
|
-
if (a.config.endTime.isAfter(b.config.endTime)) {
|
|
119
|
-
return -1;
|
|
120
|
-
}
|
|
121
|
-
if (a.config.contestName < b.config.contestName) {
|
|
122
|
-
return 1;
|
|
123
|
-
}
|
|
124
|
-
if (a.config.contestName > b.config.contestName) {
|
|
125
|
-
return -1;
|
|
126
|
-
}
|
|
127
|
-
return 0;
|
|
128
|
-
});
|
|
129
|
-
return contestIndexList;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
57
|
class ProblemStatistics {
|
|
133
58
|
constructor() {
|
|
134
59
|
this.acceptedNum = 0;
|
|
@@ -256,8 +181,8 @@ class Contest {
|
|
|
256
181
|
getContestDuration(timeFormat = "HH:mm:ss") {
|
|
257
182
|
return dayjs.duration(this.endTime.diff(this.startTime)).format(timeFormat);
|
|
258
183
|
}
|
|
259
|
-
getContestState() {
|
|
260
|
-
const now = createDayJS();
|
|
184
|
+
getContestState(nowTime) {
|
|
185
|
+
const now = createDayJS(nowTime);
|
|
261
186
|
if (now.isBefore(this.startTime)) {
|
|
262
187
|
return ContestState.PENDING;
|
|
263
188
|
}
|
|
@@ -269,29 +194,29 @@ class Contest {
|
|
|
269
194
|
}
|
|
270
195
|
return ContestState.RUNNING;
|
|
271
196
|
}
|
|
272
|
-
getContestPendingTime() {
|
|
273
|
-
let baseTime = createDayJS();
|
|
197
|
+
getContestPendingTime(nowTime) {
|
|
198
|
+
let baseTime = createDayJS(nowTime);
|
|
274
199
|
if (baseTime.isAfter(this.startTime)) {
|
|
275
200
|
baseTime = this.startTime;
|
|
276
201
|
}
|
|
277
202
|
return getTimeDiff(Math.floor(dayjs.duration(this.startTime.diff(baseTime)).asSeconds()));
|
|
278
203
|
}
|
|
279
|
-
getContestRemainingTime(
|
|
280
|
-
let baseTime =
|
|
281
|
-
if (baseTime.isAfter(endTime)) {
|
|
282
|
-
baseTime = endTime;
|
|
204
|
+
getContestRemainingTime(nowTime) {
|
|
205
|
+
let baseTime = createDayJS(nowTime);
|
|
206
|
+
if (baseTime.isAfter(this.endTime)) {
|
|
207
|
+
baseTime = this.endTime;
|
|
283
208
|
}
|
|
284
|
-
return getTimeDiff(Math.floor(dayjs.duration(endTime.diff(baseTime)).asSeconds()));
|
|
209
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.endTime.diff(baseTime)).asSeconds()));
|
|
285
210
|
}
|
|
286
|
-
getContestElapsedTime() {
|
|
287
|
-
let baseTime =
|
|
211
|
+
getContestElapsedTime(nowTime) {
|
|
212
|
+
let baseTime = createDayJS(nowTime);
|
|
288
213
|
if (baseTime.isAfter(this.endTime)) {
|
|
289
214
|
baseTime = this.endTime;
|
|
290
215
|
}
|
|
291
216
|
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.startTime)).asSeconds()));
|
|
292
217
|
}
|
|
293
|
-
getContestProgressRatio() {
|
|
294
|
-
const baseTime =
|
|
218
|
+
getContestProgressRatio(nowTime) {
|
|
219
|
+
const baseTime = createDayJS(nowTime);
|
|
295
220
|
if (this.startTime.isSameOrAfter(baseTime)) {
|
|
296
221
|
return 0;
|
|
297
222
|
}
|
|
@@ -351,6 +276,66 @@ function createContest(contestJSON) {
|
|
|
351
276
|
return c;
|
|
352
277
|
}
|
|
353
278
|
|
|
279
|
+
class ContestIndexConfig {
|
|
280
|
+
constructor() {
|
|
281
|
+
this.contestName = "";
|
|
282
|
+
this.startTime = createDayJS();
|
|
283
|
+
this.endTime = createDayJS();
|
|
284
|
+
this.freezeTime = createDayJS();
|
|
285
|
+
this.totalDurationTimestamp = 0;
|
|
286
|
+
this.freezeDurationTimestamp = 0;
|
|
287
|
+
this.unFreezeDurationTimestamp = 0;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
class ContestIndex {
|
|
291
|
+
constructor() {
|
|
292
|
+
this.contest = new Contest();
|
|
293
|
+
this.boardLink = "";
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function createContestIndex(contestIndexJSON) {
|
|
297
|
+
const c = new ContestIndex();
|
|
298
|
+
const cjc = contestIndexJSON.config;
|
|
299
|
+
c.contest = createContest(cjc);
|
|
300
|
+
c.boardLink = contestIndexJSON.board_link;
|
|
301
|
+
return c;
|
|
302
|
+
}
|
|
303
|
+
function createContestIndexList(contestListJSON) {
|
|
304
|
+
const contestIndexList = [];
|
|
305
|
+
const dfs = (contestList) => {
|
|
306
|
+
if (Object.prototype.hasOwnProperty.call(contestList, "config")) {
|
|
307
|
+
contestIndexList.push(createContestIndex(contestList));
|
|
308
|
+
} else {
|
|
309
|
+
for (const k in contestList) {
|
|
310
|
+
dfs(contestList[k]);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
dfs(contestListJSON);
|
|
315
|
+
contestIndexList.sort((a, b) => {
|
|
316
|
+
if (a.contest.startTime.isBefore(b.contest.startTime)) {
|
|
317
|
+
return 1;
|
|
318
|
+
}
|
|
319
|
+
if (a.contest.startTime.isAfter(b.contest.startTime)) {
|
|
320
|
+
return -1;
|
|
321
|
+
}
|
|
322
|
+
if (a.contest.endTime.isBefore(b.contest.endTime)) {
|
|
323
|
+
return 1;
|
|
324
|
+
}
|
|
325
|
+
if (a.contest.endTime.isAfter(b.contest.endTime)) {
|
|
326
|
+
return -1;
|
|
327
|
+
}
|
|
328
|
+
if (a.contest.name < b.contest.name) {
|
|
329
|
+
return 1;
|
|
330
|
+
}
|
|
331
|
+
if (a.contest.name > b.contest.name) {
|
|
332
|
+
return -1;
|
|
333
|
+
}
|
|
334
|
+
return 0;
|
|
335
|
+
});
|
|
336
|
+
return contestIndexList;
|
|
337
|
+
}
|
|
338
|
+
|
|
354
339
|
function getImageSource(image) {
|
|
355
340
|
if (image?.url) {
|
|
356
341
|
return image.url;
|
|
@@ -361,6 +346,15 @@ function getImageSource(image) {
|
|
|
361
346
|
return "";
|
|
362
347
|
}
|
|
363
348
|
|
|
349
|
+
class RankStatistics {
|
|
350
|
+
constructor() {
|
|
351
|
+
this.teamSolvedNum = [];
|
|
352
|
+
}
|
|
353
|
+
reset() {
|
|
354
|
+
this.teamSolvedNum = [];
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
364
358
|
class Team {
|
|
365
359
|
constructor() {
|
|
366
360
|
this.id = "";
|
|
@@ -626,6 +620,7 @@ class Rank {
|
|
|
626
620
|
this.teamsMap = new Map(this.teams.map((t) => [t.id, t]));
|
|
627
621
|
this.submissions = _.cloneDeep(submissions).sort(Submission.compare);
|
|
628
622
|
this.submissionsMap = new Map(this.submissions.map((s) => [s.id, s]));
|
|
623
|
+
this.rankStatistics = new RankStatistics();
|
|
629
624
|
}
|
|
630
625
|
buildRank(options) {
|
|
631
626
|
(() => {
|
|
@@ -712,6 +707,13 @@ class Rank {
|
|
|
712
707
|
}
|
|
713
708
|
}
|
|
714
709
|
})();
|
|
710
|
+
(() => {
|
|
711
|
+
this.rankStatistics.reset();
|
|
712
|
+
this.rankStatistics.teamSolvedNum = Array(this.contest.problems.length + 1).fill(0);
|
|
713
|
+
for (const t of this.teams) {
|
|
714
|
+
this.rankStatistics.teamSolvedNum[t.solvedProblemNum]++;
|
|
715
|
+
}
|
|
716
|
+
})();
|
|
715
717
|
return this;
|
|
716
718
|
}
|
|
717
719
|
}
|
|
@@ -804,4 +806,4 @@ class Resolver extends Rank {
|
|
|
804
806
|
}
|
|
805
807
|
}
|
|
806
808
|
|
|
807
|
-
export { Contest, ContestIndex, ContestIndexConfig, Problem, ProblemStatistics, Rank, Resolver, Submission, Team, TeamProblemStatistics, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, stringToSubmissionStatus };
|
|
809
|
+
export { Contest, ContestIndex, ContestIndexConfig, Problem, ProblemStatistics, Rank, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, stringToSubmissionStatus };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcpcio/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "XCPCIO Core",
|
|
5
5
|
"author": "Dup4 <lyuzhi.pan@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"dayjs": "^1.11.8",
|
|
44
44
|
"lodash": "^4.17.21",
|
|
45
|
-
"@xcpcio/types": "0.4.
|
|
45
|
+
"@xcpcio/types": "0.4.2"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@babel/types": "^7.22.4",
|
package/src/contest-index.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type dayjs from "dayjs";
|
|
2
2
|
|
|
3
|
-
import type { ContestIndex as IContestIndex, Image } from "@xcpcio/types";
|
|
3
|
+
import type { Contest as IContest, ContestIndex as IContestIndex, Image } from "@xcpcio/types";
|
|
4
4
|
|
|
5
5
|
import { createDayJS } from "./utils";
|
|
6
|
+
import { Contest, createContest } from "./contest";
|
|
6
7
|
|
|
7
8
|
export class ContestIndexConfig {
|
|
8
9
|
contestName: string;
|
|
@@ -31,11 +32,11 @@ export class ContestIndexConfig {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export class ContestIndex {
|
|
34
|
-
|
|
35
|
+
contest: Contest;
|
|
35
36
|
boardLink: string;
|
|
36
37
|
|
|
37
38
|
constructor() {
|
|
38
|
-
this.
|
|
39
|
+
this.contest = new Contest();
|
|
39
40
|
this.boardLink = "";
|
|
40
41
|
}
|
|
41
42
|
}
|
|
@@ -44,33 +45,9 @@ export type ContestIndexList = Array<ContestIndex>;
|
|
|
44
45
|
|
|
45
46
|
export function createContestIndex(contestIndexJSON: IContestIndex): ContestIndex {
|
|
46
47
|
const c = new ContestIndex();
|
|
47
|
-
const cc = c.config;
|
|
48
48
|
const cjc = contestIndexJSON.config;
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
cc.startTime = createDayJS(cjc.start_time);
|
|
53
|
-
cc.endTime = createDayJS(cjc.end_time);
|
|
54
|
-
|
|
55
|
-
cc.totalDurationTimestamp = cc.endTime.unix() - cc.startTime.unix();
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
// default value
|
|
59
|
-
cc.freezeTime = cc.endTime;
|
|
60
|
-
cc.freezeDurationTimestamp = 0;
|
|
61
|
-
|
|
62
|
-
if (cjc.frozen_time !== undefined && cjc.frozen_time != null) {
|
|
63
|
-
const frozenTime = Number(cjc.frozen_time);
|
|
64
|
-
|
|
65
|
-
cc.freezeTime = createDayJS(cc.endTime.unix() - frozenTime);
|
|
66
|
-
cc.freezeDurationTimestamp = frozenTime;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
cc.unFreezeDurationTimestamp = cc.totalDurationTimestamp - cc.freezeDurationTimestamp;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
cc.logo = cjc.logo;
|
|
73
|
-
|
|
50
|
+
c.contest = createContest(cjc as IContest);
|
|
74
51
|
c.boardLink = contestIndexJSON.board_link;
|
|
75
52
|
|
|
76
53
|
return c;
|
|
@@ -92,27 +69,27 @@ export function createContestIndexList(contestListJSON: any): ContestIndexList {
|
|
|
92
69
|
dfs(contestListJSON);
|
|
93
70
|
|
|
94
71
|
contestIndexList.sort((a: ContestIndex, b: ContestIndex) => {
|
|
95
|
-
if (a.
|
|
72
|
+
if (a.contest.startTime.isBefore(b.contest.startTime)) {
|
|
96
73
|
return 1;
|
|
97
74
|
}
|
|
98
75
|
|
|
99
|
-
if (a.
|
|
76
|
+
if (a.contest.startTime.isAfter(b.contest.startTime)) {
|
|
100
77
|
return -1;
|
|
101
78
|
}
|
|
102
79
|
|
|
103
|
-
if (a.
|
|
80
|
+
if (a.contest.endTime.isBefore(b.contest.endTime)) {
|
|
104
81
|
return 1;
|
|
105
82
|
}
|
|
106
83
|
|
|
107
|
-
if (a.
|
|
84
|
+
if (a.contest.endTime.isAfter(b.contest.endTime)) {
|
|
108
85
|
return -1;
|
|
109
86
|
}
|
|
110
87
|
|
|
111
|
-
if (a.
|
|
88
|
+
if (a.contest.name < b.contest.name) {
|
|
112
89
|
return 1;
|
|
113
90
|
}
|
|
114
91
|
|
|
115
|
-
if (a.
|
|
92
|
+
if (a.contest.name > b.contest.name) {
|
|
116
93
|
return -1;
|
|
117
94
|
}
|
|
118
95
|
|
package/src/contest.ts
CHANGED
|
@@ -62,8 +62,8 @@ export class Contest {
|
|
|
62
62
|
return dayjs.duration(this.endTime.diff(this.startTime)).format(timeFormat);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
getContestState(): ContestState {
|
|
66
|
-
const now = createDayJS();
|
|
65
|
+
getContestState(nowTime?: Date): ContestState {
|
|
66
|
+
const now = createDayJS(nowTime);
|
|
67
67
|
|
|
68
68
|
if (now.isBefore(this.startTime)) {
|
|
69
69
|
return ContestState.PENDING;
|
|
@@ -80,8 +80,8 @@ export class Contest {
|
|
|
80
80
|
return ContestState.RUNNING;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
getContestPendingTime(): string {
|
|
84
|
-
let baseTime = createDayJS();
|
|
83
|
+
getContestPendingTime(nowTime?: Date): string {
|
|
84
|
+
let baseTime = createDayJS(nowTime);
|
|
85
85
|
if (baseTime.isAfter(this.startTime)) {
|
|
86
86
|
baseTime = this.startTime;
|
|
87
87
|
}
|
|
@@ -89,17 +89,17 @@ export class Contest {
|
|
|
89
89
|
return getTimeDiff(Math.floor(dayjs.duration(this.startTime.diff(baseTime)).asSeconds()));
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
getContestRemainingTime(
|
|
93
|
-
let baseTime =
|
|
94
|
-
if (baseTime.isAfter(endTime)) {
|
|
95
|
-
baseTime = endTime;
|
|
92
|
+
getContestRemainingTime(nowTime?: Date): string {
|
|
93
|
+
let baseTime = createDayJS(nowTime);
|
|
94
|
+
if (baseTime.isAfter(this.endTime)) {
|
|
95
|
+
baseTime = this.endTime;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
return getTimeDiff(Math.floor(dayjs.duration(endTime.diff(baseTime)).asSeconds()));
|
|
98
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.endTime.diff(baseTime)).asSeconds()));
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
getContestElapsedTime(): string {
|
|
102
|
-
let baseTime =
|
|
101
|
+
getContestElapsedTime(nowTime?: Date): string {
|
|
102
|
+
let baseTime = createDayJS(nowTime);
|
|
103
103
|
if (baseTime.isAfter(this.endTime)) {
|
|
104
104
|
baseTime = this.endTime;
|
|
105
105
|
}
|
|
@@ -107,8 +107,8 @@ export class Contest {
|
|
|
107
107
|
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.startTime)).asSeconds()));
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
getContestProgressRatio(): number {
|
|
111
|
-
const baseTime =
|
|
110
|
+
getContestProgressRatio(nowTime?: Date): number {
|
|
111
|
+
const baseTime = createDayJS(nowTime);
|
|
112
112
|
|
|
113
113
|
if (this.startTime.isSameOrAfter(baseTime)) {
|
|
114
114
|
return 0;
|
package/src/index.ts
CHANGED
package/src/rank.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { Team } from "./team";
|
|
|
6
6
|
import type { Submissions } from "./submission";
|
|
7
7
|
import { Submission } from "./submission";
|
|
8
8
|
import { TeamProblemStatistics } from "./problem";
|
|
9
|
+
import { RankStatistics } from "./rank-statistics";
|
|
9
10
|
|
|
10
11
|
export class Rank {
|
|
11
12
|
readonly contest: Contest;
|
|
@@ -16,6 +17,8 @@ export class Rank {
|
|
|
16
17
|
submissions: Submissions;
|
|
17
18
|
submissionsMap: Map<string, Submission>;
|
|
18
19
|
|
|
20
|
+
rankStatistics: RankStatistics;
|
|
21
|
+
|
|
19
22
|
constructor(contest: Contest, teams: Teams, submissions: Submissions) {
|
|
20
23
|
this.contest = contest;
|
|
21
24
|
|
|
@@ -24,6 +27,8 @@ export class Rank {
|
|
|
24
27
|
|
|
25
28
|
this.submissions = _.cloneDeep(submissions).sort(Submission.compare);
|
|
26
29
|
this.submissionsMap = new Map(this.submissions.map(s => [s.id, s]));
|
|
30
|
+
|
|
31
|
+
this.rankStatistics = new RankStatistics();
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
buildRank(options?: { timestamp?: number }) {
|
|
@@ -137,6 +142,16 @@ export class Rank {
|
|
|
137
142
|
}
|
|
138
143
|
})();
|
|
139
144
|
|
|
145
|
+
(() => {
|
|
146
|
+
this.rankStatistics.reset();
|
|
147
|
+
|
|
148
|
+
this.rankStatistics.teamSolvedNum = Array(this.contest.problems.length + 1).fill(0);
|
|
149
|
+
|
|
150
|
+
for (const t of this.teams) {
|
|
151
|
+
this.rankStatistics.teamSolvedNum[t.solvedProblemNum]++;
|
|
152
|
+
}
|
|
153
|
+
})();
|
|
154
|
+
|
|
140
155
|
return this;
|
|
141
156
|
}
|
|
142
157
|
}
|