예제 #1
0
    def test_deck_lets_me_set_rank_and_suit_counts_in_constructor(self):
        d = Deck(count_of_suits=2, count_of_ranks=2)
        self.assertEqual(d.count_of_suits, 2)
        self.assertEqual(d.count_of_ranks, 2)

        d = Deck(count_of_suits=4, count_of_ranks=4)
        self.assertEqual(d.count_of_suits, 4)
        self.assertEqual(d.count_of_ranks, 4)
예제 #2
0
    def test_does_not_allow_deck_of_one_card(self):
        # two cards is fine
        Deck(count_of_suits=2, count_of_ranks=1)
        Deck(count_of_suits=1, count_of_ranks=2)

        # but one card makes no sense for War
        with self.assertRaises(ValueError):
            Deck(count_of_suits=1, count_of_ranks=1)
예제 #3
0
    def __init__(self) -> None:
        self._all_cards = self._create_cards()
        shuffle(self._all_cards)

        self._deck_a = Deck("A", self._all_cards[0::2])
        self._deck_b = Deck("B", self._all_cards[1::2])

        self._result = Game.Result.NOT_FINISHED
        self._number_of_turns = 0
예제 #4
0
    def test_deck_shuffle_works_and_is_non_destructive(self):
        deck = Deck()
        control = collections.deque(deck)
        self.assertEqual(len(deck), len(control))
        self.assertEqual(deck, control)

        # same number of items in different order
        deck.shuffle()
        self.assertEqual(len(deck), len(control))
        self.assertNotEqual(deck, control)

        # make a shallow copy
        another_deck = copy.copy(deck)
        self.assertEqual(len(deck), len(another_deck))
        self.assertEqual(deck, another_deck)

        # shuffle shallow copy doesn't match control or other
        another_deck.shuffle()
        self.assertEqual(len(deck), len(another_deck))
        self.assertEqual(len(deck), len(control))
        self.assertNotEqual(deck, another_deck)
        self.assertNotEqual(deck, control)
예제 #5
0
    def test_deck_remembers_its_own_starting_count(self):
        d = Deck(count_of_suits=2, count_of_ranks=2)
        self.assertEqual(d.count_of_cards, 4)
        self.assertEqual(d.count_of_cards, len(d))

        d.shuffle()
        self.assertEqual(d.count_of_cards, 4)
        self.assertEqual(d.count_of_cards, len(d))

        d.deal([Player('Alice'), Player('Bob')])
        self.assertEqual(d.count_of_cards, 4)
        self.assertNotEqual(d.count_of_cards, len(d))
예제 #6
0
    def test_deck_deals_out_to_two_players_correctly(self):
        players = []
        for n in range(2):  # 2 players
            players.append(Player(name=str(n + 1)))

        d = Deck(count_of_suits=4, count_of_ranks=4)  # 16 cards
        d.shuffle()
        d.deal(players)

        # 8 cards each ...
        self.assertEqual(len(players[0].hand), 8)
        self.assertEqual(len(players[0].hand), len(players[1].hand))

        # ... of different cards
        for n in range(len(players[0].hand)):
            self.assertNotEqual(players[0].hand[n].__hash__(),
                                players[1].hand[n].__hash__())
예제 #7
0
    def test_deck_deals_out_to_four_players_correctly(self):
        players = []
        for n in range(4):  # 4 players
            players.append(Player(name=str(n + 1)))

        d = Deck(count_of_suits=8, count_of_ranks=8)  # 64 cards
        d.shuffle()
        d.deal(players)

        # 16 cards each ...
        self.assertEqual(len(players[0].hand), 16)
        self.assertEqual(len(players[0].hand), len(players[1].hand))
        self.assertEqual(len(players[1].hand), len(players[2].hand))
        self.assertEqual(len(players[2].hand), len(players[3].hand))

        # ... of different cards
        for n in range(len(players[0].hand)):
            self.assertNotEqual(id(players[0].hand[n]), id(players[1].hand[n]))
            self.assertNotEqual(id(players[1].hand[n]), id(players[2].hand[n]))
            self.assertNotEqual(id(players[2].hand[n]), id(players[3].hand[n]))
예제 #8
0
def _create_instance() -> Deck:
    return Deck("ABC", [_get_card_example()])
예제 #9
0
 def test_deck_can_work_like_a_deque(self):
     self.assertEqual(Deck([1, 2, 3]), collections.deque([1, 2, 3]))
