예제 #1
0
    def __init__(self, name: str) -> None:
        """Initiates Player with a name and an empty hand.

        Args:
            name: Name of player.
        """
        self.hand = Deck(empty=True)
        self.name = name
예제 #2
0
def test_basic_game_4(capsys, monkeypatch):
    monkeypatch.setattr("builtins.input", lambda x: "")

    rand = Random()
    rand.seed(1)
    deck = Deck(random_instance=rand)
    deck.shuffle()

    game = Game(PLAYERS_2, deck=deck, message=MESSAGE)
    game.play()
    captured = capsys.readouterr()
    assert captured.out == GAME_4_RESULTS
예제 #3
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]
예제 #4
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]
예제 #5
0
 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()
예제 #6
0
def test_basic_game_2(capsys, monkeypatch):
    monkeypatch.setattr("builtins.input", lambda x: "")

    rand = Random()
    rand.seed(1)
    deck = Deck(random_instance=rand)
    deck.shuffle()

    game = Game(PLAYERS_1, deck=deck, message=MESSAGE, max_rounds=1)
    assert game
    game.play()
    assert not game
    captured = capsys.readouterr()
    assert captured.out == GAME_1_RESULTS

    game.new_game()
    assert game
    game.play()
    assert not game
    captured = capsys.readouterr()
    assert captured.out == GAME_2_RESULTS
예제 #7
0
def test_basic_game_5(capsys, monkeypatch):
    monkeypatch.setattr("builtins.input", lambda x: "")

    cards = [
        Card("Clubs", "6"),
        Card("Spades", "8"),
        Card("Diamonds", "3"),
        Card("Clubs", "9"),
        Card("Clubs", "Ace"),
        Card("Spades", "King"),
        Card("Diamonds", "5"),
        Card("Diamonds", "3"),
        Card("Spades", "10"),
    ]
    deck = Deck(empty=True)
    for card in cards:
        deck.add_card(card)
    game = Game(PLAYERS_2, deck=deck, message=MESSAGE)
    game.play()
    captured = capsys.readouterr()
    assert captured.out == GAME_5_RESULTS
예제 #8
0
def test__basic_game_3(capsys, monkeypatch):
    monkeypatch.setattr("builtins.input", lambda x: "")

    rand = Random()
    rand.seed(1)
    deck = Deck(empty=True, random_instance=rand)
    deck.add_card(Card("Clubs", "9"))
    deck.shuffle()

    game = Game(PLAYERS_1, deck=deck, message=MESSAGE, max_rounds=2)
    game.play()
    captured = capsys.readouterr()
    assert captured.out == GAME_3_RESULTS
예제 #9
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]
예제 #10
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]
예제 #11
0
 def clear_hand(self) -> None:
     """Empty the Player's hand."""
     self.hand = Deck(empty=True)
예제 #12
0
class Player:
    """The Player class is used to manage a person's hand and score.

    Player objects are initiated by passing a person's name. Their hand starts
    out as an empty Deck and is expanded by drawing Cards. Player total score
    or score after a specific round can be received. A Player can be compared
    to another Player based on score (< or >) or based on name and hand (==).

    Attributes:
        hand: The Player's hand of playing cards they currently hold.
        name: The Player's name.
    """
    def __init__(self, name: str) -> None:
        """Initiates Player with a name and an empty hand.

        Args:
            name: Name of player.
        """
        self.hand = Deck(empty=True)
        self.name = name

    def clear_hand(self) -> None:
        """Empty the Player's hand."""
        self.hand = Deck(empty=True)

    def draw_card(self, card: Card) -> None:
        """Have the Player draw a card.

        Args:
            card: The Card to add to the Player's hand.
        """
        self.hand.add_card(card)

    def score(self, round_number: int = 0) -> int:
        # We are assuming 1-indexed round numbers
        """Calculate and return the Player's total or round score.

        Args:
            card:
                Optional; The Card to add to the Player's hand.
        """
        if round_number:
            if round_number > len(self.hand):
                return 0
            return self.hand[round_number - 1].score
        return sum([card.score for card in self.hand])

    def __str__(self):
        return "{name} holds {hand} totalling {points} points".format(
            name=self.name, hand=self.hand, points=self.score())

    def __eq__(self, other):
        if not isinstance(other, Player):
            return False
        return self.hand == other.hand and self.name == other.name

    def __gt__(self, other):
        if not isinstance(other, Player):
            return False
        return self.score() > other.score()

    def __lt__(self, other):
        if not isinstance(other, Player):
            return False
        return self.score() < other.score()
