update
This commit is contained in:
79
backend/tests/test_rating.py
Normal file
79
backend/tests/test_rating.py
Normal file
@@ -0,0 +1,79 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user