Exemple #1
0
    def __init__(self, seats=8, quiet=False, training=False):
        self._blind_index = 0
        [self._smallblind, self._bigblind] = Table.BLIND_INCREMENTS[0]
        self._deck = Deck()
        self._evaluator = Evaluator()

        self.community = []
        self._round = 0
        self._button = 0
        self._discard = []

        self._side_pots = [0] * seats
        self._current_sidepot = 0  # index of _side_pots
        self._totalpot = 0

        self._tocall = 0
        self._lastraise = 0
        self._number_of_hands = 0

        # fill seats with dummy players
        self._seats = [Player(0, 'empty', 0, None, True) for _ in range(seats)]
        self.emptyseats = seats
        self._player_dict = {}

        self._quiet = quiet
        self._training = training
Exemple #2
0
    def __init__(self, seats=8, quiet=False, training=False):
        self._blind_index = 0
        [self._smallblind, self._bigblind] = Table.BLIND_INCREMENTS[0]
        self._deck = Deck()
        self._evaluator = Evaluator()

        self.community = []
        self._round = 0
        self._button = 0
        self._discard = []

        self._side_pots = [0] * seats
        self._current_sidepot = 0  # index of _side_pots
        self._totalpot = 0

        self._tocall = 0
        self._lastraise = 0
        self._number_of_hands = 0

        # fill seats with dummy players
        self._seats = [
            Player(-1, -1, 0, 'empty', 0, True) for _ in range(seats)
        ]
        self.emptyseats = seats
        self._player_dict = {}

        self.teacher = xmlrpc.client.ServerProxy('http://0.0.0.0:8080')

        self._quiet = quiet
        self._training = training
        self._run_thread = Thread(target=self.run, args=())
        self._run_thread.daemon = True
Exemple #3
0
    def __init__(self, smallBlind, bigBlind, maxBuyIn):
        """ Constructor accepts  blinds and maximum table buy in as integers. """

        self._players = []  #players at the table
        self._playing = []  #players who are not bankrupt
        self._sitOut = []  #players who have gone bankrupt
        self._dealer = 0  #position of dealer in self._playing
        self._eval = Evaluator()

        if type(smallBlind) != int or type(bigBlind) != int or type(
                maxBuyIn) != int:
            raise Exception('Parameters must be integer number of chips.')
        self._smallBlind = smallBlind
        self._bigBlind = bigBlind
        self._maxBuyIn = maxBuyIn
Exemple #4
0
    def __init__(self, args):
        '''
        Bot constructor

        Add data that needs to be persisted between rounds here.
        '''
        self.ev = Evaluator()

        if args.config_data is None:
            self.config =  json.load(args.config)
        else:
            self.config = json.loads(args.config_data)
        LOG_FILENAME = self.config["logfile"]

        self.eval_path = [os.path.join(os.path.dirname(os.path.realpath(__file__)), "score", "eval")]

        super(AI, self).__init__()

        # Set up a specific logger with our desired output level
        self.log = logging.getLogger('MyLogger')
        self.log.setLevel(logging.DEBUG)

        if args.no_log:
            self.log.setLevel(logging.CRITICAL)
        if args.log:
            self.handler = logging.handlers.RotatingFileHandler(
                    LOG_FILENAME, backupCount=5)
        else:
            self.handler = logging.StreamHandler(stderr)

        self.log.addHandler(self.handler)
Exemple #5
0
    def __init__(self, seats = 8, quiet = False, training = False):
        self._blind_index = 0
        [self._smallblind, self._bigblind] = Table.BLIND_INCREMENTS[0]
        self._deck = Deck()
        self._evaluator = Evaluator()

        self.community = []
        self._round = 0
        self._button = 0
        self._discard = []

        self._side_pots = [0]*seats
        self._current_sidepot = 0 # index of _side_pots
        self._totalpot = 0

        self._tocall = 0
        self._lastraise = 0
        self._number_of_hands = 0

        # fill seats with dummy players
        self._seats = [Player(-1,-1,0,'empty',0,True) for _ in range(seats)]
        self.emptyseats = seats
        self._player_dict = {}

        self.teacher = xmlrpc.client.ServerProxy('http://0.0.0.0:8080')

        self._quiet = quiet
        self._training = training
        self._run_thread = Thread(target = self.run, args=())
        self._run_thread.daemon = True
Exemple #6
0
    def __init__(self, slack_client):
        self.state = DEAD_STATE
        self.timer = WAIT

        self.players = []
        self.deck = None
        self.current_player = 0
        self.pot_manager = None
        self.slack_client = slack_client
        self.join_manager = None
        self.chat = None
        self.dealer_id = 0
        self.bet_manager = None
        self.board = []
        self.evaluator = Evaluator()
        self.last_message = None
        self.board_message = None
Exemple #7
0
    def __init__(self, board, hand):
        self.board = board
        self.hand = hand

        self.evalBoard = evalCards(board)
        self.evalHand = evalCards(hand)

        self.evaluator = Evaluator()

        self.availableCards = []
        for suit in ["d", "c", "s", "h"]:
            for val in [
                    "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K",
                    "A"
            ]:
                availCard = myCard(val + suit)
                if not availCard in self.hand + self.board:
                    self.availableCards.append(availCard)
        self.handDict = dict()
        self.discardDict = dict()
Exemple #8
0
class DeucesWrapper(object):
    def __init__(self):
        self.e = DEvaluator()

    def evaluate(self, board, hand):
        dhand = []
        dboard = []
        for c in board:
            dcard = DCard.new(repr(c))
            dboard.append(dcard)
        for c in hand.cards():
            dcard = DCard.new(repr(c))
            dhand.append(dcard)
        return self.e.evaluate(dboard, dhand)
Exemple #9
0
    def __init__(self, slack_client):
        self.state = DEAD_STATE
        self.timer = WAIT

        self.players = []
        self.deck = None
        self.current_player = 0
        self.pot_manager = None
        self.slack_client = slack_client
        self.join_manager = None
        self.chat = None
        self.dealer_id = 0
        self.bet_manager = None
        self.board = []
        self.evaluator = Evaluator()
        self.last_message = None
        self.board_message = None