예제 #13
0
def test_basic_deck_string():
    rand = Random()
    rand.seed(1)
    deck = Deck()
    assert str(deck) == str(UNSHUFFLED_DECK_TUPLES)
    deck.get_card()
    assert str(deck) == str(UNSHUFFLED_DECK_TUPLES[:-1])

    deck = Deck(random_instance=rand)
    deck.shuffle()
    assert str(deck) == str(SHUFFLED_DECK_1_TUPLES)
    deck.get_card()
    assert str(deck) == str(SHUFFLED_DECK_1_TUPLES[:-1])

    deck = Deck()
    sorted_deck = deck.sort_cards(SORT_ORDER)
    assert str(sorted_deck) == str(SORTED_DECK_TUPLES)
    sorted_deck.get_card()
    assert str(sorted_deck) == str(SORTED_DECK_TUPLES[:-1])
    for i in range(0, 51):
        sorted_deck.get_card()
    assert str(sorted_deck) == str([])
예제 #14
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]
예제 #15
0
def test_basic_deck_create():
    deck = Deck()
    assert len(deck) == 52
    assert deck == UNSHUFFLED_DECK
예제 #16
0
def test_basic_player_1():
    with pytest.raises(TypeError):
        player_1 = Player()

    deck = Deck(empty=True)
    player_1 = Player("Berkelly")
    assert player_1.name == "Berkelly"
    assert player_1.hand == deck
    assert str(player_1.hand) == str(deck)
    assert player_1.score() == 0
    assert not player_1.score(round_number=1)
    assert str(player_1) == STRING_1

    card_1 = Card("Clubs", "King")
    deck.add_card(card_1)
    player_1.draw_card(card_1)
    assert player_1.hand == deck
    assert str(player_1.hand) == str(deck)
    assert player_1.score() == 52
    assert player_1.score(round_number=1) == 52
    assert str(player_1) == STRING_2

    card_2 = Card("Hearts", "8")
    deck.add_card(card_2)
    player_1.draw_card(card_2)
    assert player_1.hand == deck
    assert str(player_1.hand) == str(deck)
    assert player_1.score() == 76
    assert player_1.score(round_number=1) == 52
    assert player_1.score(round_number=2) == 24
    assert str(player_1) == STRING_3

    assert player_1.hand == deck
    assert str(player_1.hand) == str(deck)
    assert player_1.score() == 76
    assert player_1.score(round_number=1) == 52
    assert player_1.score(round_number=2) == 24
    assert str(player_1) == STRING_3

    deck = Deck(empty=True)
    player_1.clear_hand()
    assert player_1.name == "Berkelly"
    assert player_1.hand == deck
    assert str(player_1.hand) == str(deck)
    assert player_1.score() == 0
    assert not player_1.score(round_number=1)
    assert str(player_1) == STRING_1

    player_1.draw_card(card_1)
    player_1.draw_card(card_2)
    player_2 = Player("Cez")
    assert player_1 > player_2
    assert player_2 < player_1

    card_1 = Card("Diamonds", "8")
    card_2 = Card("Clubs", "2")
    player_2.draw_card(card_1)
    player_2.draw_card(card_2)
    assert player_1 > player_2
    assert player_2 < player_1

    player_1 = Player("Cez")
    player_1.draw_card(card_1)
    player_1.draw_card(card_2)
    assert player_1 == player_2

    player_1 = Player("Cez")
    player_1.draw_card(card_2)
    assert player_1 != player_2
예제 #17
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]
예제 #18
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