def hand_with_complex_runs(): """Multiple suits, not in order, overlapping runs Should find 7 runs: (3H, 4H, 5H), (4H, 5H, 6H), (5H, 6H, 7H), (3H, 4H, 5H, 6H), (4H, 5H, 6H, 7H), (3H, 4H, 5H, 6H, 7H), (9C, 10C, JC) """ hand = Hand() hand.add(Card(rank=Rank.ACE, suit=Suit.DIAMOND)) hand.add(Card(rank=Rank.ACE, suit=Suit.HEART)) hand.add(Card(rank=Rank.THREE, suit=Suit.HEART)) hand.add(Card(rank=Rank.SEVEN, suit=Suit.HEART)) hand.add(Card(rank=Rank.FOUR, suit=Suit.HEART)) hand.add(Card(rank=Rank.SIX, suit=Suit.HEART)) hand.add(Card(rank=Rank.JACK, suit=Suit.CLUB)) hand.add(Card(rank=Rank.FIVE, suit=Suit.HEART)) hand.add(Card(rank=Rank.TEN, suit=Suit.SPADE)) hand.add(Card(rank=Rank.NINE, suit=Suit.CLUB)) hand.add(Card(rank=Rank.TEN, suit=Suit.CLUB)) yield hand
def test_small_hand_is_not_complete(): hand = Hand() hand.add(Card(rank=Rank.JACK, suit=Suit.HEART)) # 0: JH hand.add(Card(rank=Rank.QUEEN, suit=Suit.HEART)) # 1: QH md = MeldDetector(*hand.cards) assert(md.is_complete_hand == False)
def test_sets_must_be_three_long_to_count(): hand = Hand() hand.add(Card(rank=Rank.JACK, suit=Suit.HEART)) # 0: JH hand.add(Card(rank=Rank.JACK, suit=Suit.DIAMOND)) # 1: JD md = MeldDetector(*hand.cards) md._detect_all_melds() assert(len(md._melds) == 0)
def test_runs_must_be_same_suit(): hand = Hand() hand.add(Card(rank=Rank.JACK, suit=Suit.HEART)) hand.add(Card(rank=Rank.QUEEN, suit=Suit.HEART)) hand.add(Card(rank=Rank.KING, suit=Suit.CLUB)) md = MeldDetector(*hand.cards) md._detect_all_melds() assert(len(md._melds) == 0)
def hand_with_sets(): """A hand with two sets. Should find 6 sets: (QH, QC, QD) (2S, 2H, 2D, 2C) - 5 permutations of this """ hand = Hand() for card in Card.from_text( "JH", "QH", "QC", "QD", "2S", "3C", "2H", "6S", "2D", "2C" ): hand.add(card) yield hand
def __init__(self, contestant_id: str = None, handtype: type = None): """Create a new Player using the [optionally] specified type of Hand. Args: contestant_id (str): [optional] ID value of the entity operating this player handtype (Hand subclass): [optional] Allows Hand classes with different behaviors (e.g. HandWithMelds) to be used by Player """ self.game = None self.contestant_id = contestant_id if handtype is None: self.hand = Hand() else: if issubclass(handtype, Hand): self.hand = handtype() else: raise PylgrumInternalError( "Type {} is not a ".format(handtype) + "subclass of Hand.")
def hand_with_simple_sets_and_runs(): """A hand with non-overlapping sets and runs. Should find 6 melds: 2C 2S 2H (1 set) 4D 5D 6D (1 run) 9S 10S JS (1 set) 4C This hand should have 4 points of deadwood (1 deadwood card) """ hand = Hand() for card in Card.from_text( "2C", "2S", "2H", "4D", "5D", "6D", "9S", "10S", "JS", "4C" ): hand.add(card) yield hand
def test_too_many_cards(self): """Implicitly tests the add() override in Hand, too.""" h = Hand() self.assertEqual(h.size(), 0) h.add(Card(rank=Rank.QUEEN, suit=Suit.HEART)) # 0 : QH h.add(Card(rank=Rank.JACK, suit=Suit.DIAMOND)) # 1 : JD h.add(Card(rank=Rank.ACE, suit=Suit.CLUB)) # 2 : AC h.add(Card(rank=Rank.KING, suit=Suit.SPADE)) # 3 : KS h.add(Card(rank=Rank.TWO, suit=Suit.HEART)) # 4 : 2H h.add(Card(rank=Rank.THREE, suit=Suit.DIAMOND)) # 5 : 3D h.add(Card(rank=Rank.FOUR, suit=Suit.CLUB)) # 6 : 4C h.add(Card(rank=Rank.FIVE, suit=Suit.SPADE)) # 7 : 5S h.add(Card(rank=Rank.TEN, suit=Suit.HEART)) # 8 : 10H h.add(Card(rank=Rank.NINE, suit=Suit.DIAMOND)) # 9 : 9D h.add(Card(rank=Rank.EIGHT, suit=Suit.CLUB)) # 10: 8C self.assertEqual(h.size(), 11) ## a full hand with self.assertRaises(OverdealtHandError): h.add(Card(rank=Rank.SEVEN, suit=Suit.SPADE))
def hand_with_complex_sets_and_runs(): """A hand with overlapping sets and runs. Should find 10 melds: 2C 2S 2H 2D (5 permutations of set) 3D 4D 5D (3 perms of run (including 2 above): 234, 345, 2345) 3S (1 set - 333) 3C AC (1 run - A23 (2 is above)) This hand should have 0 points of deadwood (0 deadwood cards) """ hand = Hand() for card in Card.from_text( "2C", "2S", "2H", "2D", "3D", "4D", "5D", "3S", "3C", "AC" ): hand.add(card) yield hand
def test_optimal_meld_scenario_8(): h = Hand() for card in Card.from_text( "4C", "4S", "3S", "2S", "5H", "4H", "3H", "AH", "3D", "2D" ): h.add(card) ## in this scenario, there are two equally optimal outcomes optimal_expected_option1 = [ Meld(Card.from_text("4C", "4S", "4H")), Meld(Card.from_text("3H", "3S", "3D")) ] optimal_expected_option2 = [ Meld(Card.from_text("4S", "3S", "2S")), Meld(Card.from_text("5H", "4H", "3H")) ] md = MeldDetector(*h.cards) md.detect_optimal_melds() assert(len(md.optimal_hand.melds) == len(optimal_expected_option1)) # works for either is_option_1 = True is_option_2 = True for expected_meld in optimal_expected_option1: if expected_meld not in md.optimal_hand.melds: is_option_1 = False for expected_meld in optimal_expected_option2: if expected_meld not in md.optimal_hand.melds: is_option_2 = False assert(not (is_option_1 and is_option_2)) #highlander principle assert(is_option_1 or is_option_2) # b/c the two are equiv. this is true regardless of option assert(md.optimal_hand.deadwood_value == 10) assert(md.optimal_hand.deadwood_count == 4)
def hand_with_simple_runs(): """A simple, same-suit, in-order hand with two runs. Should find two runs: (JH, QH, KH) (AS, 2S, 3S) """ hand = Hand() hand.add(Card(rank=Rank.JACK, suit=Suit.HEART)) # 0: JH hand.add(Card(rank=Rank.QUEEN, suit=Suit.HEART)) # 1: QH hand.add(Card(rank=Rank.KING, suit=Suit.HEART)) # 2: KH hand.add(Card(rank=Rank.KING, suit=Suit.SPADE)) # 3: KS hand.add(Card(rank=Rank.TWO, suit=Suit.HEART)) # 4: 2H hand.add(Card(rank=Rank.THREE, suit=Suit.DIAMOND)) # 5: 3D hand.add(Card(rank=Rank.ACE, suit=Suit.SPADE)) # 6: AS hand.add(Card(rank=Rank.TWO, suit=Suit.SPADE)) # 7: 2S hand.add(Card(rank=Rank.THREE, suit=Suit.SPADE)) # 8: 3S hand.add(Card(rank=Rank.NINE, suit=Suit.DIAMOND)) # 9: 9D yield hand
def test_optimal_meld_scenario_9(): # this is a relatively simple scenario - only one card is overused h = Hand() for card in Card.from_text( "6D", "6C", "6H", "2H", "3H", "4H", "2S", "2C" ): h.add(card) optimal_expected = [ Meld(Card.from_text("6D", "6C", "6H")), Meld(Card.from_text("2H", "3H", "4H")) ] md = MeldDetector(*h.cards) md.detect_optimal_melds() assert(len(md.optimal_hand.melds) == len(optimal_expected)) for expected_meld in optimal_expected: assert(expected_meld in md.optimal_hand.melds) assert(md.optimal_hand.deadwood_value == 4) assert(md.optimal_hand.deadwood_count == 2)
def test_optimal_meld_scenario_6(): h = Hand() for card in Card.from_text( "4S", "3S", "2S", "AS", "3H", "2H", "AH", "4D", "3D", "2D" ): h.add(card) optimal_expected = [ Meld(Card.from_text("4S", "3S", "2S", "AS")), Meld(Card.from_text("3H", "2H", "AH")), Meld(Card.from_text("4D", "3D", "2D")) ] md = MeldDetector(*h.cards) md.detect_optimal_melds() assert(len(md.optimal_hand.melds) == len(optimal_expected)) for expected_meld in optimal_expected: assert(expected_meld in md.optimal_hand.melds) assert(md.optimal_hand.deadwood_value == 0) assert(md.optimal_hand.deadwood_count == 0)
def test_optimal_meld_scenario_1(): h = Hand() for card in Card.from_text( "10S", "9S", "8S", "8H", "9C", "8C", "7C", "6C", "5C", "KD" ): h.add(card) optimal_expected = [ Meld(Card.from_text("10S", "9S", "8S")), Meld(Card.from_text("9C", "8C", "7C", "6C", "5C")) ] md = MeldDetector(*h.cards) md.detect_optimal_melds() assert(len(md.optimal_hand.melds) == len(optimal_expected)) for expected_meld in optimal_expected: assert(expected_meld in md.optimal_hand.melds) assert(md.optimal_hand.deadwood_value == 18) assert(md.optimal_hand.deadwood_count == 2)
def hand_with_overlapping_sets_and_runs(): """A hand with obviously overlapping sets and runs. Should find 6 melds: 2C 2S 2H 2D (5 permutations of set) 4D 5D 6D (1 run) 8S 10S JS This hand should have 28 points of deadwood (3 deadwood cards) The optimal sets from this hand are: 2C 2S 2H 2D 4D 5D 6D """ hand = Hand() for card in Card.from_text( "2C", "2S", "2H", "2D", "4D", "5D", "6D", "8S", "10S", "JS" ): hand.add(card) yield hand