Exemple #10
0
class Game:
    def __init__(self, slack_client):
        self.state = DEAD_STATE
        self.timer = WAIT

        self.players = []
        self.deck = None
        self.current_player = 0
        self.pot_manager = None
        self.slack_client = slack_client
        self.join_manager = None
        self.chat = None
        self.dealer_id = 0
        self.bet_manager = None
        self.board = []
        self.evaluator = Evaluator()
        self.last_message = None
        self.board_message = None

    def start(self, channel):
        self.state = START_STATE
        self.timer = WAIT
        self.players = []
        self.deck = Deck()
        self.current_player = 0
        self.chat = Chat(self.slack_client, channel)
        self.pot_manager = PotManager(self.chat)
        self.join_manager = JoinManager(self.slack_client, channel, self.players)

        self.bet_manager = BetManager(self.pot_manager, self.players)
        self.board = []
        self.last_message = None
        self.board_message = None

    def process(self, data):
        if 'text' in data:
            text = data['text']
            quit_text = '{}: quit'.format(bot_name)

            if quit_text.lower() in text.lower():
                if PAUSE_BETWEEN_GAME_STATE == self.state:
                    player_to_remove = None
                    for player in self.players:
                        if player.slack_id == data['user']:
                            player_to_remove = player

                    self.players.remove(player_to_remove)
                    self.chat.message("{} has quit.".format(player_to_remove))
                else:
                    self.chat.message("You can't quit now, wait between games.")

        if DEAD_STATE == self.state:
            self.process_dead(data)

        if START_STATE == self.state:
            self.process_start(data)

        if BET_STATE == self.state:
            self.bet_manager.process(data)

    def process_dead(self, data):
        text = data['text']
        deal_text = '{}: deal'.format(bot_name)

        if deal_text.lower() in text.lower():
            self.start(data['channel'])

    def process_start(self, data):
        self.join_manager.process_message(data)

    def set_state(self, state):
        self.state = state
        self.timer = WAIT
        self.last_message = None
        self.board_message = None

    def enough_players(self):
        if len(self.players) < 2:
            self.chat.message("Not enough players.")
            self.set_state(DEAD_STATE)
            return False
        return True

    def deal_state(self):
        self.current_player = 0

        if not self.enough_players():
            return

        # burn card
        self.deck.draw(1)

        for player in self.players:
            player.deal(self.deck.draw(2))

        self.set_state(BLIND_STATE)

    def post_blind(self, blind_func):
        while True:
            player = self.players[self.current_player % len(self.players)]
            can_post = blind_func(player)
            if not can_post:
                self.players.pop(0)
                if not self.enough_players():
                    return False
            self.current_player += 1
            return True

    def blind_state(self):
        if not self.post_blind(self.pot_manager.post_small_blind):
            return

        if not self.post_blind(self.pot_manager.post_big_blind):
            return

        self.pot_manager.add_other_players(self.players)

        self.dealer_id = self.current_player

        self.display_board()
        flop_callback = partial(self.set_state, FLOP_STATE)
        fold_win_callback = partial(self.set_state, FOLD_WIN_STATE)
        self.bet_manager.request_bets(self.dealer_id, flop_callback, fold_win_callback, self.display_board)
        self.set_state(BET_STATE)

    def display_board(self):
        board_str = '```'
        for i, player in enumerate(self.players):
            if i == self.current_player % len(self.players):
                board_str += '->'
            else:
                board_str += '  '

            board_str += '<@{}>\t\t\t${}\t{}\t{} {}\n'.format(player.slack_id,
                                                              player.money,
                                                              player.state,
                                                              player.action,
                                                              player.bet)
        board_str += '```\n'
        board_str += self.pot_manager.get_pot_string()
        board_str += "\n{}".format(Game.board_to_string(self.board))

        self.board_message = self.chat.message(board_str, self.board_message)

    @staticmethod
    def board_to_string(board):
        result = ""
        for card in board:
            result += "{} ".format(Card.int_to_pretty_str(card))

        return result

    def flop_state(self):
        # burn card
        self.deck.draw(1)

        self.board.extend(self.deck.draw(3))
        self.chat.message("*Dealing the flop:*\n{}".format(Game.board_to_string(self.board)))
        turn_callback = partial(self.set_state, TURN_STATE)
        fold_win_callback = partial(self.set_state, FOLD_WIN_STATE)
        self.bet_manager.request_bets(0, turn_callback, fold_win_callback, self.display_board)
        self.set_state(BET_STATE)

    def turn_state(self):
        # burn card
        self.deck.draw(1)

        self.board.append(self.deck.draw(1))
        self.chat.message("*Dealing the turn:*\n{}".format(Game.board_to_string(self.board)))
        turn_callback = partial(self.set_state, RIVER_STATE)
        fold_win_callback = partial(self.set_state, FOLD_WIN_STATE)
        self.bet_manager.request_bets(0, turn_callback, fold_win_callback, self.display_board)
        self.set_state(BET_STATE)

    def river_state(self):
        # burn card
        self.deck.draw(1)

        self.board.append(self.deck.draw(1))
        self.chat.message("*Dealing the river:*\n{}".format(Game.board_to_string(self.board)))
        self.set_state(SHOW_HANDS_STATE)

    def count_down(self, new_state):
        self.timer -= 1
        if self.timer < 0:
            self.set_state(new_state)
            return

    def show_hands_state(self):
        for player in self.players:
            if player.state == Player.FOLD_STATE:
                continue

            card_score = self.evaluator.evaluate(self.board, player.cards)
            card_class = self.evaluator.get_rank_class(card_score)
            self.chat.message('{} had: {} {}'.format(player, player.card_str(), card_class))

        self.set_state(DETERMINE_WINNER_STATE)

    def determine_winner_state(self):

        for pot in reversed(self.pot_manager.pots):
            pot_score = 9999
            pot_winners = []
            if len(pot.players) == 1:
                self.chat.message(SINGLE_WINNER_MESSAGE.format(pot.players[0], pot.amount, pot.name))
                pot.players[0].money += pot.amount
            else:
                for player in pot.players:
                    card_score = self.evaluator.evaluate(self.board, player.cards)
                    if card_score == pot_score:
                        pot_winners.append(player)

                    if card_score < pot_score:
                        pot_winners = [player]
                        pot_score = card_score

                if len(pot_winners) == 1:
                    self.chat.message(SINGLE_WINNER_MESSAGE.format(pot_winners[0], pot.amount, pot.name))
                    pot_winners[0].money += pot.amount
                else:
                    self.chat.message(SPLIT_WINNER_MESSAGE.format(pot_winners, pot.amount, pot.name))
                    for pot_winner in pot_winners:
                        pot_winner.money += (pot.amount / len(pot_winners))

        self.set_state(PREPARE_NEW_GAME_STATE)

    def prepare_new_game_state(self):
        # rotate players
        self.players.append(self.players.pop(0))
        self.set_state(PAUSE_BETWEEN_GAME_STATE)

    def pause_between_game_state(self):
        self.last_message = self.chat.message(PAUSE_MESSAGE.format(self.timer), self.last_message)
        self.timer = NEW_GAME_WAIT
        self.count_down(DEAL_STATE)

    def tick(self):
        if START_STATE == self.state:
            self.join_manager.tick(self.timer)
            self.count_down(DEAL_STATE)

        if DEAL_STATE == self.state:
            self.deal_state()

        if BLIND_STATE == self.state:
            self.blind_state()

        if BET_STATE == self.state:
            self.bet_manager.tick()

        if FLOP_STATE == self.state:
            self.flop_state()

        if TURN_STATE == self.state:
            self.turn_state()

        if RIVER_STATE == self.state:
            self.river_state()

        if FOLD_WIN_STATE == self.state:
            self.set_state(DETERMINE_WINNER_STATE)

        if SHOW_HANDS_STATE == self.state:
            self.show_hands_state()

        if DETERMINE_WINNER_STATE == self.state:
            self.determine_winner_state()

        if PREPARE_NEW_GAME_STATE == self.state:
            self.prepare_new_game_state()

        if PAUSE_BETWEEN_GAME_STATE == self.state:
            self.pause_between_game_state()
