Skip to content

Commit 0bfdbaa

Browse files
committed
add optscore logic to order team
1 parent 7a9500a commit 0bfdbaa

File tree

6 files changed

+88
-24
lines changed

6 files changed

+88
-24
lines changed

webapp/src/Service/ScoreboardService.php

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,24 +139,44 @@ public function calculateTeamRank(
139139
$totalTime = $contest->getRuntimeAsScoreTiebreaker() ? $rankCache->getTotalruntimeRestricted() : $rankCache->getTotaltimeRestricted();
140140
}
141141
$timeType = $contest->getRuntimeAsScoreTiebreaker() ? 'runtime' : 'time';
142+
$useOpt = $contest->getOptScoreAsScoreTiebreaker();
143+
$optMode = $contest->getOptScoreOrder() === 'asc' ? 'min' : 'max';
142144
$sortOrder = $team->getCategory()->getSortorder();
143145

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+
144160
// Number of teams that definitely ranked higher.
145-
$better = $this->em->createQueryBuilder()
161+
$better = (int) $this->em->createQueryBuilder()
162+
->select('COUNT(t.teamid)')
146163
->from(RankCache::class, 'r')
147164
->join('r.team', 't')
148165
->join('t.category', 'tc')
149-
->select('COUNT(t.teamid)')
150-
->andWhere('r.contest = :contest')
166+
->andWhere('r.contest = :contest')
151167
->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)
160180
->getQuery()
161181
->getSingleScalarResult();
162182

@@ -175,12 +195,15 @@ public function calculateTeamRank(
175195
->andWhere('r.contest = :contest')
176196
->andWhere('tc.sortorder = :sortorder')
177197
->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+
))
180203
->setParameter('contest', $contest)
181204
->setParameter('sortorder', $sortOrder)
182205
->setParameter('points', $points)
183-
->setParameter('totaltime', $totalTime)
206+
->setParameter('tiebreaker', $tieValue)
184207
->getQuery()
185208
->getResult();
186209

@@ -576,10 +599,14 @@ public function updateRankCache(Contest $contest, Team $team): void
576599
$numPoints = [];
577600
$totalTime = [];
578601
$totalRuntime = [];
602+
$totalMaxOpt = [];
603+
$totalMinOpt = [];
579604
foreach ($variants as $variant => $isRestricted) {
580605
$numPoints[$variant] = 0;
581606
$totalTime[$variant] = $team->getPenalty();
582607
$totalRuntime[$variant] = 0;
608+
$totalMaxOpt[$variant] = 0;
609+
$totalMinOpt[$variant] = 0;
583610
}
584611

585612
$penaltyTime = (int) $this->config->get('penalty_time');
@@ -612,6 +639,8 @@ public function updateRankCache(Contest $contest, Team $team): void
612639
$scoreIsInSeconds
613640
) + $penalty;
614641
$totalRuntime[$variant] += $scoreCache->getRuntime($isRestricted);
642+
$totalMaxOpt[$variant] += $scoreCache->getMaxOptscore($isRestricted);
643+
$totalMinOpt[$variant] += $scoreCache->getMinOptscore($isRestricted);
615644
}
616645
}
617646
}
@@ -623,14 +652,30 @@ public function updateRankCache(Contest $contest, Team $team): void
623652
'pointsRestricted' => $numPoints['restricted'],
624653
'totalTimeRestricted' => $totalTime['restricted'],
625654
'totalRuntimeRestricted' => $totalRuntime['restricted'],
655+
'totalMaxOptRestricted' => $totalMaxOpt['restricted'],
656+
'totalMinOptRestricted' => $totalMinOpt['restricted'],
626657
'pointsPublic' => $numPoints['public'],
627658
'totalTimePublic' => $totalTime['public'],
628659
'totalRuntimePublic' => $totalRuntime['public'],
660+
'totalMaxOptPublic' => $totalMaxOpt['public'],
661+
'totalMinOptPublic' => $totalMinOpt['public']
629662
];
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+
);
634679

635680
if ($this->em->getConnection()->fetchOne('SELECT RELEASE_LOCK(:lock)',
636681
['lock' => $lockString]) != 1) {

webapp/src/Utils/Scoreboard/Scoreboard.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ protected function calculateScoreboard(): void
158158
$scoreRow->getPending($this->restricted),
159159
$scoreRow->getSolveTime($this->restricted),
160160
$penalty,
161-
$scoreRow->getRuntime($this->restricted)
161+
$scoreRow->getRuntime($this->restricted),
162+
$scoreRow->getOptscore($this->restricted)
162163
);
163164

164165
if ($scoreRow->getIsCorrect($this->restricted)) {
@@ -169,6 +170,7 @@ protected function calculateScoreboard(): void
169170
$this->scores[$teamId]->solveTimes[] = $solveTime;
170171
$this->scores[$teamId]->totalTime += $solveTime + $penalty;
171172
$this->scores[$teamId]->totalRuntime += $scoreRow->getRuntime($this->restricted);
173+
$this->scores[$teamId]->totalOptscore += $scoreRow->getOptscore($this->restricted);
172174
}
173175
}
174176

