Skip to content

Commit dd8ab3a

Browse files
nickygerritsenvmcj
authored andcommitted
Fix medal awards when skipping categories. Fixes #1982.
(cherry picked from commit e47d33f)
1 parent b8f47e4 commit dd8ab3a

File tree

2 files changed

+106
-42
lines changed

2 files changed

+106
-42
lines changed

webapp/src/Service/AwardService.php

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,19 @@ protected function loadAwards(Contest $contest, Scoreboard $scoreboard): void
6060

6161
$additionalBronzeMedals = $contest->getB() ?? 0;
6262

63-
// Can we assume this is ordered just walk the first 12+B entries?
63+
$currentSortOrder = -1;
64+
65+
// For every team that we skip because it is not in a medal category, we need to include one
66+
// additional rank. So keep track of the number of skipped teams
67+
$skippedTeams = 0;
68+
6469
foreach ($scoreboard->getScores() as $teamScore) {
70+
// If we are checking a new sort order, reset the number of skipped teams
71+
if ($teamScore->team->getCategory()->getSortorder() !== $currentSortOrder) {
72+
$currentSortOrder = $teamScore->team->getCategory()->getSortorder();
73+
$skippedTeams = 0;
74+
}
75+
6576
if ($teamScore->numPoints == 0) {
6677
continue;
6778
}
@@ -70,13 +81,17 @@ protected function loadAwards(Contest $contest, Scoreboard $scoreboard): void
7081
if ($rank === 1) {
7182
$overall_winners[] = $teamid;
7283
}
73-
if ($contest->getMedalsEnabled() && $contest->getMedalCategories()->contains($teamScore->team->getCategory())) {
74-
if ($rank <= $contest->getGoldMedals()) {
75-
$medal_winners['gold'][] = $teamid;
76-
} elseif ($rank <= $contest->getGoldMedals() + $contest->getSilverMedals()) {
77-
$medal_winners['silver'][] = $teamid;
78-
} elseif ($rank <= $contest->getGoldMedals() + $contest->getSilverMedals() + $contest->getBronzeMedals() + $additionalBronzeMedals) {
79-
$medal_winners['bronze'][] = $teamid;
84+
if ($contest->getMedalsEnabled()) {
85+
if ($contest->getMedalCategories()->contains($teamScore->team->getCategory())) {
86+
if ($rank - $skippedTeams <= $contest->getGoldMedals()) {
87+
$medal_winners['gold'][] = $teamid;
88+
} elseif ($rank - $skippedTeams <= $contest->getGoldMedals() + $contest->getSilverMedals()) {
89+
$medal_winners['silver'][] = $teamid;
90+
} elseif ($rank - $skippedTeams <= $contest->getGoldMedals() + $contest->getSilverMedals() + $contest->getBronzeMedals() + $additionalBronzeMedals) {
91+
$medal_winners['bronze'][] = $teamid;
92+
}
93+
} else {
94+
$skippedTeams++;
8095
}
8196
}
8297
}

webapp/tests/Unit/Service/AwardServiceTest.php

Lines changed: 83 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ class AwardServiceTest extends KernelTestCase
2121

2222
protected function setUp(): void
2323
{
24-
// The contest will have 1 gold, 1 silver and 2 bronze medals
24+
// The contest will have 2 gold, 2 silver and 2 bronze medals, awarded only to category A and C
2525
$this->contest = (new Contest())
2626
->setMedalsEnabled(true)
27-
->setGoldMedals(1)
27+
->setGoldMedals(2)
2828
->setSilverMedals(1)
2929
->setBronzeMedals(1);
3030
$categoryA = (new TeamCategory())
@@ -33,22 +33,33 @@ protected function setUp(): void
3333
$categoryB = (new TeamCategory())
3434
->setName('Category B')
3535
->setExternalid('cat_B');
36+
$categoryC = (new TeamCategory())
37+
->setName('Category C')
38+
->setExternalid('cat_C');
3639
$this->contest
3740
->addMedalCategory($categoryA)
38-
->addMedalCategory($categoryB);
41+
->addMedalCategory($categoryC);
3942
$reflectedProblem = new ReflectionClass(TeamCategory::class);
40-
$teamIdProperty = $reflectedProblem->getProperty('categoryid');
41-
$teamIdProperty->setAccessible(true);
42-
$teamIdProperty->setValue($categoryA, 1);
43-
$teamIdProperty->setValue($categoryB, 2);
43+
$categoryIdProperty = $reflectedProblem->getProperty('categoryid');
44+
$categoryIdProperty->setAccessible(true);
45+
$categoryIdProperty->setValue($categoryA, 1);
46+
$categoryIdProperty->setValue($categoryB, 2);
47+
$categoryIdProperty->setValue($categoryC, 3);
4448
$categories = [$categoryA, $categoryB];
45-
// Create 4 teams, each belonging to a category
49+
// Create 9 teams, each belonging to a different category
4650
$teams = [];
47-
foreach (['A', 'B', 'C', 'D'] as $teamLetter) {
51+
foreach (['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] as $teamLetter) {
52+
$category = $categoryC;
53+
if (in_array($teamLetter, ['A', 'B', 'C'])) {
54+
$category = $categoryA;
55+
}
56+
if (in_array($teamLetter, ['D', 'E', 'F'])) {
57+
$category = $categoryB;
58+
}
4859
$team = (new Team())
4960
->setName('Team ' . $teamLetter)
5061
->setExternalid('team_' . $teamLetter)
51-
->setCategory(in_array($teamLetter, ['A', 'B']) ? $categoryA : $categoryB)
62+
->setCategory($category)
5263
->setAffiliation(); // No affiliation needed
5364
$reflectedProblem = new ReflectionClass(Team::class);
5465
$teamIdProperty = $reflectedProblem->getProperty('teamid');
@@ -81,16 +92,25 @@ protected function setUp(): void
8192
// -----+-----------
8293
// A | 1 5 10 20
8394
// B | x 2 3 x
84-
// C | x x x 4
85-
// D | x x x x
95+
// C | x 2 3 x
96+
// D | x x x 12
97+
// E | x x x 13
98+
// F | x x x 14
99+
// G | x x x 15
100+
// H | x x x x
101+
// I | x x x x
86102
//
87103
// THis means A is the overall winner, will get a gold medal and is the winner
88104
// of category A. It is also first to solve problem A.
89-
// B is second, so it gets a silver medal. It is also first to solve problem B and C
90-
// C is the first to solve problem D, gets a bronze medal and is winner of category B.
91-
// D didn't solve anything, so it will not get any medals at all
105+
// B is second, so it also gets a gold medal. It is also first to solve problem B and C
106+
// C scored the exact same as B, so it also gets the same medals
107+
// D is the first to solve problem D and is the winner of category B. But will not get any medal.
108+
// E and F will get no awards at all.
109+
// G is the winner of category C and will get a bronze medal.
110+
// The reason G doesn't get silver is that C would get silver if it was ranked differently,
111+
// but it is not.
112+
// H and I didn't solve anything, so it will not get any medals at all
92113

93-
$minute = 60;
94114
// Indexed first by team, then by problem
95115
$scores = [
96116
'A' => [
@@ -104,15 +124,28 @@ protected function setUp(): void
104124
'C' => 3,
105125
],
106126
'C' => [
107-
'D' => 4,
127+
'B' => 2,
128+
'C' => 3,
129+
],
130+
'D' => [
131+
'D' => 12,
132+
],
133+
'E' => [
134+
'D' => 13,
135+
],
136+
'F' => [
137+
'D' => 14,
138+
],
139+
'G' => [
140+
'D' => 15,
108141
],
109142
];
110143
$scoreCache = [];
111144
foreach ($scores as $teamLabel => $scoresForTeam) {
112145
foreach ($scoresForTeam as $problemLabel => $minute) {
113146
$firstToSolve = in_array(
114147
$teamLabel . $problemLabel,
115-
['AA', 'BB', 'BC', 'CD']
148+
['AA', 'BB', 'BC', 'CB', 'CC', 'DD']
116149
);
117150
$scoreCache[] = (new ScoreCache())
118151
->setContest($this->contest)
@@ -164,15 +197,19 @@ public function testWinner(): void
164197
public function testMedals(): void
165198
{
166199
$medals = [
167-
'gold' => 'team_A',
168-
'silver' => 'team_B',
169-
'bronze' => 'team_C',
200+
'gold' => ['team_A', 'team_B', 'team_C'],
201+
'silver' => [],
202+
'bronze' => ['team_G'],
170203
];
171-
foreach ($medals as $medal => $team) {
204+
foreach ($medals as $medal => $teams) {
172205
$medalAward = $this->getAward($medal . '-medal');
173-
static::assertNotNull($medalAward);
174-
static::assertEquals(ucfirst($medal) . ' medal winner', $medalAward['citation']);
175-
static::assertEquals([$team], $medalAward['team_ids']);
206+
if (empty($teams)) {
207+
static::assertNull($medalAward);
208+
} else {
209+
static::assertNotNull($medalAward);
210+
static::assertEquals(ucfirst($medal) . ' medal winner', $medalAward['citation']);
211+
static::assertEquals($teams, $medalAward['team_ids']);
212+
}
176213
}
177214
}
178215

@@ -187,22 +224,29 @@ public function testGroupWinners(): void
187224
$groupBWinner = $this->getAward('group-winner-cat_B');
188225
static::assertNotNull($groupBWinner);
189226
static::assertEquals('Winner(s) of group Category B', $groupBWinner['citation']);
190-
static::assertEquals(['team_C'], $groupBWinner['team_ids']);
227+
static::assertEquals(['team_D'], $groupBWinner['team_ids']);
228+
229+
$a = $this->getAwardService()->getAwards($this->contest, $this->scoreboard);
230+
$groupBWinner = $this->getAward('group-winner-cat_C');
231+
static::assertNotNull($groupBWinner);
232+
static::assertEquals('Winner(s) of group Category C', $groupBWinner['citation']);
233+
static::assertEquals(['team_G'], $groupBWinner['team_ids']);
191234
}
192235

193236
public function testFirstToSolve(): void
194237
{
195238
$fts = [
196-
'A' => 'A',
197-
'B' => 'B',
198-
'C' => 'B',
199-
'D' => 'C',
239+
'A' => ['A'],
240+
'B' => ['B', 'C'],
241+
'C' => ['B', 'C'],
242+
'D' => ['D'],
200243
];
201-
foreach ($fts as $problem => $team) {
244+
foreach ($fts as $problem => $teams) {
202245
$firstToSolve = $this->getAward('first-to-solve-problem_' . $problem);
203246
static::assertNotNull($firstToSolve);
204247
static::assertEquals('First to solve problem ' . $problem, $firstToSolve['citation']);
205-
static::assertEquals(['team_' . $team], $firstToSolve['team_ids']);
248+
$teamIds = array_map(static fn(string $team) => 'team_' . $team, $teams);
249+
static::assertEquals($teamIds, $firstToSolve['team_ids']);
206250
}
207251
}
208252

@@ -219,8 +263,13 @@ public function testMedalType(int $teamIndex, ?string $expectedMedalType)
219263
public function provideMedalType(): \Generator
220264
{
221265
yield [0, 'gold-medal'];
222-
yield [1, 'silver-medal'];
223-
yield [2, 'bronze-medal'];
266+
yield [1, 'gold-medal'];
267+
yield [2, 'gold-medal'];
224268
yield [3, null];
269+
yield [4, null];
270+
yield [5, null];
271+
yield [6, 'bronze-medal'];
272+
yield [7, null];
273+
yield [8, null];
225274
}
226275
}

0 commit comments

Comments
 (0)