Bot-Policies auf recherchierte Level-Timelines: Runden-Ziele, Rolldown-Runden, Slow-Roll, Not-Roll bei wenig HP

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
team3
2026-07-23 09:41:51 +02:00
parent 12603267bc
commit 54a3e7f9be
2 changed files with 66 additions and 16 deletions

View File

@@ -1,4 +1,9 @@
"""Scripted planning policies — drive the bots and the autoplay benchmarks."""
"""Scripted planning policies — drive the bots and the autoplay benchmarks.
Level-Ziele und Rolldown-Zeitpunkte nach Standard-Spielweisen (Set 17):
Baseline L4@2-1, L5@2-5, L6@3-2, L7@4-1, L8@4-5. Fast 8 spiked bei 4-2,
Streaker levelt früh und rollt klein, Reroll cappt bei 6 und slow-rollt >50.
"""
import random
@@ -7,18 +12,40 @@ from tft.sim.player import InvalidAction, PlayerState
from tft.sim.pool import Pool
ARCHETYPES = {
# fast8: früh econ, ab Stage 3 leveln, Rolldown ab Level 8.
"fast8": {"level_cap": 10, "xp_stage": 3, "econ_floor": 54,
"roll_stage": 4, "roll_level": 8, "roll_floor": 30},
# reroll: Level-Cap 7, rollt Überschuss über 50 für Upgrades.
"reroll": {"level_cap": 7, "xp_stage": 3, "econ_floor": 50,
"roll_stage": 3, "roll_level": 7, "roll_floor": 50},
# streaker: gibt früh aus, levelt aggressiv, wenig Reserve.
"streaker": {"level_cap": 10, "xp_stage": 2, "econ_floor": 20,
"roll_stage": 4, "roll_level": 8, "roll_floor": 20},
"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_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_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_low_hp": 40,
"slow_roll_level": 6, # ab Level 6: Gold über 50 verrollen (Slow-Roll)
},
}
def _round_key(label: str) -> tuple[int, int]:
stage, rnd = label.split("-")
return int(stage), int(rnd)
def _target_level(params: dict, label: str) -> int:
key = _round_key(label)
return max(
(lvl for rnd, lvl in params["level_targets"].items() if _round_key(rnd) <= key),
default=0,
)
def act(p: PlayerState, pool: Pool, artifact: dict, cfg: dict, rng: random.Random,
rnd: dict, params: dict) -> None:
"""Eine Planungsrunde für einen Spieler."""
@@ -27,18 +54,28 @@ def act(p: PlayerState, pool: Pool, artifact: dict, cfg: dict, rng: random.Rando
_buy_from_shop(p, pool, artifact)
stage = rnd["stage"]
while (stage >= params["xp_stage"] and p.level < params["level_cap"]
and p.gold >= params["econ_floor"] + cfg["xp"]["buy_cost"]):
label = rnd["label"]
target = _target_level(params, label)
while p.level < target and p.gold >= cfg["xp"]["buy_cost"]:
try:
player.buy_xp(p, cfg)
except InvalidAction:
break
at_target = p.level >= params["roll_level"] or p.level >= params["level_cap"]
if stage >= params["roll_stage"] and at_target:
floor = None
slow_level = params.get("slow_roll_level")
if slow_level is not None and p.level >= slow_level:
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]
if rnd["stage"] >= 4 and p.hp < params["roll_low_hp"]:
floor = 0 # Not-Rolldown bei niedrigem Leben
if floor is not None:
_sell_junk(p, pool, artifact)
while p.gold > params["roll_floor"]:
while p.gold > floor:
_buy_upgrades(p, pool, artifact)
try:
player.reroll(p, pool, cfg, rng)