Make an absent chiamata bidder pass instead of bidding randomly
CI / Build and push docker image (push) Successful in 1m37s
CI / Build and push docker image (push) Successful in 1m37s
The auction timeout bid a random legal rank, which could hand the auction (and the call) to a disconnected player. An absent bidder now always passes; only the last player standing before any bid cannot pass, and is made to bid the ace - its suit is picked at random by the existing call timeout. This keeps a deal from stalling without a caller while never letting an absent player outbid someone. The deadline log line now says which of the two happened.
This commit is contained in:
7 files changed
+121
-38
No files matched your search
@@ -240,18 +240,43 @@ class AuctionTest(unittest.TestCase):
|
||||
self.assertEqual(63, view["legal_bids"]["points_min"])
|
||||
self.assertEqual(120, view["legal_bids"]["points_max"])
|
||||
|
||||
def test_auto_bid_bids_or_passes(self) -> None:
|
||||
def test_auto_bid_always_passes_when_legal(self) -> None:
|
||||
state = started_state()
|
||||
rules.auto_bid(state, random.Random(1))
|
||||
assert state.auction is not None
|
||||
self.assertIsNotNone(state.auction.current)
|
||||
# The auction keeps moving and eventually concludes.
|
||||
for _ in range(50):
|
||||
if state.phase != PHASE_AUCTION:
|
||||
break
|
||||
rules.auto_bid(state, random.Random(2))
|
||||
rules.auto_bid(state)
|
||||
# Seat 1 passes: nobody has bid and the turn moves on.
|
||||
self.assertEqual([1], state.auction.passed)
|
||||
self.assertIsNone(state.auction.current)
|
||||
self.assertEqual(2, state.auction.turn)
|
||||
# An absent bidder still passes when there is a standing bid.
|
||||
rules.bid_rank(state, "p2", 10)
|
||||
rules.auto_bid(state)
|
||||
self.assertEqual([1, 3], state.auction.passed)
|
||||
assert state.auction.current is not None
|
||||
self.assertEqual(10, state.auction.current.rank)
|
||||
|
||||
def test_auto_bid_passes_at_the_point_stage(self) -> None:
|
||||
state = started_state()
|
||||
rules.bid_rank(state, "p1", 2)
|
||||
rules.bid_points(state, "p2", 62)
|
||||
rules.auto_bid(state) # seat 3
|
||||
assert state.auction is not None
|
||||
self.assertIn(3, state.auction.passed)
|
||||
assert state.auction.current is not None
|
||||
self.assertEqual(62, state.auction.current.points)
|
||||
|
||||
def test_auto_bid_forced_to_call_the_ace(self) -> None:
|
||||
state = started_state()
|
||||
for seat in (1, 2, 3, 4):
|
||||
rules.pass_auction(state, f"p{seat}")
|
||||
# Seat 0 is the last one standing and nobody has bid yet: the
|
||||
# forced auto-bid calls the ace.
|
||||
rules.auto_bid(state)
|
||||
self.assertEqual(PHASE_CALLING, state.phase)
|
||||
self.assertIsNotNone(state.caller)
|
||||
self.assertEqual(0, state.caller)
|
||||
assert state.auction is not None and state.auction.current is not None
|
||||
self.assertEqual(1, state.auction.current.rank)
|
||||
self.assertEqual(61, state.declared_target)
|
||||
|
||||
|
||||
class CallTest(unittest.TestCase):
|
||||
@@ -543,7 +568,7 @@ class ScoringTest(unittest.TestCase):
|
||||
moves = 0
|
||||
while state.phase != PHASE_FINISHED and moves < 5000:
|
||||
if state.phase == PHASE_AUCTION:
|
||||
rules.auto_bid(state, rng)
|
||||
rules.auto_bid(state)
|
||||
elif state.phase == PHASE_CALLING:
|
||||
rules.auto_call(state, rng)
|
||||
else:
|
||||
|
||||
Reference in new issue
Block a user