class Croupier(Player): def __init__(self, game, name): super().__init__(game, name) self.cards = Hand(maxwidth=11) def __repr__(self): return self.cards.repr(style="horizontal")
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)