@xcpcio/core 0.23.0 → 0.24.3
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 +306 -245
- package/dist/index.d.ts +16 -2
- package/dist/index.mjs +306 -246
- package/package.json +2 -2
- package/src/balloon.ts +21 -0
- package/src/index.ts +3 -1
- package/src/problem.ts +5 -5
- package/src/rank-statistics.ts +7 -0
- package/src/rank.ts +84 -23
package/dist/index.mjs
CHANGED
|
@@ -527,17 +527,251 @@ class TeamProblemStatistics {
|
|
|
527
527
|
get isUnSubmitted() {
|
|
528
528
|
return this.totalCount === 0;
|
|
529
529
|
}
|
|
530
|
+
get solvedTimestampToMinute() {
|
|
531
|
+
return Math.floor(this.solvedTimestamp / 60);
|
|
532
|
+
}
|
|
530
533
|
get penalty() {
|
|
531
534
|
if (this.isSolved === false) {
|
|
532
535
|
return 0;
|
|
533
536
|
}
|
|
534
|
-
return
|
|
537
|
+
return this.solvedTimestampToMinute * 60 + this.failedCount * this.contestPenalty;
|
|
535
538
|
}
|
|
536
539
|
get penaltyToMinute() {
|
|
537
540
|
return Math.floor(this.penalty / 60);
|
|
538
541
|
}
|
|
539
|
-
|
|
540
|
-
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
class PlaceChartPointData {
|
|
545
|
+
constructor() {
|
|
546
|
+
this.timePoint = 0;
|
|
547
|
+
this.rank = 0;
|
|
548
|
+
this.lastSolvedProblem = null;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
class Team {
|
|
552
|
+
constructor() {
|
|
553
|
+
this.id = "";
|
|
554
|
+
this.name = "";
|
|
555
|
+
this.organization = "";
|
|
556
|
+
this.group = [];
|
|
557
|
+
this.tag = [];
|
|
558
|
+
this.rank = 0;
|
|
559
|
+
this.originalRank = 0;
|
|
560
|
+
this.organizationRank = -1;
|
|
561
|
+
this.solvedProblemNum = 0;
|
|
562
|
+
this.attemptedProblemNum = 0;
|
|
563
|
+
this.lastSolvedProblem = null;
|
|
564
|
+
this.lastSolvedProblemTimestamp = 0;
|
|
565
|
+
this.penalty = 0;
|
|
566
|
+
this.problemStatistics = [];
|
|
567
|
+
this.problemStatisticsMap = /* @__PURE__ */ new Map();
|
|
568
|
+
this.submissions = [];
|
|
569
|
+
this.placeChartPoints = [];
|
|
570
|
+
this.awards = [];
|
|
571
|
+
}
|
|
572
|
+
reset() {
|
|
573
|
+
this.rank = 0;
|
|
574
|
+
this.originalRank = 0;
|
|
575
|
+
this.organizationRank = -1;
|
|
576
|
+
this.solvedProblemNum = 0;
|
|
577
|
+
this.attemptedProblemNum = 0;
|
|
578
|
+
this.lastSolvedProblem = null;
|
|
579
|
+
this.lastSolvedProblemTimestamp = 0;
|
|
580
|
+
this.penalty = 0;
|
|
581
|
+
this.problemStatistics = [];
|
|
582
|
+
this.problemStatisticsMap = /* @__PURE__ */ new Map();
|
|
583
|
+
this.submissions = [];
|
|
584
|
+
this.placeChartPoints = [];
|
|
585
|
+
this.awards = [];
|
|
586
|
+
}
|
|
587
|
+
get penaltyToMinute() {
|
|
588
|
+
return Math.floor(this.penalty / 60);
|
|
589
|
+
}
|
|
590
|
+
get dirt() {
|
|
591
|
+
const attemptedNum = this.attemptedProblemNum;
|
|
592
|
+
const solvedNum = this.solvedProblemNum;
|
|
593
|
+
return calcDirt(attemptedNum, solvedNum);
|
|
594
|
+
}
|
|
595
|
+
get membersToString() {
|
|
596
|
+
if (typeof this.members === "string") {
|
|
597
|
+
return this.members;
|
|
598
|
+
}
|
|
599
|
+
return this.members?.join(", ");
|
|
600
|
+
}
|
|
601
|
+
calcSolvedData() {
|
|
602
|
+
this.solvedProblemNum = 0;
|
|
603
|
+
this.attemptedProblemNum = 0;
|
|
604
|
+
this.penalty = 0;
|
|
605
|
+
for (const p of this.problemStatistics) {
|
|
606
|
+
if (p.isAccepted) {
|
|
607
|
+
this.solvedProblemNum++;
|
|
608
|
+
this.attemptedProblemNum += p.failedCount + 1;
|
|
609
|
+
this.penalty += p.penalty;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
calcAwards(awards) {
|
|
614
|
+
if (!awards) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
for (const award of awards) {
|
|
618
|
+
if (this.rank >= award.minRank && this.rank <= award.maxRank) {
|
|
619
|
+
this.awards.push(award.medalType);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
isEqualRank(otherTeam) {
|
|
624
|
+
return this.solvedProblemNum === otherTeam.solvedProblemNum && this.penalty === otherTeam.penalty;
|
|
625
|
+
}
|
|
626
|
+
postProcessPlaceChartPoints() {
|
|
627
|
+
if (this.placeChartPoints.length === 0) {
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
const res = [];
|
|
631
|
+
res.push(this.placeChartPoints[0]);
|
|
632
|
+
for (let i = 1; i < this.placeChartPoints.length - 1; i++) {
|
|
633
|
+
const p = this.placeChartPoints[i];
|
|
634
|
+
const preP = res[res.length - 1];
|
|
635
|
+
if (p.rank !== preP.rank || p.lastSolvedProblem !== preP.lastSolvedProblem) {
|
|
636
|
+
res.push(p);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if (this.placeChartPoints.length > 1) {
|
|
640
|
+
res.push(this.placeChartPoints[this.placeChartPoints.length - 1]);
|
|
641
|
+
}
|
|
642
|
+
this.placeChartPoints = res;
|
|
643
|
+
}
|
|
644
|
+
static compare(lhs, rhs) {
|
|
645
|
+
if (lhs.solvedProblemNum !== rhs.solvedProblemNum) {
|
|
646
|
+
return rhs.solvedProblemNum - lhs.solvedProblemNum;
|
|
647
|
+
}
|
|
648
|
+
if (lhs.penalty !== rhs.penalty) {
|
|
649
|
+
return lhs.penalty - rhs.penalty;
|
|
650
|
+
}
|
|
651
|
+
if (lhs.lastSolvedProblemTimestamp !== rhs.lastSolvedProblemTimestamp) {
|
|
652
|
+
return lhs.lastSolvedProblemTimestamp - rhs.lastSolvedProblemTimestamp;
|
|
653
|
+
}
|
|
654
|
+
if (lhs.name < rhs.name) {
|
|
655
|
+
return -1;
|
|
656
|
+
} else if (lhs.name > rhs.name) {
|
|
657
|
+
return 1;
|
|
658
|
+
}
|
|
659
|
+
return 0;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
function createTeam(teamJSON) {
|
|
663
|
+
const t = new Team();
|
|
664
|
+
t.id = teamJSON.id ?? teamJSON.team_id ?? "";
|
|
665
|
+
t.name = teamJSON.name ?? teamJSON.team_name ?? "";
|
|
666
|
+
t.organization = teamJSON.organization ?? "";
|
|
667
|
+
t.badge = teamJSON.badge;
|
|
668
|
+
t.group = teamJSON.group ?? [];
|
|
669
|
+
t.tag = teamJSON.group ?? [];
|
|
670
|
+
t.coach = teamJSON.coach;
|
|
671
|
+
t.members = teamJSON.members;
|
|
672
|
+
if (Boolean(teamJSON.official) === true) {
|
|
673
|
+
t.group.push("official");
|
|
674
|
+
}
|
|
675
|
+
if (Boolean(teamJSON.unofficial) === true) {
|
|
676
|
+
t.group.push("unofficial");
|
|
677
|
+
}
|
|
678
|
+
if (Boolean(teamJSON.girl) === true) {
|
|
679
|
+
t.group.push("girl");
|
|
680
|
+
}
|
|
681
|
+
{
|
|
682
|
+
const tt = teamJSON;
|
|
683
|
+
for (const key of Object.keys(tt)) {
|
|
684
|
+
if (tt[key] === 1 || tt[key] === true) {
|
|
685
|
+
t.group.push(key);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
t.group = [...new Set(t.group)];
|
|
690
|
+
t.group.sort();
|
|
691
|
+
if (teamJSON.location) {
|
|
692
|
+
t.location = teamJSON.location;
|
|
693
|
+
}
|
|
694
|
+
return t;
|
|
695
|
+
}
|
|
696
|
+
function createTeams(teamsJSON) {
|
|
697
|
+
if (Array.isArray(teamsJSON)) {
|
|
698
|
+
return teamsJSON.map((t) => createTeam(t));
|
|
699
|
+
} else {
|
|
700
|
+
const teams = Object.entries(teamsJSON).map(
|
|
701
|
+
([teamId, team]) => createTeam({ ...team, team_id: team.team_id ?? teamId })
|
|
702
|
+
);
|
|
703
|
+
return teams;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
class Submission {
|
|
708
|
+
constructor() {
|
|
709
|
+
this.status = SubmissionStatus.UNKNOWN;
|
|
710
|
+
this.isIgnore = false;
|
|
711
|
+
this.id = "";
|
|
712
|
+
this.teamId = "";
|
|
713
|
+
this.problemId = "";
|
|
714
|
+
this.timestamp = 0;
|
|
715
|
+
}
|
|
716
|
+
isAccepted() {
|
|
717
|
+
return isAccepted(this.status);
|
|
718
|
+
}
|
|
719
|
+
isRejected() {
|
|
720
|
+
return isRejected(this.status);
|
|
721
|
+
}
|
|
722
|
+
isPending() {
|
|
723
|
+
return isPending(this.status);
|
|
724
|
+
}
|
|
725
|
+
isNotCalculatedPenaltyStatus() {
|
|
726
|
+
return isNotCalculatedPenaltyStatus(this.status);
|
|
727
|
+
}
|
|
728
|
+
get timestampToMinute() {
|
|
729
|
+
return Math.floor(this.timestamp / 60);
|
|
730
|
+
}
|
|
731
|
+
static compare(lhs, rhs) {
|
|
732
|
+
if (lhs.timestamp !== rhs.timestamp) {
|
|
733
|
+
return lhs.timestamp - rhs.timestamp;
|
|
734
|
+
}
|
|
735
|
+
if (lhs.teamId === rhs.teamId) {
|
|
736
|
+
if (lhs.isAccepted() && !rhs.isAccepted()) {
|
|
737
|
+
return -1;
|
|
738
|
+
}
|
|
739
|
+
if (!lhs.isAccepted() && rhs.isAccepted()) {
|
|
740
|
+
return 1;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
return 0;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
function createSubmission(submissionJSON) {
|
|
747
|
+
const s = new Submission();
|
|
748
|
+
s.id = String(submissionJSON.id ?? submissionJSON.submission_id ?? "");
|
|
749
|
+
s.teamId = String(submissionJSON.team_id);
|
|
750
|
+
s.problemId = String(submissionJSON.problem_id);
|
|
751
|
+
s.timestamp = submissionJSON.timestamp;
|
|
752
|
+
s.status = stringToSubmissionStatus(submissionJSON.status);
|
|
753
|
+
s.isIgnore = submissionJSON.is_ignore ?? false;
|
|
754
|
+
return s;
|
|
755
|
+
}
|
|
756
|
+
function createSubmissions(submissionsJSON) {
|
|
757
|
+
if (Array.isArray(submissionsJSON)) {
|
|
758
|
+
return submissionsJSON.map((s, index) => createSubmission({ ...s, id: s.submission_id ?? String(index) }));
|
|
759
|
+
} else {
|
|
760
|
+
const submissions = Object.entries(submissionsJSON).map(
|
|
761
|
+
([submissionId, s]) => createSubmission({ ...s, id: s.submission_id ?? submissionId })
|
|
762
|
+
);
|
|
763
|
+
return submissions;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
class Balloon {
|
|
768
|
+
constructor() {
|
|
769
|
+
this.problem = new Problem();
|
|
770
|
+
this.team = new Team();
|
|
771
|
+
this.submission = new Submission();
|
|
772
|
+
}
|
|
773
|
+
get key() {
|
|
774
|
+
return `balloon-${this.team.id}-${this.problem.id}`;
|
|
541
775
|
}
|
|
542
776
|
}
|
|
543
777
|
|
|
@@ -810,234 +1044,16 @@ function getImageSource(image) {
|
|
|
810
1044
|
class RankStatistics {
|
|
811
1045
|
constructor() {
|
|
812
1046
|
this.teamSolvedNum = [];
|
|
1047
|
+
this.teamSolvedNumIndex = [];
|
|
813
1048
|
this.maxSolvedProblems = 0;
|
|
814
1049
|
}
|
|
815
1050
|
reset() {
|
|
816
1051
|
this.teamSolvedNum = [];
|
|
1052
|
+
this.teamSolvedNumIndex = [];
|
|
817
1053
|
this.maxSolvedProblems = 0;
|
|
818
1054
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
class PlaceChartPointData {
|
|
822
|
-
constructor() {
|
|
823
|
-
this.timePoint = 0;
|
|
824
|
-
this.rank = 0;
|
|
825
|
-
this.lastSolvedProblem = null;
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
class Team {
|
|
829
|
-
constructor() {
|
|
830
|
-
this.id = "";
|
|
831
|
-
this.name = "";
|
|
832
|
-
this.organization = "";
|
|
833
|
-
this.group = [];
|
|
834
|
-
this.tag = [];
|
|
835
|
-
this.rank = 0;
|
|
836
|
-
this.originalRank = 0;
|
|
837
|
-
this.organizationRank = -1;
|
|
838
|
-
this.solvedProblemNum = 0;
|
|
839
|
-
this.attemptedProblemNum = 0;
|
|
840
|
-
this.lastSolvedProblem = null;
|
|
841
|
-
this.lastSolvedProblemTimestamp = 0;
|
|
842
|
-
this.penalty = 0;
|
|
843
|
-
this.problemStatistics = [];
|
|
844
|
-
this.problemStatisticsMap = /* @__PURE__ */ new Map();
|
|
845
|
-
this.submissions = [];
|
|
846
|
-
this.placeChartPoints = [];
|
|
847
|
-
this.awards = [];
|
|
848
|
-
}
|
|
849
|
-
reset() {
|
|
850
|
-
this.rank = 0;
|
|
851
|
-
this.originalRank = 0;
|
|
852
|
-
this.organizationRank = -1;
|
|
853
|
-
this.solvedProblemNum = 0;
|
|
854
|
-
this.attemptedProblemNum = 0;
|
|
855
|
-
this.lastSolvedProblem = null;
|
|
856
|
-
this.lastSolvedProblemTimestamp = 0;
|
|
857
|
-
this.penalty = 0;
|
|
858
|
-
this.problemStatistics = [];
|
|
859
|
-
this.problemStatisticsMap = /* @__PURE__ */ new Map();
|
|
860
|
-
this.submissions = [];
|
|
861
|
-
this.placeChartPoints = [];
|
|
862
|
-
this.awards = [];
|
|
863
|
-
}
|
|
864
|
-
get penaltyToMinute() {
|
|
865
|
-
return Math.floor(this.penalty / 60);
|
|
866
|
-
}
|
|
867
|
-
get dirt() {
|
|
868
|
-
const attemptedNum = this.attemptedProblemNum;
|
|
869
|
-
const solvedNum = this.solvedProblemNum;
|
|
870
|
-
return calcDirt(attemptedNum, solvedNum);
|
|
871
|
-
}
|
|
872
|
-
get membersToString() {
|
|
873
|
-
if (typeof this.members === "string") {
|
|
874
|
-
return this.members;
|
|
875
|
-
}
|
|
876
|
-
return this.members?.join(", ");
|
|
877
|
-
}
|
|
878
|
-
calcSolvedData() {
|
|
879
|
-
this.solvedProblemNum = 0;
|
|
880
|
-
this.attemptedProblemNum = 0;
|
|
881
|
-
this.penalty = 0;
|
|
882
|
-
for (const p of this.problemStatistics) {
|
|
883
|
-
if (p.isAccepted) {
|
|
884
|
-
this.solvedProblemNum++;
|
|
885
|
-
this.attemptedProblemNum += p.failedCount + 1;
|
|
886
|
-
this.penalty += p.penalty;
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
calcAwards(awards) {
|
|
891
|
-
if (!awards) {
|
|
892
|
-
return;
|
|
893
|
-
}
|
|
894
|
-
for (const award of awards) {
|
|
895
|
-
if (this.rank >= award.minRank && this.rank <= award.maxRank) {
|
|
896
|
-
this.awards.push(award.medalType);
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
isEqualRank(otherTeam) {
|
|
901
|
-
return this.solvedProblemNum === otherTeam.solvedProblemNum && this.penalty === otherTeam.penalty;
|
|
902
|
-
}
|
|
903
|
-
postProcessPlaceChartPoints() {
|
|
904
|
-
if (this.placeChartPoints.length === 0) {
|
|
905
|
-
return;
|
|
906
|
-
}
|
|
907
|
-
const res = [];
|
|
908
|
-
res.push(this.placeChartPoints[0]);
|
|
909
|
-
for (let i = 1; i < this.placeChartPoints.length - 1; i++) {
|
|
910
|
-
const p = this.placeChartPoints[i];
|
|
911
|
-
const preP = res[res.length - 1];
|
|
912
|
-
if (p.rank !== preP.rank || p.lastSolvedProblem !== preP.lastSolvedProblem) {
|
|
913
|
-
res.push(p);
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
if (this.placeChartPoints.length > 1) {
|
|
917
|
-
res.push(this.placeChartPoints[this.placeChartPoints.length - 1]);
|
|
918
|
-
}
|
|
919
|
-
this.placeChartPoints = res;
|
|
920
|
-
}
|
|
921
|
-
static compare(lhs, rhs) {
|
|
922
|
-
if (lhs.solvedProblemNum !== rhs.solvedProblemNum) {
|
|
923
|
-
return rhs.solvedProblemNum - lhs.solvedProblemNum;
|
|
924
|
-
}
|
|
925
|
-
if (lhs.penalty !== rhs.penalty) {
|
|
926
|
-
return lhs.penalty - rhs.penalty;
|
|
927
|
-
}
|
|
928
|
-
if (lhs.lastSolvedProblemTimestamp !== rhs.lastSolvedProblemTimestamp) {
|
|
929
|
-
return lhs.lastSolvedProblemTimestamp - rhs.lastSolvedProblemTimestamp;
|
|
930
|
-
}
|
|
931
|
-
if (lhs.name < rhs.name) {
|
|
932
|
-
return -1;
|
|
933
|
-
} else if (lhs.name > rhs.name) {
|
|
934
|
-
return 1;
|
|
935
|
-
}
|
|
936
|
-
return 0;
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
function createTeam(teamJSON) {
|
|
940
|
-
const t = new Team();
|
|
941
|
-
t.id = teamJSON.id ?? teamJSON.team_id ?? "";
|
|
942
|
-
t.name = teamJSON.name ?? teamJSON.team_name ?? "";
|
|
943
|
-
t.organization = teamJSON.organization ?? "";
|
|
944
|
-
t.badge = teamJSON.badge;
|
|
945
|
-
t.group = teamJSON.group ?? [];
|
|
946
|
-
t.tag = teamJSON.group ?? [];
|
|
947
|
-
t.coach = teamJSON.coach;
|
|
948
|
-
t.members = teamJSON.members;
|
|
949
|
-
if (Boolean(teamJSON.official) === true) {
|
|
950
|
-
t.group.push("official");
|
|
951
|
-
}
|
|
952
|
-
if (Boolean(teamJSON.unofficial) === true) {
|
|
953
|
-
t.group.push("unofficial");
|
|
954
|
-
}
|
|
955
|
-
if (Boolean(teamJSON.girl) === true) {
|
|
956
|
-
t.group.push("girl");
|
|
957
|
-
}
|
|
958
|
-
{
|
|
959
|
-
const tt = teamJSON;
|
|
960
|
-
for (const key of Object.keys(tt)) {
|
|
961
|
-
if (tt[key] === 1 || tt[key] === true) {
|
|
962
|
-
t.group.push(key);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
t.group = [...new Set(t.group)];
|
|
967
|
-
t.group.sort();
|
|
968
|
-
if (teamJSON.location) {
|
|
969
|
-
t.location = teamJSON.location;
|
|
970
|
-
}
|
|
971
|
-
return t;
|
|
972
|
-
}
|
|
973
|
-
function createTeams(teamsJSON) {
|
|
974
|
-
if (Array.isArray(teamsJSON)) {
|
|
975
|
-
return teamsJSON.map((t) => createTeam(t));
|
|
976
|
-
} else {
|
|
977
|
-
const teams = Object.entries(teamsJSON).map(
|
|
978
|
-
([teamId, team]) => createTeam({ ...team, team_id: team.team_id ?? teamId })
|
|
979
|
-
);
|
|
980
|
-
return teams;
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
class Submission {
|
|
985
|
-
constructor() {
|
|
986
|
-
this.status = SubmissionStatus.UNKNOWN;
|
|
987
|
-
this.isIgnore = false;
|
|
988
|
-
this.id = "";
|
|
989
|
-
this.teamId = "";
|
|
990
|
-
this.problemId = "";
|
|
991
|
-
this.timestamp = 0;
|
|
992
|
-
}
|
|
993
|
-
isAccepted() {
|
|
994
|
-
return isAccepted(this.status);
|
|
995
|
-
}
|
|
996
|
-
isRejected() {
|
|
997
|
-
return isRejected(this.status);
|
|
998
|
-
}
|
|
999
|
-
isPending() {
|
|
1000
|
-
return isPending(this.status);
|
|
1001
|
-
}
|
|
1002
|
-
isNotCalculatedPenaltyStatus() {
|
|
1003
|
-
return isNotCalculatedPenaltyStatus(this.status);
|
|
1004
|
-
}
|
|
1005
|
-
get timestampToMinute() {
|
|
1006
|
-
return Math.floor(this.timestamp / 60);
|
|
1007
|
-
}
|
|
1008
|
-
static compare(lhs, rhs) {
|
|
1009
|
-
if (lhs.timestamp !== rhs.timestamp) {
|
|
1010
|
-
return lhs.timestamp - rhs.timestamp;
|
|
1011
|
-
}
|
|
1012
|
-
if (lhs.teamId === rhs.teamId) {
|
|
1013
|
-
if (lhs.isAccepted() && !rhs.isAccepted()) {
|
|
1014
|
-
return -1;
|
|
1015
|
-
}
|
|
1016
|
-
if (!lhs.isAccepted() && rhs.isAccepted()) {
|
|
1017
|
-
return 1;
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
return 0;
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
function createSubmission(submissionJSON) {
|
|
1024
|
-
const s = new Submission();
|
|
1025
|
-
s.id = String(submissionJSON.id ?? submissionJSON.submission_id ?? "");
|
|
1026
|
-
s.teamId = String(submissionJSON.team_id);
|
|
1027
|
-
s.problemId = String(submissionJSON.problem_id);
|
|
1028
|
-
s.timestamp = submissionJSON.timestamp;
|
|
1029
|
-
s.status = stringToSubmissionStatus(submissionJSON.status);
|
|
1030
|
-
s.isIgnore = submissionJSON.is_ignore ?? false;
|
|
1031
|
-
return s;
|
|
1032
|
-
}
|
|
1033
|
-
function createSubmissions(submissionsJSON) {
|
|
1034
|
-
if (Array.isArray(submissionsJSON)) {
|
|
1035
|
-
return submissionsJSON.map((s, index) => createSubmission({ ...s, id: s.submission_id ?? String(index) }));
|
|
1036
|
-
} else {
|
|
1037
|
-
const submissions = Object.entries(submissionsJSON).map(
|
|
1038
|
-
([submissionId, s]) => createSubmission({ ...s, id: s.submission_id ?? submissionId })
|
|
1039
|
-
);
|
|
1040
|
-
return submissions;
|
|
1055
|
+
getTeamSolvedNumIndex(solvedNum) {
|
|
1056
|
+
return this.teamSolvedNumIndex[solvedNum] ?? 0;
|
|
1041
1057
|
}
|
|
1042
1058
|
}
|
|
1043
1059
|
|
|
@@ -1119,31 +1135,35 @@ class Rank {
|
|
|
1119
1135
|
this.originTeams.sort(Team.compare);
|
|
1120
1136
|
this.rankStatistics = new RankStatistics();
|
|
1121
1137
|
this.options = new RankOptions();
|
|
1138
|
+
this.balloons = [];
|
|
1122
1139
|
}
|
|
1123
|
-
|
|
1140
|
+
cleanRank() {
|
|
1124
1141
|
(() => {
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
continue;
|
|
1130
|
-
}
|
|
1131
|
-
this.teams.push(v);
|
|
1142
|
+
this.teams = [];
|
|
1143
|
+
for (const [_k, v] of this.teamsMap) {
|
|
1144
|
+
if (this.filterTeamByOrg(v)) {
|
|
1145
|
+
continue;
|
|
1132
1146
|
}
|
|
1133
|
-
|
|
1134
|
-
for (const t of this.teams) {
|
|
1135
|
-
t.reset();
|
|
1136
|
-
t.problemStatistics = this.contest.problems.map((p) => {
|
|
1137
|
-
const ps = new TeamProblemStatistics();
|
|
1138
|
-
ps.problem = p;
|
|
1139
|
-
ps.contestPenalty = this.contest.penalty;
|
|
1140
|
-
return ps;
|
|
1141
|
-
});
|
|
1142
|
-
t.problemStatisticsMap = new Map(t.problemStatistics.map((ps) => [ps.problem.id, ps]));
|
|
1147
|
+
this.teams.push(v);
|
|
1143
1148
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1149
|
+
})();
|
|
1150
|
+
for (const t of this.teams) {
|
|
1151
|
+
t.reset();
|
|
1152
|
+
t.problemStatistics = this.contest.problems.map((p) => {
|
|
1153
|
+
const ps = new TeamProblemStatistics();
|
|
1154
|
+
ps.problem = p;
|
|
1155
|
+
ps.contestPenalty = this.contest.penalty;
|
|
1156
|
+
return ps;
|
|
1146
1157
|
});
|
|
1158
|
+
t.problemStatisticsMap = new Map(t.problemStatistics.map((ps) => [ps.problem.id, ps]));
|
|
1159
|
+
}
|
|
1160
|
+
this.contest.problems.forEach((p) => {
|
|
1161
|
+
p.statistics.reset();
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
buildRank() {
|
|
1165
|
+
(() => {
|
|
1166
|
+
this.cleanRank();
|
|
1147
1167
|
this.teams.forEach(
|
|
1148
1168
|
(t) => t.placeChartPoints.push({
|
|
1149
1169
|
timePoint: 0,
|
|
@@ -1154,6 +1174,7 @@ class Rank {
|
|
|
1154
1174
|
(() => {
|
|
1155
1175
|
this.rankStatistics.reset();
|
|
1156
1176
|
this.rankStatistics.teamSolvedNum = Array(this.contest.problems.length + 1).fill(0);
|
|
1177
|
+
this.rankStatistics.teamSolvedNumIndex = Array(this.contest.problems.length + 1).fill(0);
|
|
1157
1178
|
})();
|
|
1158
1179
|
let preSubmissionTimestampToMinute = 0;
|
|
1159
1180
|
const allSubmissions = this.getSubmissions();
|
|
@@ -1235,6 +1256,15 @@ class Rank {
|
|
|
1235
1256
|
for (const t of this.teams) {
|
|
1236
1257
|
this.rankStatistics.teamSolvedNum[t.solvedProblemNum]++;
|
|
1237
1258
|
}
|
|
1259
|
+
{
|
|
1260
|
+
let current = 0;
|
|
1261
|
+
const teamSolvedNum = this.rankStatistics.teamSolvedNum;
|
|
1262
|
+
const teamSolvedNumIndex = this.rankStatistics.teamSolvedNumIndex;
|
|
1263
|
+
for (let i = teamSolvedNumIndex.length - 1; i >= 0; i--) {
|
|
1264
|
+
current += teamSolvedNum[i] > 0 ? 1 : 0;
|
|
1265
|
+
teamSolvedNumIndex[i] = current;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1238
1268
|
if (this.teams.length > 0) {
|
|
1239
1269
|
this.rankStatistics.maxSolvedProblems = this.teams[0].solvedProblemNum;
|
|
1240
1270
|
}
|
|
@@ -1312,6 +1342,36 @@ class Rank {
|
|
|
1312
1342
|
(s) => s.timestamp <= this.options.timestamp
|
|
1313
1343
|
).sort(Submission.compare);
|
|
1314
1344
|
}
|
|
1345
|
+
buildBalloons() {
|
|
1346
|
+
this.balloons = [];
|
|
1347
|
+
this.cleanRank();
|
|
1348
|
+
const allSubmissions = this.getSubmissions();
|
|
1349
|
+
for (let ix = 0; ix < allSubmissions.length; ix++) {
|
|
1350
|
+
const s = allSubmissions[ix];
|
|
1351
|
+
const teamId = s.teamId;
|
|
1352
|
+
const problemId = s.problemId;
|
|
1353
|
+
const team = this.teamsMap.get(teamId);
|
|
1354
|
+
const problem = this.contest.problemsMap.get(problemId);
|
|
1355
|
+
(() => {
|
|
1356
|
+
if (team === void 0 || problem === void 0) {
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
const problemStatistics = team.problemStatisticsMap.get(problemId);
|
|
1360
|
+
if (problemStatistics.isSolved) {
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
if (s.isAccepted()) {
|
|
1364
|
+
problemStatistics.isSolved = true;
|
|
1365
|
+
problemStatistics.solvedTimestamp = s.timestamp;
|
|
1366
|
+
const b = new Balloon();
|
|
1367
|
+
b.team = team;
|
|
1368
|
+
b.problem = problem;
|
|
1369
|
+
b.submission = s;
|
|
1370
|
+
this.balloons.push(b);
|
|
1371
|
+
}
|
|
1372
|
+
})();
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1315
1375
|
}
|
|
1316
1376
|
|
|
1317
1377
|
class ResolverOperation {
|
|
@@ -1402,4 +1462,4 @@ class Resolver extends Rank {
|
|
|
1402
1462
|
}
|
|
1403
1463
|
}
|
|
1404
1464
|
|
|
1405
|
-
export { Award, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, 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, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
|
1465
|
+
export { Award, Balloon, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, 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, 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.24.3",
|
|
4
4
|
"description": "XCPCIO Core",
|
|
5
5
|
"author": "Dup4 <lyuzhi.pan@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"lodash": "^4.17.21",
|
|
45
45
|
"string-width": "^6.1.0",
|
|
46
46
|
"xlsx-js-style": "^1.2.0",
|
|
47
|
-
"@xcpcio/types": "0.
|
|
47
|
+
"@xcpcio/types": "0.24.3"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@babel/types": "^7.22.4",
|
package/src/balloon.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Problem } from "./problem";
|
|
2
|
+
import { Team } from "./team";
|
|
3
|
+
import { Submission } from "./submission";
|
|
4
|
+
|
|
5
|
+
export class Balloon {
|
|
6
|
+
problem: Problem;
|
|
7
|
+
team: Team;
|
|
8
|
+
submission: Submission;
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
this.problem = new Problem();
|
|
12
|
+
this.team = new Team();
|
|
13
|
+
this.submission = new Submission();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get key() {
|
|
17
|
+
return `balloon-${this.team.id}-${this.problem.id}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type Balloons = Array<Balloon>;
|
package/src/index.ts
CHANGED
package/src/problem.ts
CHANGED
|
@@ -182,19 +182,19 @@ export class TeamProblemStatistics {
|
|
|
182
182
|
return this.totalCount === 0;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
get solvedTimestampToMinute() {
|
|
186
|
+
return Math.floor(this.solvedTimestamp / 60);
|
|
187
|
+
}
|
|
188
|
+
|
|
185
189
|
get penalty() {
|
|
186
190
|
if (this.isSolved === false) {
|
|
187
191
|
return 0;
|
|
188
192
|
}
|
|
189
193
|
|
|
190
|
-
return
|
|
194
|
+
return this.solvedTimestampToMinute * 60 + this.failedCount * this.contestPenalty;
|
|
191
195
|
}
|
|
192
196
|
|
|
193
197
|
get penaltyToMinute() {
|
|
194
198
|
return Math.floor(this.penalty / 60);
|
|
195
199
|
}
|
|
196
|
-
|
|
197
|
-
get solvedTimestampToMinute() {
|
|
198
|
-
return Math.floor(this.solvedTimestamp / 60);
|
|
199
|
-
}
|
|
200
200
|
}
|
package/src/rank-statistics.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
export class RankStatistics {
|
|
2
2
|
teamSolvedNum: Array<number>;
|
|
3
|
+
teamSolvedNumIndex: Array<number>;
|
|
3
4
|
maxSolvedProblems: number;
|
|
4
5
|
|
|
5
6
|
constructor() {
|
|
6
7
|
this.teamSolvedNum = [];
|
|
8
|
+
this.teamSolvedNumIndex = [];
|
|
7
9
|
this.maxSolvedProblems = 0;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
reset() {
|
|
11
13
|
this.teamSolvedNum = [];
|
|
14
|
+
this.teamSolvedNumIndex = [];
|
|
12
15
|
this.maxSolvedProblems = 0;
|
|
13
16
|
}
|
|
17
|
+
|
|
18
|
+
getTeamSolvedNumIndex(solvedNum: number): number {
|
|
19
|
+
return this.teamSolvedNumIndex[solvedNum] ?? 0;
|
|
20
|
+
}
|
|
14
21
|
}
|