fix(map): load_map rejects two deployment sides bound to the same zone letter (build_states resets its placed set per side, so shared letters deployed camps on top of each other) - fail-fast MapValidationError + README rule, reject/accept tests
This commit is contained in:
@@ -136,6 +136,9 @@ Règles de construction d'une rencontre :
|
|||||||
- Les combattants d'un camp remplissent les cases de leur zone dans l'ordre
|
- Les combattants d'un camp remplissent les cases de leur zone dans l'ordre
|
||||||
(ligne, colonne). Une zone trop petite pour le nombre de combattants est une
|
(ligne, colonne). Une zone trop petite pour le nombre de combattants est une
|
||||||
erreur.
|
erreur.
|
||||||
|
- Chaque camp du déploiement doit être lié à une lettre de zone **distincte** :
|
||||||
|
deux camps partageant la même lettre se déploieraient l'un sur l'autre, ce
|
||||||
|
qui est une erreur de carte (`share zone letters`).
|
||||||
|
|
||||||
## Interpréter le rapport
|
## Interpréter le rapport
|
||||||
|
|
||||||
|
|||||||
@@ -140,6 +140,14 @@ def _check_deployment(
|
|||||||
if missing:
|
if missing:
|
||||||
msg = f"deployment zones absent from zones layer: {missing}"
|
msg = f"deployment zones absent from zones layer: {missing}"
|
||||||
raise MapValidationError(path, msg)
|
raise MapValidationError(path, msg)
|
||||||
|
letters = list(deployment.values())
|
||||||
|
shared = sorted({letter for letter in letters if letters.count(letter) > 1})
|
||||||
|
if shared:
|
||||||
|
msg = (
|
||||||
|
"deployment sides share zone letters (each side needs its own "
|
||||||
|
f"distinct zone, or they deploy on top of each other): {shared}"
|
||||||
|
)
|
||||||
|
raise MapValidationError(path, msg)
|
||||||
|
|
||||||
|
|
||||||
def load_map(path: Path) -> MapSpec:
|
def load_map(path: Path) -> MapSpec:
|
||||||
|
|||||||
@@ -109,3 +109,20 @@ def test_rejects_deployment_without_zone(tmp_path: Path) -> None:
|
|||||||
body = _minimal_map() + "zones: |\n ...\n .A.\n ...\ndeployment:\n players: B\n"
|
body = _minimal_map() + "zones: |\n ...\n .A.\n ...\ndeployment:\n players: B\n"
|
||||||
with pytest.raises(MapValidationError):
|
with pytest.raises(MapValidationError):
|
||||||
load_map(_write(tmp_path, body))
|
load_map(_write(tmp_path, body))
|
||||||
|
|
||||||
|
|
||||||
|
def test_rejects_shared_deployment_zone_letter(tmp_path: Path) -> None:
|
||||||
|
"""Two sides bound to the same zone letter would deploy on top of each
|
||||||
|
other (build_states resets its placed set per side): a data error."""
|
||||||
|
body = _minimal_map() + (
|
||||||
|
"zones: |\n ...\n .A.\n ...\ndeployment:\n players: A\n monsters: A\n"
|
||||||
|
)
|
||||||
|
with pytest.raises(MapValidationError, match="share zone letters"):
|
||||||
|
load_map(_write(tmp_path, body))
|
||||||
|
|
||||||
|
|
||||||
|
def test_accepts_distinct_deployment_zone_letters(tmp_path: Path) -> None:
|
||||||
|
body = _minimal_map() + (
|
||||||
|
"zones: |\n ...\n AB.\n ...\ndeployment:\n players: A\n monsters: B\n"
|
||||||
|
)
|
||||||
|
assert load_map(_write(tmp_path, body)).deployment == {"players": "A", "monsters": "B"}
|
||||||
|
|||||||
Reference in New Issue
Block a user