Exemple #1
0
class Player(object):
    def __init__(self, game, name):
        self.game = game
        self.name = name
        self.cards = Hand()

    def get_card(self):
        self.cards.append(self.game.deck.pop())
Exemple #2
0
class Player(object):
    """
    Base class for player objects. Encapsulates the core game mechanics of drawing
    and playing cards.
    """
    def __init__(self, game, name):
        self.cards = Hand(style=self.__class__.style, name=name)
        self.game = game
        self.name = name
        self.message = self.game.message

    def take_card(self):
        """
        Take a card from the deck. If the deck is empty, take the bottom n-1 cards
        from the central stack and shuffle them to get a new deck.
        """
        if not self.game.deck:
            self.game.deck = self.game.central_stack[:-1]
            self.game.central_stack = [self.game.central_stack[-1]]
            shuffle(self.game.deck)
        self.cards.append(self.game.deck.pop())

    def handle_sevens(self):
        """
        Take 2n cards from the deck if there are n "active" sevens in the middle.
        """
        for _ in range(self.game.sevens):
            self.take_card()
            self.take_card()
        self.message.push("{} has to draw {} cards!".format(
            self.name, 2 * self.game.sevens))
        self.game.sevens = 0
        print(self.game)

    def matches(self, top_card):
        matching_suite = [c for c in self.cards if c.suite == top_card.suite]
        matching_rank = [c for c in self.cards if c.rank == top_card.rank]
        return matching_suite, matching_rank

    def move(self):
        """
        Automates the players choices as far as possible regardless of if it is
        a human or AI player. Returns True, if we have to skip one round, False,
        if the player has to pass, and None otherwise.
        """
        top_card = self.game.central_stack[-1]
        # If the top card is a 8, we have to skip this round if the 8 is still
        # effective, that is, if no other player before us has skipped because
        # of this card.
        if self.game.eights:
            self.message.push("{} has to skip one round.".format(self.name))
            self.game.eights = 0
            return True
        # If the top card is a 7, we can avoid having to draw 2(n) cards if we play
        # a 7 of our own. However, we leave this choice (if there is one) to the
        # player, hence, we call handle_sevens only if there is no other possibility
        elif top_card.rank == "7" and self.game.sevens:
            sevens = [c for c in self.cards if c.rank == "7"]
            if not sevens:
                self.handle_sevens()
        # Now look if we have matching cards. If not, draw a card from the deck.
        matching_suite, matching_rank = self.matches(top_card)
        if not matching_suite and not matching_rank:
            self.take_card()
            self.message.push("{} has to draw a card.".format(self.name))
            print(self.game)
        # Look (possibly) again for a match. If there is none, we have to pass.
        matching_suite, matching_rank = self.matches(top_card)
        if not matching_suite and not matching_rank:
            self.message.push("{} has to pass.".format(self.name))
            return False
        # At this point, there is (possibly) a choice left to the player, which
        # may differ for AI and human players. Therefore, we return None.
        return None

    def play(self, card):
        """
        Play out a card, announce that we have won by raising MauMau, increment
        and decrement the counters of unhandeled sevens and eights
        """
        self.cards.remove(card)
        self.game.central_stack.append(card)
        self.message.push("{} plays {} of {}.".format(self.name, card.rank,
                                                      card.suite))
        if card.rank == "7":
            self.game.sevens += 1
        else:
            self.game.sevens = 0
        if card.rank == "8":
            self.game.eights = 1
        else:
            self.game.eights = 0
        if not self.cards:
            raise MauMau

    def __repr__(self):
        return self.cards.repr(style=self.style)
Exemple #3
0
class Game(object):
    """
    Game is the class encapsulating the game logic of (counterclockwise) rounds
    of the players in Game().player_list, breaking out of the endless loop in
    Game().play() only if either MauMau or GameAbort is raised.
    """
    def __init__(self, demo=False):
        """
        Sets the stage: Shuffles the deck, hands out 7 cards to each player
        and places a card in the middle.
        demo = True creates a game with 3 AI players.
        """
        self.message = MessageHandler()
        self.deck = Deck()
        self.central_stack = Hand(style="top")
        if not demo:
            self.horst = HumanPlayer(self, "Horst")
        else:
            # Patch "Horst" to be an AIPlayer with the same __repr__ as a human player
            self.horst = AIPlayer(self, "Horst")
            self.horst.cards.style = "horizontal"
        self.player_list = [
            AIPlayer(self, "Fritz"),
            AIPlayer(self, "Franz"), self.horst
        ]
        self.players = cycle(self.player_list)
        # When simulating 3 random players a million times, it turns out that the
        # last player has a 2% handicap compared to the others. Hence: Random beginner.
        for _ in range(randint(0, 2)):
            next(self.players)
        # Distribute cards.
        for _ in range(7):
            for _ in range(3):
                self.current_player = next(self.players)
                self.current_player.take_card()
        self.central_stack.append(self.deck.pop())
        # Set up central counters for the number of unhandeled sevens and eights.
        if self.central_stack[-1].rank == "7":
            self.sevens = 1
        else:
            self.sevens = 0
        if self.central_stack[-1].rank == "8":
            self.eights = 1
        else:
            self.eights = 0

    def is_legal(self, card):
        top_card = self.central_stack[-1]
        return top_card.suite == card.suite or top_card.rank == card.rank

    def play(self):
        skipped = False
        length = 0
        while True:
            length += 1
            # Print the game
            print(self)
            # Next player
            self.current_player = next(self.players)
            time.sleep(1)
            try:
                self.current_player.move()
            except MauMau:
                # Winner, winner, chicken dinner!
                print(self)
                self.message.push("{} has won!".format(
                    self.current_player.name))
                if self.current_player != self.horst:
                    self.message.user_message(
                        "Sorry, you have lost against {}!".format(
                            self.current_player.name))
                else:
                    self.message.user_message(
                        "Congratulations {}, you have won this game!".format(
                            self.current_player.name))
                break
            except GameAbort:
                self.message.user_message("Thank you for playing!")
                break
        return self.current_player.name, length

    def __repr__(self):
        """
        Representing unicode string for the game: First row is Fritz, then Franz, then Horst (the human player).
        """
        anchor = "\x1b7\x1b[1;1f"  # ANSI escape sequence to start at row 1, columm 1
        cards = "\n".join([str(player) for player in self.player_list
                           ])  # the players' cards
        center = [""] * 4 + [
            (" " * 7) + line for line in str(self.central_stack).splitlines()
        ] + [""] * 12  # the central stack gets printed in the middle
        # Join everything up.
        all = "\n".join([anchor] +
                        [c + l for c, l in zip(cards.splitlines(), center)] + [
                            "{:<59}".format("  ".join([
                                "{:>2}".format(Hand.alphabet[i].upper())
                                for i in range(len(self.horst.cards))
                            ]))
                        ] + ["\x1b8"])
        return all