Altstand nach old_version/ eingefroren (untracked). Monolith ersetzt durch main.py + Paket loader_game/. Neu: run.sh/run.command mit venv+requirements, .gitignore, docs/ANALYSE.md, 35 Tests. Secrets entfernt. Gelöscht: loader_game.py, qr_scan*.py, INSTALL_README.txt.
This commit is contained in:
1 parent
6a2c891c3e
commit
de550e1d4d
24 files changed
+2269
-1008
No files matched your search
@@ -0,0 +1,107 @@
|
||||
"""Einlesen der Koffersequenzen aus ``case_sequences.txt``.
|
||||
|
||||
Dateiformat
|
||||
-----------
|
||||
Sequenzen sind durch Leerzeilen getrennt. Jede Zeile beschreibt einen Koffer::
|
||||
|
||||
breite,höhe,rotiert
|
||||
|
||||
* ``breite`` / ``höhe`` sind Kasten-Einheiten (1 Einheit = 100x100 Pixel).
|
||||
* ``rotiert=True`` heisst: der Koffer wird beim Einlaufen um 90° gedreht,
|
||||
Breite und Höhe werden also getauscht.
|
||||
|
||||
Beispiel::
|
||||
|
||||
3,1,False
|
||||
1,2,True -> Koffer ist effektiv 2 Einheiten breit und 1 hoch
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from . import config
|
||||
|
||||
_TRUE_VALUES = {"true", "1", "ja", "yes", "x"}
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class CaseSpec:
|
||||
"""Ein Koffer aus der Sequenzdatei – bereits in Einlauf-Orientierung."""
|
||||
|
||||
units_w: int
|
||||
units_h: int
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.units_w < 1 or self.units_h < 1:
|
||||
raise ValueError(f"Koffer muss mindestens 1x1 Einheiten gross sein: {self!r}")
|
||||
|
||||
@property
|
||||
def label(self) -> str:
|
||||
return f"{self.units_w}x{self.units_h}"
|
||||
|
||||
|
||||
#: Notfall-Sequenz, falls die Datei fehlt oder unlesbar ist.
|
||||
FALLBACK_SEQUENCE: tuple[CaseSpec, ...] = (CaseSpec(2, 1), CaseSpec(1, 2))
|
||||
|
||||
|
||||
def parse_sequences(raw: str) -> tuple[list[list[CaseSpec]], list[str]]:
|
||||
"""Zerlegt den Dateiinhalt in Sequenzen.
|
||||
|
||||
Rückgabe: ``(sequenzen, warnungen)``. Ungültige Zeilen werden gemeldet und
|
||||
übersprungen – ein Tippfehler in der Datei soll das Spiel nicht verhindern.
|
||||
"""
|
||||
sequences: list[list[CaseSpec]] = []
|
||||
warnings: list[str] = []
|
||||
|
||||
for block_number, block in enumerate(re.split(r"\n\s*\n", raw.strip()), start=1):
|
||||
specs: list[CaseSpec] = []
|
||||
for line_number, line in enumerate(block.splitlines(), start=1):
|
||||
text = line.strip()
|
||||
if not text:
|
||||
continue
|
||||
parts = [part.strip() for part in text.split(",")]
|
||||
if len(parts) != 3:
|
||||
warnings.append(
|
||||
f"Block {block_number}, Zeile {line_number}: "
|
||||
f"'breite,höhe,rotiert' erwartet, gefunden {text!r}"
|
||||
)
|
||||
continue
|
||||
try:
|
||||
units_w, units_h = int(parts[0]), int(parts[1])
|
||||
except ValueError:
|
||||
warnings.append(
|
||||
f"Block {block_number}, Zeile {line_number}: keine ganzen Zahlen in {text!r}"
|
||||
)
|
||||
continue
|
||||
rotated = parts[2].lower() in _TRUE_VALUES
|
||||
if rotated:
|
||||
units_w, units_h = units_h, units_w
|
||||
if units_w < 1 or units_h < 1:
|
||||
warnings.append(
|
||||
f"Block {block_number}, Zeile {line_number}: ungültige Masse {text!r}"
|
||||
)
|
||||
continue
|
||||
specs.append(CaseSpec(units_w, units_h))
|
||||
if specs:
|
||||
sequences.append(specs)
|
||||
|
||||
if not sequences:
|
||||
warnings.append("Keine gültige Sequenz gefunden – es wird die Notfall-Sequenz benutzt.")
|
||||
return sequences, warnings
|
||||
|
||||
|
||||
def load_sequences(path: Path | None = None) -> tuple[list[list[CaseSpec]], list[str]]:
|
||||
"""Liest die Sequenzdatei und liefert immer mindestens eine Sequenz."""
|
||||
path = path or config.SEQUENCES_FILE
|
||||
try:
|
||||
raw = path.read_text(encoding="utf-8")
|
||||
except OSError as exc:
|
||||
return [list(FALLBACK_SEQUENCE)], [f"Sequenzdatei {path} nicht lesbar: {exc}"]
|
||||
|
||||
sequences, warnings = parse_sequences(raw)
|
||||
if not sequences:
|
||||
sequences = [list(FALLBACK_SEQUENCE)]
|
||||
return sequences, warnings
|
||||
Reference in new issue
Block a user