Files
tft/.planer/einheiten/backend__tft__sim__player.py.md
2026-07-24 11:24:24 +02:00

229 lines
11 KiB
Markdown

# Einheiten: backend/tft/sim/player.py
stand: f41ac76b5789
## backend/tft/sim/player.py::InvalidAction
beschreibung: Markiert ungültige Spielaktionen als Ausnahme.
input: eine Fehlermeldung als Zeichenkette.
output: eine Exception, die von Aufrufern abgefangen wird.
entscheidungen:
- Wird als eigene Exception-Klasse statt generischer `Exception` definiert, damit Aufrufer gezielt reagieren können.
beleg: "class InvalidAction(Exception):"
- Enthält bewusst keine eigene Logik, sondern dient nur als Typ-Marker.
beleg: " pass"
kanten:
- wird-genutzt-von: backend/tft/sim/player.py::buy
- wird-genutzt-von: backend/tft/sim/player.py::sell
- wird-genutzt-von: backend/tft/sim/player.py::buy_xp
- wird-genutzt-von: backend/tft/sim/player.py::move
- wird-genutzt-von: backend/tft/sim/player.py::equip
- wird-genutzt-von: backend/tft/sim/player.py::pick_augment
## backend/tft/sim/player.py::PlayerState
beschreibung: Hält den kompletten Zustand eines Spielers über alle Runden hinweg.
input: Initialwerte für Name, Archetyp, HP, Gold und Level.
output: ein Datensatz-Objekt mit Board, Bench, Items, Augments und Shop.
entscheidungen:
- Verwendet `field(default_factory=list)` für mutable Defaults, um die geteilte-Liste-Falle zu vermeiden.
beleg: " board: list = field(default_factory=list)"
- `alive` ist als abgeleitete Property modelliert, damit Konsistenz mit `hp` garantiert ist.
beleg: " return self.hp > 0"
- Optionale Felder wie `placement` und `last_opponent` werden explizit typisiert, damit Phasen ohne Gegner sauber abgebildet werden.
beleg: " placement: int | None = None"
kanten:
- nutzt: backend/tft/sim/player.py::score
- wird-genutzt-von: backend/tft/sim/player.py::new_player
## backend/tft/sim/player.py::new_player
beschreibung: Erzeugt einen frischen `PlayerState` aus einer Konfiguration.
input: Name, Archetyp und ein Konfigurations-Dictionary.
output: ein neu initialisierter `PlayerState` mit Startwerten.
entscheidungen:
- Liest Startwerte aus `cfg`, um Regelvarianten ohne Code-Änderung zu erlauben.
beleg: " hp=cfg[\"damage\"][\"player_hp\"],"
- Fallback auf Level 1, falls `start_level` fehlt.
beleg: " level=cfg[\"xp\"].get(\"start_level\", 1),"
kanten:
- ruft-auf: backend/tft/sim/player.py::PlayerState
- nutzt: backend/tft/sim/player.py::PlayerState
## backend/tft/sim/player.py::score
beschreibung: Berechnet die Spielstärke eines Spielers für die Schaden-Berechnung.
input: ein Spielerzustand und ein Artifact-Dictionary.
output: ein Float-Score des aktuellen Boards inklusive Augments.
entscheidungen:
- Delegiert die eigentliche Berechnung an `score_board`, um die Bewertungslogik zentral zu halten.
beleg: " return score_board(p.board, p.augments, artifact)"
- Bezieht Augments in den Score ein, damit gewählte Bonüsse kampfrelevant zählen.
beleg: " return score_board(p.board, p.augments, artifact)"
kanten:
## backend/tft/sim/player.py::unit_worth
beschreibung: Liefert den ökonomischen Gegenwert einer Einheit für Aufstellungsentscheidungen.
input: Artifact-Dictionary und eine Einheit mit `api_name` und `stars`.
output: ein Float-Wert als Kombination aus Kosten und Sternen.
entscheidungen:
- Skaliert den Wert mit `3 ** (stars - 1)`, da Merge-Stufen das Vielfache an Einheiten ersetzen.
beleg: " return artifact[\"static\"][\"units\"][u[\"api_name\"]][\"cost\"] * 3 ** (u[\"stars\"] - 1)"
- Liest Einheitenkosten aus den statischen Artifact-Daten, damit Balance-Anpassungen ohne Code-Change greifen.
beleg: " return artifact[\"static\"][\"units\"][u[\"api_name\"]][\"cost\"] * 3 ** (u[\"stars\"] - 1)"
kanten:
- wird-genutzt-von: backend/tft/sim/player.py::fill_board
## backend/tft/sim/player.py::refresh_shop
beschreibung: Erneuert die Shop-Anzeige eines Spielers mit neuen Roll-Ergebnissen.
input: Spielerzustand, Pool, Konfiguration und RNG.
output: keine Rückgabe; der Shop des Spielers wird ersetzt.
entscheidungen:
- Überschreibt `p.shop` vollständig statt zu mischen, um das TFT-typische „neuer Roll" zu modellieren.
beleg: " p.shop = roll(pool, p.level, cfg, rng)"
kanten:
- wird-genutzt-von: backend/tft/sim/player.py::reroll
## backend/tft/sim/player.py::merge
beschreibung: Führt automatisch passende Einheiten gleicher Sternstufe zu höheren Sternen zusammen.
input: Spielerzustand, API-Name und aktuelle Sternstufe.
output: keine Rückgabe; Board und Bench werden konsolidiert.
entscheidungen:
- Iteriert mit `while True`, bis weniger als drei Kopien vorhanden sind.
beleg: " while True:"
- Übernimmt die Items der fusionierten Kopien auf die verbleibende Einheit.
beleg: " keep[\"items\"].extend(u[\"items\"])"
- Kürzt das Item-Inventar der behaltenen Einheit auf das maximale Limit.
beleg: " keep[\"items\"] = keep[\"items\"][:MAX_ITEMS_PER_UNIT]"
- Entfernt überschüssige Einheiten aus Board oder Bench je nach Herkunft.
beleg: " (p.board if u in p.board else p.bench).remove(u)"
kanten:
- wird-genutzt-von: backend/tft/sim/player.py::buy
- wird-genutzt-von: backend/tft/sim/player.py::grab_carousel_unit
## backend/tft/sim/player.py::buy
beschreibung: Kauft eine Einheit aus dem Shop und legt sie auf die Bank.
input: Spielerzustand, Shop-Slot, Pool und Artifact-Dictionary.
output: keine Rückgabe; Bench und Pool werden verändert.
entscheidungen:
- Prüft Shop-Slot, Gold, Bank-Kapazität und Pool-Verfügbarkeit in dieser Reihenfolge, um Mehrfach-Meldungen pro Aktion zu vermeiden.
beleg: " if not (0 <= slot < len(p.shop)) or p.shop[slot] is None:"
- Leert den Shop-Slot nach erfolgreichem Kauf explizit.
beleg: " p.shop[slot] = None"
- Startet sofort einen Merge-Versuch auf Sternstufe 1, damit Käufe direkt stapeln.
beleg: " merge(p, api, 1)"
kanten:
- ruft-auf: backend/tft/sim/player.py::merge
- nutzt: backend/tft/sim/player.py::InvalidAction
## backend/tft/sim/player.py::sell
beschreibung: Verkauft eine Einheit vom Board oder Bench und erstattet Gold und Items zurück.
input: Spielerzustand, Ort, Index, Pool und Artifact-Dictionary.
output: keine Rückgabe; Gold, Items und Pool werden aktualisiert.
entscheidungen:
- Berechnet die Anzahl der Pool-Copies exponentiell zur Sternstufe.
beleg: " copies = 3 ** (u[\"stars\"] - 1)"
- Zieht 1 Gold ab, sobald die Einheit nicht 1 kostet und mindestens 2 Sterne hat.
beleg: " if cost > 1 and u[\"stars\"] >= 2:"
- Gibt Items aus dem Inventar der Einheit in das Spieler-Inventar frei.
beleg: " p.items.extend(u[\"items\"])"
kanten:
- nutzt: backend/tft/sim/player.py::InvalidAction
## backend/tft/sim/player.py::reroll
beschreibung: Würfelt den Shop gegen Gold neu aus.
input: Spielerzustand, Pool, Konfiguration und RNG.
output: keine Rückgabe; der Shop wird aktualisiert.
entscheidungen:
- Prüft Gold erst nach dem Lesen der Kosten, damit einheitliche Fehlermeldungen entstehen.
beleg: " if p.gold < cost:"
- Delegiert das eigentliche Neu-Würfeln an `refresh_shop`, um Logik-Duplikation zu vermeiden.
beleg: " refresh_shop(p, pool, cfg, rng)"
kanten:
- ruft-auf: backend/tft/sim/player.py::refresh_shop
- nutzt: backend/tft/sim/player.py::InvalidAction
## backend/tft/sim/player.py::buy_xp
beschreibung: Kauft zusätzliche Erfahrungspunkte und aktualisiert das Level.
input: Spielerzustand und Konfiguration.
output: keine Rückgabe; Level und XP werden fortgeschrieben.
entscheidungen:
- Lehnt den Kauf ab, wenn das maximale Level bereits erreicht ist.
beleg: " if p.level >= xp[\"max_level\"]:"
- Übergibt die XP-Berechnung an `economy.apply_xp`, damit Level-Schwellen zentral gepflegt werden.
beleg: " p.level, p.xp = economy.apply_xp(p.level, p.xp, xp[\"buy_amount\"], cfg)"
kanten:
- nutzt: backend/tft/sim/player.py::InvalidAction
## backend/tft/sim/player.py::move
beschreibung: Verschiebt eine Einheit zwischen Bank und Kampf-Board.
input: Spielerzustand, Richtung und Index.
output: keine Rückgabe; Board oder Bench werden mutiert.
entscheidungen:
- Wählt Quell- und Ziel-Liste abhängig von der Richtung in einer Zeile.
beleg: " src, dst = (p.bench, p.board) if where == \"bench\" else (p.board, p.bench)"
- Prüft die Board-Kapazität gegen das aktuelle Level des Spielers, nicht gegen einen festen Maximalwert.
beleg: " if dst is p.board and len(p.board) >= p.level:"
kanten:
- nutzt: backend/tft/sim/player.py::InvalidAction
## backend/tft/sim/player.py::equip
beschreibung: Legt ein Item aus dem Inventar auf eine Board-Einheit und craftet bei passender Komponente.
input: Spielerzustand, Item-Index, Board-Index und optionales Artifact.
output: keine Rückgabe; Einheit und Inventar werden angepasst.
entscheidungen:
- Sortiert die beiden Komponenten vor dem Lookup, damit die Reihenfolge keine Rolle spielt.
beleg: " crafted = recipes.get(\"|\".join(sorted((held, new_item))))"
- Bricht die Funktion mit `return` ab, sobald ein Rezept erfolgreich gecraftet wurde.
beleg: " p.items.pop(item_idx)"
beleg: " return"
kanten:
- nutzt: backend/tft/sim/player.py::InvalidAction
## backend/tft/sim/player.py::pick_augment
beschreibung: Wählt einen Augment aus dem aktuellen Angebot des Spielers.
input: Spielerzustand und Wahl-Index.
output: keine Rückgabe; Augments-Liste wird erweitert und Angebot geleert.
entscheidungen:
- Lehnt die Aktion ab, wenn aktuell kein Angebot vorliegt.
beleg: " if not p.augment_offer:"
- Leert das Angebot nach der Auswahl, damit kein zweiter Pick möglich ist.
beleg: " p.augment_offer = []"
kanten:
- nutzt: backend/tft/sim/player.py::InvalidAction
## backend/tft/sim/player.py::grant_loot
beschreibung: Verteilt Loot-Belohnungen wie Komponenten und Gold an einen Spieler.
input: Spielerzustand, Anzahl Komponenten, Gold, Artifact und RNG.
output: keine Rückgabe; Inventar und Gold werden erhöht.
entscheidungen:
- Wählt die Item-Quelle in absteigender Priorität aus Komponenten- und Item-Pool.
beleg: " pool = (artifact.get(\"component_pool\") or artifact.get(\"item_pool\")"
- Erlaubt nur das Droppen von Komponenten, fertige Items entstehen ausschließlich durch Crafting.
beleg: " # Loot droppt Komponenten; fertige Items entstehen nur durch Craften."
kanten:
- nutzt: backend/tft/sim/player.py::InvalidAction
## backend/tft/sim/player.py::grab_carousel_unit
beschreibung: Greift eine zufällige Karussell-Einheit und legt sie auf die Bank.
input: Spielerzustand, Pool und RNG.
output: keine Rückgabe; Bench und Pool werden verändert.
entscheidungen:
- Sammelt Kandidaten aus den Kostenstufen 1 bis 3, da Karussell-Einheiten günstig sind.
beleg: " candidates = [a for c in (1, 2, 3) for a in pool.units_of_cost(c)]"
- Überspringt den Greif, wenn die Bank voll ist, ohne Fehler zu werfen.
beleg: " if candidates and len(p.bench) < BENCH_SIZE:"
- Startet sofort einen Merge-Versuch, damit Drops direkt stapeln.
beleg: " merge(p, api, 1)"
kanten:
- ruft-auf: backend/tft/sim/player.py::merge
## backend/tft/sim/player.py::fill_board
beschreibung: Füllt freie Board-Plätze und tauscht stärkere Bank-Einheiten ein.
input: Spielerzustand und Artifact-Dictionary.
output: keine Rückgabe; Board und Bench werden umsortiert.
entscheidungen:
- Sortiert die Bank absteigend nach `unit_worth`, damit starke Einheiten vorne stehen.
beleg: " p.bench.sort(key=lambda u: -unit_worth(artifact, u))"
- Tauscht Board-Einheiten nur aus, wenn der Bank-Kandidat strikt stärker ist.
beleg: " if unit_worth(artifact, best) > unit_worth(artifact, u):"
- Bricht die Swap-Schleife ab, sobald die Bank leer ist.
beleg: " if not p.bench:"
kanten:
- ruft-auf: backend/tft/sim/player.py::unit_worth