Exemple #11
0
class Table(object):
    #BLIND_INCREMENTS = [[10,25],[25,50],[50,100],[75,150],[100,200],[150,300],[200,400],[300,600],[400,800],[500,10000],[600,1200],[800,1600],[1000,2000]]
    BLIND_INCREMENTS = [[3, 6], [25, 50], [50, 100], [75, 150], [100, 200],
                        [150, 300], [200, 400], [300, 600], [400, 800],
                        [500, 10000], [600, 1200], [800, 1600], [1000, 2000]]

    def __init__(self, seats=8, quiet=False, training=False):
        self._blind_index = 0
        [self._smallblind, self._bigblind] = Table.BLIND_INCREMENTS[0]
        self._deck = Deck()
        self._evaluator = Evaluator()

        self.community = []
        self._round = 0
        self._button = 0
        self._discard = []

        self._side_pots = [0] * seats
        self._current_sidepot = 0  # index of _side_pots
        self._totalpot = 0

        self._tocall = 0
        self._lastraise = 0
        self._number_of_hands = 0

        # fill seats with dummy players
        self._seats = [
            Player(-1, -1, 0, 'empty', 0, True) for _ in range(seats)
        ]
        self.emptyseats = seats
        self._player_dict = {}

        self.teacher = xmlrpc.client.ServerProxy('http://0.0.0.0:8080')

        self._quiet = quiet
        self._training = training
        self._run_thread = Thread(target=self.run, args=())
        self._run_thread.daemon = True

    def start(self):
        self._run_thread.start()

    def run(self):
        while True:
            self.run_game()

    def run_game(self):
        self.ready_players()
        # for p in self._seats:
        #     print('Player ',p.playerID, ' playing hand: ', p.playing_hand, 'sitting out', p.sitting_out)
        players = [
            player for player in self._seats
            if not player.emptyplayer and not player.sitting_out
        ]

        self._number_of_hands = 1

        # start hand if table full
        # if len(players) == len(self._seats):
        [self._smallblind, self._bigblind] = Table.BLIND_INCREMENTS[0]

        # keep playing until there's a single player (shotgun style)
        while (self.emptyseats < len(self._seats) - 1):
            # answer = input('Press [enter] to start a game:')
            # if not answer:
            self.start_hand(players)
            self._number_of_hands += 1
            if not self._quiet:
                print('Starting game number: ', self._number_of_hands)
                for p in self._seats:
                    if p.playing_hand:
                        print('Player ', p.playerID, ' stack size: ', p.stack)

            # increment blinds every 15 hands (based on avg hands/hour of 30)
            # if (self._number_of_hands % 15) == 0 and self._number_of_hands < 60:
            #    self.increment_blinds()

            if len([p for p in players if p.playing_hand]) == 1:
                winner = [p for p in players if p.playing_hand][0]
                if self._training:
                    self.teacher.add_winner(winner.server.get_ai_id())
                break

            if self._number_of_hands == 200:
                print('no winner in 200 hands')
                break

    def start_hand(self, players):
        players = [p for p in players if p.playing_hand]
        assert sum([p.stack for p in players]) == 2000 * len(self._seats)
        self.new_round()
        self._round = 0

        player = self._first_to_act(players)

        self.post_smallblind(player)
        player = self._next(players, player)
        self.post_bigblind(player)
        player = self._next(players, player)

        self._tocall = self._bigblind

        # rounds
        self._round = 0
        while self._round < 4 and len(players) > 1:
            if self._round == 0:
                self.deal()
            elif self._round == 1:
                self.flop()
            elif self._round == 2:
                self.turn()
            elif self._round == 3:
                self.river()

            folded_players = []
            while not player.playedthisround and len(
                [p for p in players if not p.isallin]) >= 1:
                if player.isallin:
                    # print('player ', player.playerID, 'is all in, skipping their turn')
                    player = self._next(players, player)
                    continue
                # print('requesting move from ',player.playerID)
                move = player.server.player_move(
                    self.output_state(player))  # MAKE PLAYER MOVE!

                if move[0] == 'call':
                    self.player_bet(player, self._tocall)
                    if not self._quiet:
                        print('Player', player.playerID, move)
                    player = self._next(players, player)
                elif move[0] == 'check':
                    self.player_bet(player, player.currentbet)
                    if not self._quiet:
                        print('Player', player.playerID, move)
                    player = self._next(players, player)
                elif move[0] == 'raise':
                    self.player_bet(player, move[1] + player.currentbet)
                    if not self._quiet:
                        print('Player', player.playerID, move)
                    for p in players:
                        if p != player:
                            p.playedthisround = False
                    player = self._next(players, player)
                elif move[0] == 'fold':
                    player.playing_hand = False
                    folded_player = player
                    if not self._quiet:
                        print('Player', player.playerID, move)
                    player = self._next(players, player)
                    players.remove(folded_player)
                    folded_players.append(folded_player)
                    # break if a single player left
                    if len(players) == 1:
                        break

            player = self._first_to_act(players)
            self.resolve_sidepots(players + folded_players)
            self.new_round()
            if not self._quiet:
                print('totalpot', self._totalpot)
            assert sum([p.stack for p in self._seats
                        ]) + self._totalpot == 2000 * len(self._seats)

        self.resolve_game(players)
        self.reset()

    def increment_blinds(self):
        self._blind_index = min(self._blind_index + 1,
                                len(Table.BLIND_INCREMENTS) - 1)
        [self._smallblind,
         self._bigblind] = Table.BLIND_INCREMENTS[self._blind_index]

    def post_smallblind(self, player):
        if not self._quiet:
            print('player ', player.playerID, 'small blind', self._smallblind)
        self.player_bet(player, self._smallblind)
        player.playedthisround = False

    def post_bigblind(self, player):
        if not self._quiet:
            print('player ', player.playerID, 'big blind', self._bigblind)
        self.player_bet(player, self._bigblind)
        player.playedthisround = False
        self._lastraise = self._bigblind

    def player_bet(self, player, total_bet):
        # relative_bet is how much _additional_ money is the player betting this turn, on top of what they have already contributed
        # total_bet is the total contribution by player to pot in this round
        relative_bet = min(player.stack, total_bet - player.currentbet)
        player.bet(relative_bet + player.currentbet)

        self._totalpot += relative_bet
        self._tocall = max(self._tocall, total_bet)
        if self._tocall > 0:
            self._tocall = max(self._tocall, self._bigblind)
        self._lastraise = max(self._lastraise, relative_bet - self._lastraise)

    def _first_to_act(self, players):
        if self._round == 0 and len(players) == 2:
            return self._next(
                sorted(players + [self._seats[self._button]],
                       key=lambda x: x.get_seat()), self._seats[self._button])
        try:
            first = [
                player for player in players
                if player.get_seat() > self._button
            ][0]
        except IndexError:
            first = players[0]
        return first

    def _next(self, players, current_player):
        idx = players.index(current_player)
        return players[(idx + 1) % len(players)]

    def deal(self):
        for player in self._seats:
            if player.playing_hand:
                player.hand = self._deck.draw(2)

    def flop(self):
        self._discard.append(self._deck.draw(1))  #burn
        self.community = self._deck.draw(3)

    def turn(self):
        self._discard.append(self._deck.draw(1))  #burn
        self.community.append(self._deck.draw(1))

    def river(self):
        self._discard.append(self._deck.draw(1))  #burn
        self.community.append(self._deck.draw(1))

    def add_player(self, host, port, playerID, name, stack):
        if playerID not in self._player_dict:
            new_player = Player(host, port, playerID, name, stack)
            for i, player in enumerate(self._seats):
                if player.emptyplayer:
                    self._seats[i] = new_player
                    new_player.set_seat(i)
                    break
            self._player_dict[playerID] = new_player
            self.emptyseats -= 1

    def ready_players(self):
        if len([p for p in self._seats
                if not p.emptyplayer and p.sitting_out]) == len(self._seats):
            for p in self._seats:
                if not p.emptyplayer:
                    p.sitting_out = False
                    p.playing_hand = True

    def remove_player(self, playerID):
        try:
            idx = self._seats.index(self._player_dict[playerID])
            self._seats[idx] = Player(-1, -1, 0, 'empty', 0, True)
            del self._player_dict[playerID]
            self.emptyseats += 1
        except ValueError:
            pass

    def resolve_sidepots(self, players_playing):
        players = [p for p in players_playing if p.currentbet]
        if not self._quiet:
            print('current bets: ', [p.currentbet for p in players])
            print('playing hand: ', [p.playing_hand for p in players])
        if not players:
            return
        try:
            smallest_bet = min(
                [p.currentbet for p in players if p.playing_hand])
        except ValueError:
            for p in players:
                self._side_pots[self._current_sidepot] += p.currentbet
                p.currentbet = 0
            return

        smallest_players_allin = [
            p for p, bet in zip(players, [p.currentbet for p in players])
            if bet == smallest_bet and p.isallin
        ]

        for p in players:
            self._side_pots[self._current_sidepot] += min(
                smallest_bet, p.currentbet)
            p.currentbet -= min(smallest_bet, p.currentbet)
            p.lastsidepot = self._current_sidepot

        if smallest_players_allin:
            self._current_sidepot += 1
            self.resolve_sidepots(players)
        if not self._quiet:
            print('sidepots: ', self._side_pots)

    def new_round(self):
        for player in self._player_dict.values():
            player.currentbet = 0
            player.playedthisround = False
        self._round += 1
        self._tocall = 0
        self._lastraise = 0

    def resolve_game(self, players):
        # print('Community cards: ', end='')
        # Card.print_pretty_cards(self.community)
        if len(players) == 1:
            players[0].refund(sum(self._side_pots))
            # print('Player', players[0].playerID, 'wins the pot (',sum(self._side_pots),')')
            self._totalpot = 0
        else:
            # compute hand ranks
            print("Board: ", Card.print_pretty_cards(self.community))
            for player in players:
                player.handrank = self._evaluator.evaluate(
                    player.hand, self.community)
                print("Player: {}".format(player.playerID),
                      Card.print_pretty_cards(player.hand))
            # trim side_pots to only include the non-empty side pots
            temp_pots = [pot for pot in self._side_pots if pot > 0]

            # compute who wins each side pot and pay winners
            for pot_idx, _ in enumerate(temp_pots):
                # print('players last pots', [(p.playerID, p.lastsidepot) for p in players])

                # find players involved in given side_pot, compute the winner(s)
                pot_contributors = [
                    p for p in players if p.lastsidepot >= pot_idx
                ]
                winning_rank = min([p.handrank for p in pot_contributors])
                winning_players = [
                    p for p in pot_contributors if p.handrank == winning_rank
                ]

                for player in winning_players:
                    split_amount = int(self._side_pots[pot_idx] /
                                       len(winning_players))
                    if not self._quiet:
                        print(
                            'Player', player.playerID, 'wins side pot (',
                            int(self._side_pots[pot_idx] /
                                len(winning_players)), ')')
                    player.refund(split_amount)
                    self._side_pots[pot_idx] -= split_amount

                # any remaining chips after splitting go to the winner in the earliest position
                if self._side_pots[pot_idx]:
                    earliest = self._first_to_act(
                        [player for player in winning_players])
                    earliest.refund(self._side_pots[pot_idx])

    def reset(self):
        for player in self._seats:
            if not player.emptyplayer and not player.sitting_out:
                player.reset_hand()
        self.community = []
        self._current_sidepot = 0
        self._totalpot = 0
        self._side_pots = [0] * len(self._seats)
        self._deck.shuffle()

        self._button = (self._button + 1) % len(self._seats)
        while not self._seats[self._button].playing_hand:
            self._button = (self._button + 1) % len(self._seats)

    def output_state(self, current_player):
        return {
            'players': [player.player_state() for player in self._seats],
            'community': self.community,
            'my_seat': current_player.get_seat(),
            'pocket_cards': current_player.hand,
            'pot': self._totalpot,
            'button': self._button,
            'tocall': (self._tocall - current_player.currentbet),
            'stack': current_player.stack,
            'bigblind': self._bigblind,
            'playerID': current_player.playerID,
            'lastraise': self._lastraise,
            'minraise': max(self._bigblind, self._lastraise + self._tocall)
        }
Exemple #12
0
 def __init__(self):
     self.deck = Deck()
     self.reset()
     self._evaluator = Evaluator()
     self.monte_carlo_rounds = 1000
Exemple #13
0
class Analyzer:
    def __init__(self):
        self.deck = Deck()
        self.reset()
        self._evaluator = Evaluator()
        self.monte_carlo_rounds = 1000

    def reset(self):
        self.deck.shuffle()
        self.hole_cards = []
        self.community_cards = []

    def set_num_opponents(self, n):
        self.num_opponents = n

    def set_monte_carlo_rounds(self, n):
        self.monte_carlo_rounds = n

    def set_pocket_cards(self, card1, card2):
        self.deck.remove(card1)
        self.deck.remove(card2)
        self.hole_cards.append(card1)
        self.hole_cards.append(card2)

    def community_card(self, card):
        self.deck.remove(card)
        self.community_cards.append(card)

    def analyze(self):
        wins = 0
        ties = 0
        to_flop = 5 - len(self.community_cards)
        to_draw = to_flop + 2 * self.num_opponents

        total_rounds = self.monte_carlo_rounds
        total_opponent_hands = total_rounds * self.num_opponents

        # Monte Carlo simulation
        for _ in range(self.monte_carlo_rounds):
            # Draw a uniformly random combination of unseen cards (remaining
            # community cards + 2 hole cards per opponent)
            drawn_cards = self.deck.sample(to_draw)
            all_comms = self.community_cards + drawn_cards[:to_flop]
            my_ranking = self._evaluator.evaluate(self.hole_cards, all_comms)

            # 2: win, 1: tie, 0: loss
            winner = 2
            for i in range(self.num_opponents):
                their_cards = drawn_cards[to_flop + 2 * i:to_flop + 2 * i + 2]
                their_ranking = self._evaluator.evaluate(
                    their_cards, all_comms)
                if my_ranking > their_ranking:
                    winner = 0
                elif my_ranking == their_ranking:
                    winner = min(winner, 1)
            if winner == 2:
                wins += 1
            elif winner == 1:
                ties += 1

        win_ratio = wins / total_rounds
        return win_ratio
