"""Boardbewertung: Merkmale, Baumdurchlauf, Grenzfälle.""" import pytest from tft.model import rating STATIC = { "units": { "U_TANK": {"cost": 1, "traits": ["T_BRAWL"], "name": "Tank"}, "U_CARRY": {"cost": 4, "traits": ["T_BRAWL", "T_SHOT"], "name": "Carry"}, "U_FIVE": {"cost": 5, "traits": ["T_SHOT"], "name": "Five"}, }, "traits": { "T_BRAWL": {"breakpoints": [{"min_units": 2}, {"min_units": 4}]}, "T_SHOT": {"breakpoints": [{"min_units": 2}]}, }, } def board(*specs): return [{"api_name": a, "stars": s, "items": list(i)} for a, s, i in specs] @pytest.fixture def art(): return {"static": STATIC, "component_pool": ["C_SWORD"], "item_pool": ["I_BLADE"], "rating": {"tables": {}}} def test_trait_counts_and_tiers(): b = board(("U_TANK", 1, []), ("U_CARRY", 1, []), ("U_FIVE", 1, [])) counts = rating.trait_counts(b, STATIC["units"]) assert counts == {"T_BRAWL": 2, "T_SHOT": 2} assert rating.trait_tiers(counts, STATIC["traits"]) == {"T_BRAWL": 1, "T_SHOT": 1} # Eine Unit unter dem Breakpoint aktiviert nichts. single = rating.trait_counts(board(("U_TANK", 1, [])), STATIC["units"]) assert rating.trait_tiers(single, STATIC["traits"]) == {} def test_features_are_stable_in_length(art): empty = rating.features([], 1, art) full = rating.features(board(("U_CARRY", 3, ["I_BLADE", "C_SWORD"])), 9, art) assert len(empty) == len(full) assert all(isinstance(x, (int, float)) for x in empty + full) def test_unknown_units_are_ignored(art): known = rating.features(board(("U_TANK", 1, [])), 5, art) mixed = rating.features(board(("U_TANK", 1, []), ("NOPE", 3, [])), 5, art) assert known == mixed def test_no_model_means_no_prediction(art): assert rating.predict_placement(board(("U_TANK", 1, [])), 5, art) is None assert rating.board_rating(board(("U_TANK", 1, [])), 5, art) is None def test_tree_walk_and_clamping(art): # Ein Baum, der nur auf die Unit-Zahl schaut (Merkmal 4). art["rating"] = {"tables": {}, "base": 4.0, "lr": 1.0, "trees": [[4, 1.5, 2.0, -2.0]]} few = rating.predict_placement(board(("U_TANK", 1, [])), 3, art) many = rating.predict_placement( board(("U_TANK", 1, []), ("U_CARRY", 1, []), ("U_FIVE", 1, [])), 9, art) assert few == 6.0 and many == 2.0 assert rating.board_rating(board(("U_TANK", 1, [])), 3, art) == pytest.approx(-1.5) # Ausreißer werden auf 1 bis 8 gestutzt — es gibt keinen Platz 0. art["rating"]["trees"] = [[4, 1.5, 99.0, -99.0]] assert rating.predict_placement(board(("U_TANK", 1, [])), 3, art) == 8.0 assert rating.predict_placement( board(("U_TANK", 1, []), ("U_CARRY", 1, [])), 9, art) == 1.0 def test_learned_tables_reach_the_features(art): art["rating"]["tables"] = {"unit": {"U_CARRY": 1.5}} plain = rating.features(board(("U_TANK", 1, [])), 5, art) good = rating.features(board(("U_CARRY", 1, [])), 5, art) assert good != plain