Spaces:
Sleeping
Sleeping
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 |