@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 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(endTime) {
296
- let baseTime = dayjs__default();
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 = dayjs__default();
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 = dayjs__default();
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 { Image, ContestIndex as ContestIndex$1, SubmissionStatus, Submission as Submission$1, Submissions as Submissions$1, BalloonColor, Problem as Problem$1, Problems as Problems$1, StatusTimeDisplay, ContestState, Contest as Contest$1, Team as Team$1, Teams as Teams$1 } from '@xcpcio/types';
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(endTime: dayjs.Dayjs): string;
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(endTime) {
280
- let baseTime = dayjs();
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 = dayjs();
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 = dayjs();
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.0",
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.0"
45
+ "@xcpcio/types": "0.4.2"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@babel/types": "^7.22.4",
@@ -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
- config: ContestIndexConfig;
35
+ contest: Contest;
35
36
  boardLink: string;
36
37
 
37
38
  constructor() {
38
- this.config = new ContestIndexConfig();
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
- cc.contestName = cjc.contest_name;
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.config.startTime.isBefore(b.config.startTime)) {
72
+ if (a.contest.startTime.isBefore(b.contest.startTime)) {
96
73
  return 1;
97
74
  }
98
75
 
99
- if (a.config.startTime.isAfter(b.config.startTime)) {
76
+ if (a.contest.startTime.isAfter(b.contest.startTime)) {
100
77
  return -1;
101
78
  }
102
79
 
103
- if (a.config.endTime.isBefore(b.config.endTime)) {
80
+ if (a.contest.endTime.isBefore(b.contest.endTime)) {
104
81
  return 1;
105
82
  }
106
83
 
107
- if (a.config.endTime.isAfter(b.config.endTime)) {
84
+ if (a.contest.endTime.isAfter(b.contest.endTime)) {
108
85
  return -1;
109
86
  }
110
87
 
111
- if (a.config.contestName < b.config.contestName) {
88
+ if (a.contest.name < b.contest.name) {
112
89
  return 1;
113
90
  }
114
91
 
115
- if (a.config.contestName > b.config.contestName) {
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(endTime: dayjs.Dayjs): string {
93
- let baseTime = dayjs();
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 = dayjs();
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 = dayjs();
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
@@ -3,6 +3,7 @@ export * from "./utils";
3
3
  export * from "./contest";
4
4
  export * from "./image";
5
5
  export * from "./problem";
6
+ export * from "./rank-statistics";
6
7
  export * from "./rank";
7
8
  export * from "./resolver";
8
9
  export * from "./submission-status";
@@ -0,0 +1,11 @@
1
+ export class RankStatistics {
2
+ teamSolvedNum: Array<number>;
3
+
4
+ constructor() {
5
+ this.teamSolvedNum = [];
6
+ }
7
+
8
+ reset() {
9
+ this.teamSolvedNum = [];
10
+ }
11
+ }
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
  }