@@ -216,7 +218,7 @@ protected function calculateScoreboard(): void
216218
$problemId = $contestProblem->getProbid();
217219
// Provide default scores when nothing submitted for this team + problem yet
218220
if (!isset($this->matrix[$teamId][$problemId])) {
219-
$this->matrix[$teamId][$problemId] = new ScoreboardMatrixItem(false, false, 0, 0, 0, 0, 0);
221+
$this->matrix[$teamId][$problemId] = new ScoreboardMatrixItem(false, false, 0, 0, 0, 0, 0, 0);
220222
}
221223

222224
$problemMatrixItem = $this->matrix[$teamId][$problemId];
@@ -458,4 +460,13 @@ public function getRuntimeAsScoreTiebreaker(): bool
458460
{
459461
return $this->contest->getRuntimeAsScoreTiebreaker();
460462
}
463+
464+
/**
465+
* Determine whether to order by optscore instead of solvetime
466+
* @return bool
467+
*/
468+
public function getOptScoreAsScoreTiebreaker(): bool
469+
{
470+
return $this->contest->getOptScoreAsScoreTiebreaker();
471+
}
461472
}

webapp/src/Utils/Scoreboard/ScoreboardMatrixItem.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public function __construct(
1111
public int $numSubmissionsPending,
1212
public float|string $time,
1313
public int $penaltyTime,
14-
public int $runtime
14+
public int $runtime,
15+
public float|null $optscore
1516
) {}
1617
}

webapp/src/Utils/Scoreboard/SingleTeamScoreboard.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ protected function calculateScoreboard(): void
4646
$teamScore->numPoints += $this->rankCache->getPointsRestricted();
4747
$teamScore->totalTime += $this->rankCache->getTotaltimeRestricted();
4848
$teamScore->totalRuntime += $this->rankCache->getTotalruntimeRestricted();
49+
$teamScore->totalOptscore += $this->rankCache->getTotalOptscoreRestricted();
4950
}
5051
$teamScore->rank = $this->teamRank;
5152

@@ -69,7 +70,8 @@ protected function calculateScoreboard(): void
6970
$scoreRow->getPending($this->restricted),
7071
$scoreRow->getSolveTime($this->restricted),
7172
$penalty,
72-
$scoreRow->getRuntime($this->restricted)
73+
$scoreRow->getRuntime($this->restricted),
74+
$scoreRow->getOptscore($this->restricted)
7375
);
7476
}
7577

@@ -79,7 +81,7 @@ protected function calculateScoreboard(): void
7981
$teamId = $this->team->getTeamid();
8082
$problemId = $contestProblem->getProbid();
8183
if (!isset($this->matrix[$teamId][$problemId])) {
82-
$this->matrix[$teamId][$problemId] = new ScoreboardMatrixItem(false, false, 0, 0, 0, 0, 0);
84+
$this->matrix[$teamId][$problemId] = new ScoreboardMatrixItem(false, false, 0, 0, 0, 0, 0, 0);
8385
}
8486
}
8587
}

webapp/src/Utils/Scoreboard/TeamScore.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class TeamScore
1313
public int $rank = 0;
1414
public int $totalTime;
1515
public int $totalRuntime = 0;
16+
public ?float $totalOptscore = null;
1617

1718
public function __construct(public Team $team)
1819
{

webapp/templates/partials/scoreboard_table.html.twig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@
235235
<td class="scorenc">{{ totalPoints }}</td>
236236
{% if scoreboard.getRuntimeAsScoreTiebreaker() %}
237237
<td class="scorett">{{ "%0.3f s" | format(score.totalRuntime/1000.0) }}</td>
238+
{% elseif contest.getOptScoreAsScoreTiebreaker() %}
239+
<td class="scorett">{{ score.totalOptscore | formatOptScore }}</td>
238240
{% else %}
239241
<td class="scorett">{{ totalTime }}</td>
240242
{% endif %}
@@ -270,7 +272,9 @@
270272
{% set time = '' %}
271273
{% if matrixItem.isCorrect %}
272274
{% set time = matrixItem.time %}
273-
{% if scoreboard.getRuntimeAsScoreTiebreaker() %}
275+
{% if scoreboard.getOptScoreAsScoreTiebreaker() %}
276+
{% set time = matrixItem.optscore %}
277+
{% elseif scoreboard.getRuntimeAsScoreTiebreaker() %}
274278
{% set time = "%0.3f s" | format(matrixItem.runtime / 1000.0) %}
275279
{% elseif scoreInSeconds %}
276280
{% set time = time | scoreTime | printTimeRelative %}

0 commit comments

Comments
 (0)