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
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 __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 __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 __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 __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 __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()
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)
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()
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) }
def __init__(self): self.deck = Deck() self.reset() self._evaluator = Evaluator() self.monte_carlo_rounds = 1000
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
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']
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) + " "
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)
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
def __init__(self): self.e = DEvaluator()
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))
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]