This commit is contained in:
team3
2026-07-24 11:24:24 +02:00
parent f41ac76b57
commit 848c8ea1aa
41 changed files with 1776 additions and 15 deletions

View File

@@ -0,0 +1,76 @@
# Einheiten: backend/tft/sim/combat.py
stand: f41ac76b5789
## backend/tft/sim/combat.py::FightResult
beschreibung: Datenklasse, die das Ergebnis eines Kampfes zwischen zwei Teams festhält.
input: Siegerkennzeichen "a"/"b"/None, gespielte Frames und überlebende Units beider Seiten
output: Ein `FightResult`-Objekt mit `winner`, `frames`, `survivors_a` und `survivors_b`
entscheidungen:
- Das Ergebnis-Format schließt einen Unentschieden-Fall explizit als `None` mit ein.
beleg: "winner: str | None # \"a\" | \"b\" | None = Unentschieden"
- Überlebende werden seitenweise als Liste von Unit-Dicts geführt, nicht als Indizes.
beleg: "survivors_a: list[dict]"
- Die Anzahl der simulierten Frames wird als Ganzzahl gerundet (`ceil`).
beleg: "frames=math.ceil(elapsed * FPS),"
kanten:
- wird-genutzt-von: backend/tft/sim/combat.py::fight
## backend/tft/sim/combat.py::_queue
beschreibung: Bestimmt die Bearbeitungsreihenfolge der Units eines Teams als defensive zuerst, intern zufällig gemischt.
input: Team-Liste von Unit-Dicts und ein `random.Random`-RNG
output: Neue Liste, in der defensive Units vor offensiven stehen, beide Gruppen intern gemischt
entscheidungen:
- Defensive Units werden grundsätzlich vor offensiven angegriffen.
beleg: "defensive = [p for p in team if p[\"defensive\"]]"
- Innerhalb jeder Gruppe wird die Reihenfolge per `rng.shuffle` zufällig gemischt.
beleg: "rng.shuffle(defensive)"
- Die Sortierung ist nicht stabil, da die ursprüngliche Reihenfolge überschrieben wird.
beleg: "return defensive + offensive"
kanten:
- nutzt: backend/tft/sim/combat.py::_suffix_off
- wird-genutzt-von: backend/tft/sim/combat.py::fight
## backend/tft/sim/combat.py::_suffix_off
beschreibung: Berechnet die Suffix-Summe der Offensive-Werte einer Ziel-Queue.
input: Liste von Unit-Dicts mit `"off"`-Feld
output: Liste gleicher Länge + 1, in der `suffix[i]` die Gesamt-Offense ab Unit `i` ist
entscheidungen:
- Die Liste ist absichtlich um einen Eintrag länger, damit `suffix[len(queue)] = 0` als Sicherheitselement dient.
beleg: "suffix = [0.0] * (len(queue) + 1)"
- Die Summation läuft rückwärts, um die echte Suffix-Summe zu bilden.
beleg: "for i in range(len(queue) - 1, -1, -1):"
kanten:
- wird-genutzt-von: backend/tft/sim/combat.py::fight
## backend/tft/sim/combat.py::fight
beschreibung: Simuliert einen deterministischen Kampf zweier Teams eventbasiert bis zum nächsten Tod oder Zeitlimit.
input: Zwei Team-Profil-Listen, ein `random.Random`-RNG und eine Config mit `combat.max_frames`
output: `FightResult` mit Sieger, Framezahl und Überlebenden beider Seiten
entscheidungen:
- Zwischen zwei Todesereignissen werden beide Offensen als konstant angenommen, `dt = min(ta, tb)`.
beleg: "dt = min(ta, tb)"
- Bei Überschreitung des Zeitlimits wird `dt` auf das verbleibende Restbudget begrenzt.
beleg: "dt = limit - elapsed"
- Überzähliger Schaden wird verlustfrei auf das nächste Ziel übertragen, indem die Rest-Defense weiter reduziert wird.
beleg: "rb -= oa * dt"
- Bei Zeitlimit ohne verbleibende Offense wird der Sieg nach größerer Rest-Defense entschieden.
beleg: "winner = \"a\" if rest_a > rest_b + EPS else \"b\" if rest_b > rest_a + EPS else None"
- Ein gleicher Kill-Frame kann nicht beide Seiten treffen, da `else`-Zweige getrennt ausgewertet werden.
beleg: "else:"
kanten:
- ruft-auf: backend/tft/sim/combat.py::_queue
- ruft-auf: backend/tft/sim/combat.py::_suffix_off
- nutzt: backend/tft/sim/combat.py::FightResult
- wird-genutzt-von: backend/tft/sim/combat.py::player_damage
## backend/tft/sim/combat.py::player_damage
beschreibung: Berechnet den Schaden, den ein Spieler nach einer Runde abhängig von erreichter Stage und Überlebenden erhält.
input: Stage-Index (1-basiert), Liste der überlebenden Units und eine Config mit `damage`
output: Schadenswert als `int`
entscheidungen:
- Der Basis-Schaden wird stageweise aus `cfg["damage"]["stage_base"]` gelesen, bei Überschreitung wird der letzte Eintrag verwendet.
beleg: "min(stage - 1, len(d[\"stage_base\"]) - 1)"
- Pro überlebender Unit wird ein linearer Zusatzschaden addiert.
beleg: "return base + d[\"per_surviving_unit\"] * len(survivors)"
kanten:
- nutzt: backend/tft/sim/combat.py::fight