Files
Habegger_loader_game/loader_game/trailer.py
T

125 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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)