@xcpcio/core 0.35.0 → 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 +96 -28
- package/dist/index.d.ts +15 -1
- package/dist/index.mjs +96 -29
- package/package.json +2 -2
- package/src/contest.ts +63 -21
- package/src/rank.ts +40 -5
- package/src/submission.ts +2 -0
- package/src/utils/color.ts +11 -2
package/dist/index.cjs
CHANGED
|
@@ -15,8 +15,8 @@ const relativeTime = require('dayjs/plugin/relativeTime');
|
|
|
15
15
|
const _ = require('lodash');
|
|
16
16
|
const XLSX = require('xlsx-js-style');
|
|
17
17
|
const stringWidth = require('string-width');
|
|
18
|
-
const colorDiff = require('color-diff');
|
|
19
18
|
const chroma = require('chroma-js');
|
|
19
|
+
const colorDiff = require('color-diff');
|
|
20
20
|
|
|
21
21
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
|
22
22
|
|
|
@@ -469,7 +469,7 @@ function calcDirt(attemptedNum, solvedNum) {
|
|
|
469
469
|
return Math.floor((attemptedNum - solvedNum) * 100 / attemptedNum);
|
|
470
470
|
}
|
|
471
471
|
|
|
472
|
-
function
|
|
472
|
+
function getWhiteOrBlackColorV1(background) {
|
|
473
473
|
const [R, G, B] = chroma__default(background).rgb();
|
|
474
474
|
const color = { R, G, B };
|
|
475
475
|
const palette = [
|
|
@@ -483,6 +483,12 @@ function getWhiteOrBlackColor(background) {
|
|
|
483
483
|
return "#fff";
|
|
484
484
|
}
|
|
485
485
|
}
|
|
486
|
+
function getWhiteOrBlackColor(background) {
|
|
487
|
+
const [R, G, B] = chroma__default(background).rgb();
|
|
488
|
+
const brightness = (R * 299 + G * 587 + B * 114) / 1e3;
|
|
489
|
+
const threshold = 148;
|
|
490
|
+
return brightness <= threshold ? "#fff" : "#000";
|
|
491
|
+
}
|
|
486
492
|
|
|
487
493
|
class ProblemStatistics {
|
|
488
494
|
constructor() {
|
|
@@ -781,6 +787,8 @@ class Submission {
|
|
|
781
787
|
constructor() {
|
|
782
788
|
this.status = types.SubmissionStatus.UNKNOWN;
|
|
783
789
|
this.isIgnore = false;
|
|
790
|
+
this.isSolved = false;
|
|
791
|
+
this.isFirstSolved = false;
|
|
784
792
|
this.id = "";
|
|
785
793
|
this.teamId = "";
|
|
786
794
|
this.problemId = "";
|
|
@@ -951,59 +959,68 @@ class Contest {
|
|
|
951
959
|
this.tag = /* @__PURE__ */ new Map();
|
|
952
960
|
this.options = new ContestOptions();
|
|
953
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
|
+
}
|
|
954
971
|
getContestDuration(timeFormat = "HH:mm:ss") {
|
|
955
|
-
return dayjs__default.duration(this.
|
|
972
|
+
return dayjs__default.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
|
|
956
973
|
}
|
|
957
974
|
getContestState(nowTime) {
|
|
958
975
|
const now = createDayJS(nowTime);
|
|
959
|
-
if (now.isBefore(this.
|
|
976
|
+
if (now.isBefore(this.getStartTime())) {
|
|
960
977
|
return types.ContestState.PENDING;
|
|
961
978
|
}
|
|
962
|
-
if (now.isSameOrAfter(this.
|
|
979
|
+
if (now.isSameOrAfter(this.getEndTime())) {
|
|
963
980
|
return types.ContestState.FINISHED;
|
|
964
981
|
}
|
|
965
|
-
if (now.isSameOrAfter(this.
|
|
982
|
+
if (now.isSameOrAfter(this.getFreezeTime())) {
|
|
966
983
|
return types.ContestState.FROZEN;
|
|
967
984
|
}
|
|
968
985
|
return types.ContestState.RUNNING;
|
|
969
986
|
}
|
|
970
987
|
getContestPendingTime(nowTime) {
|
|
971
988
|
let baseTime = createDayJS(nowTime);
|
|
972
|
-
if (baseTime.isAfter(this.
|
|
973
|
-
baseTime = this.
|
|
989
|
+
if (baseTime.isAfter(this.getStartTime())) {
|
|
990
|
+
baseTime = this.getStartTime();
|
|
974
991
|
}
|
|
975
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(this.
|
|
992
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(this.getStartTime().diff(baseTime)).asSeconds()));
|
|
976
993
|
}
|
|
977
994
|
getContestElapsedTime(nowTime) {
|
|
978
995
|
let baseTime = createDayJS(nowTime);
|
|
979
|
-
if (baseTime.isAfter(this.
|
|
980
|
-
baseTime = this.
|
|
996
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
997
|
+
baseTime = this.getEndTime();
|
|
981
998
|
}
|
|
982
|
-
if (baseTime.isBefore(this.
|
|
983
|
-
baseTime = this.
|
|
999
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
1000
|
+
baseTime = this.getStartTime();
|
|
984
1001
|
}
|
|
985
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(baseTime.diff(this.
|
|
1002
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(baseTime.diff(this.getStartTime())).asSeconds()));
|
|
986
1003
|
}
|
|
987
1004
|
getContestRemainingTime(nowTime) {
|
|
988
1005
|
let baseTime = createDayJS(nowTime);
|
|
989
|
-
if (baseTime.isAfter(this.
|
|
990
|
-
baseTime = this.
|
|
1006
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
1007
|
+
baseTime = this.getEndTime();
|
|
991
1008
|
}
|
|
992
|
-
if (baseTime.isBefore(this.
|
|
993
|
-
baseTime = this.
|
|
1009
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
1010
|
+
baseTime = this.getStartTime();
|
|
994
1011
|
}
|
|
995
|
-
return getTimeDiff(Math.floor(dayjs__default.duration(this.
|
|
1012
|
+
return getTimeDiff(Math.floor(dayjs__default.duration(this.getEndTime().diff(baseTime)).asSeconds()));
|
|
996
1013
|
}
|
|
997
1014
|
getContestProgressRatio(nowTime) {
|
|
998
1015
|
const baseTime = createDayJS(nowTime);
|
|
999
|
-
if (this.
|
|
1016
|
+
if (this.getStartTime().isSameOrAfter(baseTime)) {
|
|
1000
1017
|
return 0;
|
|
1001
1018
|
}
|
|
1002
|
-
if (this.
|
|
1019
|
+
if (this.getEndTime().isSameOrBefore(baseTime)) {
|
|
1003
1020
|
return 100;
|
|
1004
1021
|
}
|
|
1005
|
-
const total = this.
|
|
1006
|
-
const pass = baseTime.diff(this.
|
|
1022
|
+
const total = this.getEndTime().diff(this.getStartTime(), "s");
|
|
1023
|
+
const pass = baseTime.diff(this.getStartTime(), "s");
|
|
1007
1024
|
return Math.round(pass * 100 / total);
|
|
1008
1025
|
}
|
|
1009
1026
|
isEnableAwards(group) {
|
|
@@ -1015,6 +1032,26 @@ class Contest {
|
|
|
1015
1032
|
}
|
|
1016
1033
|
return true;
|
|
1017
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
|
+
}
|
|
1018
1055
|
}
|
|
1019
1056
|
function createContest(contestJSON) {
|
|
1020
1057
|
const c = new Contest();
|
|
@@ -1227,7 +1264,7 @@ class RankOptions {
|
|
|
1227
1264
|
}
|
|
1228
1265
|
setWidth(width, contest) {
|
|
1229
1266
|
this.width = width;
|
|
1230
|
-
this.timestamp = Math.floor((contest.
|
|
1267
|
+
this.timestamp = Math.floor((contest.getEndTime().unix() - contest.getStartTime().unix()) * this.width * 1e-4);
|
|
1231
1268
|
this.enableFilterSubmissionsByTimestamp = true;
|
|
1232
1269
|
}
|
|
1233
1270
|
disableFilterSubmissionByTimestamp() {
|
|
@@ -1376,6 +1413,8 @@ class Rank {
|
|
|
1376
1413
|
team.submissions.push(s);
|
|
1377
1414
|
problem.statistics.submittedNum++;
|
|
1378
1415
|
if (problemStatistics.isSolved) {
|
|
1416
|
+
s.isSolved = false;
|
|
1417
|
+
s.isFirstSolved = false;
|
|
1379
1418
|
return;
|
|
1380
1419
|
}
|
|
1381
1420
|
if (s.isIgnore || s.isNotCalculatedPenaltyStatus()) {
|
|
@@ -1387,11 +1426,13 @@ class Rank {
|
|
|
1387
1426
|
problemStatistics.lastSubmitTimestamp = s.timestampToSecond;
|
|
1388
1427
|
problemStatistics.totalCount++;
|
|
1389
1428
|
if (s.isAccepted()) {
|
|
1429
|
+
s.isSolved = true;
|
|
1390
1430
|
problemStatistics.isSolved = true;
|
|
1391
1431
|
problemStatistics.solvedTimestamp = s.timestampToSecond;
|
|
1392
1432
|
problem.statistics.acceptedNum++;
|
|
1393
1433
|
problem.statistics.attemptedNum += problemStatistics.failedCount + 1;
|
|
1394
1434
|
if (problem.statistics.firstSolveSubmissions.length === 0 || problem.statistics.firstSolveSubmissions[problem.statistics.firstSolveSubmissions.length - 1].timestamp === s.timestamp) {
|
|
1435
|
+
s.isFirstSolved = true;
|
|
1395
1436
|
problemStatistics.isFirstSolved = true;
|
|
1396
1437
|
problem.statistics.firstSolveSubmissions.push(s);
|
|
1397
1438
|
}
|
|
@@ -1517,6 +1558,7 @@ class Rank {
|
|
|
1517
1558
|
const gold = new Award();
|
|
1518
1559
|
const silver = new Award();
|
|
1519
1560
|
const bronze = new Award();
|
|
1561
|
+
const honorable = new Award();
|
|
1520
1562
|
{
|
|
1521
1563
|
gold.medalType = MedalType.GOLD;
|
|
1522
1564
|
gold.minRank = 1;
|
|
@@ -1541,6 +1583,18 @@ class Rank {
|
|
|
1541
1583
|
award.push(bronze);
|
|
1542
1584
|
}
|
|
1543
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
|
+
}
|
|
1544
1598
|
this.contest.awards.set("official", award);
|
|
1545
1599
|
}
|
|
1546
1600
|
}
|
|
@@ -1554,12 +1608,22 @@ class Rank {
|
|
|
1554
1608
|
return false;
|
|
1555
1609
|
}
|
|
1556
1610
|
getSubmissions() {
|
|
1557
|
-
if (this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1611
|
+
if (this.contest.replayContestStartTimestamp === void 0 && this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1558
1612
|
return this.submissions;
|
|
1559
1613
|
}
|
|
1560
|
-
return this.submissions.filter(
|
|
1561
|
-
(
|
|
1562
|
-
|
|
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
|
+
});
|
|
1563
1627
|
}
|
|
1564
1628
|
buildBalloons() {
|
|
1565
1629
|
this.balloons = [];
|
|
@@ -1591,6 +1655,9 @@ class Rank {
|
|
|
1591
1655
|
})();
|
|
1592
1656
|
}
|
|
1593
1657
|
}
|
|
1658
|
+
setReplayTime(replayStartTimestamp) {
|
|
1659
|
+
this.contest.setReplayTime(replayStartTimestamp);
|
|
1660
|
+
}
|
|
1594
1661
|
}
|
|
1595
1662
|
|
|
1596
1663
|
class ResolverOperation {
|
|
@@ -1717,6 +1784,7 @@ exports.getImageSource = getImageSource;
|
|
|
1717
1784
|
exports.getTimeDiff = getTimeDiff;
|
|
1718
1785
|
exports.getTimestamp = getTimestamp;
|
|
1719
1786
|
exports.getWhiteOrBlackColor = getWhiteOrBlackColor;
|
|
1787
|
+
exports.getWhiteOrBlackColorV1 = getWhiteOrBlackColorV1;
|
|
1720
1788
|
exports.isAccepted = isAccepted;
|
|
1721
1789
|
exports.isNotCalculatedPenaltyStatus = isNotCalculatedPenaltyStatus;
|
|
1722
1790
|
exports.isPending = isPending;
|
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;
|
|
@@ -83,6 +85,7 @@ declare class TeamProblemStatistics {
|
|
|
83
85
|
|
|
84
86
|
declare function calcDirt(attemptedNum: number, solvedNum: number): number;
|
|
85
87
|
|
|
88
|
+
declare function getWhiteOrBlackColorV1(background: string): "#000" | "#fff";
|
|
86
89
|
declare function getWhiteOrBlackColor(background: string): "#000" | "#fff";
|
|
87
90
|
|
|
88
91
|
declare function createDayJS(time?: Date | string | number | undefined): dayjs.Dayjs;
|
|
@@ -125,6 +128,11 @@ declare class Contest {
|
|
|
125
128
|
startTime: dayjs.Dayjs;
|
|
126
129
|
endTime: dayjs.Dayjs;
|
|
127
130
|
freezeTime: dayjs.Dayjs;
|
|
131
|
+
replayStartTime?: dayjs.Dayjs;
|
|
132
|
+
replayEndTime?: dayjs.Dayjs;
|
|
133
|
+
replayFreezeTime?: dayjs.Dayjs;
|
|
134
|
+
replayNowTime?: dayjs.Dayjs;
|
|
135
|
+
replayContestStartTimestamp?: number;
|
|
128
136
|
totalDurationTimestamp: number;
|
|
129
137
|
freezeDurationTimestamp: number;
|
|
130
138
|
unFreezeDurationTimestamp: number;
|
|
@@ -143,6 +151,9 @@ declare class Contest {
|
|
|
143
151
|
boardLink?: string;
|
|
144
152
|
options: ContestOptions;
|
|
145
153
|
constructor();
|
|
154
|
+
getStartTime(): dayjs.Dayjs;
|
|
155
|
+
getEndTime(): dayjs.Dayjs;
|
|
156
|
+
getFreezeTime(): dayjs.Dayjs;
|
|
146
157
|
getContestDuration(timeFormat?: string): string;
|
|
147
158
|
getContestState(nowTime?: Date): ContestState;
|
|
148
159
|
getContestPendingTime(nowTime?: Date): string;
|
|
@@ -150,6 +161,8 @@ declare class Contest {
|
|
|
150
161
|
getContestRemainingTime(nowTime?: Date): string;
|
|
151
162
|
getContestProgressRatio(nowTime?: Date): number;
|
|
152
163
|
isEnableAwards(group: string): boolean;
|
|
164
|
+
resetReplayTime(): void;
|
|
165
|
+
setReplayTime(replayStartTimestamp: number): void;
|
|
153
166
|
}
|
|
154
167
|
declare function createContest(contestJSON: Contest$1): Contest;
|
|
155
168
|
|
|
@@ -265,6 +278,7 @@ declare class Rank {
|
|
|
265
278
|
filterTeamByOrg(team: Team): boolean;
|
|
266
279
|
getSubmissions(): Submissions;
|
|
267
280
|
buildBalloons(): void;
|
|
281
|
+
setReplayTime(replayStartTimestamp: number): void;
|
|
268
282
|
}
|
|
269
283
|
|
|
270
284
|
declare class CodeforcesGymGhostDATConverter {
|
|
@@ -327,4 +341,4 @@ declare function isRejected(status: SubmissionStatus): boolean;
|
|
|
327
341
|
declare function isPending(status: SubmissionStatus): boolean;
|
|
328
342
|
declare function isNotCalculatedPenaltyStatus(status: SubmissionStatus): boolean;
|
|
329
343
|
|
|
330
|
-
export { Award, Awards, Balloon, Balloons, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, getWhiteOrBlackColor, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
|
344
|
+
export { Award, Awards, Balloon, Balloons, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, getWhiteOrBlackColor, getWhiteOrBlackColorV1, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
package/dist/index.mjs
CHANGED
|
@@ -12,8 +12,8 @@ import relativeTime from 'dayjs/plugin/relativeTime';
|
|
|
12
12
|
import _ from 'lodash';
|
|
13
13
|
import * as XLSX from 'xlsx-js-style';
|
|
14
14
|
import stringWidth from 'string-width';
|
|
15
|
-
import { furthest } from 'color-diff';
|
|
16
15
|
import chroma from 'chroma-js';
|
|
16
|
+
import { furthest } from 'color-diff';
|
|
17
17
|
|
|
18
18
|
function stringToSubmissionStatus(status) {
|
|
19
19
|
status = status.toUpperCase().replace(" ", "_");
|
|
@@ -438,7 +438,7 @@ function calcDirt(attemptedNum, solvedNum) {
|
|
|
438
438
|
return Math.floor((attemptedNum - solvedNum) * 100 / attemptedNum);
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
-
function
|
|
441
|
+
function getWhiteOrBlackColorV1(background) {
|
|
442
442
|
const [R, G, B] = chroma(background).rgb();
|
|
443
443
|
const color = { R, G, B };
|
|
444
444
|
const palette = [
|
|
@@ -452,6 +452,12 @@ function getWhiteOrBlackColor(background) {
|
|
|
452
452
|
return "#fff";
|
|
453
453
|
}
|
|
454
454
|
}
|
|
455
|
+
function getWhiteOrBlackColor(background) {
|
|
456
|
+
const [R, G, B] = chroma(background).rgb();
|
|
457
|
+
const brightness = (R * 299 + G * 587 + B * 114) / 1e3;
|
|
458
|
+
const threshold = 148;
|
|
459
|
+
return brightness <= threshold ? "#fff" : "#000";
|
|
460
|
+
}
|
|
455
461
|
|
|
456
462
|
class ProblemStatistics {
|
|
457
463
|
constructor() {
|
|
@@ -750,6 +756,8 @@ class Submission {
|
|
|
750
756
|
constructor() {
|
|
751
757
|
this.status = SubmissionStatus.UNKNOWN;
|
|
752
758
|
this.isIgnore = false;
|
|
759
|
+
this.isSolved = false;
|
|
760
|
+
this.isFirstSolved = false;
|
|
753
761
|
this.id = "";
|
|
754
762
|
this.teamId = "";
|
|
755
763
|
this.problemId = "";
|
|
@@ -920,59 +928,68 @@ class Contest {
|
|
|
920
928
|
this.tag = /* @__PURE__ */ new Map();
|
|
921
929
|
this.options = new ContestOptions();
|
|
922
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
|
+
}
|
|
923
940
|
getContestDuration(timeFormat = "HH:mm:ss") {
|
|
924
|
-
return dayjs.duration(this.
|
|
941
|
+
return dayjs.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
|
|
925
942
|
}
|
|
926
943
|
getContestState(nowTime) {
|
|
927
944
|
const now = createDayJS(nowTime);
|
|
928
|
-
if (now.isBefore(this.
|
|
945
|
+
if (now.isBefore(this.getStartTime())) {
|
|
929
946
|
return ContestState.PENDING;
|
|
930
947
|
}
|
|
931
|
-
if (now.isSameOrAfter(this.
|
|
948
|
+
if (now.isSameOrAfter(this.getEndTime())) {
|
|
932
949
|
return ContestState.FINISHED;
|
|
933
950
|
}
|
|
934
|
-
if (now.isSameOrAfter(this.
|
|
951
|
+
if (now.isSameOrAfter(this.getFreezeTime())) {
|
|
935
952
|
return ContestState.FROZEN;
|
|
936
953
|
}
|
|
937
954
|
return ContestState.RUNNING;
|
|
938
955
|
}
|
|
939
956
|
getContestPendingTime(nowTime) {
|
|
940
957
|
let baseTime = createDayJS(nowTime);
|
|
941
|
-
if (baseTime.isAfter(this.
|
|
942
|
-
baseTime = this.
|
|
958
|
+
if (baseTime.isAfter(this.getStartTime())) {
|
|
959
|
+
baseTime = this.getStartTime();
|
|
943
960
|
}
|
|
944
|
-
return getTimeDiff(Math.floor(dayjs.duration(this.
|
|
961
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.getStartTime().diff(baseTime)).asSeconds()));
|
|
945
962
|
}
|
|
946
963
|
getContestElapsedTime(nowTime) {
|
|
947
964
|
let baseTime = createDayJS(nowTime);
|
|
948
|
-
if (baseTime.isAfter(this.
|
|
949
|
-
baseTime = this.
|
|
965
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
966
|
+
baseTime = this.getEndTime();
|
|
950
967
|
}
|
|
951
|
-
if (baseTime.isBefore(this.
|
|
952
|
-
baseTime = this.
|
|
968
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
969
|
+
baseTime = this.getStartTime();
|
|
953
970
|
}
|
|
954
|
-
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.
|
|
971
|
+
return getTimeDiff(Math.floor(dayjs.duration(baseTime.diff(this.getStartTime())).asSeconds()));
|
|
955
972
|
}
|
|
956
973
|
getContestRemainingTime(nowTime) {
|
|
957
974
|
let baseTime = createDayJS(nowTime);
|
|
958
|
-
if (baseTime.isAfter(this.
|
|
959
|
-
baseTime = this.
|
|
975
|
+
if (baseTime.isAfter(this.getEndTime())) {
|
|
976
|
+
baseTime = this.getEndTime();
|
|
960
977
|
}
|
|
961
|
-
if (baseTime.isBefore(this.
|
|
962
|
-
baseTime = this.
|
|
978
|
+
if (baseTime.isBefore(this.getStartTime())) {
|
|
979
|
+
baseTime = this.getStartTime();
|
|
963
980
|
}
|
|
964
|
-
return getTimeDiff(Math.floor(dayjs.duration(this.
|
|
981
|
+
return getTimeDiff(Math.floor(dayjs.duration(this.getEndTime().diff(baseTime)).asSeconds()));
|
|
965
982
|
}
|
|
966
983
|
getContestProgressRatio(nowTime) {
|
|
967
984
|
const baseTime = createDayJS(nowTime);
|
|
968
|
-
if (this.
|
|
985
|
+
if (this.getStartTime().isSameOrAfter(baseTime)) {
|
|
969
986
|
return 0;
|
|
970
987
|
}
|
|
971
|
-
if (this.
|
|
988
|
+
if (this.getEndTime().isSameOrBefore(baseTime)) {
|
|
972
989
|
return 100;
|
|
973
990
|
}
|
|
974
|
-
const total = this.
|
|
975
|
-
const pass = baseTime.diff(this.
|
|
991
|
+
const total = this.getEndTime().diff(this.getStartTime(), "s");
|
|
992
|
+
const pass = baseTime.diff(this.getStartTime(), "s");
|
|
976
993
|
return Math.round(pass * 100 / total);
|
|
977
994
|
}
|
|
978
995
|
isEnableAwards(group) {
|
|
@@ -984,6 +1001,26 @@ class Contest {
|
|
|
984
1001
|
}
|
|
985
1002
|
return true;
|
|
986
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
|
+
}
|
|
987
1024
|
}
|
|
988
1025
|
function createContest(contestJSON) {
|
|
989
1026
|
const c = new Contest();
|
|
@@ -1196,7 +1233,7 @@ class RankOptions {
|
|
|
1196
1233
|
}
|
|
1197
1234
|
setWidth(width, contest) {
|
|
1198
1235
|
this.width = width;
|
|
1199
|
-
this.timestamp = Math.floor((contest.
|
|
1236
|
+
this.timestamp = Math.floor((contest.getEndTime().unix() - contest.getStartTime().unix()) * this.width * 1e-4);
|
|
1200
1237
|
this.enableFilterSubmissionsByTimestamp = true;
|
|
1201
1238
|
}
|
|
1202
1239
|
disableFilterSubmissionByTimestamp() {
|
|
@@ -1345,6 +1382,8 @@ class Rank {
|
|
|
1345
1382
|
team.submissions.push(s);
|
|
1346
1383
|
problem.statistics.submittedNum++;
|
|
1347
1384
|
if (problemStatistics.isSolved) {
|
|
1385
|
+
s.isSolved = false;
|
|
1386
|
+
s.isFirstSolved = false;
|
|
1348
1387
|
return;
|
|
1349
1388
|
}
|
|
1350
1389
|
if (s.isIgnore || s.isNotCalculatedPenaltyStatus()) {
|
|
@@ -1356,11 +1395,13 @@ class Rank {
|
|
|
1356
1395
|
problemStatistics.lastSubmitTimestamp = s.timestampToSecond;
|
|
1357
1396
|
problemStatistics.totalCount++;
|
|
1358
1397
|
if (s.isAccepted()) {
|
|
1398
|
+
s.isSolved = true;
|
|
1359
1399
|
problemStatistics.isSolved = true;
|
|
1360
1400
|
problemStatistics.solvedTimestamp = s.timestampToSecond;
|
|
1361
1401
|
problem.statistics.acceptedNum++;
|
|
1362
1402
|
problem.statistics.attemptedNum += problemStatistics.failedCount + 1;
|
|
1363
1403
|
if (problem.statistics.firstSolveSubmissions.length === 0 || problem.statistics.firstSolveSubmissions[problem.statistics.firstSolveSubmissions.length - 1].timestamp === s.timestamp) {
|
|
1404
|
+
s.isFirstSolved = true;
|
|
1364
1405
|
problemStatistics.isFirstSolved = true;
|
|
1365
1406
|
problem.statistics.firstSolveSubmissions.push(s);
|
|
1366
1407
|
}
|
|
@@ -1486,6 +1527,7 @@ class Rank {
|
|
|
1486
1527
|
const gold = new Award();
|
|
1487
1528
|
const silver = new Award();
|
|
1488
1529
|
const bronze = new Award();
|
|
1530
|
+
const honorable = new Award();
|
|
1489
1531
|
{
|
|
1490
1532
|
gold.medalType = MedalType.GOLD;
|
|
1491
1533
|
gold.minRank = 1;
|
|
@@ -1510,6 +1552,18 @@ class Rank {
|
|
|
1510
1552
|
award.push(bronze);
|
|
1511
1553
|
}
|
|
1512
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
|
+
}
|
|
1513
1567
|
this.contest.awards.set("official", award);
|
|
1514
1568
|
}
|
|
1515
1569
|
}
|
|
@@ -1523,12 +1577,22 @@ class Rank {
|
|
|
1523
1577
|
return false;
|
|
1524
1578
|
}
|
|
1525
1579
|
getSubmissions() {
|
|
1526
|
-
if (this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1580
|
+
if (this.contest.replayContestStartTimestamp === void 0 && this.options.enableFilterSubmissionsByTimestamp === false) {
|
|
1527
1581
|
return this.submissions;
|
|
1528
1582
|
}
|
|
1529
|
-
return this.submissions.filter(
|
|
1530
|
-
(
|
|
1531
|
-
|
|
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
|
+
});
|
|
1532
1596
|
}
|
|
1533
1597
|
buildBalloons() {
|
|
1534
1598
|
this.balloons = [];
|
|
@@ -1560,6 +1624,9 @@ class Rank {
|
|
|
1560
1624
|
})();
|
|
1561
1625
|
}
|
|
1562
1626
|
}
|
|
1627
|
+
setReplayTime(replayStartTimestamp) {
|
|
1628
|
+
this.contest.setReplayTime(replayStartTimestamp);
|
|
1629
|
+
}
|
|
1563
1630
|
}
|
|
1564
1631
|
|
|
1565
1632
|
class ResolverOperation {
|
|
@@ -1650,4 +1717,4 @@ class Resolver extends Rank {
|
|
|
1650
1717
|
}
|
|
1651
1718
|
}
|
|
1652
1719
|
|
|
1653
|
-
export { Award, Balloon, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, getWhiteOrBlackColor, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
|
1720
|
+
export { Award, Balloon, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, getWhiteOrBlackColor, getWhiteOrBlackColorV1, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcpcio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.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
|
}
|
package/src/submission.ts
CHANGED
package/src/utils/color.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { furthest } from "color-diff";
|
|
2
1
|
import chroma from "chroma-js";
|
|
2
|
+
import { furthest } from "color-diff";
|
|
3
3
|
|
|
4
|
-
export function
|
|
4
|
+
export function getWhiteOrBlackColorV1(background: string) {
|
|
5
5
|
const [R, G, B] = chroma(background).rgb();
|
|
6
6
|
const color = { R, G, B };
|
|
7
7
|
const palette = [
|
|
@@ -17,3 +17,12 @@ export function getWhiteOrBlackColor(background: string) {
|
|
|
17
17
|
return "#fff";
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
|
|
21
|
+
export function getWhiteOrBlackColor(background: string) {
|
|
22
|
+
const [R, G, B] = chroma(background).rgb();
|
|
23
|
+
|
|
24
|
+
const brightness = (R * 299 + G * 587 + B * 114) / 1000;
|
|
25
|
+
const threshold = 148;
|
|
26
|
+
|
|
27
|
+
return brightness <= threshold ? "#fff" : "#000";
|
|
28
|
+
}
|