Пример #1
0
 def test_invalid_meld_init(self):
     m = Meld()
     with self.assertRaises(InvalidMeldError):
         m = Meld(Card(rank=Rank.TWO, suit=Suit.HEART),
                  Card(rank=Rank.SIX, suit=Suit.CLUB))
     self.assertFalse(m.all_same_rank)
     self.assertFalse(m.all_same_suit)
     self.assertFalse(m.is_run)
     self.assertFalse(m.is_set)
     self.assertFalse(m.complete)
     self.assertEqual(m.size(), 0)  # failed init should have emptied meld
Пример #2
0
def test_optimal_melds_chosen_from_hand_with_overlapping_melds(hand_with_overlapping_sets_and_runs):
    expected_melds = [
        Meld(Card.from_text("2C", "2S", "2D", "2H")),
        Meld(Card.from_text("4D", "5D", "6D"))
    ]
    md = MeldDetector(*hand_with_overlapping_sets_and_runs.cards)
    md.detect_optimal_melds()
    assert(len(md.optimal_hand.melds) == 2)
    for meld in expected_melds:
        assert(meld in md.optimal_hand.melds)
    assert(md.optimal_hand.deadwood_count == 3)
    assert(md.optimal_hand.deadwood_value == 28)
Пример #3
0
def test_optimal_melds_chosen_from_complex_set(hand_with_complex_sets_and_runs):
    expected_melds = [
        Meld(Card.from_text("2D", "2S", "2H")),
        Meld(Card.from_text("3D", "4D", "5D")),
        Meld(Card.from_text("AC", "2C", "3C"))
    ]
    md = MeldDetector(*hand_with_complex_sets_and_runs.cards)
    md.detect_optimal_melds()
    assert(len(md.optimal_hand.melds) == 3)
    for meld in expected_melds:
        assert(meld in md.optimal_hand.melds)
    assert(md.optimal_hand.deadwood_value == 3)
Пример #4
0
def test_optimal_melds_chosen_from_simple_hand(hand_with_simple_sets_and_runs):
    expected_melds = [
        Meld(Card.from_text("2C", "2S", "2H")),
        Meld(Card.from_text("9S", "10S", "JS")),
        Meld(Card.from_text("4D", "5D", "6D"))
    ]
    md = MeldDetector(*hand_with_simple_sets_and_runs.cards)
    md.detect_optimal_melds()
    assert(len(md.optimal_hand.melds) == 3)
    for meld in expected_melds:
        assert(meld in md.optimal_hand.melds)
    assert(md.optimal_hand.deadwood_count == 1)
    assert(md.optimal_hand.deadwood_value == 4)
Пример #5
0
    def remove_from_meld(self, meld: Meld, card: Card) -> None:
        """Remove a card from a meld.

        Args:
            meld (Meld): the meld to add to
            card (Card): the card to add

        Side effects:
         * Updates _card_to_meld_id map accordingly
         * Removes entry from _card_to_meld_id if empty
        """
        self._card_to_meld_id[card].remove(id(meld))
        if len(self._card_to_meld_id[card]) == 0:
            del self._card_to_meld_id[card]
        meld.remove(meld.find(card))
Пример #6
0
    def create_meld(self, *cards) -> Meld:
        """Create a new [potential] meld within the hand.

        Args:
            *cards (Card list): [optional] cards to add to the meld

        Any cards added must be valid - an attempt to create an invalid meld
        will fail completely (i.e. no cards will be added, no meld created).

        Raises InvalidMeldError.
        """
        # note: no check against redundant melds
        new_meld = Meld()
        added = []
        valid = True
        for card in cards:
            try:
                self.add_to_meld(new_meld, card)
            except InvalidMeldError:
                valid = False
            else:
                added.append(card)
        if not valid:
            for card in added:
                self.remove_from_meld(new_meld, card)
            raise InvalidMeldError("non-meld passed " +
                                   "to HandWithMeld:create_meld()")

        self._melds.append(new_meld)
        self._meld_id_to_meld[id(new_meld)] = new_meld
        return new_meld
