Files
poker_task1/tests/shortdeck/test_hand_evaluator.py
2025-09-24 16:54:52 +08:00

326 lines
14 KiB
Python

"""
Tests for Short Deck Hand Evaluator
"""
import pytest
from poker.card import Card, ShortDeckRank, Suit # 使用统一的Card类
from shortdeck.hand_evaluator import ShortDeckHandEvaluator
from shortdeck.hand_ranking import ShortDeckHandType, ShortDeckHandRanking
class TestShortDeckHandEvaluator:
"""Test cases for ShortDeckHandEvaluator class"""
def test_evaluate_hand_insufficient_cards(self):
"""Test evaluation with less than 5 cards"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.HEARTS),
Card(ShortDeckRank.QUEEN, Suit.DIAMONDS),
Card(ShortDeckRank.JACK, Suit.CLUBS)
]
with pytest.raises(ValueError, match="Need at least 5 cards"):
ShortDeckHandEvaluator.evaluate_hand(cards)
def test_evaluate_hand_exactly_five_cards(self):
"""Test evaluation with exactly 5 cards"""
# Royal flush
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.SPADES),
Card(ShortDeckRank.QUEEN, Suit.SPADES),
Card(ShortDeckRank.JACK, Suit.SPADES),
Card(ShortDeckRank.TEN, Suit.SPADES)
]
result = ShortDeckHandEvaluator.evaluate_hand(cards)
assert result.hand_type == ShortDeckHandType.ROYAL_FLUSH
def test_evaluate_hand_seven_cards(self):
"""Test evaluation with 7 cards - should find best 5"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.ACE, Suit.HEARTS),
Card(ShortDeckRank.ACE, Suit.DIAMONDS),
Card(ShortDeckRank.ACE, Suit.CLUBS), # Four Aces
Card(ShortDeckRank.KING, Suit.SPADES),
Card(ShortDeckRank.SIX, Suit.HEARTS),
Card(ShortDeckRank.SEVEN, Suit.DIAMONDS)
]
result = ShortDeckHandEvaluator.evaluate_hand(cards)
assert result.hand_type == ShortDeckHandType.FOUR_OF_A_KIND
assert result.key_ranks[0] == ShortDeckRank.ACE
def test_evaluate_five_cards_wrong_count(self):
"""Test evaluate5Cards with wrong number of cards"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.HEARTS)
]
with pytest.raises(ValueError, match="Must provide exactly 5 cards"):
ShortDeckHandEvaluator.evaluate_5_cards(cards)
def test_royal_flush(self):
"""Test royal flush detection"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.SPADES),
Card(ShortDeckRank.QUEEN, Suit.SPADES),
Card(ShortDeckRank.JACK, Suit.SPADES),
Card(ShortDeckRank.TEN, Suit.SPADES)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.ROYAL_FLUSH
assert result.key_ranks[0] == ShortDeckRank.ACE
def test_straight_flush(self):
"""Test straight flush detection"""
cards = [
Card(ShortDeckRank.KING, Suit.HEARTS),
Card(ShortDeckRank.QUEEN, Suit.HEARTS),
Card(ShortDeckRank.JACK, Suit.HEARTS),
Card(ShortDeckRank.TEN, Suit.HEARTS),
Card(ShortDeckRank.NINE, Suit.HEARTS)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.STRAIGHT_FLUSH
assert result.key_ranks[0] == ShortDeckRank.KING
def test_four_of_a_kind(self):
"""Test four of a kind detection"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.ACE, Suit.HEARTS),
Card(ShortDeckRank.ACE, Suit.DIAMONDS),
Card(ShortDeckRank.ACE, Suit.CLUBS),
Card(ShortDeckRank.KING, Suit.SPADES)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.FOUR_OF_A_KIND
assert result.key_ranks[0] == ShortDeckRank.ACE
assert result.key_ranks[1] == ShortDeckRank.KING # Kicker
def test_flush_beats_full_house(self):
"""Test that flush beats full house in short deck"""
# Flush
flush_cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.SPADES),
Card(ShortDeckRank.QUEEN, Suit.SPADES),
Card(ShortDeckRank.JACK, Suit.SPADES),
Card(ShortDeckRank.NINE, Suit.SPADES)
]
# Full house
full_house_cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.ACE, Suit.HEARTS),
Card(ShortDeckRank.ACE, Suit.DIAMONDS),
Card(ShortDeckRank.KING, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.HEARTS)
]
flush_result = ShortDeckHandEvaluator.evaluate_5_cards(flush_cards)
full_house_result = ShortDeckHandEvaluator.evaluate_5_cards(full_house_cards)
assert flush_result.hand_type == ShortDeckHandType.FLUSH
assert full_house_result.hand_type == ShortDeckHandType.FULL_HOUSE
assert flush_result > full_house_result # Flush beats Full House in Short Deck!
def test_full_house(self):
"""Test full house detection"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.ACE, Suit.HEARTS),
Card(ShortDeckRank.ACE, Suit.DIAMONDS),
Card(ShortDeckRank.KING, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.HEARTS)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.FULL_HOUSE
assert result.key_ranks[0] == ShortDeckRank.ACE # Trips
assert result.key_ranks[1] == ShortDeckRank.KING # Pair
def test_flush(self):
"""Test flush detection"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.SPADES),
Card(ShortDeckRank.QUEEN, Suit.SPADES),
Card(ShortDeckRank.JACK, Suit.SPADES),
Card(ShortDeckRank.NINE, Suit.SPADES) # Not a straight
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.FLUSH
assert result.key_ranks[0] == ShortDeckRank.ACE
def test_straight_regular(self):
"""Test regular straight detection"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.HEARTS),
Card(ShortDeckRank.QUEEN, Suit.DIAMONDS),
Card(ShortDeckRank.JACK, Suit.CLUBS),
Card(ShortDeckRank.TEN, Suit.SPADES)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.STRAIGHT
assert result.key_ranks[0] == ShortDeckRank.ACE
def test_straight_low_wheel(self):
"""Test short deck wheel straight: A-6-7-8-9"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.NINE, Suit.HEARTS),
Card(ShortDeckRank.EIGHT, Suit.DIAMONDS),
Card(ShortDeckRank.SEVEN, Suit.CLUBS),
Card(ShortDeckRank.SIX, Suit.SPADES)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.STRAIGHT
assert result.key_ranks[0] == ShortDeckRank.NINE # 9-high straight in short deck wheel
def test_three_of_a_kind(self):
"""Test three of a kind detection"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.ACE, Suit.HEARTS),
Card(ShortDeckRank.ACE, Suit.DIAMONDS),
Card(ShortDeckRank.KING, Suit.SPADES),
Card(ShortDeckRank.QUEEN, Suit.HEARTS)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.THREE_OF_A_KIND
assert result.key_ranks[0] == ShortDeckRank.ACE
assert ShortDeckRank.KING in result.key_ranks
assert ShortDeckRank.QUEEN in result.key_ranks
def test_two_pair(self):
"""Test two pair detection"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.ACE, Suit.HEARTS),
Card(ShortDeckRank.KING, Suit.DIAMONDS),
Card(ShortDeckRank.KING, Suit.SPADES),
Card(ShortDeckRank.QUEEN, Suit.HEARTS)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.TWO_PAIR
assert result.key_ranks[0] == ShortDeckRank.ACE # Higher pair first
assert result.key_ranks[1] == ShortDeckRank.KING # Lower pair second
assert result.key_ranks[2] == ShortDeckRank.QUEEN # Kicker
def test_one_pair(self):
"""Test one pair detection"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.ACE, Suit.HEARTS),
Card(ShortDeckRank.KING, Suit.DIAMONDS),
Card(ShortDeckRank.QUEEN, Suit.SPADES),
Card(ShortDeckRank.JACK, Suit.HEARTS)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.ONE_PAIR
assert result.key_ranks[0] == ShortDeckRank.ACE
assert ShortDeckRank.KING in result.key_ranks
assert ShortDeckRank.QUEEN in result.key_ranks
assert ShortDeckRank.JACK in result.key_ranks
def test_high_card(self):
"""Test high card detection"""
cards = [
Card(ShortDeckRank.ACE, Suit.SPADES),
Card(ShortDeckRank.KING, Suit.HEARTS),
Card(ShortDeckRank.QUEEN, Suit.DIAMONDS),
Card(ShortDeckRank.JACK, Suit.CLUBS),
Card(ShortDeckRank.NINE, Suit.HEARTS) # Not a straight (missing 10)
]
result = ShortDeckHandEvaluator.evaluate_5_cards(cards)
assert result.hand_type == ShortDeckHandType.HIGH_CARD
assert result.key_ranks[0] == ShortDeckRank.ACE
def test_is_straight_regular_straights(self):
"""Test isStraight with regular straights"""
# T-J-Q-K-A
ranks1 = [ShortDeckRank.ACE, ShortDeckRank.KING, ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.TEN]
is_straight1, high1 = ShortDeckHandEvaluator.is_straight(ranks1)
assert is_straight1 == True
assert high1 == ShortDeckRank.ACE
# 6-7-8-9-T
ranks2 = [ShortDeckRank.TEN, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN, ShortDeckRank.SIX]
is_straight2, high2 = ShortDeckHandEvaluator.is_straight(ranks2)
assert is_straight2 == True
assert high2 == ShortDeckRank.TEN
def test_is_straight_wheel(self):
"""Test isStraight with short deck wheel: A-6-7-8-9"""
ranks = [ShortDeckRank.ACE, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN, ShortDeckRank.SIX]
is_straight, high = ShortDeckHandEvaluator.is_straight(ranks)
assert is_straight == True
assert high == ShortDeckRank.NINE # 9-high straight in short deck wheel
def test_is_straight_not_straight(self):
"""Test isStraight with non-straight"""
ranks = [ShortDeckRank.ACE, ShortDeckRank.KING, ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.NINE]
is_straight, high = ShortDeckHandEvaluator.is_straight(ranks)
assert is_straight == False
assert high is None
def test_is_straight_insufficient_cards(self):
"""Test isStraight with less than 5 unique ranks"""
ranks = [ShortDeckRank.ACE, ShortDeckRank.ACE, ShortDeckRank.KING, ShortDeckRank.KING] # Only 2 unique
is_straight, high = ShortDeckHandEvaluator.is_straight(ranks)
assert is_straight == False
assert high is None
def test_evaluate_from_input_valid(self):
"""Test evaluateFromInput with valid input"""
# Four of a kind
result = ShortDeckHandEvaluator.evaluate_from_input("AsAhAdAc Ks")
assert result.hand_type == ShortDeckHandType.FOUR_OF_A_KIND
assert result.key_ranks[0] == ShortDeckRank.ACE
def test_evaluate_from_input_seven_cards(self):
"""Test evaluateFromInput with 7 cards"""
result = ShortDeckHandEvaluator.evaluate_from_input("AsAhAdAc KsQsJs")
assert result.hand_type == ShortDeckHandType.FOUR_OF_A_KIND
assert result.key_ranks[0] == ShortDeckRank.ACE
def test_evaluate_from_input_invalid_cards(self):
"""Test evaluateFromInput with invalid cards (should reject 2,3,4,5)"""
with pytest.raises(ValueError, match="Invalid rank for short deck"):
ShortDeckHandEvaluator.evaluate_from_input("2s3s4s5s6s")
def test_all_possible_straights(self):
"""Test all possible straights in short deck"""
# All possible short deck straights:
# A-6-7-8-9, 6-7-8-9-T, 7-8-9-T-J, 8-9-T-J-Q, 9-T-J-Q-K, T-J-Q-K-A
straight_combinations = [
([ShortDeckRank.ACE, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN, ShortDeckRank.SIX], ShortDeckRank.NINE),
([ShortDeckRank.TEN, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN, ShortDeckRank.SIX], ShortDeckRank.TEN),
([ShortDeckRank.JACK, ShortDeckRank.TEN, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN], ShortDeckRank.JACK),
([ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.TEN, ShortDeckRank.NINE, ShortDeckRank.EIGHT], ShortDeckRank.QUEEN),
([ShortDeckRank.KING, ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.TEN, ShortDeckRank.NINE], ShortDeckRank.KING),
([ShortDeckRank.ACE, ShortDeckRank.KING, ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.TEN], ShortDeckRank.ACE),
]
for ranks, expected_high in straight_combinations:
is_straight, high = ShortDeckHandEvaluator.is_straight(ranks)
assert is_straight == True, f"Failed to detect straight: {[r.symbol for r in ranks]}"
assert high == expected_high, f"Wrong high card for {[r.symbol for r in ranks]}: expected {expected_high.symbol}, got {high.symbol if high else None}"