Exemple #14
0
    def manage_winnings(self):
        '''
        Function that checks who the winners are and distributes the pot
        acordingly.
        '''
        if self.table.state < 4:
            # A single player remained, the rest have folded
            # Go through each bet, if they dont belong to the un-folded player,
            # add them upp so we can transfer them to the winner.
            winnings = 0
            winner = None
            for player in self.table.bets[self.table.state]:
                for state in xrange(self.table.state + 1):
                    winnings += sum(self.table.bets[state][player])
                if player.state != 6:
                    winner = player
            winner.bankroll += winnings
            winner.signal_end(win=True, amt=winnings, nr_round=self.nr_round)
            log('WINNER: %s %s' % (winner.name, winnings))
            for p in self.table.players:
                if p is not winner:
                    lost_amt = 0
                    for bets in self.table.bets.values():
                        lost_amt += sum(bets[p])
                    p.signal_end(win=False, amt=lost_amt, nr_round=self.nr_round)
        else:
            # A so called 'showdown'
            e = Evaluator()
            dboard = []
            for card in self.table.family_cards:
                dboard.append(DCard.new(repr(card)))
            vals = {}
            for p in self.table.players:
                vals[p] = [0, 0]
            for p in self.table.players:
                for s in self.table.bets:
                    vals[p][0] += sum(self.table.bets[s][p])
                hand = [
                    DCard.new(repr(p.hand.cards()[0])),
                    DCard.new(repr(p.hand.cards()[1])),
                ]
                vals[p][1] = e.evaluate(dboard, hand) if p.state != 6 else 9000

            to_distribute = sum([v[0] for v in vals.values()])
            best_card_score = min([v[1] for v in vals.values()])
            winners = [
                p
                for p, v in vals.iteritems()
                if v[1] == best_card_score
            ]
            winnings = 0
            for p, v in vals.iteritems():
                if p in winners:
                    p.bankroll += v[0]
                    winnings += v[0]
                else:
                    for w in winners:
                        w.bankroll += int(v[0]/len(winners))
                        winnings += int(v[0]/len(winners))
            for w in winners:
                w.signal_end(
                    win=True, amt=int(winnings/len(winners)),
                    nr_round=self.nr_round)
            for p in self.table.players:
                if p not in winners:
                    lost_amt = 0
                    for bets in self.table.bets.values():
                        lost_amt += sum(bets[p])
                    p.signal_end(win=False, amt=lost_amt, nr_round=self.nr_round)
            log('WINNER(s): %s %s' %
                (', '.join([w.name for w in winners]),
                 int(winnings/len(winners))))
from pokermodules.convenience_hole import all_hands_in_range, add_margins, range_plot, deck_choose_2
from pokermodules.convenience import pr
from deuces.deuces import Card, Evaluator

e = Evaluator()
rank_class_keys = ['Straight Flush', 'Four of a Kind', 'Full House', 'Flush',
                   'Straight',
                   'Set', 'Trips', 'Three of a Kind to Board',
                   'Two Pair',
                   'Overpair', 'Top Pair', '1.5 Pair', 'Middle Pair', 'Weak Pair',
                   'Ace High in Hole', 'Ace High to Board', 'No Made Hand'
                   ] # we do this to output them in order
rc_counts = {}

deuces_plus = 'AA KK QQ JJ TT 99 88 77 66 55 44 33 22'.split()
bway = 'A K Q J T'.split()
ATB = []
for i in bway:
    for j in bway:
        if i == j:
            continue
        elif bway.index(i) > bway.index(j):
            ATB.append(j + i)
        elif bway.index(i) < bway.index(j):
            ATB.append(i + j + 's')
assert len(ATB) == 20

## Input vars:
board = [Card.new('Qs'), Card.new('Td'), Card.new('4c')]
range_list = ['AA', 'KK', 'QQ', 'AK', 'AKs', 'KQ', 'KQs', 'JJ', '33', '22', 'A4', '99', 'AJ', 'KJ']
Exemple #16
0
class Table(object):
    BLIND_INCREMENTS = [[10,25],[25,50],[50,100],[75,150],[100,200],[150,300],[200,400],[300,600],[400,800],[500,10000],[600,1200],[800,1600],[1000,2000]]

    def __init__(self, seats = 8, quiet = False, training = False):
        self._blind_index = 0
        [self._smallblind, self._bigblind] = Table.BLIND_INCREMENTS[0]
        self._deck = Deck()
        self._evaluator = Evaluator()

        self.community = []
        self._round = 0
        self._button = 0
        self._discard = []

        self._side_pots = [0]*seats
        self._current_sidepot = 0 # index of _side_pots
        self._totalpot = 0

        self._tocall = 0
        self._lastraise = 0
        self._number_of_hands = 0

        # fill seats with dummy players
        self._seats = [Player(-1,-1,0,'empty',0,True) for _ in range(seats)]
        self.emptyseats = seats
        self._player_dict = {}

        self.teacher = xmlrpc.client.ServerProxy('http://0.0.0.0:8080')

        self._quiet = quiet
        self._training = training
        self._run_thread = Thread(target = self.run, args=())
        self._run_thread.daemon = True

    def start(self):
        self._run_thread.start()

    def run(self):
        while True:
            self.run_game()

    def run_game(self):
        self.ready_players()
        # for p in self._seats:
        #     print('Player ',p.playerID, ' playing hand: ', p.playing_hand, 'sitting out', p.sitting_out)
        players = [player for player in self._seats if not player.emptyplayer and not player.sitting_out]

        self._number_of_hands = 1

        # start hand if table full
        # if len(players) == len(self._seats):
        [self._smallblind, self._bigblind] = Table.BLIND_INCREMENTS[0]

        # keep playing until there's a single player (shotgun style)
        while(self.emptyseats < len(self._seats)-1):
            # answer = input('Press [enter] to start a game:')
            # if not answer:
            self.start_hand(players)
            self._number_of_hands += 1
            if not self._quiet:
                print('Starting game number: ', self._number_of_hands)
                for p in self._seats:
                    if p.playing_hand:
                        print('Player ',p.playerID, ' stack size: ', p.stack)

            # increment blinds every 15 hands (based on avg hands/hour of 30)
            if (self._number_of_hands % 15) == 0 and self._number_of_hands < 60:
                self.increment_blinds()


            if len([p for p in players if p.playing_hand]) == 1:
                winner = [p for p in players if p.playing_hand][0]
                if self._training:
                    self.teacher.add_winner(winner.server.get_ai_id())
                break

            if self._number_of_hands == 200:
                print('no winner in 200 hands')
                break

    def start_hand(self, players):
        players = [p for p in players if p.playing_hand]
        assert sum([p.stack for p in players]) == 2000*len(self._seats)
        self.new_round()
        self._round=0

        player = self._first_to_act(players)

        self.post_smallblind(player)
        player = self._next(players, player)
        self.post_bigblind(player)
        player = self._next(players, player)

        self._tocall = self._bigblind

        # rounds
        self._round = 0
        while self._round<4 and len(players)>1:
            if self._round == 0:
                self.deal()
            elif self._round == 1:
                self.flop()
            elif self._round == 2:
                self.turn()
            elif self._round ==3:
                self.river()

            folded_players = []
            while not player.playedthisround and len([p for p in players if not p.isallin]) >=1:
                if player.isallin:
                    # print('player ', player.playerID, 'is all in, skipping their turn')
                    player = self._next(players, player)
                    continue
                # print('requesting move from ',player.playerID)
                move = player.server.player_move(self.output_state(player))

                if move[0] == 'call':
                    self.player_bet(player, self._tocall)
                    if not self._quiet:
                        print('Player', player.playerID, move)
                    player = self._next(players, player)
                elif move[0] == 'check':
                    self.player_bet(player, player.currentbet)
                    if not self._quiet:
                        print('Player', player.playerID, move)
                    player = self._next(players, player)
                elif move[0] == 'raise':
                    self.player_bet(player, move[1]+player.currentbet)
                    if not self._quiet:
                        print('Player', player.playerID, move)
                    for p in players:
                        if p != player:
                            p.playedthisround = False
                    player = self._next(players, player)
                elif move[0] == 'fold':
                    player.playing_hand = False
                    folded_player = player
                    if not self._quiet:
                        print('Player', player.playerID, move)
                    player = self._next(players, player)
                    players.remove(folded_player)
                    folded_players.append(folded_player)
                    # break if a single player left
                    if len(players) ==1:
                        break

            player = self._first_to_act(players)
            self.resolve_sidepots(players + folded_players)
            self.new_round()
            if not self._quiet:
                print('totalpot', self._totalpot)
            assert sum([p.stack for p in self._seats]) + self._totalpot == 2000*len(self._seats)

        self.resolve_game(players)
        self.reset()

    def increment_blinds(self):
        self._blind_index = min(self._blind_index+1,len(Table.BLIND_INCREMENTS)-1)
        [self._smallblind, self._bigblind] = Table.BLIND_INCREMENTS[self._blind_index]

    def post_smallblind(self, player):
        if not self._quiet:
            print('player ', player.playerID, 'small blind', self._smallblind)
        self.player_bet(player, self._smallblind)
        player.playedthisround = False

    def post_bigblind(self, player):
        if not self._quiet:
            print('player ', player.playerID, 'big blind', self._bigblind)
        self.player_bet(player, self._bigblind)
        player.playedthisround = False
        self._lastraise = self._bigblind

    def player_bet(self, player, total_bet):
        # relative_bet is how much _additional_ money is the player betting this turn, on top of what they have already contributed
        # total_bet is the total contribution by player to pot in this round
        relative_bet = min(player.stack, total_bet - player.currentbet)
        player.bet(relative_bet + player.currentbet)

        self._totalpot += relative_bet
        self._tocall = max(self._tocall, total_bet)
        if self._tocall >0:
            self._tocall = max(self._tocall, self._bigblind)
        self._lastraise = max(self._lastraise, relative_bet  - self._lastraise)

    def _first_to_act(self, players):
        if self._round == 0 and len(players) == 2:
            return self._next(sorted(players + [self._seats[self._button]], key=lambda x:x.get_seat()), self._seats[self._button])
        try:
            first = [player for player in players if player.get_seat() > self._button][0]
        except IndexError:
            first = players[0]
        return first

    def _next(self, players, current_player):
        idx = players.index(current_player)
        return players[(idx+1) % len(players)]

    def deal(self):
        for player in self._seats:
            if player.playing_hand:
                player.hand = self._deck.draw(2)

    def flop(self):
        self._discard.append(self._deck.draw(1)) #burn
        self.community = self._deck.draw(3)

    def turn(self):
        self._discard.append(self._deck.draw(1)) #burn
        self.community.append(self._deck.draw(1))

    def river(self):
        self._discard.append(self._deck.draw(1)) #burn
        self.community.append(self._deck.draw(1))

    def add_player(self, host, port, playerID, name, stack):
        if playerID not in self._player_dict:
            new_player = Player(host, port, playerID, name, stack)
            for i,player in enumerate(self._seats):
                if player.emptyplayer:
                    self._seats[i] = new_player
                    new_player.set_seat(i)
                    break
            self._player_dict[playerID] = new_player
            self.emptyseats -= 1

    def ready_players(self):
        if len([p for p in self._seats if not p.emptyplayer and p.sitting_out]) == len(self._seats):
            for p in self._seats:
                if not p.emptyplayer:
                    p.sitting_out = False
                    p.playing_hand = True

    def remove_player(self, playerID):
        try:
            idx = self._seats.index(self._player_dict[playerID])
            self._seats[idx] = Player(-1,-1,0,'empty',0,True)
            del self._player_dict[playerID]
            self.emptyseats += 1
        except ValueError:
            pass

    def resolve_sidepots(self, players_playing):
        players = [p for p in players_playing if p.currentbet]
        if not self._quiet:
            print('current bets: ', [p.currentbet for p in players])
            print('playing hand: ', [p.playing_hand for p in players])
        if not players:
            return
        try:
            smallest_bet = min([p.currentbet for p in players if p.playing_hand])
        except ValueError:
            for p in players:
                self._side_pots[self._current_sidepot] += p.currentbet
                p.currentbet = 0
            return

        smallest_players_allin = [p for p,bet in zip(players, [p.currentbet for p in players]) if bet == smallest_bet and p.isallin]

        for p in players:
            self._side_pots[self._current_sidepot] += min(smallest_bet, p.currentbet)
            p.currentbet -= min(smallest_bet, p.currentbet)
            p.lastsidepot = self._current_sidepot

        if smallest_players_allin:
            self._current_sidepot += 1
            self.resolve_sidepots(players)
        if not self._quiet:
            print('sidepots: ', self._side_pots)

    def new_round(self):
        for player in self._player_dict.values():
            player.currentbet = 0
            player.playedthisround = False
        self._round += 1
        self._tocall = 0
        self._lastraise = 0

    def resolve_game(self, players):
        # print('Community cards: ', end='')
        # Card.print_pretty_cards(self.community)
        if len(players)==1:
            players[0].refund(sum(self._side_pots))
            # print('Player', players[0].playerID, 'wins the pot (',sum(self._side_pots),')')
            self._totalpot = 0
        else:
            # compute hand ranks
            for player in players:
                player.handrank = self._evaluator.evaluate(player.hand, self.community)

            # trim side_pots to only include the non-empty side pots
            temp_pots = [pot for pot in self._side_pots if pot>0]

            # compute who wins each side pot and pay winners
            for pot_idx,_ in enumerate(temp_pots):
                # print('players last pots', [(p.playerID, p.lastsidepot) for p in players])

                # find players involved in given side_pot, compute the winner(s)
                pot_contributors = [p for p in players if p.lastsidepot >= pot_idx]
                winning_rank = min([p.handrank for p in pot_contributors])
                winning_players = [p for p in pot_contributors if p.handrank == winning_rank]

                for player in winning_players:
                    split_amount = int(self._side_pots[pot_idx]/len(winning_players))
                    if not self._quiet:
                        print('Player', player.playerID, 'wins side pot (',int(self._side_pots[pot_idx]/len(winning_players)),')')
                    player.refund(split_amount)
                    self._side_pots[pot_idx] -= split_amount

                # any remaining chips after splitting go to the winner in the earliest position
                if self._side_pots[pot_idx]:
                    earliest = self._first_to_act([player for player in winning_players])
                    earliest.refund(self._side_pots[pot_idx])

    def reset(self):
        for player in self._seats:
            if not player.emptyplayer and not player.sitting_out:
                player.reset_hand()
        self.community = []
        self._current_sidepot = 0
        self._totalpot = 0
        self._side_pots = [0]*len(self._seats)
        self._deck.shuffle()

        self._button = (self._button + 1) % len(self._seats)
        while not self._seats[self._button].playing_hand:
            self._button = (self._button + 1) % len(self._seats)

    def output_state(self, current_player):
        return {'players':[player.player_state() for player in self._seats],
        'community':self.community,
        'my_seat':current_player.get_seat(),
        'pocket_cards':current_player.hand,
        'pot':self._totalpot,
        'button':self._button,
        'tocall':(self._tocall-current_player.currentbet),
        'stack':current_player.stack,
        'bigblind':self._bigblind,
        'playerID':current_player.playerID,
        'lastraise':self._lastraise,
        'minraise':max(self._bigblind, self._lastraise + self._tocall)}
