@@ -139,24 +139,44 @@ public function calculateTeamRank(
139
139
$ totalTime = $ contest ->getRuntimeAsScoreTiebreaker () ? $ rankCache ->getTotalruntimeRestricted () : $ rankCache ->getTotaltimeRestricted ();
140
140
}
141
141
$ timeType = $ contest ->getRuntimeAsScoreTiebreaker () ? 'runtime ' : 'time ' ;
142
+ $ useOpt = $ contest ->getOptScoreAsScoreTiebreaker ();
143
+ $ optMode = $ contest ->getOptScoreOrder () === 'asc ' ? 'min ' : 'max ' ;
142
144
$ sortOrder = $ team ->getCategory ()->getSortorder ();
143
145
146
+ if ($ useOpt ) {
147
+ $ tieField = "r.totaloptscore_ {$ optMode }_ {$ variant }" ;
148
+ $ tieOp = $ optMode === 'min ' ? '< ' : '> ' ;
149
+ $ tieValue = $ rankCache
150
+ ? $ rankCache ->getTotalOptscore ($ restricted )
151
+ : 0 ;
152
+ $ tieValue = $ tieValue ?? 0 ;
153
+ } else {
154
+ $ type = $ contest ->getRuntimeAsScoreTiebreaker () ? 'runtime ' : 'time ' ;
155
+ $ tieField = "r.total {$ type }_ {$ variant }" ;
156
+ $ tieOp = '< ' ;
157
+ $ tieValue = $ totalTime ;
158
+ }
159
+
144
160
// Number of teams that definitely ranked higher.
145
- $ better = $ this ->em ->createQueryBuilder ()
161
+ $ better = (int ) $ this ->em ->createQueryBuilder ()
162
+ ->select ('COUNT(t.teamid) ' )
146
163
->from (RankCache::class, 'r ' )
147
164
->join ('r.team ' , 't ' )
148
165
->join ('t.category ' , 'tc ' )
149
- ->select ('COUNT(t.teamid) ' )
150
- ->andWhere ('r.contest = :contest ' )
166
+ ->andWhere ('r.contest = :contest ' )
151
167
->andWhere ('tc.sortorder = :sortorder ' )
152
- ->andWhere ('t.enabled = 1 ' )
153
- ->andWhere (sprintf ('r.points_%s > :points OR ' .
154
- '(r.points_%s = :points AND r.total%s_%s < :totaltime) ' ,
155
- $ variant , $ variant , $ timeType , $ variant ))
156
- ->setParameter ('contest ' , $ contest )
157
- ->setParameter ('sortorder ' , $ sortOrder )
158
- ->setParameter ('points ' , $ points )
159
- ->setParameter ('totaltime ' , $ totalTime )
168
+ ->andWhere ('t.enabled = 1 ' )
169
+ ->andWhere (sprintf (
170
+ 'r.points_%1$s > :points
171
+ OR (r.points_%1$s = :points AND %2$s %3$s :tiebreaker) ' ,
172
+ $ variant ,
173
+ $ tieField ,
174
+ $ tieOp
175
+ ))
176
+ ->setParameter ('contest ' , $ contest )
177
+ ->setParameter ('sortorder ' , $ sortOrder )
178
+ ->setParameter ('points ' , $ points )
179
+ ->setParameter ('tiebreaker ' , $ tieValue )
160
180
->getQuery ()
161
181
->getSingleScalarResult ();
162
182
@@ -175,12 +195,15 @@ public function calculateTeamRank(
175
195
->andWhere ('r.contest = :contest ' )
176
196
->andWhere ('tc.sortorder = :sortorder ' )
177
197
->andWhere ('t.enabled = 1 ' )
178
- ->andWhere (sprintf ('r.points_%s = :points AND r.total%s_%s = :totaltime ' ,
179
- $ variant , $ timeType , $ variant ))
198
+ ->andWhere (sprintf (
199
+ 'r.points_%1$s = :points AND %2$s = :tiebreaker ' ,
200
+ $ variant ,
201
+ $ tieField
202
+ ))
180
203
->setParameter ('contest ' , $ contest )
181
204
->setParameter ('sortorder ' , $ sortOrder )
182
205
->setParameter ('points ' , $ points )
183
- ->setParameter ('totaltime ' , $ totalTime )
206
+ ->setParameter ('tiebreaker ' , $ tieValue )
184
207
->getQuery ()
185
208
->getResult ();
186
209
@@ -576,10 +599,14 @@ public function updateRankCache(Contest $contest, Team $team): void
576
599
$ numPoints = [];
577
600
$ totalTime = [];
578
601
$ totalRuntime = [];
602
+ $ totalMaxOpt = [];
603
+ $ totalMinOpt = [];
579
604
foreach ($ variants as $ variant => $ isRestricted ) {
580
605
$ numPoints [$ variant ] = 0 ;
581
606
$ totalTime [$ variant ] = $ team ->getPenalty ();
582
607
$ totalRuntime [$ variant ] = 0 ;
608
+ $ totalMaxOpt [$ variant ] = 0 ;
609
+ $ totalMinOpt [$ variant ] = 0 ;
583
610
}
584
611
585
612
$ penaltyTime = (int ) $ this ->config ->get ('penalty_time ' );
@@ -612,6 +639,8 @@ public function updateRankCache(Contest $contest, Team $team): void
612
639
$ scoreIsInSeconds
613
640
) + $ penalty ;
614
641
$ totalRuntime [$ variant ] += $ scoreCache ->getRuntime ($ isRestricted );
642
+ $ totalMaxOpt [$ variant ] += $ scoreCache ->getMaxOptscore ($ isRestricted );
643
+ $ totalMinOpt [$ variant ] += $ scoreCache ->getMinOptscore ($ isRestricted );
615
644
}
616
645
}
617
646
}
@@ -623,14 +652,30 @@ public function updateRankCache(Contest $contest, Team $team): void
623
652
'pointsRestricted ' => $ numPoints ['restricted ' ],
624
653
'totalTimeRestricted ' => $ totalTime ['restricted ' ],
625
654
'totalRuntimeRestricted ' => $ totalRuntime ['restricted ' ],
655
+ 'totalMaxOptRestricted ' => $ totalMaxOpt ['restricted ' ],
656
+ 'totalMinOptRestricted ' => $ totalMinOpt ['restricted ' ],
626
657
'pointsPublic ' => $ numPoints ['public ' ],
627
658
'totalTimePublic ' => $ totalTime ['public ' ],
628
659
'totalRuntimePublic ' => $ totalRuntime ['public ' ],
660
+ 'totalMaxOptPublic ' => $ totalMaxOpt ['public ' ],
661
+ 'totalMinOptPublic ' => $ totalMinOpt ['public ' ]
629
662
];
630
- $ this ->em ->getConnection ()->executeQuery ('REPLACE INTO rankcache (cid, teamid,
631
- points_restricted, totaltime_restricted, totalruntime_restricted,
632
- points_public, totaltime_public, totalruntime_public)
633
- VALUES (:cid, :teamid, :pointsRestricted, :totalTimeRestricted, :totalRuntimeRestricted, :pointsPublic, :totalTimePublic, :totalRuntimePublic) ' , $ params );
663
+ $ this ->em ->getConnection ()->executeQuery (
664
+ 'REPLACE INTO rankcache (
665
+ cid, teamid,
666
+ points_restricted, totaltime_restricted, totalruntime_restricted,
667
+ totaloptscore_max_restricted, totaloptscore_min_restricted,
668
+ totaloptscore_max_public, totaloptscore_min_public,
669
+ points_public, totaltime_public, totalruntime_public
670
+ ) VALUES (
671
+ :cid, :teamid,
672
+ :pointsRestricted, :totalTimeRestricted, :totalRuntimeRestricted,
673
+ :totalMaxOptRestricted, :totalMinOptRestricted,
674
+ :totalMaxOptPublic, :totalMinOptPublic,
675
+ :pointsPublic, :totalTimePublic, :totalRuntimePublic
676
+ ) ' ,
677
+ $ params
678
+ );
634
679
635
680
if ($ this ->em ->getConnection ()->fetchOne ('SELECT RELEASE_LOCK(:lock) ' ,
636
681
['lock ' => $ lockString ]) != 1 ) {
0 commit comments