def test_basic_deck_shuffle_seed(): rand = Random() rand.seed(1) deck = Deck(random_instance=rand) deck.shuffle() assert len(deck) == 52 assert deck == SHUFFLED_DECK_1 assert deck.top_card == SHUFFLED_DECK_1[-1] card = deck.get_card() assert len(deck) == 51 assert card == SHUFFLED_DECK_1[-1] assert deck == SHUFFLED_DECK_1[:-1] assert deck.top_card == SHUFFLED_DECK_1[-2] for i in range(50, -1, -1): card = deck.get_card() assert card == SHUFFLED_DECK_1[i] assert len(deck) == 0 assert deck == [] assert deck.top_card is None deck.new_deck() assert len(deck) == 52 assert deck == UNSHUFFLED_DECK assert deck.top_card == UNSHUFFLED_DECK[-1]
def test_basic_deck_draw(): deck = Deck() assert len(deck) == 52 assert deck == UNSHUFFLED_DECK assert deck.top_card == UNSHUFFLED_DECK[-1] card = deck.get_card() assert len(deck) == 51 assert card == UNSHUFFLED_DECK[-1] assert deck == UNSHUFFLED_DECK[:-1] assert deck.top_card == UNSHUFFLED_DECK[-2] for i in range(50, -1, -1): card = deck.get_card() assert card == UNSHUFFLED_DECK[i] assert len(deck) == 0 assert deck == [] assert deck.top_card is None with pytest.raises(DeckEmptyError): card = deck.get_card() with pytest.raises(DeckEmptyError): card = deck.get_card() assert len(deck) == 0 assert deck == [] deck.new_deck() assert len(deck) == 52 assert deck == UNSHUFFLED_DECK assert deck.top_card == UNSHUFFLED_DECK[-1]
def test_basic_deck_sort(): deck = Deck() sorted_deck = deck.sort_cards(SORT_ORDER) assert len(sorted_deck) == 52 assert sorted_deck == SORTED_DECK assert sorted_deck.top_card == SORTED_DECK[-1] card = sorted_deck.get_card() assert len(sorted_deck) == 51 assert card == SORTED_DECK[-1] assert sorted_deck == SORTED_DECK[:-1] assert sorted_deck.top_card == SORTED_DECK[-2] for i in range(50, -1, -1): card = sorted_deck.get_card() assert card == SORTED_DECK[i] assert len(sorted_deck) == 0 assert sorted_deck == [] assert sorted_deck.top_card is None sorted_deck = sorted_deck.sort_cards(SORT_ORDER) assert sorted_deck == [] deck = Deck() card_1 = deck.get_card() card_2 = deck.get_card() sorted_deck = deck.sort_cards(SORT_ORDER) assert sorted_deck == list( filter(lambda x: x not in [card_1, card_2], SORTED_DECK)) assert sorted_deck.top_card == SORTED_DECK[-1] deck = Deck() deck.shuffle() sorted_deck = deck.sort_cards(SORT_ORDER) assert sorted_deck == SORTED_DECK assert sorted_deck.top_card == SORTED_DECK[-1] deck.new_deck() assert len(deck) == 52 assert deck == UNSHUFFLED_DECK assert deck.top_card == UNSHUFFLED_DECK[-1]
def test_basic_empty_deck(): deck = Deck(empty=True) assert len(deck) == 0 assert deck == [] assert deck.top_card is None card_1 = Card("Clubs", "9") deck.add_card(card_1) assert len(deck) == 1 assert deck == [card_1] assert deck.top_card == card_1 card_2 = Card("Spades", "King") deck.add_card(card_2) assert len(deck) == 2 assert deck == [card_1, card_2] assert deck.top_card == card_2 deck.new_deck() assert len(deck) == 52 assert deck == UNSHUFFLED_DECK assert deck.top_card == UNSHUFFLED_DECK[-1]
def test_basic_deck_iter(): deck = Deck(empty=True) with pytest.raises(StopIteration): card = next(deck) deck = Deck() for i in range(0, 52): card = next(deck) assert card == UNSHUFFLED_DECK[i] with pytest.raises(StopIteration): card = next(deck) deck.new_deck() for i in range(0, 52): card = next(deck) assert card == UNSHUFFLED_DECK[i] with pytest.raises(StopIteration): card = next(deck) deck.new_deck() for i in range(0, 52): assert deck[i] == UNSHUFFLED_DECK[i]
def test_basic_deck_shuffle(): deck = Deck() deck.shuffle() assert len(deck) == 52 assert deck != UNSHUFFLED_DECK assert set(deck) == set(UNSHUFFLED_DECK) deck.get_card() assert len(deck) == 51 assert deck != UNSHUFFLED_DECK[:-1] assert set(deck).issubset(UNSHUFFLED_DECK) for i in range(0, 50): deck.get_card() deck.shuffle() assert len(deck) == 1 assert set(deck).issubset(UNSHUFFLED_DECK) deck.get_card() deck.shuffle() assert len(deck) == 0 assert deck == [] with pytest.raises(DeckEmptyError): card = deck.get_card() assert deck.top_card is None deck.shuffle() assert len(deck) == 0 assert deck == [] deck.new_deck() assert len(deck) == 52 assert deck == UNSHUFFLED_DECK assert deck.top_card == UNSHUFFLED_DECK[-1]
class Game: """The Game class allows users to start new card games. Game objects are initiated with a list of the names of the players who wish to play. Optionally, a custom message dictionary can be passed for a change in game verbiage. A custom Deck can also be used. The max number of rounds is 3 by default. A Game can be started using .play() and new rounds will be played until the max number of rounds is reached. During each round, players take turns drawing cards by pressing enter. After the game is finished, a final scoreboard is printed. A new Game can be played after invoking .new_game(). Attributes: players: Game's Players object. """ def __init__( self, names: List[str], deck: Optional[Deck] = None, max_rounds: int = 3, message: Optional[Dict[str, List[str]]] = None ) -> None: """Initiates a Game by creating Players from names. Creates a Deck and shuffles if none is supplied. Generates internal message dictionary from messages.conf if none is supplied. Sets max rounds to 3 if none is supplied. Sets Game to active. Args: name: Names of players. message: Optional; Message dictionary used for game verbiage. deck: Optional; Deck to use during the game. max_rounds: Optional; Max number of rounds to play. """ if max_rounds < 1: raise GameError("Invalid max number of rounds.") if len(names) == 0: raise GameError("Invalid number of players.") if message: self._message = message else: conf_reader = ConfigParser() try: message_path = join(dirname(abspath(__file__)), "messages.conf") with open(message_path) as file: conf_reader.read_file(file) except IOError: raise GameError( "Could not open messages config file.") from None self._message = {k: list(v.values()) for k, v in dict(conf_reader).items()} if deck: self._deck = deck else: self._deck = Deck() self._deck.shuffle() self.players = Players(names) self._current_round = 1 self._is_active = True self._max_rounds = max_rounds self._rand = Random() def end_game(self) -> None: """Sets game to inactive thus ending the Game.""" self._is_active = False def new_game(self) -> None: """Resets the Game: Sets Game back to active, resets Players, creates new Deck and shuffles. """ self._is_active = True self._deck.new_deck() self._deck.shuffle() self._current_round = 1 self.players.reset() def play(self) -> None: """Launches game. Keeps initiating a new round until Game is no longer active (max round limit reached). Prints leaderboard at the end. """ self._display_message("WELCOME") while self._is_active: self._display_message( "ROUND START", current_round=self._current_round) self._next_round() last_round = self._current_round - 1 if self.players.first(last_round).tie: self._display_message("ROUND END TIE") else: self._display_message( "ROUND END", round_winner=self.players.first(last_round).name) if self.players.first().tie: self._display_message("GAME OVER TIE") else: self._display_message( "GAME OVER", game_winner=self.players.first().name) print(self.players) def _next_round(self) -> None: """Starts the next round. Iterates through Players and asks them to draw a Card by hitting enter. If the Deck runs out of Cards will display a notification and generate a new Deck to draw from. """ for player in self.players: self._display_message( "TURN START", current_player_name=player.name) input("Hit enter to draw a card.") try: card = self._deck.get_card() except DeckEmptyError: self._display_message("EMPTY DECK") self._deck.new_deck() self._deck.shuffle() card = self._deck.get_card() player.draw_card(card) pos_result = player in self.players.first().players self._display_message( "{result} TURN END".format(result=str(pos_result).upper()), current_player_name=player.name, current_card=card, current_player_score=player.score()) if self._current_round >= self._max_rounds: self.end_game() self._current_round += 1 def _display_message(self, category: str, **kwargs) -> None: """Takes a category of message and randomly selects a corresponding message template from the instance's message dictionary, subsititutes any given args, and prints message. Args: category: Message category. **kwargs: Any arguments to be subsituted in the message template """ message = self._rand.choice(self._message[category]) message_template = Template(message) print(message_template.substitute(kwargs)) def __bool__(self): return self._is_active