@xcpcio/core 0.33.0 → 0.34.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 +71 -24
- package/dist/index.d.ts +5 -2
- package/dist/index.mjs +71 -24
- package/package.json +2 -2
- package/src/contest.ts +31 -26
- package/src/problem.ts +4 -2
- package/src/rank-statistics.ts +6 -0
- package/src/rank.ts +46 -0
- package/src/team.ts +4 -0
- package/src/utils/color.ts +4 -1
package/dist/index.cjs
CHANGED
|
@@ -468,7 +468,10 @@ function calcDirt(attemptedNum, solvedNum) {
|
|
|
468
468
|
function getWhiteOrBlackColor(background) {
|
|
469
469
|
const [R, G, B] = chroma__default(background).rgb();
|
|
470
470
|
const color = { R, G, B };
|
|
471
|
-
const palette = [
|
|
471
|
+
const palette = [
|
|
472
|
+
{ R: 0, G: 0, B: 0 },
|
|
473
|
+
{ R: 255, G: 255, B: 255 }
|
|
474
|
+
];
|
|
472
475
|
const f = colorDiff.furthest(color, palette);
|
|
473
476
|
if (f.R === 0 && f.G === 0 && f.B === 0) {
|
|
474
477
|
return "#000";
|
|
@@ -525,7 +528,7 @@ function createProblem(problemJSON) {
|
|
|
525
528
|
p.timeLimit = problemJSON.time_limit;
|
|
526
529
|
p.memoryLimit = problemJSON.memory_limit;
|
|
527
530
|
if (problemJSON.balloon_color) {
|
|
528
|
-
p.balloonColor = problemJSON.balloon_color;
|
|
531
|
+
p.balloonColor = ___default.cloneDeep(problemJSON.balloon_color);
|
|
529
532
|
}
|
|
530
533
|
p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
|
|
531
534
|
return p;
|
|
@@ -542,7 +545,7 @@ function createProblemsByProblemIds(problemIds, balloonColors) {
|
|
|
542
545
|
});
|
|
543
546
|
if (balloonColors !== void 0 && balloonColors !== null) {
|
|
544
547
|
for (const index in balloonColors) {
|
|
545
|
-
problems[index].balloonColor = balloonColors[index];
|
|
548
|
+
problems[index].balloonColor = ___default.cloneDeep(balloonColors[index]);
|
|
546
549
|
}
|
|
547
550
|
}
|
|
548
551
|
problems.forEach((p) => {
|
|
@@ -654,6 +657,9 @@ class Team {
|
|
|
654
657
|
}
|
|
655
658
|
return this.members?.join(", ");
|
|
656
659
|
}
|
|
660
|
+
get isEffectiveTeam() {
|
|
661
|
+
return this.solvedProblemNum > 0;
|
|
662
|
+
}
|
|
657
663
|
calcSolvedData(options) {
|
|
658
664
|
this.solvedProblemNum = 0;
|
|
659
665
|
this.attemptedProblemNum = 0;
|
|
@@ -1050,32 +1056,34 @@ function createContest(contestJSON) {
|
|
|
1050
1056
|
return;
|
|
1051
1057
|
}
|
|
1052
1058
|
c.awards = /* @__PURE__ */ new Map();
|
|
1053
|
-
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1059
|
+
if (typeof contestJSON.medal === "string") ; else {
|
|
1060
|
+
for (const k in contestJSON.medal) {
|
|
1061
|
+
const v = contestJSON.medal[k];
|
|
1062
|
+
{
|
|
1063
|
+
const award = [];
|
|
1064
|
+
let rank = 1;
|
|
1065
|
+
const work = (key, medalType) => {
|
|
1066
|
+
if (Object.keys(v).includes(key)) {
|
|
1067
|
+
const a = new Award();
|
|
1068
|
+
a.medalType = medalType;
|
|
1069
|
+
a.minRank = rank;
|
|
1070
|
+
rank += Number(v[key]);
|
|
1071
|
+
a.maxRank = rank - 1;
|
|
1072
|
+
award.push(a);
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
work("gold", MedalType.GOLD);
|
|
1076
|
+
work("silver", MedalType.SILVER);
|
|
1077
|
+
work("bronze", MedalType.BRONZE);
|
|
1078
|
+
{
|
|
1060
1079
|
const a = new Award();
|
|
1061
|
-
a.medalType =
|
|
1080
|
+
a.medalType = MedalType.HONORABLE;
|
|
1062
1081
|
a.minRank = rank;
|
|
1063
|
-
|
|
1064
|
-
a.maxRank = rank - 1;
|
|
1082
|
+
a.maxRank = 1061109567;
|
|
1065
1083
|
award.push(a);
|
|
1066
1084
|
}
|
|
1067
|
-
|
|
1068
|
-
work("gold", MedalType.GOLD);
|
|
1069
|
-
work("silver", MedalType.SILVER);
|
|
1070
|
-
work("bronze", MedalType.BRONZE);
|
|
1071
|
-
{
|
|
1072
|
-
const a = new Award();
|
|
1073
|
-
a.medalType = MedalType.HONORABLE;
|
|
1074
|
-
a.minRank = rank;
|
|
1075
|
-
a.maxRank = 1061109567;
|
|
1076
|
-
award.push(a);
|
|
1085
|
+
c.awards.set(k, award);
|
|
1077
1086
|
}
|
|
1078
|
-
c.awards.set(k, award);
|
|
1079
1087
|
}
|
|
1080
1088
|
}
|
|
1081
1089
|
})();
|
|
@@ -1187,11 +1195,13 @@ class RankStatistics {
|
|
|
1187
1195
|
this.teamSolvedNum = [];
|
|
1188
1196
|
this.teamSolvedNumIndex = [];
|
|
1189
1197
|
this.maxSolvedProblems = 0;
|
|
1198
|
+
this.effectiveTeamNum = 0;
|
|
1190
1199
|
}
|
|
1191
1200
|
reset() {
|
|
1192
1201
|
this.teamSolvedNum = [];
|
|
1193
1202
|
this.teamSolvedNumIndex = [];
|
|
1194
1203
|
this.maxSolvedProblems = 0;
|
|
1204
|
+
this.effectiveTeamNum = 0;
|
|
1195
1205
|
}
|
|
1196
1206
|
getTeamSolvedNumIndex(solvedNum) {
|
|
1197
1207
|
return this.teamSolvedNumIndex[solvedNum] ?? 0;
|
|
@@ -1417,6 +1427,8 @@ class Rank {
|
|
|
1417
1427
|
this.teams.sort(Team.compare);
|
|
1418
1428
|
this.buildTeamRank();
|
|
1419
1429
|
this.buildOrgRank();
|
|
1430
|
+
this.rankStatistics.effectiveTeamNum = this.teams.filter((t) => t.isEffectiveTeam).length;
|
|
1431
|
+
this.buildAwards();
|
|
1420
1432
|
this.teams.forEach((t) => t.calcAwards(this.contest.awards?.get(this.options.group)));
|
|
1421
1433
|
this.teams.forEach((t) => t.postProcessPlaceChartPoints());
|
|
1422
1434
|
})();
|
|
@@ -1493,6 +1505,41 @@ class Rank {
|
|
|
1493
1505
|
res.sort();
|
|
1494
1506
|
return res;
|
|
1495
1507
|
}
|
|
1508
|
+
buildAwards() {
|
|
1509
|
+
if (this.contest.medal === "ccpc") {
|
|
1510
|
+
this.contest.awards = /* @__PURE__ */ new Map();
|
|
1511
|
+
const tot = this.rankStatistics.effectiveTeamNum;
|
|
1512
|
+
const award = [];
|
|
1513
|
+
const gold = new Award();
|
|
1514
|
+
const silver = new Award();
|
|
1515
|
+
const bronze = new Award();
|
|
1516
|
+
{
|
|
1517
|
+
gold.medalType = MedalType.GOLD;
|
|
1518
|
+
gold.minRank = 1;
|
|
1519
|
+
gold.maxRank = Math.ceil(tot * 0.1);
|
|
1520
|
+
if (gold.maxRank >= gold.minRank) {
|
|
1521
|
+
award.push(gold);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
{
|
|
1525
|
+
silver.medalType = MedalType.SILVER;
|
|
1526
|
+
silver.minRank = gold.maxRank + 1;
|
|
1527
|
+
silver.maxRank = Math.ceil(tot * 0.3);
|
|
1528
|
+
if (silver.maxRank >= silver.minRank) {
|
|
1529
|
+
award.push(silver);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
{
|
|
1533
|
+
bronze.medalType = MedalType.BRONZE;
|
|
1534
|
+
bronze.minRank = silver.maxRank + 1;
|
|
1535
|
+
bronze.maxRank = Math.ceil(tot * 0.6);
|
|
1536
|
+
if (bronze.maxRank >= bronze.minRank) {
|
|
1537
|
+
award.push(bronze);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
this.contest.awards.set("official", award);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1496
1543
|
filterTeamByOrg(team) {
|
|
1497
1544
|
const o = this.options;
|
|
1498
1545
|
if (o.enableFilterTeamsByGroup) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TimeUnit, SubmissionStatus, Submission as Submission$1, Submissions as Submissions$1, BalloonColor, Problem as Problem$1, Problems as Problems$1, Lang, CalculationOfPenalty, StatusTimeDisplay, Image, ContestState, Contest as Contest$1, Team as Team$1, Teams as Teams$1, ContestIndex as ContestIndex$1 } from '@xcpcio/types';
|
|
1
|
+
import { TimeUnit, SubmissionStatus, Submission as Submission$1, Submissions as Submissions$1, BalloonColor, Problem as Problem$1, Problems as Problems$1, Lang, CalculationOfPenalty, StatusTimeDisplay, MedalPreset, Image, ContestState, Contest as Contest$1, Team as Team$1, Teams as Teams$1, ContestIndex as ContestIndex$1 } from '@xcpcio/types';
|
|
2
2
|
import dayjs from 'dayjs';
|
|
3
3
|
export { default as dayjs } from 'dayjs';
|
|
4
4
|
import * as XLSX from 'xlsx-js-style';
|
|
@@ -133,7 +133,7 @@ declare class Contest {
|
|
|
133
133
|
problemsMap: Map<string, Problem>;
|
|
134
134
|
statusTimeDisplay: StatusTimeDisplay;
|
|
135
135
|
badge?: string;
|
|
136
|
-
medal?: Record<string, Record<string, number
|
|
136
|
+
medal?: Record<string, Record<string, number>> | MedalPreset;
|
|
137
137
|
awards?: Awards;
|
|
138
138
|
organization?: string;
|
|
139
139
|
group: Map<string, Group>;
|
|
@@ -187,6 +187,7 @@ declare class Team {
|
|
|
187
187
|
get penaltyToMinute(): number;
|
|
188
188
|
get dirt(): number;
|
|
189
189
|
get membersToString(): string | undefined;
|
|
190
|
+
get isEffectiveTeam(): boolean;
|
|
190
191
|
calcSolvedData(options: ContestOptions): void;
|
|
191
192
|
calcAwards(awards?: Award[]): void;
|
|
192
193
|
isEqualRank(otherTeam: Team): boolean;
|
|
@@ -201,6 +202,7 @@ declare class RankStatistics {
|
|
|
201
202
|
teamSolvedNum: Array<number>;
|
|
202
203
|
teamSolvedNumIndex: Array<number>;
|
|
203
204
|
maxSolvedProblems: number;
|
|
205
|
+
effectiveTeamNum: number;
|
|
204
206
|
constructor();
|
|
205
207
|
reset(): void;
|
|
206
208
|
getTeamSolvedNumIndex(solvedNum: number): number;
|
|
@@ -259,6 +261,7 @@ declare class Rank {
|
|
|
259
261
|
buildTeamRank(): void;
|
|
260
262
|
buildOrgRank(): void;
|
|
261
263
|
buildOrganizations(): string[];
|
|
264
|
+
buildAwards(): void;
|
|
262
265
|
filterTeamByOrg(team: Team): boolean;
|
|
263
266
|
getSubmissions(): Submissions;
|
|
264
267
|
buildBalloons(): void;
|
package/dist/index.mjs
CHANGED
|
@@ -437,7 +437,10 @@ function calcDirt(attemptedNum, solvedNum) {
|
|
|
437
437
|
function getWhiteOrBlackColor(background) {
|
|
438
438
|
const [R, G, B] = chroma(background).rgb();
|
|
439
439
|
const color = { R, G, B };
|
|
440
|
-
const palette = [
|
|
440
|
+
const palette = [
|
|
441
|
+
{ R: 0, G: 0, B: 0 },
|
|
442
|
+
{ R: 255, G: 255, B: 255 }
|
|
443
|
+
];
|
|
441
444
|
const f = furthest(color, palette);
|
|
442
445
|
if (f.R === 0 && f.G === 0 && f.B === 0) {
|
|
443
446
|
return "#000";
|
|
@@ -494,7 +497,7 @@ function createProblem(problemJSON) {
|
|
|
494
497
|
p.timeLimit = problemJSON.time_limit;
|
|
495
498
|
p.memoryLimit = problemJSON.memory_limit;
|
|
496
499
|
if (problemJSON.balloon_color) {
|
|
497
|
-
p.balloonColor = problemJSON.balloon_color;
|
|
500
|
+
p.balloonColor = _.cloneDeep(problemJSON.balloon_color);
|
|
498
501
|
}
|
|
499
502
|
p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
|
|
500
503
|
return p;
|
|
@@ -511,7 +514,7 @@ function createProblemsByProblemIds(problemIds, balloonColors) {
|
|
|
511
514
|
});
|
|
512
515
|
if (balloonColors !== void 0 && balloonColors !== null) {
|
|
513
516
|
for (const index in balloonColors) {
|
|
514
|
-
problems[index].balloonColor = balloonColors[index];
|
|
517
|
+
problems[index].balloonColor = _.cloneDeep(balloonColors[index]);
|
|
515
518
|
}
|
|
516
519
|
}
|
|
517
520
|
problems.forEach((p) => {
|
|
@@ -623,6 +626,9 @@ class Team {
|
|
|
623
626
|
}
|
|
624
627
|
return this.members?.join(", ");
|
|
625
628
|
}
|
|
629
|
+
get isEffectiveTeam() {
|
|
630
|
+
return this.solvedProblemNum > 0;
|
|
631
|
+
}
|
|
626
632
|
calcSolvedData(options) {
|
|
627
633
|
this.solvedProblemNum = 0;
|
|
628
634
|
this.attemptedProblemNum = 0;
|
|
@@ -1019,32 +1025,34 @@ function createContest(contestJSON) {
|
|
|
1019
1025
|
return;
|
|
1020
1026
|
}
|
|
1021
1027
|
c.awards = /* @__PURE__ */ new Map();
|
|
1022
|
-
|
|
1023
|
-
const
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1028
|
+
if (typeof contestJSON.medal === "string") ; else {
|
|
1029
|
+
for (const k in contestJSON.medal) {
|
|
1030
|
+
const v = contestJSON.medal[k];
|
|
1031
|
+
{
|
|
1032
|
+
const award = [];
|
|
1033
|
+
let rank = 1;
|
|
1034
|
+
const work = (key, medalType) => {
|
|
1035
|
+
if (Object.keys(v).includes(key)) {
|
|
1036
|
+
const a = new Award();
|
|
1037
|
+
a.medalType = medalType;
|
|
1038
|
+
a.minRank = rank;
|
|
1039
|
+
rank += Number(v[key]);
|
|
1040
|
+
a.maxRank = rank - 1;
|
|
1041
|
+
award.push(a);
|
|
1042
|
+
}
|
|
1043
|
+
};
|
|
1044
|
+
work("gold", MedalType.GOLD);
|
|
1045
|
+
work("silver", MedalType.SILVER);
|
|
1046
|
+
work("bronze", MedalType.BRONZE);
|
|
1047
|
+
{
|
|
1029
1048
|
const a = new Award();
|
|
1030
|
-
a.medalType =
|
|
1049
|
+
a.medalType = MedalType.HONORABLE;
|
|
1031
1050
|
a.minRank = rank;
|
|
1032
|
-
|
|
1033
|
-
a.maxRank = rank - 1;
|
|
1051
|
+
a.maxRank = 1061109567;
|
|
1034
1052
|
award.push(a);
|
|
1035
1053
|
}
|
|
1036
|
-
|
|
1037
|
-
work("gold", MedalType.GOLD);
|
|
1038
|
-
work("silver", MedalType.SILVER);
|
|
1039
|
-
work("bronze", MedalType.BRONZE);
|
|
1040
|
-
{
|
|
1041
|
-
const a = new Award();
|
|
1042
|
-
a.medalType = MedalType.HONORABLE;
|
|
1043
|
-
a.minRank = rank;
|
|
1044
|
-
a.maxRank = 1061109567;
|
|
1045
|
-
award.push(a);
|
|
1054
|
+
c.awards.set(k, award);
|
|
1046
1055
|
}
|
|
1047
|
-
c.awards.set(k, award);
|
|
1048
1056
|
}
|
|
1049
1057
|
}
|
|
1050
1058
|
})();
|
|
@@ -1156,11 +1164,13 @@ class RankStatistics {
|
|
|
1156
1164
|
this.teamSolvedNum = [];
|
|
1157
1165
|
this.teamSolvedNumIndex = [];
|
|
1158
1166
|
this.maxSolvedProblems = 0;
|
|
1167
|
+
this.effectiveTeamNum = 0;
|
|
1159
1168
|
}
|
|
1160
1169
|
reset() {
|
|
1161
1170
|
this.teamSolvedNum = [];
|
|
1162
1171
|
this.teamSolvedNumIndex = [];
|
|
1163
1172
|
this.maxSolvedProblems = 0;
|
|
1173
|
+
this.effectiveTeamNum = 0;
|
|
1164
1174
|
}
|
|
1165
1175
|
getTeamSolvedNumIndex(solvedNum) {
|
|
1166
1176
|
return this.teamSolvedNumIndex[solvedNum] ?? 0;
|
|
@@ -1386,6 +1396,8 @@ class Rank {
|
|
|
1386
1396
|
this.teams.sort(Team.compare);
|
|
1387
1397
|
this.buildTeamRank();
|
|
1388
1398
|
this.buildOrgRank();
|
|
1399
|
+
this.rankStatistics.effectiveTeamNum = this.teams.filter((t) => t.isEffectiveTeam).length;
|
|
1400
|
+
this.buildAwards();
|
|
1389
1401
|
this.teams.forEach((t) => t.calcAwards(this.contest.awards?.get(this.options.group)));
|
|
1390
1402
|
this.teams.forEach((t) => t.postProcessPlaceChartPoints());
|
|
1391
1403
|
})();
|
|
@@ -1462,6 +1474,41 @@ class Rank {
|
|
|
1462
1474
|
res.sort();
|
|
1463
1475
|
return res;
|
|
1464
1476
|
}
|
|
1477
|
+
buildAwards() {
|
|
1478
|
+
if (this.contest.medal === "ccpc") {
|
|
1479
|
+
this.contest.awards = /* @__PURE__ */ new Map();
|
|
1480
|
+
const tot = this.rankStatistics.effectiveTeamNum;
|
|
1481
|
+
const award = [];
|
|
1482
|
+
const gold = new Award();
|
|
1483
|
+
const silver = new Award();
|
|
1484
|
+
const bronze = new Award();
|
|
1485
|
+
{
|
|
1486
|
+
gold.medalType = MedalType.GOLD;
|
|
1487
|
+
gold.minRank = 1;
|
|
1488
|
+
gold.maxRank = Math.ceil(tot * 0.1);
|
|
1489
|
+
if (gold.maxRank >= gold.minRank) {
|
|
1490
|
+
award.push(gold);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
{
|
|
1494
|
+
silver.medalType = MedalType.SILVER;
|
|
1495
|
+
silver.minRank = gold.maxRank + 1;
|
|
1496
|
+
silver.maxRank = Math.ceil(tot * 0.3);
|
|
1497
|
+
if (silver.maxRank >= silver.minRank) {
|
|
1498
|
+
award.push(silver);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
{
|
|
1502
|
+
bronze.medalType = MedalType.BRONZE;
|
|
1503
|
+
bronze.minRank = silver.maxRank + 1;
|
|
1504
|
+
bronze.maxRank = Math.ceil(tot * 0.6);
|
|
1505
|
+
if (bronze.maxRank >= bronze.minRank) {
|
|
1506
|
+
award.push(bronze);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
this.contest.awards.set("official", award);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1465
1512
|
filterTeamByOrg(team) {
|
|
1466
1513
|
const o = this.options;
|
|
1467
1514
|
if (o.enableFilterTeamsByGroup) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcpcio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.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.34.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@babel/types": "^7.22.4",
|
package/src/contest.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Contest as IContest, Image, StatusTimeDisplay } from "@xcpcio/types";
|
|
1
|
+
import type { Contest as IContest, Image, MedalPreset, StatusTimeDisplay } from "@xcpcio/types";
|
|
2
2
|
import { ContestState } from "@xcpcio/types";
|
|
3
3
|
|
|
4
4
|
import type { Problem, Problems } from "./problem";
|
|
@@ -28,7 +28,7 @@ export class Contest {
|
|
|
28
28
|
statusTimeDisplay: StatusTimeDisplay;
|
|
29
29
|
|
|
30
30
|
badge?: string;
|
|
31
|
-
medal?: Record<string, Record<string, number
|
|
31
|
+
medal?: Record<string, Record<string, number>> | MedalPreset;
|
|
32
32
|
awards?: Awards;
|
|
33
33
|
organization?: string;
|
|
34
34
|
|
|
@@ -217,37 +217,42 @@ export function createContest(contestJSON: IContest): Contest {
|
|
|
217
217
|
|
|
218
218
|
c.awards = new Map<string, Award[]>();
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
if (typeof contestJSON.medal === "string") {
|
|
221
|
+
// eslint-disable-next-line no-empty
|
|
222
|
+
{}
|
|
223
|
+
} else {
|
|
224
|
+
for (const k in contestJSON.medal) {
|
|
225
|
+
const v = contestJSON.medal[k];
|
|
222
226
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
227
|
+
{
|
|
228
|
+
const award: Award[] = [];
|
|
229
|
+
|
|
230
|
+
let rank = 1;
|
|
231
|
+
const work = (key: string, medalType: MedalType) => {
|
|
232
|
+
if (Object.keys(v).includes(key)) {
|
|
233
|
+
const a = new Award();
|
|
234
|
+
a.medalType = medalType;
|
|
235
|
+
a.minRank = rank;
|
|
236
|
+
rank += Number(v[key]);
|
|
237
|
+
a.maxRank = rank - 1;
|
|
238
|
+
award.push(a);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
work("gold", MedalType.GOLD);
|
|
243
|
+
work("silver", MedalType.SILVER);
|
|
244
|
+
work("bronze", MedalType.BRONZE);
|
|
245
|
+
|
|
246
|
+
{
|
|
229
247
|
const a = new Award();
|
|
230
|
-
a.medalType =
|
|
248
|
+
a.medalType = MedalType.HONORABLE;
|
|
231
249
|
a.minRank = rank;
|
|
232
|
-
|
|
233
|
-
a.maxRank = rank - 1;
|
|
250
|
+
a.maxRank = 0x3F3F3F3F;
|
|
234
251
|
award.push(a);
|
|
235
252
|
}
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
work("gold", MedalType.GOLD);
|
|
239
|
-
work("silver", MedalType.SILVER);
|
|
240
|
-
work("bronze", MedalType.BRONZE);
|
|
241
253
|
|
|
242
|
-
|
|
243
|
-
const a = new Award();
|
|
244
|
-
a.medalType = MedalType.HONORABLE;
|
|
245
|
-
a.minRank = rank;
|
|
246
|
-
a.maxRank = 0x3F3F3F3F;
|
|
247
|
-
award.push(a);
|
|
254
|
+
c.awards.set(k, award);
|
|
248
255
|
}
|
|
249
|
-
|
|
250
|
-
c.awards.set(k, award);
|
|
251
256
|
}
|
|
252
257
|
}
|
|
253
258
|
})();
|
package/src/problem.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import _ from "lodash";
|
|
2
|
+
|
|
1
3
|
import type { BalloonColor, Problem as IProblem, Problems as IProblems } from "@xcpcio/types";
|
|
2
4
|
|
|
3
5
|
import type { Submissions } from "./submission";
|
|
@@ -92,7 +94,7 @@ export function createProblem(problemJSON: IProblem): Problem {
|
|
|
92
94
|
p.memoryLimit = problemJSON.memory_limit;
|
|
93
95
|
|
|
94
96
|
if (problemJSON.balloon_color) {
|
|
95
|
-
p.balloonColor = problemJSON.balloon_color;
|
|
97
|
+
p.balloonColor = _.cloneDeep(problemJSON.balloon_color);
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color as string);
|
|
@@ -115,7 +117,7 @@ export function createProblemsByProblemIds(problemIds: string[], balloonColors?:
|
|
|
115
117
|
|
|
116
118
|
if (balloonColors !== undefined && balloonColors !== null) {
|
|
117
119
|
for (const index in balloonColors) {
|
|
118
|
-
problems[index].balloonColor = balloonColors[index];
|
|
120
|
+
problems[index].balloonColor = _.cloneDeep(balloonColors[index]);
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
|
package/src/rank-statistics.ts
CHANGED
|
@@ -3,16 +3,22 @@ export class RankStatistics {
|
|
|
3
3
|
teamSolvedNumIndex: Array<number>;
|
|
4
4
|
maxSolvedProblems: number;
|
|
5
5
|
|
|
6
|
+
effectiveTeamNum: number;
|
|
7
|
+
|
|
6
8
|
constructor() {
|
|
7
9
|
this.teamSolvedNum = [];
|
|
8
10
|
this.teamSolvedNumIndex = [];
|
|
9
11
|
this.maxSolvedProblems = 0;
|
|
12
|
+
|
|
13
|
+
this.effectiveTeamNum = 0;
|
|
10
14
|
}
|
|
11
15
|
|
|
12
16
|
reset() {
|
|
13
17
|
this.teamSolvedNum = [];
|
|
14
18
|
this.teamSolvedNumIndex = [];
|
|
15
19
|
this.maxSolvedProblems = 0;
|
|
20
|
+
|
|
21
|
+
this.effectiveTeamNum = 0;
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
getTeamSolvedNumIndex(solvedNum: number): number {
|
package/src/rank.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { Submission } from "./submission";
|
|
|
10
10
|
import { TeamProblemStatistics } from "./problem";
|
|
11
11
|
import { RankStatistics } from "./rank-statistics";
|
|
12
12
|
import { Balloon, type Balloons } from "./balloon";
|
|
13
|
+
import { Award, MedalType } from "./award";
|
|
13
14
|
|
|
14
15
|
export interface SelectOptionItem {
|
|
15
16
|
value: string;
|
|
@@ -342,6 +343,9 @@ export class Rank {
|
|
|
342
343
|
this.buildTeamRank();
|
|
343
344
|
this.buildOrgRank();
|
|
344
345
|
|
|
346
|
+
this.rankStatistics.effectiveTeamNum = this.teams.filter(t => t.isEffectiveTeam).length;
|
|
347
|
+
this.buildAwards();
|
|
348
|
+
|
|
345
349
|
this.teams.forEach(t => t.calcAwards(this.contest.awards?.get(this.options.group)));
|
|
346
350
|
this.teams.forEach(t => t.postProcessPlaceChartPoints());
|
|
347
351
|
})();
|
|
@@ -440,6 +444,48 @@ export class Rank {
|
|
|
440
444
|
return res;
|
|
441
445
|
}
|
|
442
446
|
|
|
447
|
+
buildAwards() {
|
|
448
|
+
if (this.contest.medal === "ccpc") {
|
|
449
|
+
this.contest.awards = new Map<string, Award[]>();
|
|
450
|
+
|
|
451
|
+
const tot = this.rankStatistics.effectiveTeamNum;
|
|
452
|
+
const award: Award[] = [];
|
|
453
|
+
|
|
454
|
+
const gold = new Award();
|
|
455
|
+
const silver = new Award();
|
|
456
|
+
const bronze = new Award();
|
|
457
|
+
|
|
458
|
+
{
|
|
459
|
+
gold.medalType = MedalType.GOLD;
|
|
460
|
+
gold.minRank = 1;
|
|
461
|
+
gold.maxRank = Math.ceil(tot * 0.1);
|
|
462
|
+
if (gold.maxRank >= gold.minRank) {
|
|
463
|
+
award.push(gold);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
{
|
|
468
|
+
silver.medalType = MedalType.SILVER;
|
|
469
|
+
silver.minRank = gold.maxRank + 1;
|
|
470
|
+
silver.maxRank = Math.ceil(tot * 0.3);
|
|
471
|
+
if (silver.maxRank >= silver.minRank) {
|
|
472
|
+
award.push(silver);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
{
|
|
477
|
+
bronze.medalType = MedalType.BRONZE;
|
|
478
|
+
bronze.minRank = silver.maxRank + 1;
|
|
479
|
+
bronze.maxRank = Math.ceil(tot * 0.6);
|
|
480
|
+
if (bronze.maxRank >= bronze.minRank) {
|
|
481
|
+
award.push(bronze);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
this.contest.awards.set("official", award);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
443
489
|
filterTeamByOrg(team: Team) {
|
|
444
490
|
const o = this.options;
|
|
445
491
|
|
package/src/team.ts
CHANGED
|
@@ -127,6 +127,10 @@ export class Team {
|
|
|
127
127
|
return this.members?.join(", ");
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
get isEffectiveTeam() {
|
|
131
|
+
return this.solvedProblemNum > 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
130
134
|
calcSolvedData(options: ContestOptions) {
|
|
131
135
|
this.solvedProblemNum = 0;
|
|
132
136
|
this.attemptedProblemNum = 0;
|
package/src/utils/color.ts
CHANGED
|
@@ -4,7 +4,10 @@ import chroma from "chroma-js";
|
|
|
4
4
|
export function getWhiteOrBlackColor(background: string) {
|
|
5
5
|
const [R, G, B] = chroma(background).rgb();
|
|
6
6
|
const color = { R, G, B };
|
|
7
|
-
const palette = [
|
|
7
|
+
const palette = [
|
|
8
|
+
{ R: 0, G: 0, B: 0 },
|
|
9
|
+
{ R: 255, G: 255, B: 255 },
|
|
10
|
+
];
|
|
8
11
|
|
|
9
12
|
const f = furthest(color, palette);
|
|
10
13
|
|