werewolftown_agent / tests /features /test_clusters.py
gabiwzx's picture
refactor: 五层架构重构 M1-M8 完成
1c66cf8
Raw
History Blame Contribute Delete
3.83 kB
"""Tests for features/clusters.py."""
from __future__ import annotations
from werewolftown.features.clusters import (
achievable_size,
calc_cluster_gain,
find_full_count_gaps,
find_typed_clusters,
)
class TestFindTypedClusters:
def test_single_cluster(self):
built = {4: "Happy", 5: "Happy"}
clusters = find_typed_clusters(built, "Happy")
assert len(clusters) == 1
assert clusters[0] == [4, 5]
def test_multiple_clusters(self):
built = {4: "Happy", 5: "Happy", 8: "Happy"}
# 4 adj 5 (same row), 8 adj 4 (vertical) → all connected
clusters = find_typed_clusters(built, "Happy")
assert len(clusters) == 1
assert sorted(clusters[0]) == [4, 5, 8]
def test_empty_built(self):
assert find_typed_clusters({}, "Happy") == []
def test_wrong_type(self):
built = {4: "Happy", 5: "猫天天"}
assert find_typed_clusters(built, "Happy") == [[4]]
class TestCalcClusterGain:
def test_gain_from_extending_cluster(self, make_state):
state = make_state(
plots=frozenset({4, 5, 6}),
built_on={4: "Happy", 5: "Happy"},
shops=("Happy",),
)
# Building Happy on 6 (adjacent to 5): 3-cluster vs 2-cluster
# rev(3,4)=50000 - rev(2,4)=30000 = 20000
gain = calc_cluster_gain(state, 6, "Happy")
assert gain == 20000
def test_zero_for_already_built(self, make_state):
state = make_state(
plots=frozenset({4, 5}),
built_on={4: "Happy", 5: "Happy"},
)
assert calc_cluster_gain(state, 4, "Happy") == 0
def test_zero_for_isolated_plot(self, make_state):
# Plot 7 is not adjacent to 4/5
state = make_state(
plots=frozenset({4, 5, 7}),
built_on={4: "Happy", 5: "Happy"},
)
gain = calc_cluster_gain(state, 7, "Happy")
# 7 is isolated → building creates a new 1-cluster = 10000 revenue
assert gain == 10000
class TestAchievableSize:
def test_with_adjacent_empty_and_cards(self, make_state):
state = make_state(
plots=frozenset({4, 5, 6}),
built_on={4: "Happy", 5: "Happy"},
shops=("Happy", "Happy"),
)
# existing=2, adjacent_empties={6}, cards=2 → min(1,2)=1 → total=3
assert achievable_size(state, "Happy") == 3
def test_fc5_capped_at_3(self, make_state):
state = make_state(
plots=frozenset({4, 5, 6, 1, 2}),
built_on={4: "淘小宝", 5: "淘小宝"},
shops=("淘小宝", "淘小宝", "淘小宝"),
)
# fc=5 but capped at 3
assert achievable_size(state, "淘小宝") == 3
def test_zero_for_no_cards_no_built(self, make_state):
state = make_state(plots=frozenset({4, 5}))
assert achievable_size(state, "Happy") == 0
class TestFindFullCountGaps:
def test_finds_2_cluster_gap(self, make_state):
state = make_state(
plots=frozenset({4, 5, 6}),
built_on={4: "Happy", 5: "Happy"},
shops=("Happy",),
)
gaps = find_full_count_gaps(state)
assert len(gaps) >= 1
gap = gaps[0]
assert gap.shop_type == "Happy"
assert gap.gap == 2 # fc=4, size=2, gap=2
assert gap.gain_if_filled > 0
def test_empty_for_full_cluster(self, make_state):
state = make_state(
plots=frozenset({4, 5}),
built_on={4: "钉三多", 5: "钉三多"},
)
# fc=2, 2-cluster = full → no gap
gaps = find_full_count_gaps(state)
assert len(gaps) == 0
def test_empty_for_no_built(self, make_state):
state = make_state(plots=frozenset({4, 5}))
assert find_full_count_gaps(state) == []