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)
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)
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
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)
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))
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__())
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]))
def _create_instance() -> Deck: return Deck("ABC", [_get_card_example()])
def test_deck_can_work_like_a_deque(self): self.assertEqual(Deck([1, 2, 3]), collections.deque([1, 2, 3]))
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
def _get_loser() -> Deck: return Deck("Loser", [card_loser_1, card_loser_2, card_loser_3])
def _get_winner() -> Deck: return Deck("Winner", [card_winner_1, card_winner_2, card_winner_3])
def _get_loser() -> Deck: return Deck("Loser", [Card(Card.Figure.Queen, Card.Color.Hearts)])
def _get_winner() -> Deck: return Deck("Winner", [Card(Card.Figure.King, Card.Color.Hearts)])