from itertools import combinations
from deuces.deuces import Card, Evaluator, Deck
from pokermodules.nuts import nut_hand

### What are the theoretical and actual nut hands (on the flop), given
### a certain number of players?

evaluator = Evaluator()

def omaha_eval(hole, board):
    assert(len(hole)) == 4
    ranks = []
    for ph in combinations(hole, 2):
        thisrank = evaluator.evaluate(list(ph), board)
        ranks.append(thisrank)
    return min(ranks)

def r2t(x):
    return evaluator.class_to_string(evaluator.get_rank_class(x))

def r2c(x):
    return evaluator.get_rank_class(x)

def list_to_pretty_str(card_ints):
    output = " "
    for i in range(len(card_ints)):
        c = card_ints[i]
        if i != len(card_ints) - 1:
            output += Card.int_to_pretty_str(c) + ","
        else:
            output += Card.int_to_pretty_str(c) + " "
Exemple #18
0
class Table:
    """
    This class is primarily responsible for core holdem simulation logic. Basic usage consists of 
    adding players via addPlayer() and simulating a single hand via playhand(). For simplicity, betting takes place
    with integer number of chips with uniform value.
    """
    def __init__(self, smallBlind, bigBlind, maxBuyIn):
        """ Constructor accepts  blinds and maximum table buy in as integers. """

        self._players = []  #players at the table
        self._playing = []  #players who are not bankrupt
        self._sitOut = []  #players who have gone bankrupt
        self._dealer = 0  #position of dealer in self._playing
        self._eval = Evaluator()

        if type(smallBlind) != int or type(bigBlind) != int or type(
                maxBuyIn) != int:
            raise Exception('Parameters must be integer number of chips.')
        self._smallBlind = smallBlind
        self._bigBlind = bigBlind
        self._maxBuyIn = maxBuyIn

    def addPlayer(self, player):

        self._sitOut.append(player)
        self._players.append(player)

    def playHand(self, vocal=False):
        """ 
        This method simulates one hand between added players. Narrates hand if vocal is True.
        Returns False if unable to play hand. 
        """

        self._vocal = vocal

        #add players to hand who are eligible to play
        for p in self._sitOut[:]:
            if p.getStack() >= self._bigBlind:
                if p.getStack() > self._maxBuyIn:
                    raise Exception(
                        'Player\'s stack is greater than maximum buy in.')
                self._playing.append(p)
                self._sitOut.remove(p)

        if len(self._playing) <= 1: return False

        #reset table game state before hand
        self._s = GameState(self._playing)

        #commence simulation
        self._generateDeck()
        self._dealHoleCards()
        self._preFlop()
        self._flip(3)
        self._flip(1)
        self._flip(1)
        self._payWinners()
        for p in self._playing:
            p.endHand()

        #find next dealer
        dealerPos = (self._dealer + 1) % self._s.numP
        while self._playing[dealerPos].getStack() < self._bigBlind:
            dealerPos = (dealerPos + 1) % self._s.numP
        dealer = self._playing[dealerPos]

        #remove players who have gone bankrupt
        for p in self._playing[:]:
            if p.getStack() < self._bigBlind:
                self._playing.remove(p)
                self._sitOut.append(p)

        #move dealer chip
        self._dealer = 0
        while self._playing[self._dealer] != dealer:
            self._dealer = (self._dealer + 1) % self._s.numP

        if vocal: print
        return True

    def _generateDeck(self):

        self._deck = []
        for s in ['c', 'd', 'h', 's']:
            for i in range(2, 15):
                self._deck.append(Card(i, s))
        shuffle(self._deck)

    def _dealHoleCards(self):
        """ This method gives each player their starting cards at the beginning of the hand. """

        for p in self._playing:
            p.takeHoleCards((self._deck[0], self._deck[1]))
            if self._vocal:
                print p.getName() + '(' + str(p.getStack(
                )) + ')', 'dealt', self._deck[0], 'and', self._deck[1]
            self._deck = self._deck[2:]
        if self._vocal: print

    def _preFlop(self):
        """ This method posts the blinds and commences betting. """

        self._s.minRaise = 2 * self._bigBlind  #minimum first raise before flop is 2 x Big Blind

        sbPos = (self._dealer + 1) % self._s.numP  #small blind position
        bbPos = (self._dealer + 2) % self._s.numP  #big blind position
        self._s.actor = (self._dealer + 3) % self._s.numP  #first player to act

        #Heads-Up (1v1) has different rules prelop
        if self._s.numP == 2:
            sbPos = self._dealer
            bbPos = (self._dealer + 1) % self._s.numP
            self._s.actor = self._dealer

        #post blinds
        self._s.currBets[sbPos] += self._smallBlind
        self._playing[sbPos].removeChips(self._smallBlind)
        if self._vocal:
            print self._playing[sbPos].getName(
            ), 'posts small blind of', self._smallBlind
        self._s.currBets[bbPos] += self._bigBlind
        self._playing[bbPos].removeChips(self._bigBlind)
        if self._vocal:
            print self._playing[bbPos].getName(
            ), 'posts big blind of', self._bigBlind

        self._openBetting()
        if self._vocal: print

    def _flip(self, numCards):
        """ This method flips numCards cards from deck to be seen by players and then commences betting. """

        if len(self._s.folded) + 1 == self._s.numP:
            return  #all players but one have folded

        self._s.minRaise = self._bigBlind  #minimum first bet after the flop is Big Blind

        #flip numCards
        self._s.cards += self._deck[:numCards]
        if self._vocal: print[str(c) for c in self._s.cards]
        self._deck = self._deck[numCards:]

        self._s.actor = (self._dealer +
                         1) % self._s.numP  #first actor is player after dealer

        self._openBetting()
        if self._vocal: print

    def _payWinners(self):
        """ This method distributes the pot to the winner(s). """

        board = [card.toInt() for card in self._s.cards]

        #evaluate rank of hand for each player
        ranks = {}
        for p in self._playing:
            if not board:
                rank = -1  #all players but one have folded before flop
            else:
                rank = self._eval.evaluate(
                    board, [p.show()[0].toInt(),
                            p.show()[1].toInt()])
            ranks[p] = rank

        n = 0
        while sum(self._s.bets) > 0:  #to handle n side pots

            #get rank of best hand and bet of each player who is eligible to win sub pot
            minLiveBet = None  #bet that any eligible player has in current sub pot
            minRank = None
            eligibleWinners = []
            for i in range(self._s.numP):
                if not i in self._s.folded and self._s.bets[
                        i] != 0:  #if player hasnt folded and has stake in current sub pot
                    if minLiveBet == None: minLiveBet = self._s.bets[i]
                    else: minLiveBet = min(minLiveBet, self._s.bets[i])
                    player = self._playing[i]
                    eligibleWinners.append(player)
                    if minRank == None: minRank = ranks[player]
                    else: minRank = min(minRank, ranks[player])

            #create sub pot by adding contributions of its members
            winners = [p for p in eligibleWinners if ranks[p] == minRank]
            subPot = 0
            for i in range(self._s.numP):
                contribution = min(minLiveBet, self._s.bets[i])
                self._s.bets[i] -= contribution
                subPot += contribution

            #pay winners
            winnings = int(float(subPot) / len(winners))
            for w in winners:
                w.addChips(winnings)
                subPot -= winnings
                if self._vocal:
                    if minRank == -1:  #everyone else folded
                        print w.getName(), 'wins', winnings
                    else:
                        if n == 0:
                            print w.getName(
                            ), 'wins', winnings, 'from main pot'
                        if n > 0:
                            print w.getName(
                            ), 'wins', winnings, 'from side pot'

            #give odd chips to player in earliest position
            if subPot > 0:
                actor = (self._dealer + 1) % self._s.numP
                while subPot > 0:
                    player = self._playing[actor]
                    if player in winners:
                        player.addChips(subPot)
                        if self._vocal:
                            print player.getName(), 'wins', subPot, 'odd chips'
                        subPot = 0
                    actor = (actor + 1) % self._s.numP

            n += 1

    def _openBetting(self):
        """ The method starts a round of betting. """

        lastRaiser = self._s.actor  #so that action ends when everyone checks

        #main betting loop
        t = 0
        while True:
            t += 1

            actor = self._s.actor

            if actor == lastRaiser and t > 1:
                break  #break if last raising player has been reached

            #break if no further calls are possible
            notAllinOrFold = []
            for i in range(self._s.numP):
                if i not in self._s.folded and i not in self._s.allIn:
                    notAllinOrFold.append(i)
            if len(notAllinOrFold) == 0:
                break  #break if all players are folded or all-in
            #break if last player's raise cannot be matched
            if len(notAllinOrFold) == 1 and self._s.currBets[
                    notAllinOrFold[0]] == max(self._s.currBets):
                break

            #skip player if player folded or player is all in
            if actor in self._s.folded or actor in self._s.allIn:
                self._s.actor = (actor + 1) % self._s.numP
                continue

            self._s.toCall = max(self._s.currBets) - self._s.currBets[
                actor]  #player must call maximum bet to call

            #request player action and parse action
            action = self._playing[actor].act(self._s)
            self._parseAction(action)
            if action[0] == 'raise': lastRaiser = actor

            self._s.actor = (actor + 1) % self._s.numP  #move to next player

        #return uncalled chips to raiser
        uniqueBets = sorted(set(self._s.currBets))
        maxBet = uniqueBets[-1]
        if len(uniqueBets) >= 2: belowMax = uniqueBets[-2]
        if len([b for b in self._s.currBets if b == maxBet]) == 1:
            for i in range(self._s.numP):
                if self._s.currBets[i] == maxBet:
                    self._s.currBets[i] = belowMax
                    player = self._playing[i]
                    player.addChips(maxBet - belowMax)
                    if self._vocal:
                        print maxBet - belowMax, 'uncalled chips return to', player.getName(
                        )

        self._s.actor = None  #action has closed

        #add bets of current round to bets and flush currBets and numRaises
        for i in range(len(self._s.currBets)):
            self._s.bets[i] += self._s.currBets[i]
            self._s.currBets[i] = 0
            self._s.numRaises[i] = 0

    def _parseAction(self, action):
        """ 
        This method accepts a tuple of the form (action string, amount) or (action string,) and changes
        the GameState, self._s, appropriately.
        """
        actor = self._s.actor
        player = self._playing[actor]
        m = max(self._s.currBets
                )  #largest contribution that any player has in current pot
        currentBet = self._s.currBets[actor]

        if action[0] == 'check':
            if currentBet < m:
                raise Exception('Player must call to remain in the pot.')
            if self._vocal: print player.getName(), 'checks.'

        elif action[0] == 'fold':
            self._s.folded.append(actor)
            if self._vocal: print player.getName(), 'folds.'

        elif action[0] == 'call':
            toCall = self._s.toCall
            if toCall == 0:
                raise Exception(
                    'Player called a bet of 0 chips. Did you mean to check?')
            stack = player.getStack()
            if stack <= toCall:  #player has all-in called
                self._s.currBets[actor] += stack
                player.removeChips(stack)
                if self._vocal:
                    print player.getName(), 'all-in calls with', stack
                self._s.allIn.append(actor)
            else:
                self._s.currBets[actor] = m
                player.removeChips(m - currentBet)
                if self._vocal: print player.getName(), 'calls', m - currentBet

        elif action[0] == 'raise' or action[
                0] == 'bet':  #raising is interpreted as "raise to" a a new total bet
            raiseTo = action[1]  #new total bet of player
            raiseBy = raiseTo - m  #change in maximum bet in pot
            # if action[0] == 'bet' and m > 0: raise Exception('Cannot bet when pot has been opened. Did you mean to raise?')
            # if action[0] == 'raise' and m == 0: raise Exception('Cannot raise when pot is unopened. Did you mean to bet?')
            if raiseTo < self._s.minRaise:
                raise Exception('Raise amount is less than minimum raise.')
            self._s.minRaise = raiseTo + raiseBy  #player must raise by twice as much as last raise
            self._s.currBets[actor] = raiseTo
            player.removeChips(raiseTo - currentBet)
            self._s.numRaises[actor] += 1
            allIn = player.getStack() == 0
            if allIn: self._s.allIn.append(actor)
            if self._vocal:
                if not allIn:
                    print player.getName(), 'raises', raiseBy, 'to', raiseTo
                else:
                    print player.getName(
                    ), 'raises all-in', raiseBy, 'to', raiseTo

        else:
            raise Exception('Invalid player action.')

    def getPlaying(self):
        return self._playing[:]

    def getSitOut(self):
        return self._sitOut[:]

    def getPlayers(self):
        return self._players[:]

    def getParams(self):
        return (self._smallBlind, self._bigBlind, self._maxBuyIn)
Exemple #19
0
class AI(GameInfoTracker):
    '''
    Main bot class
    '''
    def __init__(self, args):
        '''
        Bot constructor

        Add data that needs to be persisted between rounds here.
        '''
        self.ev = Evaluator()

        if args.config_data is None:
            self.config =  json.load(args.config)
        else:
            self.config = json.loads(args.config_data)
        LOG_FILENAME = self.config["logfile"]

        self.eval_path = [os.path.join(os.path.dirname(os.path.realpath(__file__)), "score", "eval")]

        super(AI, self).__init__()

        # Set up a specific logger with our desired output level
        self.log = logging.getLogger('MyLogger')
        self.log.setLevel(logging.DEBUG)

        if args.no_log:
            self.log.setLevel(logging.CRITICAL)
        if args.log:
            self.handler = logging.handlers.RotatingFileHandler(
                    LOG_FILENAME, backupCount=5)
        else:
            self.handler = logging.StreamHandler(stderr)

        self.log.addHandler(self.handler)

    def run(self):
        '''
        Main loop

        Keeps running while begin fed data from stdin.
        Writes output to stdout, remember to flush.
        '''
        while not stdin.closed:
            try:
                rawline = stdin.readline()

                # End of file check
                if len(rawline) == 0:
                    break

                line = rawline.strip()

                # Empty lines can be ignored
                if len(line) == 0:
                    continue

                parts = line.split()
                command = parts[0].lower()
                self.log.debug("INCOMING:\t {0}".format(line))

                if command == 'settings' or command == 'match':
                    self.update_settings(parts[1], parts[2])
                    pass
                elif command.startswith('player'):
                    self.update_game_state(parts[0], parts[1], parts[2])
                    pass
                elif command == 'action':
                    totalsize = len(self.table.hand) + len(self.player.hand)
                    self.log.debug("ACTION: totalsize={0}".format(totalsize))
                    if self.log: # converting this to pretty hands is expensive enough to catch
                        self.log.debug("  Table: {0}".format(self.table.getHumanHand()))
                        self.log.debug("  Us:    {0}".format(self.player.getHumanHand()))

                    back = None
                    if totalsize == 2: 
                        back = self.turn(parts[2], "pre_flop") + '\n'
                    elif totalsize == 5:
                        back = self.turn(parts[2], "flop") + '\n'
                    elif totalsize == 6:
                        back = self.turn(parts[2], "turn") + '\n'
                    elif totalsize == 7:
                        back = self.turn(parts[2], "river") + '\n'
                    else:
                        #self.log.debug('Unknown stage!')
                        pass
                    self.log.debug("OUT: {0}\n".format(back))
                    stdout.write(back)
                    stdout.flush()
                else:
                    stderr.write("Unknown command: %s\n".format(command))
                    self.log.debug("ERR: Unknown command: %s\n".format(command))
                    stderr.flush()
            except EOFError:
                return

    def turn(self, timeout, stage):
        '''
        Once the turn is out, action is to us
        '''
        ours   = None
        action = "call"
        stagec = self.config[stage]
        amount = self.amount_to_call
        if len(self.table.hand) > 0:
            ours = self.get_score(stagec)
            

        # check call amount
        if amount >= self.player.stack:
            # this strategy is annoying... so check if our hand is "good enough"
            if ours > self.config["max_stack_bet_threshold"]:
                return "call 0"
            return "fold 0"

        self.log.debug("")
        self.log.debug("")
        self.log.debug("STAGE: " + stage)
        self.log.debug("    Our score: " + str(ours))

        if stage == "pre_flop":
            # if we have a high pair or a high matching suit, raise
            if self.player.hand[0].number == self.player.hand[1].number or\
                self.player.hand[0].suit == self.player.hand[1].suit and \
                (self.player.hand[0].number > 10 and self.player.hand[1].number > 10):
                amount = stagec["raise_multiplier"] * self.player.stack
                return self.raise_amount(amount, stage)
            elif amount >= stagec["fold_amount_threshold"]:
                return "fold 0"
            return '{0} {1}'.format(action, amount)

        # check if call amount is higher than what we could possibly have
        if ours >= stagec["fold_threshold"]  \
            or self.get_raise(ours, stagec) < self.amount_to_call:
            return "fold 0"

        if ours >= stagec["raise_threshold"]:
            return self.raise_amount(self.get_raise(ours, stagec), stage)

        if ours < stagec['fold_threshold']:
            action = "fold"

        self.spentPerStage[stage] += amount
        return '{0} {1}'.format(action, amount)

    def get_raise(self, ours, stage_config):
        if ours < 1:
            return 0
        return(stage_config["raise_threshold"] \
            / ours * stage_config["raise_multiplier"])

    def raise_amount(self, amount, stage):
        if amount > self.player.stack:
            amount = self.player.stack

        if self.amount_to_call >= amount:
            return "call 0"

        amount -= self.spentPerStage[stage]

        if amount < self.minimum_raise:
            self.log.debug("Amount to raise ({0}) is below minimum".format(amount))
            return "call 0"

        self.spentPerStage[stage] += amount
        return '{0} {1}'.format("raise", amount)
    
    def get_score(self, stagec):
        """
        Returns a score that adjusts for their average hand.
        return > 0: our hand is better on average by #
        return < 0: our hand is worse on average by #
        """
        if self.last_hand_count == len(self.table.hand)+len(self.player.hand) or len(self.table.getHand()) == 0:
            return self.last_hand_score
        else:
            self.last_hand_count = len(self.table.hand) + len(self.player.hand)
        
        score = 0

        base_score = self.ev.evaluate(self.table.getHand(), self.player.getHand())
        table_adjusted = tuple(self.table.getHand())

        # change deck into deuces cards
        deck_adjusted = (dCard.new(x) for x in self.deck.cards)

        # all possbile hands
        possibilities = itertools.combinations(deck_adjusted, 2)

        length = len(self.table.hand) + len(self.player.hand)
        scoresum = 0
        num = 0
        for p in possibilities:
            scoresum += self.ev.hand_size_map[length](table_adjusted+p)
            num += 1
        scoresum /= float(num)
        # get our score adjusted for what they could have
        self.log.debug("  Base score:     {0}".format(base_score))
        self.log.debug("  Score average:  {0}".format(scoresum))
        self.log.debug("  Relative Score: {0}".format(base_score - scoresum))
        self.log.debug("  Confidence:     {0}".format(self.config["confidence"]))

        score = (base_score + stagec["score_offset"])
        self.log.debug("  Offset Score:   {0}".format(score))

        if score < 0:
            score /= self.config["confidence"]
        else:
            score *= self.config["confidence"]
        score -= scoresum 

        self.last_hand_score = score
        self.log.debug("  Score:          {0}".format(score))

        return score
Exemple #20
0
 def __init__(self):
     self.e = DEvaluator()
Exemple #21
0
class Game:
    def __init__(self, slack_client):
        self.state = DEAD_STATE
        self.timer = WAIT

        self.players = []
        self.deck = None
        self.current_player = 0
        self.pot_manager = None
        self.slack_client = slack_client
        self.join_manager = None
        self.chat = None
        self.dealer_id = 0
        self.bet_manager = None
        self.board = []
        self.evaluator = Evaluator()
        self.last_message = None
        self.board_message = None

    def start(self, channel):
        self.state = START_STATE
        self.timer = WAIT
        self.players = []
        self.deck = Deck()
        self.current_player = 0
        self.chat = Chat(self.slack_client, channel)
        self.pot_manager = PotManager(self.chat)
        self.join_manager = JoinManager(self.slack_client, channel,
                                        self.players)

        self.bet_manager = BetManager(self.pot_manager, self.players)
        self.board = []
        self.last_message = None
        self.board_message = None

    def process(self, data):
        if 'text' in data:
            text = data['text']
            quit_text = '{}: quit'.format(bot_name)

            if quit_text.lower() in text.lower():
                if PAUSE_BETWEEN_GAME_STATE == self.state:
                    player_to_remove = None
                    for player in self.players:
                        if player.slack_id == data['user']:
                            player_to_remove = player

                    self.players.remove(player_to_remove)
                    self.chat.message("{} has quit.".format(player_to_remove))
                else:
                    self.chat.message(
                        "You can't quit now, wait between games.")

        if DEAD_STATE == self.state:
            self.process_dead(data)

        if START_STATE == self.state:
            self.process_start(data)

        if BET_STATE == self.state:
            self.bet_manager.process(data)

    def process_dead(self, data):
        text = data['text']
        deal_text = '{}: deal'.format(bot_name)

        if deal_text.lower() in text.lower():
            self.start(data['channel'])

    def process_start(self, data):
        self.join_manager.process_message(data)

    def set_state(self, state):
        self.state = state
        self.timer = WAIT
        self.last_message = None
        self.board_message = None

    def enough_players(self):
        if len(self.players) < 2:
            self.chat.message("Not enough players.")
            self.set_state(DEAD_STATE)
            return False
        return True

    def deal_state(self):
        self.current_player = 0

        if not self.enough_players():
            return

        # burn card
        self.deck.draw(1)

        for player in self.players:
            player.deal(self.deck.draw(2))

        self.set_state(BLIND_STATE)

    def post_blind(self, blind_func):
        while True:
            player = self.players[self.current_player % len(self.players)]
            can_post = blind_func(player)
            if not can_post:
                self.players.pop(0)
                if not self.enough_players():
                    return False
            self.current_player += 1
            return True

    def blind_state(self):
        if not self.post_blind(self.pot_manager.post_small_blind):
            return

        if not self.post_blind(self.pot_manager.post_big_blind):
            return

        self.pot_manager.add_other_players(self.players)

        self.dealer_id = self.current_player

        self.display_board()
        flop_callback = partial(self.set_state, FLOP_STATE)
        fold_win_callback = partial(self.set_state, FOLD_WIN_STATE)
        self.bet_manager.request_bets(self.dealer_id, flop_callback,
                                      fold_win_callback, self.display_board)
        self.set_state(BET_STATE)

    def display_board(self):
        board_str = '```'
        for i, player in enumerate(self.players):
            if i == self.current_player % len(self.players):
                board_str += '->'
            else:
                board_str += '  '

            board_str += '<@{}>\t\t\t${}\t{}\t{} {}\n'.format(
                player.slack_id, player.money, player.state, player.action,
                player.bet)
        board_str += '```\n'
        board_str += self.pot_manager.get_pot_string()
        board_str += "\n{}".format(Game.board_to_string(self.board))

        self.board_message = self.chat.message(board_str, self.board_message)

    @staticmethod
    def board_to_string(board):
        result = ""
        for card in board:
            result += "{} ".format(Card.int_to_pretty_str(card))

        return result

    def flop_state(self):
        # burn card
        self.deck.draw(1)

        self.board.extend(self.deck.draw(3))
        self.chat.message("*Dealing the flop:*\n{}".format(
            Game.board_to_string(self.board)))
        turn_callback = partial(self.set_state, TURN_STATE)
        fold_win_callback = partial(self.set_state, FOLD_WIN_STATE)
        self.bet_manager.request_bets(0, turn_callback, fold_win_callback,
                                      self.display_board)
        self.set_state(BET_STATE)

    def turn_state(self):
        # burn card
        self.deck.draw(1)

        self.board.append(self.deck.draw(1))
        self.chat.message("*Dealing the turn:*\n{}".format(
            Game.board_to_string(self.board)))
        turn_callback = partial(self.set_state, RIVER_STATE)
        fold_win_callback = partial(self.set_state, FOLD_WIN_STATE)
        self.bet_manager.request_bets(0, turn_callback, fold_win_callback,
                                      self.display_board)
        self.set_state(BET_STATE)

    def river_state(self):
        # burn card
        self.deck.draw(1)

        self.board.append(self.deck.draw(1))
        self.chat.message("*Dealing the river:*\n{}".format(
            Game.board_to_string(self.board)))
        self.set_state(SHOW_HANDS_STATE)

    def count_down(self, new_state):
        self.timer -= 1
        if self.timer < 0:
            self.set_state(new_state)
            return

    def show_hands_state(self):
        for player in self.players:
            if player.state == Player.FOLD_STATE:
                continue

            card_score = self.evaluator.evaluate(self.board, player.cards)
            card_class = self.evaluator.get_rank_class(card_score)
            self.chat.message('{} had: {} {}'.format(player, player.card_str(),
                                                     card_class))

        self.set_state(DETERMINE_WINNER_STATE)

    def determine_winner_state(self):

        for pot in reversed(self.pot_manager.pots):
            pot_score = 9999
            pot_winners = []
            if len(pot.players) == 1:
                self.chat.message(
                    SINGLE_WINNER_MESSAGE.format(pot.players[0], pot.amount,
                                                 pot.name))
                pot.players[0].money += pot.amount
            else:
                for player in pot.players:
                    card_score = self.evaluator.evaluate(
                        self.board, player.cards)
                    if card_score == pot_score:
                        pot_winners.append(player)

                    if card_score < pot_score:
                        pot_winners = [player]
                        pot_score = card_score

                if len(pot_winners) == 1:
                    self.chat.message(
                        SINGLE_WINNER_MESSAGE.format(pot_winners[0],
                                                     pot.amount, pot.name))
                    pot_winners[0].money += pot.amount
                else:
                    self.chat.message(
                        SPLIT_WINNER_MESSAGE.format(pot_winners, pot.amount,
                                                    pot.name))
                    for pot_winner in pot_winners:
                        pot_winner.money += (pot.amount / len(pot_winners))

        self.set_state(PREPARE_NEW_GAME_STATE)

    def prepare_new_game_state(self):
        # rotate players
        self.players.append(self.players.pop(0))
        self.set_state(PAUSE_BETWEEN_GAME_STATE)

    def pause_between_game_state(self):
        self.last_message = self.chat.message(PAUSE_MESSAGE.format(self.timer),
                                              self.last_message)
        self.timer = NEW_GAME_WAIT
        self.count_down(DEAL_STATE)

    def tick(self):
        if START_STATE == self.state:
            self.join_manager.tick(self.timer)
            self.count_down(DEAL_STATE)

        if DEAL_STATE == self.state:
            self.deal_state()

        if BLIND_STATE == self.state:
            self.blind_state()

        if BET_STATE == self.state:
            self.bet_manager.tick()

        if FLOP_STATE == self.state:
            self.flop_state()

        if TURN_STATE == self.state:
            self.turn_state()

        if RIVER_STATE == self.state:
            self.river_state()

        if FOLD_WIN_STATE == self.state:
            self.set_state(DETERMINE_WINNER_STATE)

        if SHOW_HANDS_STATE == self.state:
            self.show_hands_state()

        if DETERMINE_WINNER_STATE == self.state:
            self.determine_winner_state()

        if PREPARE_NEW_GAME_STATE == self.state:
            self.prepare_new_game_state()

        if PAUSE_BETWEEN_GAME_STATE == self.state:
            self.pause_between_game_state()
