Exemplo n.º 1
0
    def __init__(self, players, little_blind, big_blind, deck_seed):
        """Initialize a new Round.

        Arguments:
        players -- a list of Player objects, representing the individual
                   players that will be in the round
        little_blind -- amount of chips that must be bet by the little blind
        big_blind -- amount of chips that must be bet by the big blind
        deck_seed -- the seed which will be used to generate the psuedorandom
                     deck ordering, as well as the round's unique ID which will
                     can be used to verify the deck ordering after a game ends

        """
        self.round_id = self.generate_id(deck_seed)
        self.logger = self.get_logger()
        self.logger.info("Initializing Round")
        self.logger.info("Deck seed: " + binascii.hexlify(deck_seed))
        self.logger.info("Players:")
        self.players = players
        for player in self.players:
            self.logger.info(str(player))
            player.game_round = self
        self.table = []
        self.pots = [Pot(0, 0)]
        self.action_position = 0
        self.deck = Deck(deck_seed)
        self.logger.info(str(self.deck))
        self.logger.info("Little blind: " + str(little_blind))
        self.little_blind = little_blind
        self.logger.info("Big blind: " + str(big_blind))
        self.big_blind = big_blind
        self.blinds_in = False
        self.latest_action = None
        self.logger.info("Round initialized")
