Ejemplo n.º 1
0
class TestDeck(unittest.TestCase):
    def setUp(self):
        super().setUp()
        self.deck = Deck()

    def get_all_cards_in_deck(self):
        cards = []
        for rank in Rank:
            for suit in Suit:
                cards.append(Card(rank, suit))
        return cards

    def test_init(self):
        self.assertEqual(sorted(self.deck.cards),
                         sorted(self.get_all_cards_in_deck()))
        self.assertEqual(len(self.deck.cards), 52)
        self.assertFalse(self.deck.dealt)

    def test_deal(self):
        self.assertFalse(self.deck.dealt)
        player_1, player_2 = self.deck.deal()
        self.assertTrue(self.deck.dealt)
        self.assertEqual(len(player_1), 26)
        self.assertEqual(len(player_2), 26)

        # The hands combined should be the contents of a deck
        self.assertEqual(sorted(player_1 + player_2),
                         sorted(self.get_all_cards_in_deck()))

    def test_double_deal_raise_error(self):
        _, _ = self.deck.deal()
        with self.assertRaises(DoubleDealtDeckError):
            _, _ = self.deck.deal()
Ejemplo n.º 2
0
 def test_simulate_game_empty_deck(self):
     mock_deck = Deck()
     mock_deck.deal = MagicMock(return_value=([], []))
     game = Egrt(0.5, deck=mock_deck)
     winner, turns = game.simulate_game()
     self.assertEqual(winner, 'T')
     self.assertEqual(turns, 0)
Ejemplo n.º 3
0
 def test_simulate_queen_wins(self):
     mock_deck = Deck()
     mock_deck.deal = MagicMock(return_value=([
         Card(Rank.SIX, Suit.DIAMOND),
         Card(Rank.SEVEN, Suit.CLUB),
         Card(Rank.EIGHT, Suit.SPADE)
     ], [Card(Rank.QUEEN, Suit.HEART),
         Card(Rank.TWO, Suit.SPADE)]))
     game = Egrt(0.5, deck=mock_deck)
     winner, turns = game.simulate_game()
     self.assertEqual(winner, 'B')
     self.assertEqual(turns, 4)
Ejemplo n.º 4
0
 def test_simulate_game_king_and_jack_win(self):
     mock_deck = Deck()
     mock_deck.deal = MagicMock(return_value=(
         [Card(Rank.KING, Suit.CLUB),
          Card(Rank.JACK, Suit.CLUB)], [
              Card(Rank.TWO, Suit.CLUB),
              Card(Rank.SEVEN, Suit.DIAMOND),
              Card(Rank.FOUR, Suit.CLUB),
              Card(Rank.NINE, Suit.SPADE)
          ]))
     game = Egrt(0.5, deck=mock_deck)
     winner, turns = game.simulate_game()
     self.assertEqual(winner, 'A')
     self.assertEqual(turns, 6)
