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,124 @@
|
||||
"""Stapelregeln im Auflieger – reine Logik, ohne pygame.
|
||||
|
||||
Begriffe
|
||||
--------
|
||||
Barriere (``wall_x``)
|
||||
Rechte Kante des bereits gestapelten Ladeguts. Neue Koffer werden dort
|
||||
eingerastet. Reicht die Barriere über das Heck des Aufliegers hinaus, ist
|
||||
das Spiel verloren.
|
||||
|
||||
Plattform
|
||||
Ein bereits platzierter Koffer, auf den der aktuelle Koffer obendrauf
|
||||
gesetzt werden darf (nur bündig an der Barriere, nicht zu schmal, und die
|
||||
Fläche obendrauf muss frei sein).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from . import config
|
||||
from .case import Case
|
||||
|
||||
|
||||
class Trailer:
|
||||
"""Der Auflieger samt Stapel und Barrieren-Logik."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
x: int = config.TRAILER_X,
|
||||
y: int = config.TRAILER_Y,
|
||||
width: int = config.TRAILER_WIDTH,
|
||||
height: int = config.TRAILER_HEIGHT,
|
||||
) -> None:
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.stack: list[Case] = []
|
||||
self.wall_x: float = float(x)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Masse
|
||||
# ------------------------------------------------------------------
|
||||
@property
|
||||
def right(self) -> float:
|
||||
return self.x + self.width
|
||||
|
||||
@property
|
||||
def bottom(self) -> float:
|
||||
return self.y + self.height
|
||||
|
||||
def reset(self) -> None:
|
||||
self.stack.clear()
|
||||
self.wall_x = float(self.x)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Auswertung
|
||||
# ------------------------------------------------------------------
|
||||
def overflow(self) -> bool:
|
||||
"""Ragt die Barriere über das Heck hinaus?"""
|
||||
return self.wall_x > self.right
|
||||
|
||||
def load_percent(self) -> float:
|
||||
"""Beladung in Prozent (Fläche der Koffer / Fläche des Aufliegers)."""
|
||||
total = self.width * self.height
|
||||
if total <= 0:
|
||||
return 0.0
|
||||
used = sum(case.width * case.height for case in self.stack)
|
||||
return min(100.0, used / total * 100.0)
|
||||
|
||||
def find_platform(self, case: Case) -> Case | None:
|
||||
"""Koffer, auf den ``case`` obendrauf gesetzt werden darf (oder ``None``)."""
|
||||
for base in reversed(self.stack):
|
||||
if base.y <= self.y:
|
||||
continue # Oberkante = Auflieger-Oberkante
|
||||
if base.y - case.height < self.y:
|
||||
continue # oben kein Platz mehr
|
||||
if case.width > base.width:
|
||||
continue # zu breit für die Plattform
|
||||
if abs(base.right - self.wall_x) >= config.PLATFORM_TOLERANCE:
|
||||
continue # nicht bündig an der Barriere
|
||||
if self._top_is_busy(base):
|
||||
continue
|
||||
return base
|
||||
return None
|
||||
|
||||
def _top_is_busy(self, base: Case) -> bool:
|
||||
"""Liegt schon ein Koffer auf ``base``?"""
|
||||
for other in self.stack:
|
||||
if other is base:
|
||||
continue
|
||||
if abs(other.bottom - base.y) <= 0.5 and other.x < base.right and other.right > base.x:
|
||||
return True
|
||||
return False
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Platzieren
|
||||
# ------------------------------------------------------------------
|
||||
def stack_at_wall(self, case: Case) -> None:
|
||||
"""Koffer bündig an die Barriere schieben."""
|
||||
case.x = self.wall_x
|
||||
case.placed = True
|
||||
case.snapped = True
|
||||
self.stack.append(case)
|
||||
self.wall_x = case.right
|
||||
|
||||
def stack_with_gap(self, case: Case) -> None:
|
||||
"""Koffer mit einer Lücke einreihen (nach einer Kollision)."""
|
||||
case.x = self.wall_x + config.SNAP_THRESHOLD
|
||||
case.placed = True
|
||||
self.stack.append(case)
|
||||
self.wall_x = case.right
|
||||
|
||||
def place_on_top(self, case: Case, base: Case) -> None:
|
||||
"""Koffer rechtsbündig auf ``base`` ablegen."""
|
||||
case.y = base.y - case.height
|
||||
case.x = base.right - case.width
|
||||
case.placed = True
|
||||
case.snapped = True
|
||||
self.stack.append(case)
|
||||
self.wall_x = case.right
|
||||
|
||||
def remove(self, case: Case) -> None:
|
||||
"""Koffer wieder entfernen (er ragt über das Heck hinaus)."""
|
||||
if case in self.stack:
|
||||
self.stack.remove(case)
|
||||
Reference in new issue
Block a user