From: W. Trevor King Date: Tue, 7 Dec 2010 20:09:36 +0000 (-0500) Subject: Add pbotlib.odds. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;p=poker.git Add pbotlib.odds. Brute force implementation depends on `pbot.deck.SevenChooseFiveHand.score()`, so it takes a while if there are unknown public cards. --- diff --git a/pbotlib/odds.py b/pbotlib/odds.py new file mode 100644 index 0000000..6015ea8 --- /dev/null +++ b/pbotlib/odds.py @@ -0,0 +1,66 @@ +"""Calculate the probability of various poker hands +""" + +from pbot.combinations import xunique_combinations +from pbot.deck import new_deck, SevenChooseFiveHand + + +class Odds (object): + """Calculate the odds of winning given the current game state. + + >>> from pprint import pprint + >>> from pbot.deck import unpp_card + + The only thing that can beat 4 aces is a straight flush. With + spaced out public cards, that is impossible, so we only get wins + in that case. The total number of opposing hands is + `choose(52-7,2)=990`. + + >>> o = Odds(hole=[unpp_card(c) for c in ['As', 'Ah']], + ... public=[unpp_card(c) for c in ['Ad', 'Ac', 'Ts', '7h', '4d']]) + >>> pprint(o.results) + {'losses': 0, 'ties': 0, 'wins': 990} + + However, with properly aligned public cards, the straight flush is + within reach, so we get losses whenever the opposing hole contains + `Tc`. This leaves `52-8=44` options for the other hole card. + + >>> o.public = [unpp_card(c) for c in ['Ad', 'Ac', 'Kc', 'Qc', 'Jc']] + >>> pprint(o.calculate()) + {'losses': 44, 'ties': 0, 'wins': 946} + + The odds caclulator will cycle through unknown public cards, but + this can be slow. + + >>> o.public.pop() + >>> pprint(o.calculate()) + {'losses': 134, 'ties': 0, 'wins': 47476} + """ + deck = new_deck() + + def __init__(self, hole, public=None): + self.hole = hole + if public == None: + public = [] + self.public = public + self.results = self.calculate() + + def calculate(self): + known = self.hole + self.public + hidden = [c for c in self.deck if c not in known] + remaining = 5 - len(self.public) + results = {'wins': 0, 'ties': 0, 'losses': 0} + for new_public in xunique_combinations(hidden, remaining): + p = self.public + new_public + h = [c for c in hidden if c not in p] + hand = SevenChooseFiveHand(self.hole + p) + for hole in xunique_combinations(hidden, 2): + other_hand = SevenChooseFiveHand(hole + p) + result = cmp(hand, other_hand) + if result == 1: + results['wins'] += 1 + elif result == 0: + results['ties'] += 1 + else: + results['losses'] += 1 + return results