Something went wrong. Try again.
bayes for days
Something went wrong. Try again.
Python
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147"""The docker command line a MatchSpec turns into."""
from __future__ import annotations
import jsonimport subprocessimport tempfileimport unittestfrom pathlib import Pathfrom unittest import mock
from sds import matchfrom sds.match import MatchSpec, Seat
def _argv(spec: MatchSpec) -> list[str]: """Run one match with docker and the result file both faked out.""" seen: list[list[str]] = [] payload = json.dumps({"outcome": "victory"})
def fake_run(command, *popenargs, **kwargs): if command[:2] == ["docker", "run"]: seen.append(command) inside = command[command.index("--out") + 1] (match.REPO / inside.removeprefix("/work/")).write_text(payload) return subprocess.CompletedProcess(command, 0)
# Inside the repository, because run() names paths as the container sees # them and that is a relative_to(REPO). with ( tempfile.TemporaryDirectory(dir=match.REPO) as tmp, mock.patch.object(match, "preflight", lambda _spec: None), mock.patch.object(match.subprocess, "run", fake_run), ): match.run(spec, Path(tmp)) return seen[0]
class CommandLine(unittest.TestCase): """Every knob on a MatchSpec has to reach SdsHost to be worth having."""
def spec(self, **kwargs) -> MatchSpec: return MatchSpec( scenario=match.REPO / "scenarios" / "mirror-lance.mms", seats=[Seat("A"), Seat("B")], **kwargs, )
def test_stall_seconds_reaches_the_host(self): argv = _argv(self.spec(stall_seconds=90)) self.assertEqual(argv[argv.index("--stall-seconds") + 1], "90")
def test_stall_seconds_is_passed_even_at_its_default(self): argv = _argv(self.spec()) self.assertEqual(argv[argv.index("--stall-seconds") + 1], "300")
if __name__ == "__main__": unittest.main()
class TestScenarioPicking(unittest.TestCase): """Which scenario the nth game of a run plays.
A suite is sorted by filename and the filename carries the era, so taking the first N entries is taking an era, not a sample. 60 games over a 228-scenario suite played 48 civil-war matches and 12 clan-invasion ones and nothing else, and every number that run printed was reported as a measurement over the whole suite. """
def test_a_long_run_still_covers_the_suite_exactly(self): from sds.cli import _pick
self.assertEqual({_pick(57, g, 114) for g in range(114)}, set(range(57)))
def test_a_short_run_spans_the_suite_rather_than_its_prefix(self): from sds.cli import _pick
picked = {_pick(228, g, 60) for g in range(60)} self.assertEqual(len(picked), 60) # The tail of the suite has to be reachable; a prefix stops at 59. self.assertGreater(max(picked), 200)
def test_it_is_deterministic(self): from sds.cli import _pick
self.assertEqual( [_pick(228, g, 60) for g in range(60)], [_pick(228, g, 60) for g in range(60)], )
class TestSidePicking(unittest.TestCase): """Which faction the bot plays, and why it cannot key off the game index.
No two deployment edges are equally good, so a scenario has to be played from both sides or the benchmark measures the edge. `game % 2` did that only when the suite size was odd: the scenario is `game % count`, so a scenario's repeats are `count` games apart and share a parity whenever `count` is even. `scenarios/suite` has 24 and `scenarios/tonight` has 228. Over either, every scenario was played twice from the same side, and the seat totals still came out level - which is why nothing ever looked wrong. """
def repeats(self, count: int, games: int) -> dict[int, list[int]]: from sds.cli import _pick, _side
out: dict[int, list[int]] = {} for game in range(games): out.setdefault(_pick(count, game, games), []).append(_side(count, game, games)) return out
def test_an_even_suite_still_swaps_sides(self): # The case that was silently broken: 24 scenarios, each played twice. for scenario, sides in self.repeats(24, 48).items(): self.assertEqual(sorted(sides), [0, 1], f"scenario {scenario} never swapped")
def test_an_odd_suite_still_swaps_sides(self): for sides in self.repeats(57, 114).values(): self.assertEqual(sorted(sides), [0, 1])
def test_no_scenario_is_ever_repeated_on_one_side(self): for count in (2, 7, 24, 25, 56, 57): for games in (count, count * 2, count * 3, count * 2 + 1): for scenario, sides in self.repeats(count, games).items(): if len(sides) > 1: self.assertGreater( len(set(sides)), 1, f"suite {count}, {games} games, scenario {scenario}" )
def test_an_odd_number_of_repeats_still_balances_the_totals(self): # Three passes alternate 0,1,0 for every scenario and come out 48-24 # unless the starting side is offset by the scenario. from sds.cli import _side
sides = [_side(24, game, 72) for game in range(72)] self.assertEqual(sides.count(0), sides.count(1))
def test_a_short_run_alternates_by_game(self): # Nothing repeats below the suite size, so the game index is what keeps # the seat totals level. from sds.cli import _side
sides = [_side(228, game, 60) for game in range(60)] self.assertEqual(sides.count(0), sides.count(1))