Drop variant B, adopt Black-belt Exam defender, add one-sidedness metrics
- Remove variant B (Brown cap, +1 for higher beating lower) from rules, engine, bots and simulator; a higher belt beating a lower one gains 0. - Final Exam: the defender fights as a Black belt (RULES.md v0.7). Ties to the defender and best-of-3 stay as simulator switches (`--exam`). - Report stripe income per source as gains and losses. - Add ten one-sidedness measures sampled at turn ends (lead gap, winner margin and lead share, halfway leader, last lead change, contention, rank swaps, leader Kumite losses, Exam challengers, winner pace). - Plan: decisions D28-D33 and the detailed Phase 6. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+35
-13
@@ -2,6 +2,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from dojo.rules import RulesConfig
|
||||
from dojo.sim import BoardFiles, Scenario, matrix, run
|
||||
|
||||
BOARD = Path(__file__).parent.parent / "board"
|
||||
@@ -10,16 +11,35 @@ LINEUP = ("balanced", "random")
|
||||
|
||||
|
||||
def test_matrix_crosses_every_axis() -> None:
|
||||
scenarios = matrix(["A", "B"], [3, 4], [2, 1], [0], [LINEUP])
|
||||
scenarios = matrix(["none", "acd"], [3, 4], [2, 1], [0], [LINEUP])
|
||||
|
||||
assert len(scenarios) == 8
|
||||
assert scenarios[0].name == "A p3 kiai+2 start0 balanced,random"
|
||||
assert scenarios[-1].config.kiai_bonus == 1
|
||||
assert scenarios[-1].config.brown_requires_kumite
|
||||
assert scenarios[0].name == "exam:none p3 kiai+2 start0 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
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("exam", "ties", "black", "rounds"),
|
||||
[
|
||||
("none", False, False, 1),
|
||||
("a", True, False, 1),
|
||||
("c", False, True, 1),
|
||||
("d", False, False, 3),
|
||||
("cd", False, True, 3),
|
||||
],
|
||||
)
|
||||
def test_exam_options_map_to_rules(exam: str, ties: bool, black: bool, rounds: int) -> None:
|
||||
config = Scenario(exam, 4, 2, 0, LINEUP).config
|
||||
|
||||
assert (config.exam_ties_to_defender, config.exam_defender_black) == (ties, black)
|
||||
assert config.exam_rounds == rounds
|
||||
|
||||
|
||||
def test_lineup_fills_the_seats_and_rotates_each_game() -> None:
|
||||
scenario = Scenario("A", 3, 2, 0, LINEUP)
|
||||
scenario = Scenario("none", 3, 2, 0, LINEUP)
|
||||
|
||||
assert scenario.seating(0) == ("balanced", "random", "balanced")
|
||||
assert scenario.seating(1) == ("random", "balanced", "balanced")
|
||||
@@ -27,23 +47,25 @@ def test_lineup_fills_the_seats_and_rotates_each_game() -> None:
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("variant", "players", "lineup", "message"),
|
||||
("exam", "players", "lineup", "message"),
|
||||
[
|
||||
("C", 4, LINEUP, "unknown variant"),
|
||||
("A", 4, ("balanced", "cheater"), "unknown bots"),
|
||||
("A", 4, (), "unknown bots"),
|
||||
("A", 9, LINEUP, "supported range"),
|
||||
("b", 4, LINEUP, "unknown Exam options"),
|
||||
("aa", 4, LINEUP, "unknown Exam options"),
|
||||
("", 4, LINEUP, "unknown Exam options"),
|
||||
("none", 4, ("balanced", "cheater"), "unknown bots"),
|
||||
("none", 4, (), "unknown bots"),
|
||||
("none", 9, LINEUP, "supported range"),
|
||||
],
|
||||
)
|
||||
def test_invalid_scenarios_are_rejected(
|
||||
variant: str, players: int, lineup: tuple[str, ...], message: str
|
||||
exam: str, players: int, lineup: tuple[str, ...], message: str
|
||||
) -> None:
|
||||
with pytest.raises(ValueError, match=message):
|
||||
Scenario(variant, players, 2, 0, lineup)
|
||||
Scenario(exam, players, 2, 0, lineup)
|
||||
|
||||
|
||||
def test_runs_are_reproducible_and_independent_of_worker_count() -> None:
|
||||
scenarios = matrix(["A", "B"], [3], [2], [0], [LINEUP])
|
||||
scenarios = matrix(["none", "acd"], [3], [2], [0], [LINEUP])
|
||||
|
||||
serial = run(FILES, scenarios, games=2, seed=5, jobs=1)
|
||||
parallel = run(FILES, scenarios, games=2, seed=5, jobs=2)
|
||||
|
||||
Reference in New Issue
Block a user