import poker_functions as p from fractions import Fraction from collections import Counter class Player: def __init__(self, number, cards=[]): if len(cards) > 0: cards = p.make_card(cards) else: cards = [] self.number = number self.cards = cards self.hand = None self.starting_cards = None self.wins = 0 def __str__(self): return "player_" + str(self.number) def dedup(board): duplicate = False c = Counter(board) for card in board: if c[card] > 1: duplicate = True return duplicate return duplicate def validate_card(check): """Detect invalid cards in a passed collection""" valid = True deck = p.generate_deck() valid_cards = [card.name for card in deck] for card in check: if card not in valid_cards: valid = False return valid return valid def convert_and_update(deck, cards): if len(cards) == 0: return deck, cards else: cards = p.make_card(cards) for card in cards: deck.update_deck(card) return deck, cards ##### SIMULATIONS ##### def evaluate_hand(hole_cards, flop=[], turn=[], river=[]): board = flop + turn + river hand = None if len(hole_cards + board) < 5: return hand else: for func in p.HAND_REGISTRY: func = func(hole_cards, board) if not func: continue else: return func def score_game(contestants): # TODO make this more elegant by functionizing repeated code. """Application will determine the highest hand, including low and kicker for each player in player_list""" high = ['flush', 'straight', 'straight_flush'] kick = ['4ok'] hi_lo = ['boat'] hi_lo_kick = ['2pair', 'hc', '3ok', 'pair'] high_hand = max(contestants, key=lambda x: x.hand.hand_value) # contestant with highest hand same_high_hand = [player for player in contestants if player.hand.hand_value == high_hand.hand.hand_value] if len(same_high_hand) == 1: same_high_hand[0].wins += 1 return contestants elif high_hand.hand.type in high: high_card = max(same_high_hand, key=lambda x: x.hand.high_value) same_high_card = [player for player in same_high_hand if player.hand.high_value == high_card.hand.high_value] if len(same_high_card) == 1: high_card.wins += 1 return contestants else: return contestants elif high_hand.hand.type in hi_lo: over = max(same_high_hand, key=lambda x: x.hand.high_value) # Highest pair in hand same_over = [player for player in same_high_hand if player.hand.high_value == over.hand.high_value] if len(same_over) == 1: over.wins += 1 return contestants else: under = max(same_over, key=lambda x: x.hand.low_value) # lowest pair in hand same_under = [player for player in same_over if player.hand.low_value == under.hand.low_value] if len(same_under) == 1: under.wins += 1 return contestants else: return contestants elif high_hand.hand.type in hi_lo_kick: over = max(same_high_hand, key=lambda x: x.hand.high_value) # Highest pair in hand same_over = [player for player in same_high_hand if player.hand.high_value == over.hand.high_value] if len(same_over) == 1: over.wins += 1 return contestants else: under = max(same_over, key=lambda x: x.hand.low_value) # lowest pair in hand same_under = [player for player in same_over if player.hand.low_value == under.hand.low_value] if len(same_under) == 1: under.wins += 1 return contestants else: kicker = max(same_under, key=lambda x: x.hand.kicker) same_kicker = [player for player in same_under if player.hand.kicker == kicker.hand.kicker] if len(same_kicker) == 1: kicker.wins += 1 return contestants else: return contestants elif high_hand.hand.type in kick: low_val = max(same_high_hand, key=lambda x: x.hand.low_value) same_low_val = [player for player in same_high_hand if player.hand.low_value == low_val.hand.low_value] if len(same_low_val) == 1: low_val.wins += 1 return contestants else: return contestants def simulation_one_player(hole, flop=None, turn=None, river=None, sims=100000): if flop is None: flop = [] if turn is None: turn = [] if river is None: river = [] full_board = 7 # number of cards required to run sim passed_cards = len(hole) + len(flop) + len(turn) + len(river) passed_flop = list(flop) high_cards = 0 pairs = 0 two_pairs = 0 trips = 0 straights = 0 flushes = 0 boats = 0 quads = 0 straight_flushes = 0 invalid = 0 for i in range(sims): deck = p.generate_deck() deck, hole = convert_and_update(deck, hole) deck, flop = convert_and_update(deck, flop) deck, turn = convert_and_update(deck, turn) deck, river = convert_and_update(deck, river) j = full_board - passed_cards for _ in range(j): deal, deck = deck.deal_card() flop.append(deal) # Adding to flop because it shouldn't matter, will revert flop back at end of loop hand = evaluate_hand(hole, flop, turn, river) if hand.type == '2pair': two_pairs += 1 elif hand.type == '3ok': trips += 1 elif hand.type == '4ok': quads += 1 elif hand.type == 'boat': boats += 1 elif hand.type == 'flush': flushes += 1 elif hand.type == 'hc': high_cards += 1 elif hand.type == 'pair': pairs += 1 elif hand.type == 'straight': straights += 1 elif hand.type == 'straight_flush': straight_flushes += 1 else: invalid += 1 i += 1 flop = list(passed_flop) return sims, high_cards, pairs, two_pairs, trips, straights, flushes, boats, quads, straight_flushes def simulation_multiplayer(hole_one, hole_two=[], hole_three=[], hole_four=[], hole_five=[], hole_six=[], flop = [], turn = [], river = [], opponents=2, sims=10000): contestant_hands = [hole_one, hole_two, hole_three, hole_four, hole_five, hole_six] contestants = [] flop = p.make_card(flop) turn = p.make_card(turn) river = p.make_card(river) passed_flop_stable = [card for card in flop] for n in range(opponents): player_name = 'opponent' + str(n+1) player_name = Player(n, contestant_hands[n]) contestants.append(player_name) i = 0 passed_board = len(flop) + len(turn) + len(river) full_board = 5 k = full_board - passed_board for i in range(sims): deck = p.generate_deck() for contestant in contestants: # TODO move assigning Player.starting_cards to init if len(contestant.cards) == 2: contestant.starting_cards = True for card in contestant.cards: deck.update_deck(card) # remove known hole cards from deck else: contestant.starting_cards = False hole_cards = [] for j in range(2): deal, deck = deck.deal_card() hole_cards.append(deal) contestant.cards = hole_cards # assign new hole cards if not passed for l in range(k): # complete the board as needed deal, deck = deck.deal_card() flop.append(deal) for contestant in contestants: hand = evaluate_hand(contestant.cards, flop, turn, river) contestant.hand = hand # Compare hand values in contestants contestants = score_game(contestants) i += 1 # Revert to starting state flop = [card for card in passed_flop_stable] for contestant in contestants: if contestant.starting_cards is False: contestant.cards = [] hole_cards = [] return contestants # TODO for single and mult: find and return most likely hand. Return number of outs and odds. ##### MATH ##### def percent(hits, sims): percent = round((hits / sims) * 100,0) return percent def ratio(hits, sims): """Return a ratio (e.g. 3:5) for two input numbers""" percent = round((hits / sims),2) fraction = str(Fraction(percent).limit_denominator()) fraction = fraction.replace('/', ':') return fraction ##### REFERENCE ##### outs = {'1':('46:1','45:1',"22:1"), '2':('22:1','22:1','11:1'), '3':('15:1', '14:1', '7:1'), '4':('11:1','10:1','5:1'), '5':('8.5:1', '8:1','4:1'), '6':('7:1','7:1','3:1'), '7':('6:1','6:1','2.5:1'), '8':('5:1','5:1','2.5:1'), '9':('4:1','4:1','2:1'), '10':('3.5:1','3.5:1','1.5:1'), '11':('3.3:1','3.2:1','1.5:1'), '12':('3:1','3:1','1.2:1'), } rank_value = p.rank_value