@xcpcio/core 0.35.1 → 0.37.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 +137 -27
- package/dist/index.d.ts +16 -0
- package/dist/index.mjs +137 -27
- package/package.json +2 -2
- package/src/contest.ts +63 -21
- package/src/export/general-excel.ts +36 -1
- package/src/rank.ts +40 -5
- package/src/submission.ts +2 -0
- package/src/team.ts +26 -0
package/dist/index.cjs
CHANGED
|
@@ -409,6 +409,8 @@ class GeneralExcelConverter {
|
|
|
409
409
|
convertToAoa(rank) {
|
|
410
410
|
const aoa = [];
|
|
411
411
|
const enableAwards = rank.contest.isEnableAwards(rank.options.group);
|
|
412
|
+
const enableMembers = (Array.isArray(rank.teams) && rank.teams[0]?.members) ?? false;
|
|
413
|
+
const enableCoach = rank.teams[0]?.coach ?? false;
|
|
412
414
|
{
|
|
413
415
|
aoa.push([rank.contest.name]);
|
|
414
416
|
}
|
|
@@ -419,10 +421,18 @@ class GeneralExcelConverter {
|
|
|
419
421
|
head.push(`${rank.contest.organization} Rank`);
|
|
420
422
|
head.push(rank.contest.organization);
|
|
421
423
|
}
|
|
422
|
-
head.push("
|
|
424
|
+
head.push("Team", "Solved", "Penalty", ...rank.contest.problems.map((p) => p.label), "Dirt");
|
|
423
425
|
if (enableAwards) {
|
|
424
426
|
head.push("Medal");
|
|
425
427
|
}
|
|
428
|
+
if (enableMembers) {
|
|
429
|
+
head.push("Member1", "Member2", "Member3");
|
|
430
|
+
}
|
|
431
|
+
if (enableCoach) {
|
|
432
|
+
head.push("Coach");
|
|
433
|
+
}
|
|
434
|
+
head.push("Unofficial");
|
|
435
|
+
head.push("Girl");
|
|
426
436
|
aoa.push(head);
|
|
427
437
|
}
|
|
428
438
|
for (const team of rank.teams) {
|
|
@@ -456,6 +466,25 @@ class GeneralExcelConverter {
|
|
|
456
466
|
const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
|
|
457
467
|
arr.push(medals.join(", "));
|
|
458
468
|
}
|
|
469
|
+
if (enableMembers) {
|
|
470
|
+
const members = team.members;
|
|
471
|
+
if (Array.isArray(members)) {
|
|
472
|
+
arr.push(members[0] ?? "");
|
|
473
|
+
arr.push(members[1] ?? "");
|
|
474
|
+
arr.push(members[2] ?? "");
|
|
475
|
+
} else {
|
|
476
|
+
arr.push("", "", "");
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (enableCoach) {
|
|
480
|
+
if (typeof team.coach === "string") {
|
|
481
|
+
arr.push(team.coach ?? "");
|
|
482
|
+
} else {
|
|
483
|
+
arr.push("");
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
arr.push(team.isUnofficial ? "Y" : "N");
|
|
487
|
+
arr.push(team.isGirl ? "Y" : "N");
|
|
459
488
|
aoa.push(arr);
|
|
460
489
|
}
|
|
461
490
|
return aoa;
|
|
@@ -661,6 +690,26 @@ class Team {
|
|
|
661
690
|
const solvedNum = this.solvedProblemNum;
|
|
662
691
|
return calcDirt(attemptedNum, solvedNum);
|
|
663
692
|
}
|
|
693
|
+
get isUnofficial() {
|
|
694
|
+
return this.group.includes("unofficial");
|
|
695
|
+
}
|
|
696
|
+
get isGirl() {
|
|
697
|
+
return this.group.includes("girl");
|
|
698
|
+
}
|
|
699
|
+
get membersToArray() {
|
|
700
|
+
if (Array.isArray(this.members)) {
|
|
701
|
+
return this.members;
|
|
702
|
+
}
|
|
703
|
+
if (typeof this.members === "string") {
|
|
704
|
+
if (this.members.includes(", ")) {
|
|
705
|
+
return this.members.split(", ");
|
|
706
|
+
}
|
|
707
|
+
if (this.members.includes("\u3001")) {
|
|
708
|
+
return this.members.split("\u3001");
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return [];
|
|
712
|
+
}
|
|
664
713
|
get membersToString() {
|
|
665
714
|
if (typeof this.members === "string") {
|
|
666
715
|
return this.members;
|
|
@@ -787,6 +836,8 @@ class Submission {
|
|
|
787
836
|
constructor() {
|
|
788
837
|
this.status = types.SubmissionStatus.UNKNOWN;
|
|
789
838
|
this.isIgnore = false;
|
|
839
|
+
this.isSolved = false;
|
|
840
|
+
this.isFirstSolved = false;
|
|
790
841
|
this.id = "";
|
|
791
842
|
this.teamId = "";
|
|
792
843
|
this.problemId = "";
|
|
@@ -957,59 +1008,68 @@ class Contest {
|
|
|
957
1008
|
this.tag = /* @__PURE__ */ new Map();
|
|
958
1009
|
this.options = new ContestOptions();
|
|
959
1010
|
}
|
|
1011
|
+
getStartTime() {
|
|
1012
|
+
return this.replayStartTime ?? this.startTime;
|
|
1013
|
+
}
|
|
1014
|
+
getEndTime() {
|
|
1015
|
+
return this.replayEndTime ?? this.endTime;
|
|
1016
|
+
}
|
|
1017
|
+
getFreezeTime() {
|
|
1018
|
+
return this.replayFreezeTime ?? this.freezeTime;
|
|
1019
|
+
}
|
|
960
1020
|
getContestDuration(timeFormat = "HH:mm:ss") {
|
|
961
|
-
return dayjs__default.duration(this.
|
|
1021
|
+
return dayjs__default.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
|
|
962
1022
|
}
|
|
963
1023
|
getContestState(nowTime) {
|
|
964
1024
|
const now = createDayJS(nowTime);
|
|
965
|
-
if (now.isBefore(this.
|
|
1025
|
+
if (now.isBefore(this.getStartTime())) {
|
|
966
1026
|
return types.ContestState.PENDING;
|
|
967
1027
|
}
|
|
968
|
-
if (now.isSameOrAfter(this.
|
|
1028
|
+
if (now.isSameOrAfter(this.getEndTime())) {
|
|
969
1029
|
return types.ContestState.FINISHED;
|
|
970
1030
|
}
|
|
971
|
-
if (now.isSameOrAfter(this.
|
|
1031
|
+
if (now.isSameOrAfter(this.getFreezeTime())) {
|
|
972
1032
|
return types.ContestState.FROZEN;
|
|
973
1033
|
}
|
|
974
1034
|
return types.ContestState.RUNNING;
|
|
975
1035
|
}
|
|
976
1036
|
getContestPendingTime(nowTime) {
|
|
977
1037
|
let baseTime = createDayJS(nowTime);
|
|
978
|
-
if (baseTime.isAfter(this.
|
|
979
|
-
baseTime = this.
|
|
1038
|
+
if (baseTime.isAfter(this.getStartTime())) {
|
|
1039
|
+
baseTime = this.getStartTime();
|
|
980
1040
|
}
|
|
981
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(this.
|
|
1041
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(this.getStartTime().diff(baseTime)).asSeconds()));
|
|
982
1042
|
}
|
|
983
1043
|
getContestElapsedTime(nowTime) {
|
|
984
1044
|
let baseTime = createDayJS(nowTime);
|
|
985
|
-
if (baseTime.isAfter(this.
|
|
986
|
-
baseTime = this.
|
|
1045
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
1046
|
+
baseTime = this.getEndTime();
|
|
987
1047
|
}
|
|
988
|
-
if (baseTime.isBefore(this.
|
|
989
|
-
baseTime = this.
|
|
1048
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
1049
|
+
baseTime = this.getStartTime();
|
|
990
1050
|
}
|
|
991
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(baseTime.diff(this.
|
|
1051
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(baseTime.diff(this.getStartTime())).asSeconds()));
|
|
992
1052
|
}
|
|
993
1053
|
getContestRemainingTime(nowTime) {
|
|
994
1054
|
let baseTime = createDayJS(nowTime);
|
|
995
|
-
if (baseTime.isAfter(this.
|
|
996
|
-
baseTime = this.
|
|
1055
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
1056
|
+
baseTime = this.getEndTime();
|
|
997
1057
|
}
|
|
998
|
-
if (baseTime.isBefore(this.
|
|
999
|
-
baseTime = this.
|
|
1058
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
1059
|
+
baseTime = this.getStartTime();
|
|
1000
1060
|
}
|
|
1001
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(this.
|
|
1061
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(this.getEndTime().diff(baseTime)).asSeconds()));
|
|
1002
1062
|
}
|
|
1003
1063
|
getContestProgressRatio(nowTime) {
|
|
1004
1064
|
const baseTime = createDayJS(nowTime);
|
|
1005
|
-
if (this.
|
|
1065
|
+
if (this.getStartTime().isSameOrAfter(baseTime)) {
|
|
1006
1066
|
return 0;
|
|
1007
1067
|
}
|
|
1008
|
-
if (this.
|
|
1068
|
+
if (this.getEndTime().isSameOrBefore(baseTime)) {
|
|
1009
1069
|
return 100;
|
|
1010
1070
|
}
|
|
1011
|
-
const total = this.
|
|
1012
|
-
const pass = baseTime.diff(this.
|
|
1071
|
+
const total = this.getEndTime().diff(this.getStartTime(), "s");
|
|
1072
|
+
const pass = baseTime.diff(this.getStartTime(), "s");
|
|
1013
1073
|
return Math.round(pass * 100 / total);
|
|
1014
1074
|
}
|
|
1015
1075
|
isEnableAwards(group) {
|
|
@@ -1021,6 +1081,26 @@ class Contest {
|
|
|
1021
1081
|
}
|
|
1022
1082
|
return true;
|
|
1023
1083
|
}
|
|
1084
|
+
resetReplayTime() {
|
|
1085
|
+
this.replayStartTime = void 0;
|
|
1086
|
+
this.replayEndTime = void 0;
|
|
1087
|
+
this.replayFreezeTime = void 0;
|
|
1088
|
+
this.replayNowTime = void 0;
|
|
1089
|
+
this.replayContestStartTimestamp = void 0;
|
|
1090
|
+
}
|
|
1091
|
+
setReplayTime(replayStartTimestamp) {
|
|
1092
|
+
if (replayStartTimestamp === 0) {
|
|
1093
|
+
this.resetReplayTime();
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
const replayStartTime = createDayJS(replayStartTimestamp);
|
|
1097
|
+
const diff = replayStartTime.diff(this.startTime, "s");
|
|
1098
|
+
this.replayStartTime = this.startTime.add(diff, "s");
|
|
1099
|
+
this.replayEndTime = this.endTime.add(diff, "s");
|
|
1100
|
+
this.replayFreezeTime = this.freezeTime.add(diff, "s");
|
|
1101
|
+
this.replayNowTime = createDayJS();
|
|
1102
|
+
this.replayContestStartTimestamp = this.replayNowTime.diff(this.replayStartTime, "s");
|
|
1103
|
+
}
|
|
1024
1104
|
}
|
|
1025
1105
|
function createContest(contestJSON) {
|
|
1026
1106
|
const c = new Contest();
|
|
@@ -1233,7 +1313,7 @@ class RankOptions {
|
|
|
1233
1313
|
}
|
|
1234
1314
|
setWidth(width, contest) {
|
|
1235
1315
|
this.width = width;
|
|
1236
|
-
this.timestamp = Math.floor((contest.
|
|
1316
|
+
this.timestamp = Math.floor((contest.getEndTime().unix() - contest.getStartTime().unix()) * this.width * 1e-4);
|
|
1237
1317
|
this.enableFilterSubmissionsByTimestamp = true;
|
|
1238
1318
|
}
|
|
1239
1319
|
disableFilterSubmissionByTimestamp() {
|
|
@@ -1382,6 +1462,8 @@ class Rank {
|
|
|
1382
1462
|
team.submissions.push(s);
|
|
1383
1463
|
problem.statistics.submittedNum++;
|
|
1384
1464
|
if (problemStatistics.isSolved) {
|
|
1465
|
+
s.isSolved = false;
|
|
1466
|
+
s.isFirstSolved = false;
|
|
1385
1467
|
return;
|
|
1386
1468
|
}
|
|
1387
1469
|
if (s.isIgnore || s.isNotCalculatedPenaltyStatus()) {
|
|
@@ -1393,11 +1475,13 @@ class Rank {
|
|
|
1393
1475
|
problemStatistics.lastSubmitTimestamp = s.timestampToSecond;
|
|
1394
1476
|
problemStatistics.totalCount++;
|
|
1395
1477
|
if (s.isAccepted()) {
|
|
1478
|
+
s.isSolved = true;
|
|
1396
1479
|
problemStatistics.isSolved = true;
|
|
1397
1480
|
problemStatistics.solvedTimestamp = s.timestampToSecond;
|
|
1398
1481
|
problem.statistics.acceptedNum++;
|
|
1399
1482
|
problem.statistics.attemptedNum += problemStatistics.failedCount + 1;
|
|
1400
1483
|
if (problem.statistics.firstSolveSubmissions.length === 0 || problem.statistics.firstSolveSubmissions[problem.statistics.firstSolveSubmissions.length - 1].timestamp === s.timestamp) {
|
|
1484
|
+
s.isFirstSolved = true;
|
|
1401
1485
|
problemStatistics.isFirstSolved = true;
|
|
1402
1486
|
problem.statistics.firstSolveSubmissions.push(s);
|
|
1403
1487
|
}
|
|
@@ -1523,6 +1607,7 @@ class Rank {
|
|
|
1523
1607
|
const gold = new Award();
|
|
1524
1608
|
const silver = new Award();
|
|
1525
1609
|
const bronze = new Award();
|
|
1610
|
+
const honorable = new Award();
|
|
1526
1611
|
{
|
|
1527
1612
|
gold.medalType = MedalType.GOLD;
|
|
1528
1613
|
gold.minRank = 1;
|
|
@@ -1547,6 +1632,18 @@ class Rank {
|
|
|
1547
1632
|
award.push(bronze);
|
|
1548
1633
|
}
|
|
1549
1634
|
}
|
|
1635
|
+
{
|
|
1636
|
+
honorable.medalType = MedalType.HONORABLE;
|
|
1637
|
+
honorable.minRank = bronze.maxRank + 1;
|
|
1638
|
+
this.teams.forEach((t) => {
|
|
1639
|
+
if (t.solvedProblemNum > 0) {
|
|
1640
|
+
honorable.maxRank = Math.max(honorable.maxRank, t.rank);
|
|
1641
|
+
}
|
|
1642
|
+
});
|
|
1643
|
+
if (honorable.maxRank >= honorable.minRank) {
|
|
1644
|
+
award.push(honorable);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1550
1647
|
this.contest.awards.set("official", award);
|
|
1551
1648
|
}
|
|
1552
1649
|
}
|
|
@@ -1560,12 +1657,22 @@ class Rank {
|
|
|
1560
1657
|
return false;
|
|
1561
1658
|
}
|
|
1562
1659
|
getSubmissions() {
|
|
1563
|
-
if (this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1660
|
+
if (this.contest.replayContestStartTimestamp === void 0 && this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1564
1661
|
return this.submissions;
|
|
1565
1662
|
}
|
|
1566
|
-
return this.submissions.filter(
|
|
1567
|
-
(
|
|
1568
|
-
|
|
1663
|
+
return this.submissions.filter((s) => {
|
|
1664
|
+
if (this.contest.replayContestStartTimestamp !== void 0) {
|
|
1665
|
+
if (s.timestampToSecond > this.contest.replayContestStartTimestamp) {
|
|
1666
|
+
return false;
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
if (this.options.enableFilterSubmissionsByTimestamp) {
|
|
1670
|
+
if (s.timestampToSecond > this.options.timestamp) {
|
|
1671
|
+
return false;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
return true;
|
|
1675
|
+
});
|
|
1569
1676
|
}
|
|
1570
1677
|
buildBalloons() {
|
|
1571
1678
|
this.balloons = [];
|
|
@@ -1597,6 +1704,9 @@ class Rank {
|
|
|
1597
1704
|
})();
|
|
1598
1705
|
}
|
|
1599
1706
|
}
|
|
1707
|
+
setReplayTime(replayStartTimestamp) {
|
|
1708
|
+
this.contest.setReplayTime(replayStartTimestamp);
|
|
1709
|
+
}
|
|
1600
1710
|
}
|
|
1601
1711
|
|
|
1602
1712
|
class ResolverOperation {
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ declare class Submission {
|
|
|
13
13
|
language?: string;
|
|
14
14
|
status: SubmissionStatus;
|
|
15
15
|
isIgnore: boolean;
|
|
16
|
+
isSolved: boolean;
|
|
17
|
+
isFirstSolved: boolean;
|
|
16
18
|
constructor();
|
|
17
19
|
isAccepted(): boolean;
|
|
18
20
|
isRejected(): boolean;
|
|
@@ -126,6 +128,11 @@ declare class Contest {
|
|
|
126
128
|
startTime: dayjs.Dayjs;
|
|
127
129
|
endTime: dayjs.Dayjs;
|
|
128
130
|
freezeTime: dayjs.Dayjs;
|
|
131
|
+
replayStartTime?: dayjs.Dayjs;
|
|
132
|
+
replayEndTime?: dayjs.Dayjs;
|
|
133
|
+
replayFreezeTime?: dayjs.Dayjs;
|
|
134
|
+
replayNowTime?: dayjs.Dayjs;
|
|
135
|
+
replayContestStartTimestamp?: number;
|
|
129
136
|
totalDurationTimestamp: number;
|
|
130
137
|
freezeDurationTimestamp: number;
|
|
131
138
|
unFreezeDurationTimestamp: number;
|
|
@@ -144,6 +151,9 @@ declare class Contest {
|
|
|
144
151
|
boardLink?: string;
|
|
145
152
|
options: ContestOptions;
|
|
146
153
|
constructor();
|
|
154
|
+
getStartTime(): dayjs.Dayjs;
|
|
155
|
+
getEndTime(): dayjs.Dayjs;
|
|
156
|
+
getFreezeTime(): dayjs.Dayjs;
|
|
147
157
|
getContestDuration(timeFormat?: string): string;
|
|
148
158
|
getContestState(nowTime?: Date): ContestState;
|
|
149
159
|
getContestPendingTime(nowTime?: Date): string;
|
|
@@ -151,6 +161,8 @@ declare class Contest {
|
|
|
151
161
|
getContestRemainingTime(nowTime?: Date): string;
|
|
152
162
|
getContestProgressRatio(nowTime?: Date): number;
|
|
153
163
|
isEnableAwards(group: string): boolean;
|
|
164
|
+
resetReplayTime(): void;
|
|
165
|
+
setReplayTime(replayStartTimestamp: number): void;
|
|
154
166
|
}
|
|
155
167
|
declare function createContest(contestJSON: Contest$1): Contest;
|
|
156
168
|
|
|
@@ -187,6 +199,9 @@ declare class Team {
|
|
|
187
199
|
reset(): void;
|
|
188
200
|
get penaltyToMinute(): number;
|
|
189
201
|
get dirt(): number;
|
|
202
|
+
get isUnofficial(): boolean;
|
|
203
|
+
get isGirl(): boolean;
|
|
204
|
+
get membersToArray(): string[];
|
|
190
205
|
get membersToString(): string | undefined;
|
|
191
206
|
get isEffectiveTeam(): boolean;
|
|
192
207
|
calcSolvedData(options: ContestOptions): void;
|
|
@@ -266,6 +281,7 @@ declare class Rank {
|
|
|
266
281
|
filterTeamByOrg(team: Team): boolean;
|
|
267
282
|
getSubmissions(): Submissions;
|
|
268
283
|
buildBalloons(): void;
|
|
284
|
+
setReplayTime(replayStartTimestamp: number): void;
|
|
269
285
|
}
|
|
270
286
|
|
|
271
287
|
declare class CodeforcesGymGhostDATConverter {
|
package/dist/index.mjs
CHANGED
|
@@ -378,6 +378,8 @@ class GeneralExcelConverter {
|
|
|
378
378
|
convertToAoa(rank) {
|
|
379
379
|
const aoa = [];
|
|
380
380
|
const enableAwards = rank.contest.isEnableAwards(rank.options.group);
|
|
381
|
+
const enableMembers = (Array.isArray(rank.teams) && rank.teams[0]?.members) ?? false;
|
|
382
|
+
const enableCoach = rank.teams[0]?.coach ?? false;
|
|
381
383
|
{
|
|
382
384
|
aoa.push([rank.contest.name]);
|
|
383
385
|
}
|
|
@@ -388,10 +390,18 @@ class GeneralExcelConverter {
|
|
|
388
390
|
head.push(`${rank.contest.organization} Rank`);
|
|
389
391
|
head.push(rank.contest.organization);
|
|
390
392
|
}
|
|
391
|
-
head.push("
|
|
393
|
+
head.push("Team", "Solved", "Penalty", ...rank.contest.problems.map((p) => p.label), "Dirt");
|
|
392
394
|
if (enableAwards) {
|
|
393
395
|
head.push("Medal");
|
|
394
396
|
}
|
|
397
|
+
if (enableMembers) {
|
|
398
|
+
head.push("Member1", "Member2", "Member3");
|
|
399
|
+
}
|
|
400
|
+
if (enableCoach) {
|
|
401
|
+
head.push("Coach");
|
|
402
|
+
}
|
|
403
|
+
head.push("Unofficial");
|
|
404
|
+
head.push("Girl");
|
|
395
405
|
aoa.push(head);
|
|
396
406
|
}
|
|
397
407
|
for (const team of rank.teams) {
|
|
@@ -425,6 +435,25 @@ class GeneralExcelConverter {
|
|
|
425
435
|
const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
|
|
426
436
|
arr.push(medals.join(", "));
|
|
427
437
|
}
|
|
438
|
+
if (enableMembers) {
|
|
439
|
+
const members = team.members;
|
|
440
|
+
if (Array.isArray(members)) {
|
|
441
|
+
arr.push(members[0] ?? "");
|
|
442
|
+
arr.push(members[1] ?? "");
|
|
443
|
+
arr.push(members[2] ?? "");
|
|
444
|
+
} else {
|
|
445
|
+
arr.push("", "", "");
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (enableCoach) {
|
|
449
|
+
if (typeof team.coach === "string") {
|
|
450
|
+
arr.push(team.coach ?? "");
|
|
451
|
+
} else {
|
|
452
|
+
arr.push("");
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
arr.push(team.isUnofficial ? "Y" : "N");
|
|
456
|
+
arr.push(team.isGirl ? "Y" : "N");
|
|
428
457
|
aoa.push(arr);
|
|
429
458
|
}
|
|
430
459
|
return aoa;
|
|
@@ -630,6 +659,26 @@ class Team {
|
|
|
630
659
|
const solvedNum = this.solvedProblemNum;
|
|
631
660
|
return calcDirt(attemptedNum, solvedNum);
|
|
632
661
|
}
|
|
662
|
+
get isUnofficial() {
|
|
663
|
+
return this.group.includes("unofficial");
|
|
664
|
+
}
|
|
665
|
+
get isGirl() {
|
|
666
|
+
return this.group.includes("girl");
|
|
667
|
+
}
|
|
668
|
+
get membersToArray() {
|
|
669
|
+
if (Array.isArray(this.members)) {
|
|
670
|
+
return this.members;
|
|
671
|
+
}
|
|
672
|
+
if (typeof this.members === "string") {
|
|
673
|
+
if (this.members.includes(", ")) {
|
|
674
|
+
return this.members.split(", ");
|
|
675
|
+
}
|
|
676
|
+
if (this.members.includes("\u3001")) {
|
|
677
|
+
return this.members.split("\u3001");
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return [];
|
|
681
|
+
}
|
|
633
682
|
get membersToString() {
|
|
634
683
|
if (typeof this.members === "string") {
|
|
635
684
|
return this.members;
|
|
@@ -756,6 +805,8 @@ class Submission {
|
|
|
756
805
|
constructor() {
|
|
757
806
|
this.status = SubmissionStatus.UNKNOWN;
|
|
758
807
|
this.isIgnore = false;
|
|
808
|
+
this.isSolved = false;
|
|
809
|
+
this.isFirstSolved = false;
|
|
759
810
|
this.id = "";
|
|
760
811
|
this.teamId = "";
|
|
761
812
|
this.problemId = "";
|
|
@@ -926,59 +977,68 @@ class Contest {
|
|
|
926
977
|
this.tag = /* @__PURE__ */ new Map();
|
|
927
978
|
this.options = new ContestOptions();
|
|
928
979
|
}
|
|
980
|
+
getStartTime() {
|
|
981
|
+
return this.replayStartTime ?? this.startTime;
|
|
982
|
+
}
|
|
983
|
+
getEndTime() {
|
|
984
|
+
return this.replayEndTime ?? this.endTime;
|
|
985
|
+
}
|
|
986
|
+
getFreezeTime() {
|
|
987
|
+
return this.replayFreezeTime ?? this.freezeTime;
|
|
988
|
+
}
|
|
929
989
|
getContestDuration(timeFormat = "HH:mm:ss") {
|
|
930
|
-
return dayjs.duration(this.
|
|
990
|
+
return dayjs.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
|
|
931
991
|
}
|
|
932
992
|
getContestState(nowTime) {
|
|
933
993
|
const now = createDayJS(nowTime);
|
|
934
|
-
if (now.isBefore(this.
|
|
994
|
+
if (now.isBefore(this.getStartTime())) {
|
|
935
995
|
return ContestState.PENDING;
|
|
936
996
|
}
|
|
937
|
-
if (now.isSameOrAfter(this.
|
|
997
|
+
if (now.isSameOrAfter(this.getEndTime())) {
|
|
938
998
|
return ContestState.FINISHED;
|
|
939
999
|
}
|
|
940
|
-
if (now.isSameOrAfter(this.
|
|
1000
|
+
if (now.isSameOrAfter(this.getFreezeTime())) {
|
|
941
1001
|
return ContestState.FROZEN;
|
|
942
1002
|
}
|
|
943
1003
|
return ContestState.RUNNING;
|
|
944
1004
|
}
|
|
945
1005
|
getContestPendingTime(nowTime) {
|
|
946
1006
|
let baseTime = createDayJS(nowTime);
|
|
947
|
-
if (baseTime.isAfter(this.
|
|
948
|
-
baseTime = this.
|
|
1007
|
+
if (baseTime.isAfter(this.getStartTime())) {
|
|
1008
|
+
baseTime = this.getStartTime();
|
|
949
1009
|
}
|
|
950
|
-
return getTimeDiff(Math.floor(dayjs.duration(this.
|
|
1010
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.getStartTime().diff(baseTime)).asSeconds()));
|
|
951
1011
|
}
|
|
952
1012
|
getContestElapsedTime(nowTime) {
|
|
953
1013
|
let baseTime = createDayJS(nowTime);
|
|
954
|
-
if (baseTime.isAfter(this.
|
|
955
|
-
baseTime = this.
|
|
1014
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
1015
|
+
baseTime = this.getEndTime();
|
|
956
1016
|
}
|
|
957
|
-
if (baseTime.isBefore(this.
|
|
958
|
-
baseTime = this.
|
|
1017
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
1018
|
+
baseTime = this.getStartTime();
|
|
959
1019
|
}
|
|
960
|
-
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.
|
|
1020
|
+
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.getStartTime())).asSeconds()));
|
|
961
1021
|
}
|
|
962
1022
|
getContestRemainingTime(nowTime) {
|
|
963
1023
|
let baseTime = createDayJS(nowTime);
|
|
964
|
-
if (baseTime.isAfter(this.
|
|
965
|
-
baseTime = this.
|
|
1024
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
1025
|
+
baseTime = this.getEndTime();
|
|
966
1026
|
}
|
|
967
|
-
if (baseTime.isBefore(this.
|
|
968
|
-
baseTime = this.
|
|
1027
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
1028
|
+
baseTime = this.getStartTime();
|
|
969
1029
|
}
|
|
970
|
-
return getTimeDiff(Math.floor(dayjs.duration(this.
|
|
1030
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.getEndTime().diff(baseTime)).asSeconds()));
|
|
971
1031
|
}
|
|
972
1032
|
getContestProgressRatio(nowTime) {
|
|
973
1033
|
const baseTime = createDayJS(nowTime);
|
|
974
|
-
if (this.
|
|
1034
|
+
if (this.getStartTime().isSameOrAfter(baseTime)) {
|
|
975
1035
|
return 0;
|
|
976
1036
|
}
|
|
977
|
-
if (this.
|
|
1037
|
+
if (this.getEndTime().isSameOrBefore(baseTime)) {
|
|
978
1038
|
return 100;
|
|
979
1039
|
}
|
|
980
|
-
const total = this.
|
|
981
|
-
const pass = baseTime.diff(this.
|
|
1040
|
+
const total = this.getEndTime().diff(this.getStartTime(), "s");
|
|
1041
|
+
const pass = baseTime.diff(this.getStartTime(), "s");
|
|
982
1042
|
return Math.round(pass * 100 / total);
|
|
983
1043
|
}
|
|
984
1044
|
isEnableAwards(group) {
|
|
@@ -990,6 +1050,26 @@ class Contest {
|
|
|
990
1050
|
}
|
|
991
1051
|
return true;
|
|
992
1052
|
}
|
|
1053
|
+
resetReplayTime() {
|
|
1054
|
+
this.replayStartTime = void 0;
|
|
1055
|
+
this.replayEndTime = void 0;
|
|
1056
|
+
this.replayFreezeTime = void 0;
|
|
1057
|
+
this.replayNowTime = void 0;
|
|
1058
|
+
this.replayContestStartTimestamp = void 0;
|
|
1059
|
+
}
|
|
1060
|
+
setReplayTime(replayStartTimestamp) {
|
|
1061
|
+
if (replayStartTimestamp === 0) {
|
|
1062
|
+
this.resetReplayTime();
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
const replayStartTime = createDayJS(replayStartTimestamp);
|
|
1066
|
+
const diff = replayStartTime.diff(this.startTime, "s");
|
|
1067
|
+
this.replayStartTime = this.startTime.add(diff, "s");
|
|
1068
|
+
this.replayEndTime = this.endTime.add(diff, "s");
|
|
1069
|
+
this.replayFreezeTime = this.freezeTime.add(diff, "s");
|
|
1070
|
+
this.replayNowTime = createDayJS();
|
|
1071
|
+
this.replayContestStartTimestamp = this.replayNowTime.diff(this.replayStartTime, "s");
|
|
1072
|
+
}
|
|
993
1073
|
}
|
|
994
1074
|
function createContest(contestJSON) {
|
|
995
1075
|
const c = new Contest();
|
|
@@ -1202,7 +1282,7 @@ class RankOptions {
|
|
|
1202
1282
|
}
|
|
1203
1283
|
setWidth(width, contest) {
|
|
1204
1284
|
this.width = width;
|
|
1205
|
-
this.timestamp = Math.floor((contest.
|
|
1285
|
+
this.timestamp = Math.floor((contest.getEndTime().unix() - contest.getStartTime().unix()) * this.width * 1e-4);
|
|
1206
1286
|
this.enableFilterSubmissionsByTimestamp = true;
|
|
1207
1287
|
}
|
|
1208
1288
|
disableFilterSubmissionByTimestamp() {
|
|
@@ -1351,6 +1431,8 @@ class Rank {
|
|
|
1351
1431
|
team.submissions.push(s);
|
|
1352
1432
|
problem.statistics.submittedNum++;
|
|
1353
1433
|
if (problemStatistics.isSolved) {
|
|
1434
|
+
s.isSolved = false;
|
|
1435
|
+
s.isFirstSolved = false;
|
|
1354
1436
|
return;
|
|
1355
1437
|
}
|
|
1356
1438
|
if (s.isIgnore || s.isNotCalculatedPenaltyStatus()) {
|
|
@@ -1362,11 +1444,13 @@ class Rank {
|
|
|
1362
1444
|
problemStatistics.lastSubmitTimestamp = s.timestampToSecond;
|
|
1363
1445
|
problemStatistics.totalCount++;
|
|
1364
1446
|
if (s.isAccepted()) {
|
|
1447
|
+
s.isSolved = true;
|
|
1365
1448
|
problemStatistics.isSolved = true;
|
|
1366
1449
|
problemStatistics.solvedTimestamp = s.timestampToSecond;
|
|
1367
1450
|
problem.statistics.acceptedNum++;
|
|
1368
1451
|
problem.statistics.attemptedNum += problemStatistics.failedCount + 1;
|
|
1369
1452
|
if (problem.statistics.firstSolveSubmissions.length === 0 || problem.statistics.firstSolveSubmissions[problem.statistics.firstSolveSubmissions.length - 1].timestamp === s.timestamp) {
|
|
1453
|
+
s.isFirstSolved = true;
|
|
1370
1454
|
problemStatistics.isFirstSolved = true;
|
|
1371
1455
|
problem.statistics.firstSolveSubmissions.push(s);
|
|
1372
1456
|
}
|
|
@@ -1492,6 +1576,7 @@ class Rank {
|
|
|
1492
1576
|
const gold = new Award();
|
|
1493
1577
|
const silver = new Award();
|
|
1494
1578
|
const bronze = new Award();
|
|
1579
|
+
const honorable = new Award();
|
|
1495
1580
|
{
|
|
1496
1581
|
gold.medalType = MedalType.GOLD;
|
|
1497
1582
|
gold.minRank = 1;
|
|
@@ -1516,6 +1601,18 @@ class Rank {
|
|
|
1516
1601
|
award.push(bronze);
|
|
1517
1602
|
}
|
|
1518
1603
|
}
|
|
1604
|
+
{
|
|
1605
|
+
honorable.medalType = MedalType.HONORABLE;
|
|
1606
|
+
honorable.minRank = bronze.maxRank + 1;
|
|
1607
|
+
this.teams.forEach((t) => {
|
|
1608
|
+
if (t.solvedProblemNum > 0) {
|
|
1609
|
+
honorable.maxRank = Math.max(honorable.maxRank, t.rank);
|
|
1610
|
+
}
|
|
1611
|
+
});
|
|
1612
|
+
if (honorable.maxRank >= honorable.minRank) {
|
|
1613
|
+
award.push(honorable);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1519
1616
|
this.contest.awards.set("official", award);
|
|
1520
1617
|
}
|
|
1521
1618
|
}
|
|
@@ -1529,12 +1626,22 @@ class Rank {
|
|
|
1529
1626
|
return false;
|
|
1530
1627
|
}
|
|
1531
1628
|
getSubmissions() {
|
|
1532
|
-
if (this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1629
|
+
if (this.contest.replayContestStartTimestamp === void 0 && this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1533
1630
|
return this.submissions;
|
|
1534
1631
|
}
|
|
1535
|
-
return this.submissions.filter(
|
|
1536
|
-
(
|
|
1537
|
-
|
|
1632
|
+
return this.submissions.filter((s) => {
|
|
1633
|
+
if (this.contest.replayContestStartTimestamp !== void 0) {
|
|
1634
|
+
if (s.timestampToSecond > this.contest.replayContestStartTimestamp) {
|
|
1635
|
+
return false;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
if (this.options.enableFilterSubmissionsByTimestamp) {
|
|
1639
|
+
if (s.timestampToSecond > this.options.timestamp) {
|
|
1640
|
+
return false;
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
return true;
|
|
1644
|
+
});
|
|
1538
1645
|
}
|
|
1539
1646
|
buildBalloons() {
|
|
1540
1647
|
this.balloons = [];
|
|
@@ -1566,6 +1673,9 @@ class Rank {
|
|
|
1566
1673
|
})();
|
|
1567
1674
|
}
|
|
1568
1675
|
}
|
|
1676
|
+
setReplayTime(replayStartTimestamp) {
|
|
1677
|
+
this.contest.setReplayTime(replayStartTimestamp);
|
|
1678
|
+
}
|
|
1569
1679
|
}
|
|
1570
1680
|
|
|
1571
1681
|
class ResolverOperation {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcpcio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.37.0",
|
|
4
4
|
"description": "XCPCIO Core",
|
|
5
5
|
"author": "Dup4 <lyuzhi.pan@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"lodash": "^4.17.21",
|
|
47
47
|
"string-width": "^6.1.0",
|
|
48
48
|
"xlsx-js-style": "^1.2.0",
|
|
49
|
-
"@xcpcio/types": "0.
|
|
49
|
+
"@xcpcio/types": "0.37.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@babel/types": "^7.22.4",
|
package/src/contest.ts
CHANGED
|
@@ -16,6 +16,12 @@ export class Contest {
|
|
|
16
16
|
endTime: dayjs.Dayjs;
|
|
17
17
|
freezeTime: dayjs.Dayjs;
|
|
18
18
|
|
|
19
|
+
replayStartTime?: dayjs.Dayjs;
|
|
20
|
+
replayEndTime?: dayjs.Dayjs;
|
|
21
|
+
replayFreezeTime?: dayjs.Dayjs;
|
|
22
|
+
replayNowTime?: dayjs.Dayjs;
|
|
23
|
+
replayContestStartTimestamp?: number;
|
|
24
|
+
|
|
19
25
|
totalDurationTimestamp: number;
|
|
20
26
|
freezeDurationTimestamp: number;
|
|
21
27
|
unFreezeDurationTimestamp: number;
|
|
@@ -68,22 +74,34 @@ export class Contest {
|
|
|
68
74
|
this.options = new ContestOptions();
|
|
69
75
|
}
|
|
70
76
|
|
|
77
|
+
getStartTime() {
|
|
78
|
+
return this.replayStartTime ?? this.startTime;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
getEndTime() {
|
|
82
|
+
return this.replayEndTime ?? this.endTime;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getFreezeTime() {
|
|
86
|
+
return this.replayFreezeTime ?? this.freezeTime;
|
|
87
|
+
}
|
|
88
|
+
|
|
71
89
|
getContestDuration(timeFormat = "HH:mm:ss"): string {
|
|
72
|
-
return dayjs.duration(this.
|
|
90
|
+
return dayjs.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
|
|
73
91
|
}
|
|
74
92
|
|
|
75
93
|
getContestState(nowTime?: Date): ContestState {
|
|
76
94
|
const now = createDayJS(nowTime);
|
|
77
95
|
|
|
78
|
-
if (now.isBefore(this.
|
|
96
|
+
if (now.isBefore(this.getStartTime())) {
|
|
79
97
|
return ContestState.PENDING;
|
|
80
98
|
}
|
|
81
99
|
|
|
82
|
-
if (now.isSameOrAfter(this.
|
|
100
|
+
if (now.isSameOrAfter(this.getEndTime())) {
|
|
83
101
|
return ContestState.FINISHED;
|
|
84
102
|
}
|
|
85
103
|
|
|
86
|
-
if (now.isSameOrAfter(this.
|
|
104
|
+
if (now.isSameOrAfter(this.getFreezeTime())) {
|
|
87
105
|
return ContestState.FROZEN;
|
|
88
106
|
}
|
|
89
107
|
|
|
@@ -92,52 +110,52 @@ export class Contest {
|
|
|
92
110
|
|
|
93
111
|
getContestPendingTime(nowTime?: Date): string {
|
|
94
112
|
let baseTime = createDayJS(nowTime);
|
|
95
|
-
if (baseTime.isAfter(this.
|
|
96
|
-
baseTime = this.
|
|
113
|
+
if (baseTime.isAfter(this.getStartTime())) {
|
|
114
|
+
baseTime = this.getStartTime();
|
|
97
115
|
}
|
|
98
116
|
|
|
99
|
-
return getTimeDiff(Math.floor(dayjs.duration(this.
|
|
117
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.getStartTime().diff(baseTime)).asSeconds()));
|
|
100
118
|
}
|
|
101
119
|
|
|
102
120
|
getContestElapsedTime(nowTime?: Date): string {
|
|
103
121
|
let baseTime = createDayJS(nowTime);
|
|
104
|
-
if (baseTime.isAfter(this.
|
|
105
|
-
baseTime = this.
|
|
122
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
123
|
+
baseTime = this.getEndTime();
|
|
106
124
|
}
|
|
107
125
|
|
|
108
|
-
if (baseTime.isBefore(this.
|
|
109
|
-
baseTime = this.
|
|
126
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
127
|
+
baseTime = this.getStartTime();
|
|
110
128
|
}
|
|
111
129
|
|
|
112
|
-
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.
|
|
130
|
+
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.getStartTime())).asSeconds()));
|
|
113
131
|
}
|
|
114
132
|
|
|
115
133
|
getContestRemainingTime(nowTime?: Date): string {
|
|
116
134
|
let baseTime = createDayJS(nowTime);
|
|
117
|
-
if (baseTime.isAfter(this.
|
|
118
|
-
baseTime = this.
|
|
135
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
136
|
+
baseTime = this.getEndTime();
|
|
119
137
|
}
|
|
120
138
|
|
|
121
|
-
if (baseTime.isBefore(this.
|
|
122
|
-
baseTime = this.
|
|
139
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
140
|
+
baseTime = this.getStartTime();
|
|
123
141
|
}
|
|
124
142
|
|
|
125
|
-
return getTimeDiff(Math.floor(dayjs.duration(this.
|
|
143
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.getEndTime().diff(baseTime)).asSeconds()));
|
|
126
144
|
}
|
|
127
145
|
|
|
128
146
|
getContestProgressRatio(nowTime?: Date): number {
|
|
129
147
|
const baseTime = createDayJS(nowTime);
|
|
130
148
|
|
|
131
|
-
if (this.
|
|
149
|
+
if (this.getStartTime().isSameOrAfter(baseTime)) {
|
|
132
150
|
return 0;
|
|
133
151
|
}
|
|
134
152
|
|
|
135
|
-
if (this.
|
|
153
|
+
if (this.getEndTime().isSameOrBefore(baseTime)) {
|
|
136
154
|
return 100;
|
|
137
155
|
}
|
|
138
156
|
|
|
139
|
-
const total = this.
|
|
140
|
-
const pass = baseTime.diff(this.
|
|
157
|
+
const total = this.getEndTime().diff(this.getStartTime(), "s");
|
|
158
|
+
const pass = baseTime.diff(this.getStartTime(), "s");
|
|
141
159
|
|
|
142
160
|
return Math.round((pass * 100) / total);
|
|
143
161
|
}
|
|
@@ -153,6 +171,30 @@ export class Contest {
|
|
|
153
171
|
|
|
154
172
|
return true;
|
|
155
173
|
}
|
|
174
|
+
|
|
175
|
+
resetReplayTime() {
|
|
176
|
+
this.replayStartTime = undefined;
|
|
177
|
+
this.replayEndTime = undefined;
|
|
178
|
+
this.replayFreezeTime = undefined;
|
|
179
|
+
this.replayNowTime = undefined;
|
|
180
|
+
this.replayContestStartTimestamp = undefined;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
setReplayTime(replayStartTimestamp: number) {
|
|
184
|
+
if (replayStartTimestamp === 0) {
|
|
185
|
+
this.resetReplayTime();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const replayStartTime = createDayJS(replayStartTimestamp);
|
|
190
|
+
const diff = replayStartTime.diff(this.startTime, "s");
|
|
191
|
+
|
|
192
|
+
this.replayStartTime = this.startTime.add(diff, "s");
|
|
193
|
+
this.replayEndTime = this.endTime.add(diff, "s");
|
|
194
|
+
this.replayFreezeTime = this.freezeTime.add(diff, "s");
|
|
195
|
+
this.replayNowTime = createDayJS();
|
|
196
|
+
this.replayContestStartTimestamp = this.replayNowTime.diff(this.replayStartTime, "s");
|
|
197
|
+
}
|
|
156
198
|
}
|
|
157
199
|
|
|
158
200
|
export function createContest(contestJSON: IContest): Contest {
|
|
@@ -110,6 +110,8 @@ export class GeneralExcelConverter {
|
|
|
110
110
|
const aoa: string[][] = [];
|
|
111
111
|
|
|
112
112
|
const enableAwards = rank.contest.isEnableAwards(rank.options.group);
|
|
113
|
+
const enableMembers = (Array.isArray(rank.teams) && rank.teams[0]?.members) ?? false;
|
|
114
|
+
const enableCoach = rank.teams[0]?.coach ?? false;
|
|
113
115
|
|
|
114
116
|
{
|
|
115
117
|
aoa.push([rank.contest.name]);
|
|
@@ -124,12 +126,23 @@ export class GeneralExcelConverter {
|
|
|
124
126
|
head.push(rank.contest.organization);
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
head.push("
|
|
129
|
+
head.push("Team", "Solved", "Penalty", ...rank.contest.problems.map(p => p.label), "Dirt");
|
|
128
130
|
|
|
129
131
|
if (enableAwards) {
|
|
130
132
|
head.push("Medal");
|
|
131
133
|
}
|
|
132
134
|
|
|
135
|
+
if (enableMembers) {
|
|
136
|
+
head.push("Member1", "Member2", "Member3");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (enableCoach) {
|
|
140
|
+
head.push("Coach");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
head.push("Unofficial");
|
|
144
|
+
head.push("Girl");
|
|
145
|
+
|
|
133
146
|
aoa.push(head);
|
|
134
147
|
}
|
|
135
148
|
|
|
@@ -176,6 +189,28 @@ export class GeneralExcelConverter {
|
|
|
176
189
|
arr.push(medals.join(", "));
|
|
177
190
|
}
|
|
178
191
|
|
|
192
|
+
if (enableMembers) {
|
|
193
|
+
const members = team.members;
|
|
194
|
+
if (Array.isArray(members)) {
|
|
195
|
+
arr.push(members[0] ?? "");
|
|
196
|
+
arr.push(members[1] ?? "");
|
|
197
|
+
arr.push(members[2] ?? "");
|
|
198
|
+
} else {
|
|
199
|
+
arr.push("", "", "");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (enableCoach) {
|
|
204
|
+
if (typeof team.coach === "string") {
|
|
205
|
+
arr.push(team.coach ?? "");
|
|
206
|
+
} else {
|
|
207
|
+
arr.push("");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
arr.push(team.isUnofficial ? "Y" : "N");
|
|
212
|
+
arr.push(team.isGirl ? "Y" : "N");
|
|
213
|
+
|
|
179
214
|
aoa.push(arr);
|
|
180
215
|
}
|
|
181
216
|
|
package/src/rank.ts
CHANGED
|
@@ -51,7 +51,7 @@ export class RankOptions {
|
|
|
51
51
|
|
|
52
52
|
setWidth(width: number, contest: Contest) {
|
|
53
53
|
this.width = width;
|
|
54
|
-
this.timestamp = Math.floor((contest.
|
|
54
|
+
this.timestamp = Math.floor((contest.getEndTime().unix() - contest.getStartTime().unix()) * this.width * 0.0001);
|
|
55
55
|
this.enableFilterSubmissionsByTimestamp = true;
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -270,6 +270,8 @@ export class Rank {
|
|
|
270
270
|
problem.statistics.submittedNum++;
|
|
271
271
|
|
|
272
272
|
if (problemStatistics.isSolved) {
|
|
273
|
+
s.isSolved = false;
|
|
274
|
+
s.isFirstSolved = false;
|
|
273
275
|
return;
|
|
274
276
|
}
|
|
275
277
|
|
|
@@ -284,6 +286,8 @@ export class Rank {
|
|
|
284
286
|
problemStatistics.totalCount++;
|
|
285
287
|
|
|
286
288
|
if (s.isAccepted()) {
|
|
289
|
+
s.isSolved = true;
|
|
290
|
+
|
|
287
291
|
problemStatistics.isSolved = true;
|
|
288
292
|
problemStatistics.solvedTimestamp = s.timestampToSecond;
|
|
289
293
|
|
|
@@ -294,6 +298,7 @@ export class Rank {
|
|
|
294
298
|
problem.statistics.firstSolveSubmissions.length === 0
|
|
295
299
|
|| problem.statistics.firstSolveSubmissions[problem.statistics.firstSolveSubmissions.length - 1].timestamp === s.timestamp
|
|
296
300
|
) {
|
|
301
|
+
s.isFirstSolved = true;
|
|
297
302
|
problemStatistics.isFirstSolved = true;
|
|
298
303
|
problem.statistics.firstSolveSubmissions.push(s);
|
|
299
304
|
}
|
|
@@ -454,6 +459,7 @@ export class Rank {
|
|
|
454
459
|
const gold = new Award();
|
|
455
460
|
const silver = new Award();
|
|
456
461
|
const bronze = new Award();
|
|
462
|
+
const honorable = new Award();
|
|
457
463
|
|
|
458
464
|
{
|
|
459
465
|
gold.medalType = MedalType.GOLD;
|
|
@@ -482,6 +488,19 @@ export class Rank {
|
|
|
482
488
|
}
|
|
483
489
|
}
|
|
484
490
|
|
|
491
|
+
{
|
|
492
|
+
honorable.medalType = MedalType.HONORABLE;
|
|
493
|
+
honorable.minRank = bronze.maxRank + 1;
|
|
494
|
+
this.teams.forEach((t) => {
|
|
495
|
+
if (t.solvedProblemNum > 0) {
|
|
496
|
+
honorable.maxRank = Math.max(honorable.maxRank, t.rank);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
if (honorable.maxRank >= honorable.minRank) {
|
|
500
|
+
award.push(honorable);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
485
504
|
this.contest.awards.set("official", award);
|
|
486
505
|
}
|
|
487
506
|
}
|
|
@@ -499,13 +518,25 @@ export class Rank {
|
|
|
499
518
|
}
|
|
500
519
|
|
|
501
520
|
getSubmissions() {
|
|
502
|
-
if (this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
521
|
+
if (this.contest.replayContestStartTimestamp === undefined && this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
503
522
|
return this.submissions;
|
|
504
523
|
}
|
|
505
524
|
|
|
506
|
-
return this.submissions.filter(s =>
|
|
507
|
-
|
|
508
|
-
|
|
525
|
+
return this.submissions.filter((s) => {
|
|
526
|
+
if (this.contest.replayContestStartTimestamp !== undefined) {
|
|
527
|
+
if (s.timestampToSecond > this.contest.replayContestStartTimestamp) {
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (this.options.enableFilterSubmissionsByTimestamp) {
|
|
533
|
+
if (s.timestampToSecond > this.options.timestamp) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return true;
|
|
539
|
+
});
|
|
509
540
|
}
|
|
510
541
|
|
|
511
542
|
buildBalloons() {
|
|
@@ -547,4 +578,8 @@ export class Rank {
|
|
|
547
578
|
})();
|
|
548
579
|
}
|
|
549
580
|
}
|
|
581
|
+
|
|
582
|
+
setReplayTime(replayStartTimestamp: number) {
|
|
583
|
+
this.contest.setReplayTime(replayStartTimestamp);
|
|
584
|
+
}
|
|
550
585
|
}
|
package/src/submission.ts
CHANGED
package/src/team.ts
CHANGED
|
@@ -119,6 +119,32 @@ export class Team {
|
|
|
119
119
|
return calcDirt(attemptedNum, solvedNum);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
get isUnofficial() {
|
|
123
|
+
return this.group.includes("unofficial");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
get isGirl() {
|
|
127
|
+
return this.group.includes("girl");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get membersToArray() {
|
|
131
|
+
if (Array.isArray(this.members)) {
|
|
132
|
+
return this.members;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (typeof this.members === "string") {
|
|
136
|
+
if (this.members.includes(", ")) {
|
|
137
|
+
return this.members.split(", ");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (this.members.includes("、")) {
|
|
141
|
+
return this.members.split("、");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
|
|
122
148
|
get membersToString() {
|
|
123
149
|
if (typeof this.members === "string") {
|
|
124
150
|
return this.members;
|