Пример #7
0
 def test_not_same_rank(self):
     m = Meld(Card(rank=Rank.TWO, suit=Suit.HEART),
              Card(rank=Rank.THREE, suit=Suit.HEART))
     self.assertFalse(m.all_same_rank)
     self.assertTrue(m.all_same_suit)
     self.assertFalse(m.is_run)
     self.assertFalse(m.is_set)
     self.assertFalse(m.complete)
Пример #8
0
    def add_to_meld(self, meld: Meld, card: Card) -> None:
        """Add a card to a meld.

        Args:
            meld (Meld): the meld to add to
            card (Card): the card to add

        Side effects:
            Updates _card_to_meld_id map accordingly

        Raises InvalidMeldError.
        """
        meld.add(card)
        if card in self._card_to_meld_id.keys():
            self._card_to_meld_id[card].add(id(meld))
        else:
            self._card_to_meld_id[card] = set([id(meld)])
Пример #9
0
 def test_partial_set(self):
     m = Meld(Card(rank=Rank.TWO, suit=Suit.HEART),
              Card(rank=Rank.TWO, suit=Suit.DIAMOND))
     self.assertTrue(m.all_same_rank)
     self.assertFalse(m.all_same_suit)
     self.assertFalse(m.is_run)
     self.assertFalse(m.is_set)
     self.assertFalse(m.complete)
Пример #10
0
    def test_add_sorts(self):
        c2 = Card(rank=Rank.TWO, suit=Suit.CLUB)
        c3 = Card(rank=Rank.THREE, suit=Suit.CLUB)
        c4 = Card(rank=Rank.FOUR, suit=Suit.CLUB)

        m = Meld(c2)
        m.add(c4)
        m.add(c3)
        self.assertFalse(m.all_same_rank)
        self.assertTrue(m.all_same_suit)
        self.assertTrue(m.is_run)
        self.assertFalse(m.is_set)
        self.assertTrue(m.complete)

        # cards were implicitly re-ordered by add()
        self.assertEqual(m.cards[0], c2)
        self.assertEqual(m.cards[1], c3)
        self.assertEqual(m.cards[2], c4)
Пример #11
0
    def test_large_valid_run_grows_to_inside_straight(self):
        """A run becomes incomplete after inside straight conversion."""
        m = Meld(Card(rank=Rank.TWO, suit=Suit.HEART),
                 Card(rank=Rank.THREE, suit=Suit.HEART),
                 Card(rank=Rank.FOUR, suit=Suit.HEART))
        self.assertTrue(m.all_same_suit)
        self.assertFalse(m.all_same_rank)
        self.assertTrue(m.is_run)
        self.assertFalse(m.is_set)
        self.assertTrue(m.complete)

        m.add(Card(rank=Rank.SIX, suit=Suit.HEART))

        self.assertEqual(m.size(), 4)
        self.assertTrue(m.all_same_suit)
        self.assertFalse(m.all_same_rank)
        self.assertFalse(m.is_run)
        self.assertFalse(m.is_set)
        self.assertFalse(m.complete)
Пример #12
0
    def test_singleton_add(self):
        """Test adding a card to a single-card partial meld.

        This is significant b/c until the 2nd card is added, any
        single-card partial meld is both a potential run and set.
        """
        m = Meld(Card(rank=Rank.KING, suit=Suit.CLUB))
        self.assertTrue(m.all_same_rank)
        self.assertTrue(m.all_same_suit)
        self.assertFalse(m.is_run)
        self.assertFalse(m.is_set)
        self.assertFalse(m.complete)

        m.add(Card(rank=Rank.TWO, suit=Suit.CLUB))
        self.assertFalse(m.all_same_rank)
        self.assertTrue(m.all_same_suit)
        self.assertFalse(m.is_run)
        self.assertFalse(m.is_set)
        self.assertFalse(m.complete)
