diff --git a/backend/tft/sim/player.py b/backend/tft/sim/player.py index 9f37265..52d97e4 100644 --- a/backend/tft/sim/player.py +++ b/backend/tft/sim/player.py @@ -193,7 +193,15 @@ def grab_carousel_unit(p: PlayerState, pool: Pool, rng: random.Random) -> None: def fill_board(p: PlayerState, artifact: dict) -> None: - """Wie in TFT: freie Board-Plätze werden beim Kampfstart von der Bank aufgefüllt.""" + """Freie Board-Plätze auffüllen und stärkere Bank-Units einwechseln.""" p.bench.sort(key=lambda u: -unit_worth(artifact, u)) while len(p.board) < p.level and p.bench: p.board.append(p.bench.pop(0)) + for i, u in enumerate(p.board): + if not p.bench: + break + best = max(p.bench, key=lambda b: unit_worth(artifact, b)) + if unit_worth(artifact, best) > unit_worth(artifact, u): + p.bench.remove(best) + p.bench.append(u) + p.board[i] = best diff --git a/backend/tft/sim/policy.py b/backend/tft/sim/policy.py index 8cfebef..e3700eb 100644 --- a/backend/tft/sim/policy.py +++ b/backend/tft/sim/policy.py @@ -12,21 +12,25 @@ from tft.sim.player import InvalidAction, PlayerState from tft.sim.pool import Pool ARCHETYPES = { + # roll_at_level: ab diesem Level (und Stage >= 4) wird auf roll_floor gerollt. "fast8": { "level_targets": {"2-1": 4, "2-5": 5, "3-2": 6, "4-1": 7, "4-2": 8, "5-2": 9}, - "roll_rounds": {"4-2": 30, "5-2": 20}, + "roll_at_level": 8, + "roll_floor": 30, "roll_low_hp": 40, "slow_roll_level": None, }, "streaker": { "level_targets": {"2-1": 4, "2-5": 5, "3-1": 6, "3-5": 7, "4-5": 8, "5-5": 9}, - "roll_rounds": {"4-1": 30, "4-5": 20}, + "roll_at_level": 7, + "roll_floor": 30, "roll_low_hp": 50, "slow_roll_level": None, }, "reroll": { "level_targets": {"2-1": 4, "2-5": 5, "3-2": 6, "5-1": 7, "6-1": 8}, - "roll_rounds": {}, + "roll_at_level": None, + "roll_floor": 30, "roll_low_hp": 40, "slow_roll_level": 6, # ab Level 6: Gold über 50 verrollen (Slow-Roll) }, @@ -69,8 +73,9 @@ def act(p: PlayerState, pool: Pool, artifact: dict, cfg: dict, rng: random.Rando floor = 50 if p.level >= max(params["level_targets"].values()): floor = 50 # Endstufe erreicht: Überschuss in Upgrades rollen - if label in params["roll_rounds"]: - floor = params["roll_rounds"][label] + roll_level = params.get("roll_at_level") + if roll_level is not None and p.level >= roll_level and rnd["stage"] >= 4: + floor = params["roll_floor"] if rnd["stage"] >= 4 and p.hp < params["roll_low_hp"]: floor = 0 # Not-Rolldown bei niedrigem Leben @@ -102,13 +107,15 @@ def _buy_from_shop(p: PlayerState, pool: Pool, artifact: dict) -> None: def _buy_upgrades(p: PlayerState, pool: Pool, artifact: dict) -> None: + """Im Rolldown: Kopien für Upgrades UND neue starke Carries (4-Cost+) kaufen.""" for slot, api in enumerate(list(p.shop)): if api is None: continue cost = artifact["static"]["units"][api]["cost"] owned = sum(1 for u in p.board + p.bench if u["api_name"] == api and u["stars"] < 3) - if p.gold >= cost and owned >= 1: + wants = owned >= 1 or (cost >= 4 and len(p.bench) < 7) + if p.gold >= cost and wants: try: player.buy(p, slot, pool, artifact) except InvalidAction: