2 # -*- coding: iso-8859-15
5 # Simple Hold'em equity calculator
6 # Copyright (C) 2007-2011 Mika Boström <bostik@iki.fi>
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, version 3 of the License.
12 # TODO gettextify usage print
15 _
= L10n
.get_translation()
21 SUITS
= ['h', 'd', 's', 'c']
23 CONNECTORS
= ['32', '43', '54', '65', '76', '87', '98', 'T9', 'JT', 'QJ', 'KQ', 'AK']
29 ev
= pokereval
.PokerEval()
38 def set_board_with_list(self
, board
):
41 def set_board_string(self
, string
):
45 b
= string
.strip().split()
57 def set_hero_cards_string(self
, string
):
59 cc
= string
.strip().split()
62 pocket_cards
= Cards(c1
, c2
)
63 self
.hand
= pocket_cards
65 def set_villain_range_string(self
, string
):
68 hands_in_range
= string
.strip().split(',')
69 for h
in hands_in_range
:
71 h_range
.expand(expand_hands(_h
, self
.hand
, self
.board
))
73 self
.h_range
= h_range
77 def __init__(self
, c1
, c2
):
82 return [self
.c1
, self
.c2
]
85 def __init__(self
, b1
=None, b2
=None, b3
=None, b4
=None, b5
=None):
94 if self
.b3
is not None:
99 b
.extend(["__", "__", "__"])
101 if self
.b4
is not None:
106 if self
.b5
is not None:
118 self
.__hands
.add(hand
)
120 def expand(self
, hands
):
121 self
.__hands
.update(set(hands
))
124 return sorted(self
.__hands
)
129 def __init__(self
, plays
, win
, tie
, lose
):
145 self
.n_hands
+= ev
.n_hands
146 self
.n_wins
+= ev
.n_wins
147 self
.n_ties
+= ev
.n_ties
148 self
.n_losses
+= ev
.n_losses
150 def show(self
, hand
, h_range
):
151 win_pct
= 100 * (float(self
.n_wins
) / float(self
.n_hands
))
152 lose_pct
= 100 * (float(self
.n_losses
) / float(self
.n_hands
))
153 tie_pct
= 100 * (float(self
.n_ties
) / float(self
.n_hands
))
155 Enumerated %d possible plays.
157 Against the range: %s
159 %5.2f%% %5.2f%% %5.2f%%
160 """ % (self
.n_hands
, hand
.c1
, hand
.c2
, cards_from_range(h_range
), win_pct
, lose_pct
, tie_pct
)
165 # Expands hand abbreviations such as JJ and AK to full hand ranges.
166 # Takes into account cards already known to be in player's hand and/or
168 def expand_hands(abbrev
, hand
, board
):
171 known_cards
.update(set([hand
.c2
, hand
.c2
]))
172 known_cards
.update(set([board
.b1
, board
.b2
, board
.b3
, board
.b4
, board
.b5
]))
174 re
.search('[2-9TJQKA]{2}(s|o)',abbrev
)
176 if re
.search('^[2-9TJQKA]{2}(s|o)$',abbrev
): #AKs or AKo
177 return standard_expand(abbrev
, hand
, known_cards
)
178 elif re
.search('^[2-9TJQKA]{2}(s|o)\+$',abbrev
): #76s+ or 76o+
179 return iterative_expand(abbrev
, hand
, known_cards
)
183 def iterative_expand(abbrev
, hand
, known_cards
):
190 idx
= CONNECTORS
.index('%s%s' % (r1
, r2
))
195 for h
in CONNECTORS
[idx
:]:
196 abr
= "%s%s" % (h
, ltr
)
197 h_range
+= standard_expand(abr
, hand
, known_cards
)
202 def standard_expand(abbrev
, hand
, known_cards
):
203 # Card ranks may be different
206 # There may be a specifier: 's' for 'suited'; 'o' for 'off-suit'
220 if c1
in known_cards
:
225 if selection
== SUITED
and s1
!= s2
:
227 elif selection
== OFFSUIT
and s1
== s2
:
229 if c2
not in considered
and c2
not in known_cards
:
230 h_range
.append(Cards(c1
, c2
))
234 def parse_args(args
, container
):
235 # args[0] is the path being executed; need 3 more args
239 container
.set_board_string(args
[1])
240 container
.set_hero_cards_string(args
[2])
241 container
.set_villain_range_string(args
[3])
246 def odds_for_hand(hand1
, hand2
, board
, iterations
):
247 res
= ev
.poker_eval(game
='holdem',
254 iterations
= iterations
257 plays
= int(res
['info'][0])
258 eval = res
['eval'][0]
260 win
= int(eval['winhi'])
261 lose
= int(eval['losehi'])
262 tie
= int(eval['tiehi'])
264 _ev
= EV(plays
, win
, tie
, lose
)
268 def odds_for_range(holder
):
272 # Construct board list
275 if board
.b3
is not None:
276 b
.extend([board
.b1
, board
.b2
, board
.b3
])
278 b
.extend(['__', '__', '__'])
280 if board
.b4
is not None:
284 if board
.b5
is not None:
290 print _('No board given. Using Monte-Carlo simulation...')
291 iters
= random
.randint(25000, 125000)
294 for h
in holder
.h_range
.get():
296 [holder
.hand
.c1
, holder
.hand
.c2
],
303 sev
.show(holder
.hand
, holder
.h_range
.get())
307 print """Texas Hold'Em odds calculator
308 Calculates odds against a range of hands.
310 To use: %s '<board cards>' '<your hand>' '<opponent's range>' [...]
312 Separate cards with space.
313 Separate hands in range with commas.
316 def cards_from_range(h_range
):
319 if h
.c1
== '__' and h
.c2
== '__':
322 s
+= '%s%s, ' % (h
.c1
, h
.c2
)
329 if not parse_args(sys
.argv
, stove
):
332 odds_for_range(stove
)
334 if __name__
== '__main__':