"""Carries: Kontrollen, Zielstufe, Zerlegung.""" from tft.model import carries UNITS = {a: {"cost": 3, "traits": ["T"]} for a in ("A", "B", "CARRY", "TANK")} UNITS["TEUER"] = {"cost": 5, "traits": ["T"]} TRAITS = {"T": {"breakpoints": [{"min_units": 1}, {"min_units": 3}]}} def board(place, level, items_total, *ents): """ents: (api, sterne, itemzahl)""" return {"place": place, "level": level, "items": items_total, "entities": list(ents)} def prepared(boards): return carries.prepare(boards, UNITS, TRAITS) def test_other_three_stars_are_part_of_the_comparison_group(): """Wer eine Unit auf 3★ hat, hatte Gold übrig — das Board ist deshalb gut. Die eigenen 3★ zählen dabei nicht mit, sonst würde man den Effekt misst, den man erklären will. """ b = prepared([board(1, 9, 3, ("A", 3, 3), ("B", 3, 0))])[0] assert carries.cell(b, 3) == (9, 3, 1) # eigene 3★ abgezogen assert carries.cell(b, 2) == (9, 3, 2) # aus Sicht einer 2★-Unit beide def test_reroll_carries_are_shown_on_three_stars(): """Auf 2★ negativ, auf 3★ positiv: so spielt man diesen Champion.""" boards = prepared([board(6, 9, 3, ("A", 2, 3)) for _ in range(60)] + [board(1, 9, 3, ("A", 3, 3)) for _ in range(60)]) base = carries.baseline(boards) out = carries.values(boards, base, UNITS, min_boards=10) assert out["A"]["stars"] == 3 and out["A"]["edge"] > 0 def test_expensive_units_are_never_shown_on_three_stars(): """Ein 5-Kosten auf 3★ heißt: das Spiel war schon gewonnen. In den Daten holen 5-Kosten auf 3★ in 98 % der Fälle Platz 1. """ boards = prepared([board(6, 9, 3, ("TEUER", 2, 3)) for _ in range(60)] + [board(1, 9, 3, ("TEUER", 3, 3)) for _ in range(60)]) base = carries.baseline(boards) out = carries.values(boards, base, UNITS, min_boards=10) assert out["TEUER"]["stars"] == 2 def test_units_below_the_rate_are_kept_but_not_carries(): """Ein Tank ohne Items bleibt in der Tabelle — er ist der Maßstab. Der Buchstabe im Reiter vergleicht mit allen Units, nicht nur mit den Carries. """ boards = prepared([board(1, 9, 3, ("CARRY", 2, 3), ("TANK", 2, 0)) for _ in range(60)] + [board(4, 9, 3, ("CARRY", 2, 3), ("TANK", 2, 3)) for _ in range(20)]) base = carries.baseline(boards) out = carries.values(boards, base, UNITS, min_boards=10) assert out["CARRY"]["carry"] and not out["TANK"]["carry"] def test_rare_units_are_dropped(): boards = prepared([board(1, 9, 3, ("A", 2, 3)) for _ in range(9)]) base = carries.baseline(boards) assert carries.values(boards, base, UNITS, min_boards=10) == {} def test_reasons_separate_unit_from_the_rest(): """Zwei Carries, gleiche Traits, aber einer steht neben besseren Units. Der Unterschied muss im Topf "rest" landen, nicht in "unit". """ boards = prepared( [board(2, 9, 3, ("A", 2, 3), ("TANK", 2, 0)) for _ in range(400)] + [board(2, 9, 3, ("B", 2, 3), ("CARRY", 2, 0)) for _ in range(400)] + [board(7, 9, 3, ("TANK", 2, 3)) for _ in range(400)] + [board(1, 9, 3, ("CARRY", 2, 3)) for _ in range(400)]) base = carries.baseline(boards) beta, idx, own_of = carries._weights(boards, base, UNITS, carries.RIDGE) why = carries.reasons(boards, base, own_of, idx, beta, min_boards=100) a, b = why[("A", 2)], why[("B", 2)] # B steht neben CARRY (gut), A neben TANK (schlecht). assert b["rest"] > a["rest"] def test_build_is_empty_without_data(): assert carries.build([], UNITS, TRAITS, min_boards=10) == {} def test_enabler_measures_the_same_carry_with_and_without(): """Stützt die Unit fremde Carries — oder steht sie nur daneben? CARRY läuft mit B besser als ohne. B trägt selbst nie Items, kann den Vorsprung also nicht selbst erklären. """ boards = prepared( [board(2, 9, 3, ("CARRY", 2, 3), ("B", 2, 0)) for _ in range(400)] + [board(6, 9, 3, ("CARRY", 2, 3), ("TANK", 2, 0)) for _ in range(400)]) base = carries.baseline(boards) lift = carries.enabler_edge(boards, base, UNITS, min_pair=100, min_total=100) assert lift["B"] > 0 > lift["TANK"] def test_supported_is_relative_to_comparable_boards(): """Ein Carry mit starken Stützern liegt über dem Üblichen.""" boards = prepared( [board(2, 9, 3, ("A", 2, 3), ("B", 2, 0)) for _ in range(400)] + [board(6, 9, 3, ("CARRY", 2, 3), ("TANK", 2, 0)) for _ in range(400)]) base = carries.baseline(boards) lift = {"B": 0.4, "TANK": -0.4} prop = carries.supported(boards, base, lift, min_boards=100) assert prop[("A", 2)] > prop[("CARRY", 2)]