예제 #1
0
    def __init__(self, players):
        pf = Profiler()
        pf.printer.indent()
        pf.printer.silent = not PERFORMANCE_LOGGING

        self.players = players

        # Set up the deck
        deck = INITIAL_DECK[:]
        pf.measure("Set up deck")
        shuffle(deck)

        pf.measure("Shuffle deck")

        self.deck = deck
        """ Current draw deck. Excludes Snitches. """

        self.discard_deck = []
        """ Deck discarded (played) cards. Excludes Snitches. """

        pf.measure("Other set up")
        # Give each player the initial number of Snitches and deal the rest.
        for player in self.players:
            number_of_character_cards_to_deal = INITIAL_CARDS_PER_PLAYER - INITIAL_SNITCHES_PER_PLAYER
            character_hand = self.deck[:number_of_character_cards_to_deal]
            del self.deck[:number_of_character_cards_to_deal]
            player.set_up(
                hand=INITIAL_SNITCH_HAND + character_hand,
                coins=INITIAL_COINS_PER_PLAYER)
            player.prepare()
        
        pf.measure("Give players cards")
예제 #2
0
    def play(self, silent=False):
        p = Printer(silent=silent)
        pf = Profiler()
        pf.printer.indent()
        pf.printer.silent = not PERFORMANCE_LOGGING

        round_info = RoundInfo()

        for round_number in range(GAME_ROUNDS):
            p.print(f"-- Round {round_number} --")
            p.indent()
            pf.reset()

            # Select game leader
            leader_player = self.players[round_number % len(self.players)]
        
            # Leader player selects the number of players.
            heist_difficulty = leader_player.select_heist_difficulty(len(self.players))
            assert(heist_difficulty >= 1 and heist_difficulty <= len(self.players))
            p.print(f"{leader_player.short_name} selects difficulty of {heist_difficulty}")

            # Draw this many cards to form the contract
            contract_cards = self.drawSafe(how_many=heist_difficulty)
            p.print(f"Contract cards: {contract_cards}")

            # Set up round info, to pass to each player instance.
            round_info.number = round_number
            round_info.contract_cards = contract_cards

            # Ask each player to play a card
            player_cards = [(player, player.play_card(round_info)) for player in self.players]
            played_cards = []
            for (player, card) in player_cards:
                p.print(f"{player.short_name} plays {card}")
                played_cards.append(card)

            pf.measure("Draw cards")

            # Evaluate game
            heist_success = self.evaluate_contract(contract_cards, played_cards)
            if heist_success:
                p.print("Heist SUCCESS 🙌!")
                # All non-snitching players get reward
                for (player, card) in player_cards:
                    if card in CHARACTER_CARDS:
                        p.print(f"{player.short_name} contributed and wins {heist_difficulty}💰. Yay 😊")
                        player.coins += heist_difficulty
                    else:
                        p.print(f"{player.short_name} snitched and gets nothing. 🤥 ")
            else:
                p.print("Heist FAILED ❌!")
                
                if not Card.SNITCH in played_cards:
                    # There were no snitches. The heist simply failed due to lack of cards.
                    p.print("No one played a Snitch. All players retain their coins.") 
                elif len([card for card in played_cards if card == Card.SNITCH]) == len(self.players):
                    # Everyone played Snitch.
                    p.print("Everyone played a Snitch. All players retain their coins.") 
                else:
                    # All snitched-on players lose -1
                    pot = 0
                    snitch_players = []
                    for (player, card) in player_cards:
                        if card in CHARACTER_CARDS:
                            if player.coins > 0:
                                player.coins -= 1
                                pot += 1
                                p.print(f"{player.short_name} got betrayed and loses 1💰. Grr 😤")
                            else:
                                p.print(f"{player.short_name} got betrayed but has no money.")
                        else:
                            snitch_players.append(player)

                    # All snitching players (if any) split the reward, to a minimum of 1
                    reward = max(1, ceil(pot / len(snitch_players)))
                    for player in snitch_players:
                        player.coins += reward
                        p.print(f"{player.short_name} snitched and gets {reward}💰. Ha! 😆")

            pf.measure("Evaluate")

            # Discard all cards
            self.discard_deck.extend(contract_cards)
            for (_, card) in player_cards:
                self.discard_deck.append(card)

            p.deindent()

        p.print("*** Game Summary ***")
        p.indent()
        # Sort by money.
        players = list(self.players)
        players.sort(key=lambda player: player.coins, reverse=True)
    
        # Determine winners
        winners = [player for player in players if player.coins == players[0].coins]
        if len(winners) == 1:
            p.print(f"{winners[0].short_name} wins with ${winners[0].coins}")
        elif len(winners) == len(players):
            p.print(f"All players draw.")
            winners = []
        else:
            winner_names = ", ".join(p.short_name for p in winners)
            p.print(f"{winner_names} drew with ${winners[0].coins}")
        p.deindent()

        # Return result and stats
        return {
            "winners": winners
        }
예제 #3
0
    shared_wins = 0  # i.e. where multiple but not all players won
    draws = 0  # i.e. all players drew.
    wins_per_player = {player: 0 for player in players}

    pf = Profiler()
    for _ in range(GAMES):
        game = Game(players)
        result = game.play(silent=True)
        # Record stats about the game
        winners = result["winners"]

        if len(winners) == 0:
            draws += 1
        else:
            for winner in winners:
                wins_per_player[winner] += 1
            if len(winners) == 1:
                pure_wins += 1
            else:
                shared_wins += 1
    pf.measure("Time taken")

    # Print stats
    print(f"Player {GAMES} games with {NUMBER_OF_PLAYERS} players")
    print(f"There were:")
    print(f"\t{pure_wins}\tPure wins")
    print(f"\t{shared_wins}\tShared wins")
    print(f"\t{draws}\tDraws")
    print(f"Wins per player:")
    for player, wins in wins_per_player.items():
        print(f"\t{wins}\t{player.short_name}")