I'm all in! that's what she said, you know. let's calculate poker odds. submissions can be written in any language.
you can represent cards in any format. this specification will use the convention of rank followed by suit, both as single letters, 10 represented as T. (for example, AS is the ace of spades.)
poker1 has several types of 5-card "hands", which are ranked by how rare they are. you'll need to know about all of these, so quick overview GO! from highest to lowest:
a straight flush has 5 cards of the same suit in sequential rank, such as JC TC 9C 8C 7C.
four of a kind has 4 cards of the same rank and 1 different, such as 5C 5D 5H 5S 2D.
a full house has 3 cards of the same rank and 2 of a second rank, such as 6S 6H 6D KC KH.
a flush has 5 cards of the same suit that do not form a straight flush, such as JD 9D 8D 4D 3D.
a straight has 5 cards in sequential rank that do not form a straight flush, such as TD 9S 8H 7D 6C.
three of a kind has 3 cards of the same rank and 2 of different ranks, such as QC QS QH 9H 2S.
two pair has 2 cards of the same rank, 2 cards of a second rank, and 1 different, such as JH JS 3C 3S 2H.
a pair has 2 cards of the same rank and 3 of different ranks, such as TS TH 8S 7H 4C.
high card is any hand that is not in one of the above categories.
aces are the rank above kings, unless registering as the rank below 2 would cause a straight to be formed. this means that AS KS QS JS TS and 5S 4S 3S 2S AS are both straight flushes.
within a category, hands are ranked by first grouping them by rank, ordering the groups by length then by value, and comparing lexicographically. id est:
straight flushes and straights are ranked by the highest card in them.
flushes and high card simply rank first by the highest card, then second highest, etc.
four of a kind, three of a kind, full houses, two pair, and pairs are ranked first by the largest groups of identical ranks, then the smaller ones. for instance, 8S 8H 8D 2S 2D ranks higher than 7S 7H 7D KS KD.
suits are not ranked in any way, so 2 hands are able to rank exactly the same. that'll come up later!
now! we are playing texas hold 'em, which means that several players with 2 secret cards each are trying to form the best hand from a mix of their cards and 5 community cards.
for instance, if the community cards are 2D 9S 9C 4H 5C, and Paul is holding 9H 3D, he has three of a kind (9S 9C 9H 5C 4H). Vanessa sitting next to him could have him beat if she holds a straight (like 6D 3C) or full house (like 9D 5H). the deck does not have duplicate cards, so she cannot have four of a kind.
not all of the community cards are revealed at once. on the television, the chance of each player winning (given that each player's hand is known) is displayed in real-time as the community cards are revealed. that is our task for today.
let's return to the example before. if the only visible cards are the first 3 community cards ("flop"), 2D 9S 9C, Paul has 9H 3D, and Vanessa has 6D 3C, the chance of Paul being the winner when the next 2 cards are revealed is 98.38%! when the four of hearts is revealed, that chance falls to 90.91%, and when the five of clubs is revealed, it becomes 0.0% (because Vanessa has now won). what a bad beat!
note that tying is not winning. if no cards are revealed, Paul has AC AH, and Vanessa has AS AD, the chance of either one winning (due to a flush) is only 2.17%. in most cases, the suits of the cards won't matter, and Paul and Vanessa will tie, sharing the pot.
your challenge, given a list of 2-card hands and face-up community cards (either 0, 3, 4, or 5 of them), is to calculate the odds of each hand winning. you may also accept a list of cards known not to be in the deck (perhaps because a player folded them), but this is not a requirement.
specifically, the rules listed are for "high rules", as we are playing texas hold 'em. some things change under "low rules", where lower hands are considered better.↩
importitertoolsfromcollectionsimportCounter,defaultdictdeffind_straight(many):run_next=Nonehave_ace=Falseforkey,_initertools.groupby(many):ifkey==14:have_ace=Trueifrun_next==key:ifrun_length==4orrun_length==3andkey==2andhave_ace:returnrun_next+run_lengthelse:run_length=0run_length+=1run_next=key-1# GOD THIS FLUMMERY IS SO TARNATION ANNOYINGdefeval_hand(cards):cards.sort(reverse=True)ranks=[card[0]forcardincards]# flushesby_suit=defaultdict(list)forcardincards:suit=by_suit[card[1]]suit.append(card[0])iflen(suit)==5:# FLUSH!ifstraight:=find_straight(suit):# STRAIGHT FLUSH!!!return[5],straightreturn[3,1.75],suit# straightsifstraight:=find_straight(ranks):return[3,1.25],straight# everything elsecounts=[]values=[]s=0forvalue,countinCounter(ranks).most_common():count=min(count,5-s)ifnotcount:breaks+=countcounts.append(count)values.append(value)returncounts,valuesdefentry(hands,commune,out_of_play=()):deck=set(itertools.product(range(2,15),"HDCS"))deck.difference_update(out_of_play)deck.difference_update(commune)forhandinhands:deck.difference_update(hand)c=0winners=Counter()forrestinitertools.combinations(deck,5-len(commune)):c+=1best_hand=Nonewinner=Noneforidx,handinenumerate(hands):us=eval_hand([*commune,*rest,*hand])ifnotbest_handorus>best_hand:best_hand=uswinner=idxelifus==best_hand:winner=NoneifwinnerisnotNone:winners[winner]+=1return{x:y/cforx,yinwinners.items()}
post a comment