Spaces:
Sleeping
Sleeping
File size: 5,065 Bytes
1c66cf8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | """Tests for features/plot_value.py."""
from __future__ import annotations
from werewolftown.features.plot_value import (
find_best_buy_candidate,
plot_buyer_gain,
plot_opportunity_cost,
plot_value,
)
from werewolftown.state.game_state import PlayerView
class TestPlotValue:
def test_empty_plot_best_shop(self, make_state):
state = make_state(
plots=frozenset({4, 5, 6}),
built_on={4: "Happy", 5: "Happy"},
shops=("Happy",),
)
# Plot 6 adjacent to 5 (Happy) → gain = rev(3,4) - rev(2,4) = 50000-30000
val = plot_value(state, 6, viewer="me")
assert val == 20000
def test_built_plot_fixed_type(self, make_state):
state = make_state(
plots=frozenset({4, 5, 6}),
built_on={4: "Happy", 5: "Happy", 6: "猫天天"},
shops=(),
)
# Plot 6 is built with 猫天天 → gain from acquiring = 0 (already built, fixed type)
# Actually, gain is the marginal revenue from having this plot
# For a built plot, it's the cluster gain for that type
val = plot_value(state, 6, viewer="me")
# 6 is isolated 猫天天 (no adjacent 猫天天) → gain = 0
assert val == 0
def test_isolated_empty_plot(self, make_state):
state = make_state(
plots=frozenset({4, 5, 7}),
built_on={4: "Happy"},
shops=("Happy",),
)
# Plot 7 not adjacent to any Happy → can still build 1-cluster = 10000
val = plot_value(state, 7, viewer="me")
assert val == 10000
class TestPlotOpportunityCost:
def test_built_plot_loss(self, make_state, cfg):
state = make_state(
round=1,
plots=frozenset({4, 5}),
built_on={4: "Happy", 5: "Happy"},
shops=(),
)
# Selling plot 4: lose 2-cluster → 1-cluster
# rev(2,4)=30000, rev(1,4)=10000 → loss=20000/round * 4 rounds = 80000
# + extra_penalty 5000*4 = 20000 → total = 100000
cost = plot_opportunity_cost(state, 4, cfg)
assert cost == 100000
def test_empty_plot_adjacent(self, make_state, cfg):
state = make_state(
round=1,
plots=frozenset({4, 5, 6}),
built_on={4: "Happy", 5: "Happy"},
shops=("Happy",),
)
# Empty plot 6, adjacent to my plots → floor=10000 * 4 = 40000
cost = plot_opportunity_cost(state, 6, cfg)
assert cost == 40000
def test_empty_plot_isolated(self, make_state, cfg):
state = make_state(
round=1,
plots=frozenset({4, 5, 7}),
built_on={4: "Happy", 5: "Happy"},
shops=("Happy",),
)
# Empty plot 7, not adjacent → floor=5000 * 4 = 20000
cost = plot_opportunity_cost(state, 7, cfg)
assert cost == 20000
class TestPlotBuyerGain:
def test_buyer_gain_with_penalty(self, make_state, cfg):
state = make_state(
round=1,
player_id="子涵",
plots=frozenset({4, 5}),
built_on={4: "Happy", 5: "Happy"},
shops=("Happy",),
other_players={"浩宇": PlayerView(
name="浩宇", cash=50000,
plots=frozenset({6, 10}),
shops=("Happy",),
)},
)
# 浩宇 has Happy card, plot 6 → can build 1-cluster = 10000/round
# penalty ratio R1 = 0.4, remaining = 4 → 10000 * 4 * 0.4 = 16000
gain = plot_buyer_gain(state, 6, "浩宇", cfg)
assert gain == 16000
def test_zero_for_no_gain(self, make_state, cfg):
state = make_state(round=1)
gain = plot_buyer_gain(state, 4, "浩宇", cfg)
assert gain == 0
class TestFindBestBuyCandidate:
def test_finds_adjacent_opp_plot(self, make_state, cfg):
state = make_state(
round=1,
player_id="子涵",
plots=frozenset({4, 5}),
built_on={4: "Happy", 5: "Happy"},
shops=("Happy",),
other_players={"浩宇": PlayerView(
name="浩宇", cash=50000,
plots=frozenset({6}), # 6 adj 5
shops=(),
)},
)
cand = find_best_buy_candidate(state, cfg)
assert cand is not None
assert cand.plot_id == 6
assert cand.owner == "浩宇"
assert cand.is_adjacent is True
assert cand.gain > 0
def test_none_when_no_adjacent(self, make_state, cfg):
state = make_state(
plots=frozenset({4, 5}),
other_players={"浩宇": PlayerView(
name="浩宇", cash=50000,
plots=frozenset({10}), # 10 adj 9, not adj to 4/5
shops=(),
)},
)
assert find_best_buy_candidate(state, cfg) is None
def test_none_when_no_opponents(self, make_state, cfg):
state = make_state(plots=frozenset({4, 5}))
assert find_best_buy_candidate(state, cfg) is None
|