Пример #13
0
    def test_invalid_add_does_not_break_complete_run(self):
        """A bad addition to a complete run doesn't break it."""
        m = Meld(Card(rank=Rank.TWO, suit=Suit.HEART),
                 Card(rank=Rank.THREE, suit=Suit.HEART),
                 Card(rank=Rank.FOUR, suit=Suit.HEART))
        self.assertTrue(m.all_same_suit)
        self.assertFalse(m.all_same_rank)
        self.assertTrue(m.is_run)
        self.assertFalse(m.is_set)
        self.assertTrue(m.complete)

        with self.assertRaises(InvalidMeldError):
            m.add(Card(rank=Rank.SIX, suit=Suit.CLUB))

        self.assertEqual(m.size(), 3)
        self.assertTrue(m.all_same_suit)
        self.assertFalse(m.all_same_rank)
        self.assertTrue(m.is_run)
        self.assertFalse(m.is_set)
        self.assertTrue(m.complete)
Пример #14
0
 def test_full_run(self):
     # these cards are intentionally out of order - order is not
     #  reliable for cards added at init time
     m = Meld(Card(rank=Rank.TWO, suit=Suit.HEART),
              Card(rank=Rank.FOUR, suit=Suit.HEART),
              Card(rank=Rank.THREE, suit=Suit.HEART))
     self.assertTrue(m.all_same_suit)
     self.assertFalse(m.all_same_rank)
     self.assertTrue(m.is_run)
     self.assertFalse(m.is_set)
     self.assertTrue(m.complete)
Пример #15
0
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)
Пример #16
0
def test_overlapping_set_and_run_detection(hand_with_complex_sets_and_runs):
    expected_melds = [
        Meld(Card.from_text("2C", "2S", "2D", "2H")),
        Meld(Card.from_text("2S", "2D", "2H")),
        Meld(Card.from_text("2C", "2D", "2H")),
        Meld(Card.from_text("2C", "2S", "2H")),
        Meld(Card.from_text("2C", "2S", "2D")),

        Meld(Card.from_text("2D", "3D", "4D")),
        Meld(Card.from_text("3D", "4D", "5D")),
        Meld(Card.from_text("2D", "3D", "4D", "5D")),

        Meld(Card.from_text("3D", "3S", "3C")),

        Meld(Card.from_text("AC", "2C", "3C")),
    ]
    md = MeldDetector(*hand_with_complex_sets_and_runs.cards)
    md._detect_all_melds()
    assert(len(md._melds) == 10)
    for meld in expected_melds:
        assert(meld in md._melds)
Пример #17
0
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)
Пример #18
0
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)
Пример #19
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)
Пример #20
0
    def test_invalid_set_add(self):
        m = Meld(Card(rank=Rank.TWO, suit=Suit.HEART),
                 Card(rank=Rank.TWO, suit=Suit.DIAMOND))
        self.assertTrue(m.all_same_rank)
        self.assertFalse(m.all_same_suit)
        self.assertFalse(m.is_run)
        self.assertFalse(m.is_set)
        self.assertFalse(m.complete)
        self.assertEqual(m.size(), 2)

        with self.assertRaises(InvalidMeldError):
            m.add(Card(rank=Rank.THREE, suit=Suit.CLUB))

        self.assertEqual(m.size(), 2)
Пример #21
0
def test_complex_run_detection(hand_with_complex_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)
    expected_melds = [
        Meld(Card.from_text("3H", "4H", "5H")),
        Meld(Card.from_text("4H", "5H", "6H")),
        Meld(Card.from_text("5H", "6H", "7H")),
        Meld(Card.from_text("3H", "4H", "5H", "6H")),
        Meld(Card.from_text("4H", "5H", "6H", "7H")),
        Meld(Card.from_text("3H", "4H", "5H", "6H", "7H")),
        Meld(Card.from_text("9C", "10C", "JC"))
    ]
    md = MeldDetector(*hand_with_complex_runs.cards)
    md._detect_all_melds()
    assert(len(md._melds) == 7)
    for meld in expected_melds:
        assert(meld in md._melds)
Пример #22
0
 def test_melds_are_equal_if_same_cards(self):
     m1 = Meld(Card.from_text("2H", "JH", "AH"))
     m2 = Meld(Card.from_text("AH", "2H", "JH"))
     self.assertEqual(m1, m2)
Пример #23
0
 def test_remove_last(self):
     """Test removing the last card in a meld (leaving it empty)."""
     c = Card(rank=Rank.KING, suit=Suit.CLUB)
     m = Meld(c)
     m.remove(m.find(c))