import random import pytest from tft.constants.loader import load_constants from tft.sim import economy from tft.sim.pool import Pool from tft.sim.rounds import schedule from tft.sim.shop import roll def make_static(per_tier: int = 13) -> dict: units = {} for cost in range(1, 6): for i in range(per_tier): units[f"U{cost}_{i}"] = { "cost": cost, "traits": ["T1"], "role": "Tank", "stats": {"hp": 600 + 100 * cost, "armor": 40, "magicResist": 40, "damage": 55, "attackSpeed": 0.7, "mana": 60, "initialMana": 0, "range": 1}, } return { "meta": {"set": 17}, "units": units, "traits": {"T1": {"breakpoints": [{"min_units": 2, "style": 1}]}}, "items": {f"TFT_Item_{i}": {} for i in range(10)}, "augments": {f"TFT17_Augment_{i}": {} for i in range(8)}, } @pytest.fixture(scope="module") def cfg(): return load_constants(17) @pytest.fixture def static(): return make_static() def test_pool_take_put_back(static, cfg): pool = Pool(static["units"], cfg["pool"]["sizes"]) assert pool.available("U1_0") == 30 pool.take("U1_0", 3) assert pool.available("U1_0") == 27 pool.put_back("U1_0", 3) assert pool.available("U1_0") == 30 with pytest.raises(ValueError): pool.take("U5_0", 10) def test_shop_odds_empirical(static, cfg): pool = Pool(static["units"], cfg["pool"]["sizes"]) rng = random.Random(42) counts = [0] * 5 n = 10_000 for _ in range(n // cfg["shop"]["slots"]): for api in roll(pool, 8, cfg, rng): counts[static["units"][api]["cost"] - 1] += 1 expected = cfg["shop"]["odds"][7] for tier in range(5): assert counts[tier] / n == pytest.approx(expected[tier] / 100, abs=0.02) def test_interest_cap(cfg): assert economy.interest(0, cfg) == 0 assert economy.interest(39, cfg) == 3 assert economy.interest(80, cfg) == cfg["gold"]["interest_cap"] def test_streak_gold(cfg): assert economy.streak_gold(1, cfg) == 0 assert economy.streak_gold(3, cfg) == 1 assert economy.streak_gold(-5, cfg) == 2 assert economy.streak_gold(9, cfg) == 3 def test_apply_xp_levels_up(cfg): level, xp = economy.apply_xp(1, 0, 4, cfg) assert level == 3 # 1->2 costs 2, 2->3 costs 2 assert xp == 0 level, _ = economy.apply_xp(9, 0, 1000, cfg) assert level == cfg["xp"]["max_level"] def test_schedule(cfg): rounds = schedule(cfg) labels = [r["label"] for r in rounds] assert labels[:4] == ["1-1", "1-2", "1-3", "1-4"] assert rounds[0]["kind"] == "carousel" aug = [r["label"] for r in rounds if r["augment"]] assert aug == cfg["rounds"]["augment_rounds"] stage2 = [r for r in rounds if r["stage"] == 2] assert [r["kind"] for r in stage2] == cfg["rounds"]["stage_n"]