Ejemplo n.º 5
0
class Egrt(object):
    def __init__(self, a_slap_probability, deck=None):
        if a_slap_probability < 0 or a_slap_probability >= 1:
            raise ValueError('a_slap_probability must be between 0 and 1')
        self.a_slap_probability = a_slap_probability

        if deck is None:
            self.deck = Deck()
        else:
            if isinstance(deck, Deck):
                self.deck = deck
            else:
                raise TypeError('deck must be of type Deck')

        self.top_card = None
        self.prev_card = None
        self.pile = deque()

        hand_1, hand_2 = self.deck.deal()
        self.a_player = deque(hand_1)
        self.b_player = deque(hand_2)

        self.a_turn = True  # the A player always goes first

        # When chances_remaining is None, a player is not responding to
        # the other player's face card. When it becomes 0, the
        # player responding to the face card has lost the hand
        # and chances_remaining should be reset to None.
        self.chances_remaining = None

        self.counter = 0

    def simulate_game(self, debug_print=False):
        while not self.game_over():
            self.counter += 1
            if debug_print:
                sleep(SLEEP_DELAY)
                print()
                print('turn: {}'.format(self.counter))
                print('A: {}, B: {}, pile: {}'.format(len(self.a_player),
                                                      len(self.b_player),
                                                      self.pile_size()))
            if self.a_turn:
                new_card = self.a_player.popleft()
                if debug_print:
                    print('A plays {}'.format(new_card))
            else:
                new_card = self.b_player.popleft()
                if debug_print:
                    print('B plays {}'.format(new_card))

            # Need to check if a slap happened before pushing new_card to
            # top_card so that it is possible to check for sandwiches.
            slap_happened = self.is_slap(new_card)

            # Push prev_card to pile, top_card to prev_card, and new_card
            # to top_card
            if self.prev_card is not None:
                self.pile.append(self.prev_card)
            if self.top_card is not None:
                self.prev_card = self.top_card
            self.top_card = new_card

            if slap_happened:
                if self.a_won_slap():
                    if debug_print:
                        sleep(SLEEP_DELAY)
                        print('A wins slap')
                    self.add_cards_to_hand(self.a_player)
                    self.a_turn = True
                else:
                    if debug_print:
                        sleep(SLEEP_DELAY)
                        print('B wins slap')
                    self.add_cards_to_hand(self.b_player)
                    self.a_turn = False
                continue

            if self.top_card.is_face_card():
                self.set_chances_remaining()
                self.a_turn = not self.a_turn
                continue

            if self.chances_remaining is None:
                self.a_turn = not self.a_turn
                continue

            self.chances_remaining -= 1

            # Whichever player is up just ran out of turns
            if self.chances_remaining == 0:
                # If a just lost the turn, add the cards to b
                if self.a_turn:
                    self.add_cards_to_hand(self.b_player)
                    if debug_print:
                        sleep(SLEEP_DELAY)
                        print('B wins hand')
                else:  # if b just lost the turn, add cards to a
                    self.add_cards_to_hand(self.a_player)
                    if debug_print:
                        sleep(SLEEP_DELAY)
                        print('A wins hand')
                self.a_turn = not self.a_turn

        if len(self.a_player) == 0 and len(self.b_player) == 0:
            victor = 'T'
        elif len(self.b_player) == 0:
            victor = 'A'
        else:
            victor = 'B'

        return victor, self.counter

    def game_over(self):
        return len(self.a_player) == 0 or len(self.b_player) == 0

    def is_slap(self, new_card):
        # Can't be a slap if it is the first card in the pile
        if self.top_card is None:
            return False

        # check classic slap
        if self.top_card == new_card:
            return True

        # check Queen / King slap
        if (self.top_card.rank == Rank.QUEEN and new_card.rank == Rank.KING
                or self.top_card.rank == Rank.KING
                and new_card.rank == Rank.QUEEN):
            return True

        # check sandwich slap
        if self.prev_card is not None and self.prev_card == new_card:
            return True
        else:
            return False

    def a_won_slap(self):
        return True if random() < self.a_slap_probability else False

    def add_cards_to_hand(self, hand):
        if self.top_card is None or self.prev_card is None:
            raise ValueError(
                'Must be at least two cards to call add_cards_to_hand')

        hand.extend(self.pile)
        hand.append(self.prev_card)
        hand.append(self.top_card)

        self.pile.clear()
        self.prev_card = None
        self.top_card = None
        self.chances_remaining = None

    def set_chances_remaining(self):
        """
        When a face card is played, the number of chances remaining needs to
        be set depending on the value of the face card.

        This method assumes that the face card that has already been played
        from which the value is to be set has already been assigned to
        self.top_card.

        This method throws an error if the top_card is not a face card because
        there are no chances remaining when the card is not a face card.
        """
        if not self.top_card.is_face_card():
            raise ValueError(
                'top_card must be a face card to set chances_remaining')

        if self.top_card.rank == Rank.ACE:
            self.chances_remaining = 4
        elif self.top_card.rank == Rank.KING:
            self.chances_remaining = 3
        elif self.top_card.rank == Rank.QUEEN:
            self.chances_remaining = 2
        elif self.top_card.rank == Rank.JACK:
            self.chances_remaining = 1
        else:
            raise NotImplementedError('THIS SHOULD NEVER HAPPEN')

    def pile_size(self):
        size = 0
        if self.top_card is not None:
            size += 1
        if self.prev_card is not None:
            size += 1
        return size + len(self.pile)
Ejemplo n.º 6
0
class War(object):
    """
    Simulates a game of war. The order in which the players' cards stack in
    each hand is nondeterministic.

    The game is over when either of the players runs out of cards. This is the
    case even if there are left over cards (e.g. the last card a player puts
    down results in a tie).
    """
    def __init__(self, deck=None):
        if deck is None:
            self.deck = Deck()
        else:
            if isinstance(deck, Deck):
                self.deck = deck
            else:
                raise TypeError('deck must be of type Deck')

        hand_1, hand_2 = self.deck.deal()
        self.a_player = deque(hand_1)
        self.b_player = deque(hand_2)
        self.pile = deque()
        self.counter = 0

    def simulate_game(self, debug_print=False):
        while not self.game_over():
            a_card = self.a_player.popleft()
            b_card = self.b_player.popleft()
            a_on_top = (randint(0, 1) == 0)

            if a_card > b_card:
                if len(self.pile) > 0:
                    self.append_pile(self.a_player)
                if a_on_top:
                    self.append_cards(self.a_player, b_card, a_card)
                else:
                    self.append_cards(self.a_player, a_card, b_card)
            elif b_card > a_card:
                if len(self.pile) > 0:
                    self.append_pile(self.b_player)
                if a_on_top:
                    self.append_cards(self.b_player, b_card, a_card)
                else:
                    self.append_cards(self.b_player, a_card, b_card)
            else:
                if a_on_top:
                    self.append_cards(self.pile, b_card, a_card)
                else:
                    self.append_cards(self.pile, a_card, b_card)
            self.counter += 1
            if debug_print:
                self.summarize_turn(a_card, b_card)
        return self.counter

    def game_over(self):
        return len(self.a_player) == 0 or len(self.b_player) == 0

    def append_cards(self, hand, card_1, card_2):
        hand.append(card_1)
        hand.append(card_2)

    def append_pile(self, hand):
        """
        Adds all the cards in the pile to the hand passed in (preserving order)
        Also clears the pile.
        """
        hand.extend(self.pile)
        self.pile.clear()

    def summarize_turn(self, a_card, b_card):
        if a_card > b_card:
            print('A WINS')
        elif b_card > a_card:
            print('B WINS')
        else:
            print('TIE')

        print('TURN: {}'.format(self.counter))
        print('a-card: {} b-card: {}'.format(a_card, b_card))
        print('a-length: {} b-length: {}'.format(len(self.a_player),
                                                 len(self.b_player)))
        print()