from deuces.deuces import Evaluator, Deck, Card
from pokermodules.convenience import pr, draw_sure
from itertools import combinations
from sys import argv

if '--test' in argv:
    pause = False
else:
    pause = True

e = Evaluator()
deck = Deck()
hole = deck.draw(2)
pr(hole)

def card_pairs_board(c, b):
    card_rank = Card.get_rank_int(c)
    board_ranks = map(Card.get_rank_int, b)
    return card_rank in board_ranks

def deck_without(cards):
    returnme = []
    for c in Deck.GetFullDeck():
        if c not in cards:
            returnme.append(c)
    return returnme

flop = deck.draw(3)
pr(flop)
h_rc_flop = e.get_rank_class(e.evaluate(hole, flop))
Exemple #23
0
class PercentWin:
    def __init__(self, board, hand):
        self.board = board
        self.hand = hand

        self.evalBoard = evalCards(board)
        self.evalHand = evalCards(hand)

        self.evaluator = Evaluator()

        self.availableCards = []
        for suit in ["d", "c", "s", "h"]:
            for val in [
                    "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K",
                    "A"
            ]:
                availCard = myCard(val + suit)
                if not availCard in self.hand + self.board:
                    self.availableCards.append(availCard)
        self.handDict = dict()
        self.discardDict = dict()
        #print self.availableCards

    def addToBoard(self, card):
        self.board.append(card)
        self.evalBoard.append(card.evalCard)
        self.availableCards.remove(card)
        #print self.availableCards
    def updateHand(self, oldCard, newCard):
        self.hand.remove(oldCard)
        self.hand.append(newCard)
        self.evalHand = evalCards(self.hand)
        self.availableCards.remove(newCard)

    # dont do this when board is zero
    def getWinPercentage(self):
        setOfCards = SetOfCards(self.hand, self.board)
        if len(self.board) >= 3 and not setOfCards in self.handDict:
            myHandRank = self.evaluator.evaluate(self.evalBoard, self.evalHand)
            #print myHandRank, self.board, self.hand
            possibleOppHand = []
            numWinsForMe = 0
            total = 0
            for handCard1 in self.availableCards:
                for handCard2 in self.availableCards:
                    if not handCard1 == handCard2:

                        possibleOppHand = [
                            handCard1.evalCard, handCard2.evalCard
                        ]
                        thisHandRank = self.evaluator.evaluate(
                            self.evalBoard, possibleOppHand)
                        #print total, thisHandRank, self.board, handCard1, handCard2
                        if thisHandRank >= myHandRank:
                            numWinsForMe += 1
                        total += 1
            handPer = (float(numWinsForMe) / total) * 100
            self.handDict[setOfCards] = handPer
            return handPer
        # starting hand
        elif len(self.board) == 0 and not setOfCards in self.handDict:
            f = open("startinghanddata.txt", "r")
            myHandSameSuit = self.hand[0].suit == self.hand[1].suit
            while True:
                lineList = f.readline().strip().split()
                if lineList == []:
                    break
                handStr = lineList[1].upper()
                if (self.hand[0].face.upper() in handStr
                        and self.hand[1].face.upper() in handStr):
                    if myHandSameSuit and handStr[-1] == "S":
                        self.startingHandRank = float(lineList[3]) * 100
                        return self.startingHandRank
                    elif not myHandSameSuit and not handStr[-1] == "S":
                        self.startingHandRank = float(lineList[3]) * 100
                        return self.startingHandRank
            return 0
        if setOfCards in self.handDict:
            self.startingHandRank = self.handDict[setOfCards]
            return self.startingHandRank
        else:
            return 0

    def shouldDiscard(self, handPercentWin):
        myHandRank = self.evaluator.evaluate(self.evalBoard, self.evalHand)
        discardPercent = []
        protect = []
        for card in self.hand:
            setOfCards = SetOfCards([card], self.board)
            if setOfCards in self.discardDict:
                discardPercent.append(self.discardDict[setOfCards])
            else:
                discardData = self.discardLoop(card, myHandRank)
                discardPercent.append(discardData[0])
                protect.append(discardData[1])
        if protect[0]:
            discardPercent[1] = 0.0
        if protect[1]:
            discardPercent[0] = 0.0
        discPercs = [(discardPercent[1], self.hand[0]),
                     (discardPercent[0], self.hand[1])]
        #print discPercs
        if discPercs[0][0] > discPercs[1][0]:
            discardThisCard = discPercs[0]
        elif discPercs[0][0] < discPercs[1][0]:
            discardThisCard = discPercs[1]
        elif discPercs[0][1] < discPercs[1][1]:
            discardThisCard = discPercs[0]
        else:
            discardThisCard = discPercs[1]
        if discardThisCard[0] <= 50.0:
            return "CHECK\n"
        elif discardThisCard[0] >= 80.0 or discardThisCard[
                0] >= handPercentWin or handPercentWin <= 50.0:
            return "DISCARD:" + discardThisCard[1].strCard + "\n"
        else:
            return "CHECK\n"

    def discardLoop(self, handCard, myHandRank):
        #print myHandRank
        numWinsForNewHand = 0
        total = 0
        protect = False
        for replacementCard in self.availableCards:
            if handCard != replacementCard:
                newHandDiscard = [handCard.evalCard, replacementCard.evalCard]
                thisHandRank = self.evaluator.evaluate(self.evalBoard,
                                                       newHandDiscard)
                #print thisHandRank, replacementCard, handCard
                if thisHandRank <= 1609:
                    protect = True
                if thisHandRank - 3 <= myHandRank:
                    numWinsForNewHand += 1
                total += 1  # 7642
        discardPercent = (numWinsForNewHand / float(total)) * 100

        self.discardDict[SetOfCards([],
                                    [handCard] + self.board)] = discardPercent
        return [discardPercent, protect]