예제 #10
0
class Game:
    """Game class"""
    class Result(Enum):
        """Battle results."""
        A_WON, B_WON, TIMEOUT, NOT_FINISHED = range(4)

    def __init__(self) -> None:
        self._all_cards = self._create_cards()
        shuffle(self._all_cards)

        self._deck_a = Deck("A", self._all_cards[0::2])
        self._deck_b = Deck("B", self._all_cards[1::2])

        self._result = Game.Result.NOT_FINISHED
        self._number_of_turns = 0

    @staticmethod
    def _create_cards() -> List[Card]:
        cards = []
        for color in Card.Color:
            for figure in Card.Figure:
                cards.append(Card(figure, color))
        return cards

    def set_custom_decks(self, deck_a: Deck, deck_b: Deck) -> None:
        """Change created decks to custom decks."""
        self._deck_a = deck_a
        self._deck_b = deck_b

    def get_decks(self) -> Tuple[Deck, Deck]:
        """Returns created decks."""
        return self._deck_a, self._deck_b

    def _perform_duel(self) -> Result:
        """Perform single duel.

        Order of returning cards to deck has big importance.
        Read README for more information.
        Function puts back cards to deck in order:
            normal duel:
                1 winner card
                2 loser card
            duel with playoff:
                1 winner card from second duel
                2 loser card from second duel
                3 winner hidden card
                4 loser hidden card
                5 winner card from first duel
                6 loser card from first duel

        Returns:
            Result: A_WON if player a won, B_WON otherwise.
        """
        card_a = self._deck_a.take_next_card()
        card_b = self._deck_b.take_next_card()

        if card_a > card_b:
            self._deck_a.add_cards([card_a, card_b])
            return Game.Result.A_WON
        if card_a < card_b:
            self._deck_b.add_cards([card_b, card_a])
            return Game.Result.B_WON

        # it's draw!
        card_a_hidden = self._deck_a.take_next_card()
        card_b_hidden = self._deck_b.take_next_card()
        play_off = self._perform_duel()
        assert play_off in (Game.Result.A_WON, Game.Result.B_WON)

        if play_off == Game.Result.A_WON:
            self._deck_a.add_cards(
                [card_a_hidden, card_b_hidden, card_a, card_b])
            return Game.Result.A_WON
        self._deck_b.add_cards([card_b_hidden, card_a_hidden, card_b, card_a])
        return Game.Result.B_WON

    def _perform_turn(self) -> bool:
        """Perform single turn.
        Returns:
            bool: False if game is finished, True otherwise.
        """
        self._number_of_turns += 1
        logging.debug("Starting turn %s A=%s B=%s", self._number_of_turns,
                      len(self._deck_a), len(self._deck_b))
        try:
            self._perform_duel()
        except IndexError:  # one of deck is out of cards, game is finished
            return False
        return True

    TIMEOUT_TURN_THRESHOLD = 10000

    def perform_game(self) -> Tuple[Result, int]:
        """Performs game and returns number of turns."""
        while self._perform_turn():
            if self._debug_against_stalled_games():
                break
        return self._gather_results()

    def _debug_against_stalled_games(self) -> bool:
        if self._number_of_turns > Game.TIMEOUT_TURN_THRESHOLD - 10:
            logging.debug(self._deck_a)
            logging.debug(self._deck_b)
        if self._number_of_turns == Game.TIMEOUT_TURN_THRESHOLD:
            self._result = Game.Result.TIMEOUT
            return True
        return False

    def _gather_results(self) -> Tuple[Result, int]:
        logging.info("Finished with %d A=%d B=%d", self._number_of_turns,
                     len(self._deck_a), len(self._deck_b))
        if self._result == Game.Result.TIMEOUT:
            return self._result, self._number_of_turns

        a_number = len(self._deck_a)
        b_number = len(self._deck_b)

        if a_number == 0:
            assert b_number != 0
            self._result = Game.Result.B_WON
            return self._result, self._number_of_turns

        assert a_number != 0 and b_number == 0
        self._result = Game.Result.A_WON
        return self._result, self._number_of_turns
예제 #11
0
 def _get_loser() -> Deck:
     return Deck("Loser", [card_loser_1, card_loser_2, card_loser_3])
예제 #12
0
 def _get_winner() -> Deck:
     return Deck("Winner", [card_winner_1, card_winner_2, card_winner_3])
예제 #13
0
 def _get_loser() -> Deck:
     return Deck("Loser", [Card(Card.Figure.Queen, Card.Color.Hearts)])
예제 #14
0
 def _get_winner() -> Deck:
     return Deck("Winner", [Card(Card.Figure.King, Card.Color.Hearts)])