@xcpcio/core 0.35.1 → 0.36.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 +87 -26
- package/dist/index.d.ts +13 -0
- package/dist/index.mjs +87 -26
- package/package.json +2 -2
- package/src/contest.ts +63 -21
- package/src/rank.ts +40 -5
- package/src/submission.ts +2 -0
package/dist/index.cjs
CHANGED
|
@@ -787,6 +787,8 @@ class Submission {
|
|
|
787
787
|
constructor() {
|
|
788
788
|
this.status = types.SubmissionStatus.UNKNOWN;
|
|
789
789
|
this.isIgnore = false;
|
|
790
|
+
this.isSolved = false;
|
|
791
|
+
this.isFirstSolved = false;
|
|
790
792
|
this.id = "";
|
|
791
793
|
this.teamId = "";
|
|
792
794
|
this.problemId = "";
|
|
@@ -957,59 +959,68 @@ class Contest {
|
|
|
957
959
|
this.tag = /* @__PURE__ */ new Map();
|
|
958
960
|
this.options = new ContestOptions();
|
|
959
961
|
}
|
|
962
|
+
getStartTime() {
|
|
963
|
+
return this.replayStartTime ?? this.startTime;
|
|
964
|
+
}
|
|
965
|
+
getEndTime() {
|
|
966
|
+
return this.replayEndTime ?? this.endTime;
|
|
967
|
+
}
|
|
968
|
+
getFreezeTime() {
|
|
969
|
+
return this.replayFreezeTime ?? this.freezeTime;
|
|
970
|
+
}
|
|
960
971
|
getContestDuration(timeFormat = "HH:mm:ss") {
|
|
961
|
-
return dayjs__default.duration(this.
|
|
972
|
+
return dayjs__default.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
|
|
962
973
|
}
|
|
963
974
|
getContestState(nowTime) {
|
|
964
975
|
const now = createDayJS(nowTime);
|
|
965
|
-
if (now.isBefore(this.
|
|
976
|
+
if (now.isBefore(this.getStartTime())) {
|
|
966
977
|
return types.ContestState.PENDING;
|
|
967
978
|
}
|
|
968
|
-
if (now.isSameOrAfter(this.
|
|
979
|
+
if (now.isSameOrAfter(this.getEndTime())) {
|
|
969
980
|
return types.ContestState.FINISHED;
|
|
970
981
|
}
|
|
971
|
-
if (now.isSameOrAfter(this.
|
|
982
|
+
if (now.isSameOrAfter(this.getFreezeTime())) {
|
|
972
983
|
return types.ContestState.FROZEN;
|
|
973
984
|
}
|
|
974
985
|
return types.ContestState.RUNNING;
|
|
975
986
|
}
|
|
976
987
|
getContestPendingTime(nowTime) {
|
|
977
988
|
let baseTime = createDayJS(nowTime);
|
|
978
|
-
if (baseTime.isAfter(this.
|
|
979
|
-
baseTime = this.
|
|
989
|
+
if (baseTime.isAfter(this.getStartTime())) {
|
|
990
|
+
baseTime = this.getStartTime();
|
|
980
991
|
}
|
|
981
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(this.
|
|
992
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(this.getStartTime().diff(baseTime)).asSeconds()));
|
|
982
993
|
}
|
|
983
994
|
getContestElapsedTime(nowTime) {
|
|
984
995
|
let baseTime = createDayJS(nowTime);
|
|
985
|
-
if (baseTime.isAfter(this.
|
|
986
|
-
baseTime = this.
|
|
996
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
997
|
+
baseTime = this.getEndTime();
|
|
987
998
|
}
|
|
988
|
-
if (baseTime.isBefore(this.
|
|
989
|
-
baseTime = this.
|
|
999
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
1000
|
+
baseTime = this.getStartTime();
|
|
990
1001
|
}
|
|
991
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(baseTime.diff(this.
|
|
1002
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(baseTime.diff(this.getStartTime())).asSeconds()));
|
|
992
1003
|
}
|
|
993
1004
|
getContestRemainingTime(nowTime) {
|
|
994
1005
|
let baseTime = createDayJS(nowTime);
|
|
995
|
-
if (baseTime.isAfter(this.
|
|
996
|
-
baseTime = this.
|
|
1006
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
1007
|
+
baseTime = this.getEndTime();
|
|
997
1008
|
}
|
|
998
|
-
if (baseTime.isBefore(this.
|
|
999
|
-
baseTime = this.
|
|
1009
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
1010
|
+
baseTime = this.getStartTime();
|
|
1000
1011
|
}
|
|
1001
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(this.
|
|
1012
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(this.getEndTime().diff(baseTime)).asSeconds()));
|
|
1002
1013
|
}
|
|
1003
1014
|
getContestProgressRatio(nowTime) {
|
|
1004
1015
|
const baseTime = createDayJS(nowTime);
|
|
1005
|
-
if (this.
|
|
1016
|
+
if (this.getStartTime().isSameOrAfter(baseTime)) {
|
|
1006
1017
|
return 0;
|
|
1007
1018
|
}
|
|
1008
|
-
if (this.
|
|
1019
|
+
if (this.getEndTime().isSameOrBefore(baseTime)) {
|
|
1009
1020
|
return 100;
|
|
1010
1021
|
}
|
|
1011
|
-
const total = this.
|
|
1012
|
-
const pass = baseTime.diff(this.
|
|
1022
|
+
const total = this.getEndTime().diff(this.getStartTime(), "s");
|
|
1023
|
+
const pass = baseTime.diff(this.getStartTime(), "s");
|
|
1013
1024
|
return Math.round(pass * 100 / total);
|
|
1014
1025
|
}
|
|
1015
1026
|
isEnableAwards(group) {
|
|
@@ -1021,6 +1032,26 @@ class Contest {
|
|
|
1021
1032
|
}
|
|
1022
1033
|
return true;
|
|
1023
1034
|
}
|
|
1035
|
+
resetReplayTime() {
|
|
1036
|
+
this.replayStartTime = void 0;
|
|
1037
|
+
this.replayEndTime = void 0;
|
|
1038
|
+
this.replayFreezeTime = void 0;
|
|
1039
|
+
this.replayNowTime = void 0;
|
|
1040
|
+
this.replayContestStartTimestamp = void 0;
|
|
1041
|
+
}
|
|
1042
|
+
setReplayTime(replayStartTimestamp) {
|
|
1043
|
+
if (replayStartTimestamp === 0) {
|
|
1044
|
+
this.resetReplayTime();
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
const replayStartTime = createDayJS(replayStartTimestamp);
|
|
1048
|
+
const diff = replayStartTime.diff(this.startTime, "s");
|
|
1049
|
+
this.replayStartTime = this.startTime.add(diff, "s");
|
|
1050
|
+
this.replayEndTime = this.endTime.add(diff, "s");
|
|
1051
|
+
this.replayFreezeTime = this.freezeTime.add(diff, "s");
|
|
1052
|
+
this.replayNowTime = createDayJS();
|
|
1053
|
+
this.replayContestStartTimestamp = this.replayNowTime.diff(this.replayStartTime, "s");
|
|
1054
|
+
}
|
|
1024
1055
|
}
|
|
1025
1056
|
function createContest(contestJSON) {
|
|
1026
1057
|
const c = new Contest();
|
|
@@ -1233,7 +1264,7 @@ class RankOptions {
|
|
|
1233
1264
|
}
|
|
1234
1265
|
setWidth(width, contest) {
|
|
1235
1266
|
this.width = width;
|
|
1236
|
-
this.timestamp = Math.floor((contest.
|
|
1267
|
+
this.timestamp = Math.floor((contest.getEndTime().unix() - contest.getStartTime().unix()) * this.width * 1e-4);
|
|
1237
1268
|
this.enableFilterSubmissionsByTimestamp = true;
|
|
1238
1269
|
}
|
|
1239
1270
|
disableFilterSubmissionByTimestamp() {
|
|
@@ -1382,6 +1413,8 @@ class Rank {
|
|
|
1382
1413
|
team.submissions.push(s);
|
|
1383
1414
|
problem.statistics.submittedNum++;
|
|
1384
1415
|
if (problemStatistics.isSolved) {
|
|
1416
|
+
s.isSolved = false;
|
|
1417
|
+
s.isFirstSolved = false;
|
|
1385
1418
|
return;
|
|
1386
1419
|
}
|
|
1387
1420
|
if (s.isIgnore || s.isNotCalculatedPenaltyStatus()) {
|
|
@@ -1393,11 +1426,13 @@ class Rank {
|
|
|
1393
1426
|
problemStatistics.lastSubmitTimestamp = s.timestampToSecond;
|
|
1394
1427
|
problemStatistics.totalCount++;
|
|
1395
1428
|
if (s.isAccepted()) {
|
|
1429
|
+
s.isSolved = true;
|
|
1396
1430
|
problemStatistics.isSolved = true;
|
|
1397
1431
|
problemStatistics.solvedTimestamp = s.timestampToSecond;
|
|
1398
1432
|
problem.statistics.acceptedNum++;
|
|
1399
1433
|
problem.statistics.attemptedNum += problemStatistics.failedCount + 1;
|
|
1400
1434
|
if (problem.statistics.firstSolveSubmissions.length === 0 || problem.statistics.firstSolveSubmissions[problem.statistics.firstSolveSubmissions.length - 1].timestamp === s.timestamp) {
|
|
1435
|
+
s.isFirstSolved = true;
|
|
1401
1436
|
problemStatistics.isFirstSolved = true;
|
|
1402
1437
|
problem.statistics.firstSolveSubmissions.push(s);
|
|
1403
1438
|
}
|
|
@@ -1523,6 +1558,7 @@ class Rank {
|
|
|
1523
1558
|
const gold = new Award();
|
|
1524
1559
|
const silver = new Award();
|
|
1525
1560
|
const bronze = new Award();
|
|
1561
|
+
const honorable = new Award();
|
|
1526
1562
|
{
|
|
1527
1563
|
gold.medalType = MedalType.GOLD;
|
|
1528
1564
|
gold.minRank = 1;
|
|
@@ -1547,6 +1583,18 @@ class Rank {
|
|
|
1547
1583
|
award.push(bronze);
|
|
1548
1584
|
}
|
|
1549
1585
|
}
|
|
1586
|
+
{
|
|
1587
|
+
honorable.medalType = MedalType.HONORABLE;
|
|
1588
|
+
honorable.minRank = bronze.maxRank + 1;
|
|
1589
|
+
this.teams.forEach((t) => {
|
|
1590
|
+
if (t.solvedProblemNum > 0) {
|
|
1591
|
+
honorable.maxRank = Math.max(honorable.maxRank, t.rank);
|
|
1592
|
+
}
|
|
1593
|
+
});
|
|
1594
|
+
if (honorable.maxRank >= honorable.minRank) {
|
|
1595
|
+
award.push(honorable);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1550
1598
|
this.contest.awards.set("official", award);
|
|
1551
1599
|
}
|
|
1552
1600
|
}
|
|
@@ -1560,12 +1608,22 @@ class Rank {
|
|
|
1560
1608
|
return false;
|
|
1561
1609
|
}
|
|
1562
1610
|
getSubmissions() {
|
|
1563
|
-
if (this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1611
|
+
if (this.contest.replayContestStartTimestamp === void 0 && this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1564
1612
|
return this.submissions;
|
|
1565
1613
|
}
|
|
1566
|
-
return this.submissions.filter(
|
|
1567
|
-
(
|
|
1568
|
-
|
|
1614
|
+
return this.submissions.filter((s) => {
|
|
1615
|
+
if (this.contest.replayContestStartTimestamp !== void 0) {
|
|
1616
|
+
if (s.timestampToSecond > this.contest.replayContestStartTimestamp) {
|
|
1617
|
+
return false;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
if (this.options.enableFilterSubmissionsByTimestamp) {
|
|
1621
|
+
if (s.timestampToSecond > this.options.timestamp) {
|
|
1622
|
+
return false;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
return true;
|
|
1626
|
+
});
|
|
1569
1627
|
}
|
|
1570
1628
|
buildBalloons() {
|
|
1571
1629
|
this.balloons = [];
|
|
@@ -1597,6 +1655,9 @@ class Rank {
|
|
|
1597
1655
|
})();
|
|
1598
1656
|
}
|
|
1599
1657
|
}
|
|
1658
|
+
setReplayTime(replayStartTimestamp) {
|
|
1659
|
+
this.contest.setReplayTime(replayStartTimestamp);
|
|
1660
|
+
}
|
|
1600
1661
|
}
|
|
1601
1662
|
|
|
1602
1663
|
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
|
|
|
@@ -266,6 +278,7 @@ declare class Rank {
|
|
|
266
278
|
filterTeamByOrg(team: Team): boolean;
|
|
267
279
|
getSubmissions(): Submissions;
|
|
268
280
|
buildBalloons(): void;
|
|
281
|
+
setReplayTime(replayStartTimestamp: number): void;
|
|
269
282
|
}
|
|
270
283
|
|
|
271
284
|
declare class CodeforcesGymGhostDATConverter {
|
package/dist/index.mjs
CHANGED
|
@@ -756,6 +756,8 @@ class Submission {
|
|
|
756
756
|
constructor() {
|
|
757
757
|
this.status = SubmissionStatus.UNKNOWN;
|
|
758
758
|
this.isIgnore = false;
|
|
759
|
+
this.isSolved = false;
|
|
760
|
+
this.isFirstSolved = false;
|
|
759
761
|
this.id = "";
|
|
760
762
|
this.teamId = "";
|
|
761
763
|
this.problemId = "";
|
|
@@ -926,59 +928,68 @@ class Contest {
|
|
|
926
928
|
this.tag = /* @__PURE__ */ new Map();
|
|
927
929
|
this.options = new ContestOptions();
|
|
928
930
|
}
|
|
931
|
+
getStartTime() {
|
|
932
|
+
return this.replayStartTime ?? this.startTime;
|
|
933
|
+
}
|
|
934
|
+
getEndTime() {
|
|
935
|
+
return this.replayEndTime ?? this.endTime;
|
|
936
|
+
}
|
|
937
|
+
getFreezeTime() {
|
|
938
|
+
return this.replayFreezeTime ?? this.freezeTime;
|
|
939
|
+
}
|
|
929
940
|
getContestDuration(timeFormat = "HH:mm:ss") {
|
|
930
|
-
return dayjs.duration(this.
|
|
941
|
+
return dayjs.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
|
|
931
942
|
}
|
|
932
943
|
getContestState(nowTime) {
|
|
933
944
|
const now = createDayJS(nowTime);
|
|
934
|
-
if (now.isBefore(this.
|
|
945
|
+
if (now.isBefore(this.getStartTime())) {
|
|
935
946
|
return ContestState.PENDING;
|
|
936
947
|
}
|
|
937
|
-
if (now.isSameOrAfter(this.
|
|
948
|
+
if (now.isSameOrAfter(this.getEndTime())) {
|
|
938
949
|
return ContestState.FINISHED;
|
|
939
950
|
}
|
|
940
|
-
if (now.isSameOrAfter(this.
|
|
951
|
+
if (now.isSameOrAfter(this.getFreezeTime())) {
|
|
941
952
|
return ContestState.FROZEN;
|
|
942
953
|
}
|
|
943
954
|
return ContestState.RUNNING;
|
|
944
955
|
}
|
|
945
956
|
getContestPendingTime(nowTime) {
|
|
946
957
|
let baseTime = createDayJS(nowTime);
|
|
947
|
-
if (baseTime.isAfter(this.
|
|
948
|
-
baseTime = this.
|
|
958
|
+
if (baseTime.isAfter(this.getStartTime())) {
|
|
959
|
+
baseTime = this.getStartTime();
|
|
949
960
|
}
|
|
950
|
-
return getTimeDiff(Math.floor(dayjs.duration(this.
|
|
961
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.getStartTime().diff(baseTime)).asSeconds()));
|
|
951
962
|
}
|
|
952
963
|
getContestElapsedTime(nowTime) {
|
|
953
964
|
let baseTime = createDayJS(nowTime);
|
|
954
|
-
if (baseTime.isAfter(this.
|
|
955
|
-
baseTime = this.
|
|
965
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
966
|
+
baseTime = this.getEndTime();
|
|
956
967
|
}
|
|
957
|
-
if (baseTime.isBefore(this.
|
|
958
|
-
baseTime = this.
|
|
968
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
969
|
+
baseTime = this.getStartTime();
|
|
959
970
|
}
|
|
960
|
-
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.
|
|
971
|
+
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.getStartTime())).asSeconds()));
|
|
961
972
|
}
|
|
962
973
|
getContestRemainingTime(nowTime) {
|
|
963
974
|
let baseTime = createDayJS(nowTime);
|
|
964
|
-
if (baseTime.isAfter(this.
|
|
965
|
-
baseTime = this.
|
|
975
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
976
|
+
baseTime = this.getEndTime();
|
|
966
977
|
}
|
|
967
|
-
if (baseTime.isBefore(this.
|
|
968
|
-
baseTime = this.
|
|
978
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
979
|
+
baseTime = this.getStartTime();
|
|
969
980
|
}
|
|
970
|
-
return getTimeDiff(Math.floor(dayjs.duration(this.
|
|
981
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.getEndTime().diff(baseTime)).asSeconds()));
|
|
971
982
|
}
|
|
972
983
|
getContestProgressRatio(nowTime) {
|
|
973
984
|
const baseTime = createDayJS(nowTime);
|
|
974
|
-
if (this.
|
|
985
|
+
if (this.getStartTime().isSameOrAfter(baseTime)) {
|
|
975
986
|
return 0;
|
|
976
987
|
}
|
|
977
|
-
if (this.
|
|
988
|
+
if (this.getEndTime().isSameOrBefore(baseTime)) {
|
|
978
989
|
return 100;
|
|
979
990
|
}
|
|
980
|
-
const total = this.
|
|
981
|
-
const pass = baseTime.diff(this.
|
|
991
|
+
const total = this.getEndTime().diff(this.getStartTime(), "s");
|
|
992
|
+
const pass = baseTime.diff(this.getStartTime(), "s");
|
|
982
993
|
return Math.round(pass * 100 / total);
|
|
983
994
|
}
|
|
984
995
|
isEnableAwards(group) {
|
|
@@ -990,6 +1001,26 @@ class Contest {
|
|
|
990
1001
|
}
|
|
991
1002
|
return true;
|
|
992
1003
|
}
|
|
1004
|
+
resetReplayTime() {
|
|
1005
|
+
this.replayStartTime = void 0;
|
|
1006
|
+
this.replayEndTime = void 0;
|
|
1007
|
+
this.replayFreezeTime = void 0;
|
|
1008
|
+
this.replayNowTime = void 0;
|
|
1009
|
+
this.replayContestStartTimestamp = void 0;
|
|
1010
|
+
}
|
|
1011
|
+
setReplayTime(replayStartTimestamp) {
|
|
1012
|
+
if (replayStartTimestamp === 0) {
|
|
1013
|
+
this.resetReplayTime();
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
const replayStartTime = createDayJS(replayStartTimestamp);
|
|
1017
|
+
const diff = replayStartTime.diff(this.startTime, "s");
|
|
1018
|
+
this.replayStartTime = this.startTime.add(diff, "s");
|
|
1019
|
+
this.replayEndTime = this.endTime.add(diff, "s");
|
|
1020
|
+
this.replayFreezeTime = this.freezeTime.add(diff, "s");
|
|
1021
|
+
this.replayNowTime = createDayJS();
|
|
1022
|
+
this.replayContestStartTimestamp = this.replayNowTime.diff(this.replayStartTime, "s");
|
|
1023
|
+
}
|
|
993
1024
|
}
|
|
994
1025
|
function createContest(contestJSON) {
|
|
995
1026
|
const c = new Contest();
|
|
@@ -1202,7 +1233,7 @@ class RankOptions {
|
|
|
1202
1233
|
}
|
|
1203
1234
|
setWidth(width, contest) {
|
|
1204
1235
|
this.width = width;
|
|
1205
|
-
this.timestamp = Math.floor((contest.
|
|
1236
|
+
this.timestamp = Math.floor((contest.getEndTime().unix() - contest.getStartTime().unix()) * this.width * 1e-4);
|
|
1206
1237
|
this.enableFilterSubmissionsByTimestamp = true;
|
|
1207
1238
|
}
|
|
1208
1239
|
disableFilterSubmissionByTimestamp() {
|
|
@@ -1351,6 +1382,8 @@ class Rank {
|
|
|
1351
1382
|
team.submissions.push(s);
|
|
1352
1383
|
problem.statistics.submittedNum++;
|
|
1353
1384
|
if (problemStatistics.isSolved) {
|
|
1385
|
+
s.isSolved = false;
|
|
1386
|
+
s.isFirstSolved = false;
|
|
1354
1387
|
return;
|
|
1355
1388
|
}
|
|
1356
1389
|
if (s.isIgnore || s.isNotCalculatedPenaltyStatus()) {
|
|
@@ -1362,11 +1395,13 @@ class Rank {
|
|
|
1362
1395
|
problemStatistics.lastSubmitTimestamp = s.timestampToSecond;
|
|
1363
1396
|
problemStatistics.totalCount++;
|
|
1364
1397
|
if (s.isAccepted()) {
|
|
1398
|
+
s.isSolved = true;
|
|
1365
1399
|
problemStatistics.isSolved = true;
|
|
1366
1400
|
problemStatistics.solvedTimestamp = s.timestampToSecond;
|
|
1367
1401
|
problem.statistics.acceptedNum++;
|
|
1368
1402
|
problem.statistics.attemptedNum += problemStatistics.failedCount + 1;
|
|
1369
1403
|
if (problem.statistics.firstSolveSubmissions.length === 0 || problem.statistics.firstSolveSubmissions[problem.statistics.firstSolveSubmissions.length - 1].timestamp === s.timestamp) {
|
|
1404
|
+
s.isFirstSolved = true;
|
|
1370
1405
|
problemStatistics.isFirstSolved = true;
|
|
1371
1406
|
problem.statistics.firstSolveSubmissions.push(s);
|
|
1372
1407
|
}
|
|
@@ -1492,6 +1527,7 @@ class Rank {
|
|
|
1492
1527
|
const gold = new Award();
|
|
1493
1528
|
const silver = new Award();
|
|
1494
1529
|
const bronze = new Award();
|
|
1530
|
+
const honorable = new Award();
|
|
1495
1531
|
{
|
|
1496
1532
|
gold.medalType = MedalType.GOLD;
|
|
1497
1533
|
gold.minRank = 1;
|
|
@@ -1516,6 +1552,18 @@ class Rank {
|
|
|
1516
1552
|
award.push(bronze);
|
|
1517
1553
|
}
|
|
1518
1554
|
}
|
|
1555
|
+
{
|
|
1556
|
+
honorable.medalType = MedalType.HONORABLE;
|
|
1557
|
+
honorable.minRank = bronze.maxRank + 1;
|
|
1558
|
+
this.teams.forEach((t) => {
|
|
1559
|
+
if (t.solvedProblemNum > 0) {
|
|
1560
|
+
honorable.maxRank = Math.max(honorable.maxRank, t.rank);
|
|
1561
|
+
}
|
|
1562
|
+
});
|
|
1563
|
+
if (honorable.maxRank >= honorable.minRank) {
|
|
1564
|
+
award.push(honorable);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1519
1567
|
this.contest.awards.set("official", award);
|
|
1520
1568
|
}
|
|
1521
1569
|
}
|
|
@@ -1529,12 +1577,22 @@ class Rank {
|
|
|
1529
1577
|
return false;
|
|
1530
1578
|
}
|
|
1531
1579
|
getSubmissions() {
|
|
1532
|
-
if (this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1580
|
+
if (this.contest.replayContestStartTimestamp === void 0 && this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1533
1581
|
return this.submissions;
|
|
1534
1582
|
}
|
|
1535
|
-
return this.submissions.filter(
|
|
1536
|
-
(
|
|
1537
|
-
|
|
1583
|
+
return this.submissions.filter((s) => {
|
|
1584
|
+
if (this.contest.replayContestStartTimestamp !== void 0) {
|
|
1585
|
+
if (s.timestampToSecond > this.contest.replayContestStartTimestamp) {
|
|
1586
|
+
return false;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
if (this.options.enableFilterSubmissionsByTimestamp) {
|
|
1590
|
+
if (s.timestampToSecond > this.options.timestamp) {
|
|
1591
|
+
return false;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
return true;
|
|
1595
|
+
});
|
|
1538
1596
|
}
|
|
1539
1597
|
buildBalloons() {
|
|
1540
1598
|
this.balloons = [];
|
|
@@ -1566,6 +1624,9 @@ class Rank {
|
|
|
1566
1624
|
})();
|
|
1567
1625
|
}
|
|
1568
1626
|
}
|
|
1627
|
+
setReplayTime(replayStartTimestamp) {
|
|
1628
|
+
this.contest.setReplayTime(replayStartTimestamp);
|
|
1629
|
+
}
|
|
1569
1630
|
}
|
|
1570
1631
|
|
|
1571
1632
|
class ResolverOperation {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcpcio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.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.36.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 {
|
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
|
}
|