Skip to content

Commit 01c0955

Browse files
authored
Merge pull request #430 from CnCNet/develop
Fix for the force logic in the faction policy
2 parents 02a591f + 93d8b46 commit 01c0955

File tree

2 files changed

+75
-20
lines changed

2 files changed

+75
-20
lines changed

cncnet-api/app/Http/Services/FactionPolicyService.php

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ protected function createCandidates(array $currentSides, MapPool $pool): array
8282
return $valid;
8383
}
8484

85+
public function getDelta(int $total, int $forced, float $ratio): float
86+
{
87+
if ($total === 0)
88+
{
89+
return $ratio - 1.0;
90+
}
91+
$current = $forced / $total;
92+
return $ratio - $current;
93+
}
94+
8595
public function applyPolicy1v1(MapPool $pool, Ladder $ladder, LadderHistory $history, QmMap $qmMap, QmMatchPlayer $p1, QmMatchPlayer $p2): void
8696
{
8797
$forcedId = $pool->forced_faction_id !== null ? (int)$pool->forced_faction_id : null;
@@ -177,46 +187,46 @@ public function applyPolicy1v1(MapPool $pool, Ladder $ladder, LadderHistory $his
177187
'p2' => ['total' => $totalGames2, 'forced' => $forcedFaction2],
178188
]);
179189

190+
$delta1 = $this->getDelta($totalGames1, $forcedFaction1, $ratio);
191+
$delta2 = $this->getDelta($totalGames2, $forcedFaction2, $ratio);
192+
193+
Log::debug('applyPolicy1v1: deltas', [
194+
'p1_delta' => $delta1,
195+
'p2_delta' => $delta2,
196+
]);
197+
180198
$bestPair = $currentSides;
181-
$lowestForcedRatioDeviation = INF;
182-
$bestChanges = PHP_INT_MAX;
199+
$bestScore = -INF;
183200

184201
foreach ($filteredCandidates as [$a, $b])
185202
{
186-
$err = 0.5;
203+
$score = 0.0;
187204

188205
if ($a === $forcedId && $b !== $forcedId)
189206
{
190-
$err = abs((($forcedFaction1 + 1) / ($totalGames1 + 1)) - $ratio);
207+
$score = $delta1;
191208
}
192209
else if ($a !== $forcedId && $b === $forcedId)
193210
{
194-
$err = abs((($forcedFaction2 + 1) / ($totalGames2 + 1)) - $ratio);
211+
$score = $delta2;
195212
}
196213
else if ($a === $forcedId && $b === $forcedId)
197214
{
198-
$err1 = abs((($forcedFaction1 + 1) / ($totalGames1 + 1)) - $ratio);
199-
$err2 = abs((($forcedFaction2 + 1) / ($totalGames2 + 1)) - $ratio);
200-
$err = ($err1 + $err2) / 2.0;
215+
$score = ($delta1 + $delta2) / 2.0;
201216
}
202217

203-
$changes = (int)($a !== $currentSides[0]) + (int)($b !== $currentSides[1]);
204-
205218
Log::debug('applyPolicy1v1: candidate evaluation', [
206219
'pair' => [$a, $b],
207-
'err' => $err,
208-
'changes' => $changes,
220+
'score' => $score,
209221
]);
210222

211-
if ($err < $lowestForcedRatioDeviation || ($err == $lowestForcedRatioDeviation && $changes < $bestChanges))
223+
if ($score > $bestScore)
212224
{
213-
$lowestForcedRatioDeviation = $err;
214-
$bestChanges = $changes;
225+
$bestScore = $score;
215226
$bestPair = [$a, $b];
216227
Log::debug('applyPolicy1v1: new bestPair', [
217228
'bestPair' => $bestPair,
218-
'lowestErr'=> $lowestForcedRatioDeviation,
219-
'bestChanges' => $bestChanges,
229+
'bestScore'=> $bestScore,
220230
]);
221231
}
222232
}
@@ -235,5 +245,4 @@ public function applyPolicy1v1(MapPool $pool, Ladder $ladder, LadderHistory $his
235245
Log::info('applyPolicy1v1: keeping p1='. $p1->actual_side . ' and p2=' . $p2->actual_side);
236246
}
237247
}
238-
239248
}

cncnet-api/tests/Feature/Api/Duplicates/FactionPolicyServiceTest.php

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,52 @@ public function applyPolicy1v1_no_map_candidates_keeps_sides(): void
105105
$this->assertSame(3, $p2->actual_side);
106106
}
107107

108+
#[Test]
109+
public function applyPolicy1v1_mueller_vs_drunk(): void
110+
{
111+
$pool = new MapPool();
112+
$pool->forced_faction_id = 9;
113+
$pool->forced_faction_ratio = 0.5;
114+
$pool->invalid_faction_pairs = [[0, 6], [0, 0], [6, 6], [9, 9]];
115+
116+
// Map allows forced faction.
117+
$qmMap = $this->mockQmMap([0, 6, 9]);
118+
119+
$ladder = $this->makeLadder(1);
120+
$history = $this->makeHistory();
121+
122+
$mueller = $this->makePlayerWithActualSide(101, 0);
123+
$drunkmaster = $this->makePlayerWithActualSide(202, 0);
124+
125+
$this->mockStatsFor($mueller, [24, 1], $drunkmaster, [8, 7]);
126+
$this->svc->applyPolicy1v1($pool, $ladder, $history, $qmMap, $mueller, $drunkmaster);
127+
$this->assertSame(0, $drunkmaster->actual_side);
128+
$this->assertSame(9, $mueller->actual_side);
129+
}
130+
131+
#[Test]
132+
public function applyPolicy1v1_sneer_vs_funky(): void
133+
{
134+
$pool = new MapPool();
135+
$pool->forced_faction_id = 9;
136+
$pool->forced_faction_ratio = 0.5;
137+
$pool->invalid_faction_pairs = [[0, 6], [0, 0], [6, 6], [9, 9]];
138+
139+
// Map allows forced faction.
140+
$qmMap = $this->mockQmMap([0, 6, 9]);
141+
142+
$ladder = $this->makeLadder(1);
143+
$history = $this->makeHistory();
144+
145+
$sneer = $this->makePlayerWithActualSide(101, 6);
146+
$funky = $this->makePlayerWithActualSide(202, 6);
147+
148+
$this->mockStatsFor($sneer, [13, 3], $funky, [20, 0]);
149+
$this->svc->applyPolicy1v1($pool, $ladder, $history, $qmMap, $sneer, $funky);
150+
$this->assertSame(6, $sneer->actual_side);
151+
$this->assertSame(9, $funky->actual_side);
152+
}
153+
108154
#[Test]
109155
public function applyPolicy1v1_one_candidate_applies(): void
110156
{
@@ -138,8 +184,8 @@ public function applyPolicy1v1_one_candidate_applies(): void
138184
$this->assertSame(6, $p1->actual_side);
139185
$this->assertSame(9, $p2->actual_side);
140186

141-
// Player 2 will end up with a forced faction ratio of 2/6 while player 1
142-
// will have 0.5. So faction for player 1 is changed.
187+
// Player 1 will end up with a forced faction ratio of 2/6 while player 2
188+
// will have 100%. So faction for player 1 is changed.
143189
$p1 = $this->makePlayerWithActualSide(101, 6);
144190
$p2 = $this->makePlayerWithActualSide(202, 0);
145191
$this->mockStatsFor($p1, [5, 1], $p2, [0, 0]);

0 commit comments

Comments
 (0)