예제 #1
0
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]
예제 #2
0
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]
예제 #3
0
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]
예제 #4
0
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]
예제 #5
0
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]
예제 #6
0
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]
예제 #7
0
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