@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 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 = [{ R: 0, G: 0, B: 0 }, { R: 255, G: 255, B: 255 }];
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
- for (const k in contestJSON.medal) {
1054
- const v = contestJSON.medal[k];
1055
- {
1056
- const award = [];
1057
- let rank = 1;
1058
- const work = (key, medalType) => {
1059
- if (Object.keys(v).includes(key)) {
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 = medalType;
1080
+ a.medalType = MedalType.HONORABLE;
1062
1081
  a.minRank = rank;
1063
- rank += Number(v[key]);
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 = [{ R: 0, G: 0, B: 0 }, { R: 255, G: 255, B: 255 }];
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
- for (const k in contestJSON.medal) {
1023
- const v = contestJSON.medal[k];
1024
- {
1025
- const award = [];
1026
- let rank = 1;
1027
- const work = (key, medalType) => {
1028
- if (Object.keys(v).includes(key)) {
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 = medalType;
1049
+ a.medalType = MedalType.HONORABLE;
1031
1050
  a.minRank = rank;
1032
- rank += Number(v[key]);
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.33.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.33.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
- for (const k in contestJSON.medal) {
221
- const v = contestJSON.medal[k];
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
- const award: Award[] = [];
225
-
226
- let rank = 1;
227
- const work = (key: string, medalType: MedalType) => {
228
- if (Object.keys(v).includes(key)) {
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 = medalType;
248
+ a.medalType = MedalType.HONORABLE;
231
249
  a.minRank = rank;
232
- rank += Number(v[key]);
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
 
@@ -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;
@@ -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 = [{ R: 0, G: 0, B: 0 }, { R: 255, G: 255, B: 255 }];
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