Add failed-Exam loss switch; keep -3 and accept the length (6.11, D50)
RulesConfig.exam_failure_loss (bots aware) with the sim axis --exam-loss. Losing 1 or 0 stripes saves 3-5 minutes but weakens comebacks, so the rules keep -3. Default games are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+9
-5
@@ -68,7 +68,7 @@ def test_sim_prints_a_summary_per_scenario_and_writes_games(
|
||||
assert main([*argv, "--csv", str(games)]) == EXIT_OK
|
||||
|
||||
output = capsys.readouterr().out
|
||||
assert "== exam:none p3 kiai+2 start0 balanced,farmer,aggressive (2 games" in output
|
||||
assert "== exam:none p3 kiai+2 start0 fail-3 balanced,farmer,aggressive (2 games" in output
|
||||
assert "== exam:c p3 kiai+2 start0" in output
|
||||
rows = games.read_text(encoding="utf-8").splitlines()
|
||||
assert rows[0].startswith("scenario,seed,lineup,winner_seat")
|
||||
@@ -78,21 +78,25 @@ def test_sim_prints_a_summary_per_scenario_and_writes_games(
|
||||
def test_sim_writes_one_summary_row_per_scenario(tmp_path: Path) -> None:
|
||||
path = tmp_path / "summary.csv"
|
||||
argv = ["sim", "--games", "2", "--players", "3", "4", "--lineup", "casual", "--jobs", "1"]
|
||||
argv += ["--exam-loss", "3", "0"]
|
||||
|
||||
assert main([*argv, "--summary-csv", str(path)]) == EXIT_OK
|
||||
|
||||
with path.open(encoding="utf-8", newline="") as file:
|
||||
rows = list(csv.DictReader(file))
|
||||
assert [row["scenario"] for row in rows] == [
|
||||
"exam:c p3 kiai+2 start0 casual",
|
||||
"exam:c p4 kiai+2 start0 casual",
|
||||
"exam:c p3 kiai+2 start0 fail-3 casual",
|
||||
"exam:c p3 kiai+2 start0 fail-0 casual",
|
||||
"exam:c p4 kiai+2 start0 fail-3 casual",
|
||||
"exam:c p4 kiai+2 start0 fail-0 casual",
|
||||
]
|
||||
assert {"rounds_mean", "square_gain_per_turn", "win_rate_casual"} <= rows[0].keys()
|
||||
assert (rows[0]["seat3_win_rate"], rows[1]["seat3_win_rate"] != "") == ("", True)
|
||||
assert (rows[0]["seat3_win_rate"], rows[2]["seat3_win_rate"] != "") == ("", True)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"bad", [["--lineup", "balanced,cheater"], ["--games", "0"], ["--exam", "b"]]
|
||||
"bad",
|
||||
[["--lineup", "balanced,cheater"], ["--games", "0"], ["--exam", "b"], ["--exam-loss", "-1"]],
|
||||
)
|
||||
def test_sim_rejects_bad_arguments(bad: list[str], capsys: pytest.CaptureFixture[str]) -> None:
|
||||
with pytest.raises(SystemExit) as exit_info:
|
||||
|
||||
@@ -677,6 +677,22 @@ def test_failing_the_exam_costs_a_belt_and_the_defender_gains_nothing() -> None:
|
||||
assert game.players[2].track == 12
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("loss", "track"), [(0, 15), (1, 14)])
|
||||
def test_failed_exam_loss_is_configurable(loss: int, track: int) -> None:
|
||||
config = RulesConfig(exam_failure_loss=loss)
|
||||
game, agents = dojo_game([1, 1, 1, 6], config=config, p1=9, p2=12)
|
||||
|
||||
turn(game, agents, 0, Pos(6, 7))
|
||||
|
||||
assert game.players[0].track == track
|
||||
assert game.players[0].position == START_0
|
||||
|
||||
|
||||
def test_failed_exam_loss_cannot_be_negative() -> None:
|
||||
with pytest.raises(ValueError, match="exam_failure_loss"):
|
||||
RulesConfig(exam_failure_loss=-1)
|
||||
|
||||
|
||||
def test_uke_in_the_exam_returns_to_the_entrance() -> None:
|
||||
game, agents = dojo_game([1, 1, 1, 6], p1=9, p2=12)
|
||||
game.players[0].tecnica = Card.UKE
|
||||
|
||||
+13
-4
@@ -11,13 +11,17 @@ LINEUP = ("balanced", "random")
|
||||
|
||||
|
||||
def test_matrix_crosses_every_axis() -> None:
|
||||
scenarios = matrix(["none", "acd"], [3, 4], [2, 1], [0], [LINEUP])
|
||||
scenarios = matrix(["none", "acd"], [3, 4], [2, 1], [0], [LINEUP], [3, 0])
|
||||
|
||||
assert len(scenarios) == 8
|
||||
assert scenarios[0].name == "exam:none p3 kiai+2 start0 balanced,random"
|
||||
assert len(scenarios) == 16
|
||||
assert scenarios[0].name == "exam:none p3 kiai+2 start0 fail-3 balanced,random"
|
||||
assert scenarios[0].config == RulesConfig(exam_defender_black=False)
|
||||
assert scenarios[-1].config == RulesConfig(
|
||||
exam_ties_to_defender=True, exam_defender_black=True, exam_rounds=3, kiai_bonus=1
|
||||
exam_ties_to_defender=True,
|
||||
exam_defender_black=True,
|
||||
exam_rounds=3,
|
||||
exam_failure_loss=0,
|
||||
kiai_bonus=1,
|
||||
)
|
||||
|
||||
|
||||
@@ -64,6 +68,11 @@ def test_invalid_scenarios_are_rejected(
|
||||
Scenario(exam, players, 2, 0, lineup)
|
||||
|
||||
|
||||
def test_invalid_exam_loss_is_rejected() -> None:
|
||||
with pytest.raises(ValueError, match="exam_failure_loss"):
|
||||
Scenario("c", 4, 2, 0, LINEUP, exam_loss=-1)
|
||||
|
||||
|
||||
def test_runs_are_reproducible_and_independent_of_worker_count() -> None:
|
||||
scenarios = matrix(["none", "acd"], [3], [2], [0], [LINEUP])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user