Exemplo n.º 2
0
class Round:
    def __init__(self, players, little_blind, big_blind, deck_seed):
        """Initialize a new Round.

        Arguments:
        players -- a list of Player objects, representing the individual
                   players that will be in the round
        little_blind -- amount of chips that must be bet by the little blind
        big_blind -- amount of chips that must be bet by the big blind
        deck_seed -- the seed which will be used to generate the psuedorandom
                     deck ordering, as well as the round's unique ID which will
                     can be used to verify the deck ordering after a game ends

        """
        self.round_id = self.generate_id(deck_seed)
        self.logger = self.get_logger()
        self.logger.info("Initializing Round")
        self.logger.info("Deck seed: " + binascii.hexlify(deck_seed))
        self.logger.info("Players:")
        self.players = players
        for player in self.players:
            self.logger.info(str(player))
            player.game_round = self
        self.table = []
        self.pots = [Pot(0, 0)]
        self.action_position = 0
        self.deck = Deck(deck_seed)
        self.logger.info(str(self.deck))
        self.logger.info("Little blind: " + str(little_blind))
        self.little_blind = little_blind
        self.logger.info("Big blind: " + str(big_blind))
        self.big_blind = big_blind
        self.blinds_in = False
        self.latest_action = None
        self.logger.info("Round initialized")

    def get_logger(self):
        """Return the logger which this round will use"""
        return loggers.get_round_logger(self.round_id[:8])

    def generate_id(self, seed):
        """Create a unique ID for the round based on the round seed

        Arguments:
        seed -- the round's unique seed string

        """
        hf = hashlib.sha256()
        hf.update(seed)
        return hf.hexdigest()

    def round_is_over(self):
        """Return whether the round is over.

        Returns False if more than one player is still in the round, and
        True otherwise

        """
        self.logger.debug("Checking if > 1 player is left in the round")
        players_in_round = 0
        for player in self.players:
            if player.in_round:
                players_in_round = players_in_round + 1
        if players_in_round >= 2:
            self.logger.debug("There is more than one player in the round")
            return False
        else:
            self.logger.debug("There is not more than one player in the round")
            return True

    def betting_is_over(self):
        """Return whether there are enough players in the round with chips
           to continue betting"""
        self.logger.info("Checking if more than one player is in the round" + " and has chips")
        players_that_can_bet = 0
        for player in self.players:
            if player.in_round and not player.all_in:
                players_that_can_bet = players_that_can_bet + 1
        self.logger.debug("Number of players that can bet: " + str(players_that_can_bet))
        if players_that_can_bet >= 2:
            return False
        else:
            return True

    def get_player_by_id(self, bcc_id):
        """Return the Player object with the given bcc_id if it exists
           or else None

        Arguments:
        bcc_id -- a string representing a player's unique BCC ID

        """
        self.logger.debug("Trying to find a player with the id %s", bcc_id)
        for player in self.players:
            if player.user.bcc_id == bcc_id:
                self.logger.debug("Found a player with the id %s", bcc_id)
                return player
        self.logger.debug("Did not find a player with the id %s", bcc_id)
        return None

    def get_top_card(self):
        """Return the top card from the deck."""
        card = self.deck.get_next_card()
        self.logger.info("Taking a card off the deck: " + str(card))
        return card

    def get_player_with_action(self):
        """Return the player which the action is to."""
        player = self.players[self.action_position]
        self.logger.debug("Returning the player with action: " + str(player))
        return player

    def player_with_action_id(self):
        """Return the bcc_id of the player with the action"""
        return self.get_player_with_action().user.bcc_id

    def advance_to_next_player(self):
        """Move the action to the next player on the table."""
        self.logger.debug("Moving the action to the next table position")
        self.action_position = (self.action_position + 1) % len(self.players)

    def deal_hands(self):
        """Deal a hand to each player."""
        for i in range(2):
            for player in self.players:
                self.logger.info("Dealing card to %s", str(player))
                player.deal_card(self.get_top_card())

    def deal_flop(self):
        """Deal the flop."""
        self.logger.info("Burying a card")
        self.get_top_card()
        for i in range(3):
            self.logger.info("Putting a card on the table")
            self.table.append(self.get_top_card())

    def deal_turn(self):
        """Deal the turn."""
        self.logger.info("Burying a card")
        self.get_top_card()
        self.logger.info("Putting a card on the table")
        self.table.append(self.get_top_card())

    def deal_river(self):
        """Deal the river."""
        self.logger.info("Burying a card")
        self.get_top_card()
        self.logger.info("Putting a card on the table")
        self.table.append(self.get_top_card())

    def do_betting_round(self):
        """Do a betting round."""
        self.logger.info("Starting a betting round")
        raised_in_round = 0  # amount each player must put in to stay in
        chips_in_round = 0  # amount of chips that have been put in round
        for player in self.players:
            player.chips_in_round = 0
        self.logger.info("Resetting the amount of chips each player has in" + " the round to zero")
        if not self.blinds_in:
            little = self.get_player_with_action()
            little.bet_blind(self.little_blind)
            self.logger.info("The small blind has been bet")
            chips_in_round = self.little_blind
            raised_in_round = self.little_blind
            self.advance_to_next_player()
            big = self.get_player_with_action()
            big.bet_blind(self.big_blind)
            self.logger.info("The big blind has been bet")
            chips_in_round = chips_in_round + self.big_blind
            raised_in_round = self.big_blind
            self.advance_to_next_player()
            self.blinds_in = True
        starting_betting = True
        betting_ends_on = self.get_player_with_action()
        self.logger.info("Starting the betting")
        # starting_betting is true before the first player in the round has
        # performed an action.
        # self.betting_is_over is true when only one player can bet.
        # starting_betting should always mean the loop is entered.
        # betting_ends_on is initially set to the first player who would
        # have action if he was in the round, and can also be set to the last
        # player to have raised.
        # The betting round should be exited out of early if there is only
        # one player left who hasn't folded or if there is only one player
        # left who can play, and no one has raised anything in the round.
        while starting_betting or (
            betting_ends_on != self.get_player_with_action()
            and (not (self.betting_is_over() and raised_in_round == 0))
            and (not self.round_is_over())
        ):
            starting_betting = False
            player = self.get_player_with_action()
            self.logger.info("Moving action to " + str(player))
            action = player.get_action(raised_in_round, self.big_blind)
            if action.choice == Action.VOID:
                self.logger.info("Void action")
            else:
                if action.choice == Action.RAISE:
                    new_chips_in = action.amount
                    raised_in_round = player.chips_in_round
                    chips_in_round = chips_in_round + new_chips_in
                    betting_ends_on = self.get_player_with_action()
                elif action.choice == Action.CALL:
                    new_chips_in = action.amount
                    chips_in_round = chips_in_round + new_chips_in
                elif action.choice == Action.CHECK:
                    pass
                elif action.choice == Action.FOLD:
                    pass
                self.latest_action = action
                self.logger.info("The action has been applied")
            self.advance_to_next_player()
            self.logger.info("Done with this player, moving to the next")
        self.logger.info("Done with the betting. Move on to sorting out pots.")
        players_in = filter(lambda p: p.chips_in_round > 0, self.players)
        ordered = sorted(players_in, key=lambda p: p.chips_in_round)
        self.logger.info("Sorting players still in by number of chips" + " that were played in this round.")
        pot = self.pots[len(self.pots) - 1]
        for p in ordered:
            if p.all_in and p.chips_in_round > 0:
                self.logger.info(
                    "Found a player who is all in and has chips"
                    + " in the round. This will cause the current "
                    + "pot to be finalized."
                )
                pot.chips_to_win = p.chips_in_pot
                self.logger.debug(
                    "Set the minimum number of chips needed to"
                    + " win the current pot to the number of chips "
                    + "this player has put into all of the pots."
                )
                chips_for_pot = p.chips_in_round
                # chips_for_pot is the number of chips that will be put in this
                # pot by each player
                for o in players_in:
                    if o.chips_in_round != 0:
                        if o.chips_in_round < chips_for_pot:
                            # this player has folded and has less chips to
                            # put in than the player who this pot is being
                            # created for has, so they all go into this pot
                            pot.chips = pot.chips + o.chips_in_round
                            chips_in_round = chips_in_round - o.chips_in_round
                            o.chips_in_round = 0
                        else:
                            o.chips_in_round = o.chips_in_round - chips_for_pot
                            pot.chips = pot.chips + chips_for_pot
                            chips_in_round = chips_in_round - chips_for_pot
                            self.logger.debug("Put %i chips in this pot from" + " %s", chips_for_pot, str(player))
                self.logger.info("Finalized the pot, creating the next pot")
                pot = Pot(0, 0)
                self.pots.append(pot)
        self.logger.info("Putting the remaining chips from the round into " + "the current open pot")
        pot.chips = pot.chips + chips_in_round

    def reveal_hands(self):
        """Reveal the hands of all players who are still in the round"""
        for player in self.players:
            if player.in_round:
                player.cards_revealed = True

    def get_player_best_hand(self, player):
        """Return the best poker hand from the 7 cards available to the player.

        Argument:
        player -- a Player object

        """
        available_cards = []
        available_cards.extend(self.table)
        available_cards.extend(player.cards)
        self.logger.debug("All cards available to %s: %s", str(player), available_cards)
        assert len(available_cards) == 7
        hands = []
        for hand in combinations(available_cards, 5):
            hands.append(get_category(hand))
        sorted_hands = sorted(hands, reverse=True)
        self.logger.debug("Best hand: %s", sorted_hands[0])
        return sorted_hands[0]

    def rank_players(self):
        """Return the players still in the round ordered by their hands."""
        players_in = []
        for player in self.players:
            if player.in_round:
                players_in.append((player, self.get_player_best_hand(player)))
        return sorted(players_in, key=lambda player: player[1], reverse=True)

    def tie_break_winners(self, winners):
        """Return the player who wins the tie-breaker from a list of winners.

        Argument:
        winners -- a list of Player objects who have the same best hand

        """
        highest_card_hash = 0
        player_with_highest_card = None
        for winner in winners:
            for card in winner.cards:
                if card.__hash__ > highest_card_hash:
                    highest_card_hash = card.__hash__
                    player_with_highest_card = winner
        return player_with_highest_card

    def award_chips(self):
        """Award chips to the players who won the pots."""
        ordered_winners = []  # a list of tuples of players with their winning
        # hands in order, player with best hand at [0]
        if self.round_is_over():
            # game ended with only one player left in, so give all chips to
            # that player
            for player in self.players:
                if player.in_round:
                    assert ordered_winners == []
                    ordered_winners = [(player, None)]
        else:
            ordered_winners = self.rank_players()
        self.logger.info("Ordered winners by hands:")
        for player in ordered_winners:
            self.logger.info(str(player[0].user.bcc_id))
        self.logger.info("Handing out chips")
        for pot in self.pots:
            self.logger.info("Handing out chips for %s", str(pot))
            iterator = iter(ordered_winners)
            for player, hand in iterator:
                if player.chips_in_pot >= pot.chips_to_win:
                    winners = [player]
                    self.logger.debug("winner of pot: %s", str(player))
                    for next_player, next_hand in iterator:
                        if hand == next_hand and next_player.chips_in_pot >= pot.chips_to_win:
                            winners.append(next_player)
                            self.logger.debug("%s has tied", str(next_player))
                    self.logger.debug("winners of pot: %s", winners)
                    chips_per_winner = pot.chips / len(winners)
                    self.logger.debug("chips per winner: %d", chips_per_winner)
                    for winner in winners:
                        winner.chips = winner.chips + chips_per_winner
                        pot.chips = pot.chips - chips_per_winner
                        assert pot.chips >= 0
                        self.logger.debug("gave %d chips to %s", chips_per_winner, str(winner))
                    if pot.chips != 0:
                        self.logger.debug("there are %d chips left over", pot.chips)
                        winner = self.tie_break_winners(winners)
                        self.logger.debug("winner of tie-breaking procedure:" + " %s", winner)
                        winner.chips = winner.chips + pot.chips
                        pot.chips = 0
                    if pot.chips != 0:
                        self.logger.info(
                            "Chips were left over in this pot"
                            + " for the administrator! How kind."
                            + " Chips left over: %i",
                            pot.chips,
                        )
                    self.logger.info("finished dealing out chips for this pot")
                    break

    def play(self):
        """Play the round."""
        self.deal_hands()
        if not self.round_is_over():
            if self.betting_is_over():
                self.reveal_hands()
            else:
                self.action_position = 0
                self.do_betting_round()
        if not self.round_is_over():
            self.deal_flop()
            if self.betting_is_over():
                self.reveal_hands()
            else:
                self.action_position = 0
                self.do_betting_round()
        if not self.round_is_over():
            self.deal_turn()
            if self.betting_is_over():
                self.reveal_hands()
            else:
                self.action_position = 0
                self.do_betting_round()
        if not self.round_is_over():
            self.deal_river()
            if self.betting_is_over():
                self.reveal_hands()
            else:
                self.action_position = 0
                self.do_betting_round()
        if not self.round_is_over():
            self.reveal_hands()
        self.award_chips()
        self.logger.info("the round is over")