2 # -*- coding: utf-8 -*-
4 #Copyright 2008-2011 Carl Gherardi
5 #This program is free software: you can redistribute it and/or modify
6 #it under the terms of the GNU Affero General Public License as published by
7 #the Free Software Foundation, version 3 of the License.
9 #This program is distributed in the hope that it will be useful,
10 #but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 #GNU General Public License for more details.
14 #You should have received a copy of the GNU Affero General Public License
15 #along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #In the "official" distribution you can find the license in agpl-3.0.txt.
20 from decimal_wrapper
import Decimal
23 # logging has been set up in fpdb.py or HUD_main.py, use their settings:
24 log
= logging
.getLogger("parser")
27 def __init__(self
, hand
):
31 self
.handsplayers
= {}
32 self
.handsactions
= {}
33 self
._initStats
= DerivedStats
._buildStatsInitializer
()
36 def _buildStatsInitializer():
38 #Init vars that may not be used, but still need to be inserted.
39 # All stud street4 need this when importing holdem
42 init
['totalProfit'] = 0
43 init
['street4Aggr'] = False
44 init
['wonWhenSeenStreet1'] = 0.0
45 init
['sawShowdown'] = False
46 init
['showed'] = False
48 init
['startCards'] = 0
50 init
['street0_3BChance'] = False
51 init
['street0_3BDone'] = False
52 init
['street0_4BChance'] = False
53 init
['street0_4BDone'] = False
54 init
['street0_C4BChance'] = False
55 init
['street0_C4BDone'] = False
56 init
['street0_FoldTo3BChance']= False
57 init
['street0_FoldTo3BDone']= False
58 init
['street0_FoldTo4BChance']= False
59 init
['street0_FoldTo4BDone']= False
60 init
['street0_SqueezeChance']= False
61 init
['street0_SqueezeDone'] = False
62 init
['success_Steal'] = False
63 init
['raiseToStealChance'] = False
64 init
['raiseToStealDone'] = False
65 init
['raiseFirstInChance'] = False
66 init
['raisedFirstIn'] = False
67 init
['foldBbToStealChance'] = False
68 init
['foldSbToStealChance'] = False
69 init
['foldedSbToSteal'] = False
70 init
['foldedBbToSteal'] = False
71 init
['tourneyTypeId'] = None
72 init
['street1Seen'] = False
73 init
['street2Seen'] = False
74 init
['street3Seen'] = False
75 init
['street4Seen'] = False
79 init
['street%dCalls' % i
] = 0
80 init
['street%dBets' % i
] = 0
81 init
['street%dRaises' % i
] = 0
83 init
['street%dCBChance' %i] = False
84 init
['street%dCBDone' %i] = False
85 init
['street%dCheckCallRaiseChance' %i] = False
86 init
['street%dCheckCallRaiseDone' %i] = False
87 init
['otherRaisedStreet%d' %i] = False
88 init
['foldToOtherRaisedStreet%d' %i] = False
90 #FIXME - Everything below this point is incomplete.
91 init
['other3BStreet0'] = False
92 init
['other4BStreet0'] = False
93 init
['otherRaisedStreet0'] = False
94 init
['foldToOtherRaisedStreet0'] = False
96 init
['foldToStreet%dCBChance' %i] = False
97 init
['foldToStreet%dCBDone' %i] = False
98 init
['wonWhenSeenStreet2'] = 0.0
99 init
['wonWhenSeenStreet3'] = 0.0
100 init
['wonWhenSeenStreet4'] = 0.0
103 def getStats(self
, hand
):
104 for player
in hand
.players
:
105 self
.handsplayers
[player
[1]] = self
._initStats
.copy()
107 self
.assembleHands(self
.hand
)
108 self
.assembleHandsPlayers(self
.hand
)
110 if self
.hand
.saveActions
:
111 self
.assembleHandsActions(self
.hand
)
116 def getHandsPlayers(self
):
117 return self
.handsplayers
119 def getHandsActions(self
):
120 return self
.handsactions
122 def assembleHands(self
, hand
):
123 self
.hands
['tableName'] = hand
.tablename
124 self
.hands
['siteHandNo'] = hand
.handid
125 self
.hands
['gametypeId'] = None # Leave None, handled later after checking db
126 self
.hands
['sessionId'] = None # Leave None, added later if caching sessions
127 self
.hands
['gameSessionId'] = None # Leave None, added later if caching sessions
128 self
.hands
['startTime'] = hand
.startTime
# format this!
129 self
.hands
['importTime'] = None
130 self
.hands
['seats'] = self
.countPlayers(hand
)
131 #self.hands['maxSeats'] = hand.maxseats
132 self
.hands
['texture'] = None # No calculation done for this yet.
133 self
.hands
['tourneyId'] = hand
.tourneyId
135 # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and
136 # those values remain default in stud.
138 for street
in hand
.communityStreets
:
139 boardcards
+= hand
.board
[street
]
140 boardcards
+= [u
'0x', u
'0x', u
'0x', u
'0x', u
'0x']
141 cards
= [Card
.encodeCard(c
) for c
in boardcards
[0:5]]
142 self
.hands
['boardcard1'] = cards
[0]
143 self
.hands
['boardcard2'] = cards
[1]
144 self
.hands
['boardcard3'] = cards
[2]
145 self
.hands
['boardcard4'] = cards
[3]
146 self
.hands
['boardcard5'] = cards
[4]
148 self
.hands
['boards'] = []
149 self
.hands
['runItTwice'] = False
150 for i
in range(hand
.runItTimes
):
151 self
.hands
['runItTwice'] = True
153 for street
in hand
.communityStreets
:
155 street_i
= street
+ str(boardId
)
156 if street_i
in hand
.board
:
157 boardcards
+= hand
.board
[street_i
]
158 boardcards
= [u
'0x', u
'0x', u
'0x', u
'0x', u
'0x'] + boardcards
159 cards
= [Card
.encodeCard(c
) for c
in boardcards
[-5:]]
160 self
.hands
['boards'] += [[boardId
] + cards
]
162 #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % hand.getStreetTotals()
163 totals
= hand
.getStreetTotals()
164 totals
= [int(100*i
) for i
in totals
]
165 self
.hands
['street1Pot'] = totals
[0]
166 self
.hands
['street2Pot'] = totals
[1]
167 self
.hands
['street3Pot'] = totals
[2]
168 self
.hands
['street4Pot'] = totals
[3]
169 self
.hands
['showdownPot'] = totals
[4]
171 self
.vpip(hand
) # Gives playersVpi (num of players vpip)
172 #print "DEBUG: vpip: %s" %(self.hands['playersVpi'])
173 self
.playersAtStreetX(hand
) # Gives playersAtStreet1..4 and Showdown
174 #print "DEBUG: playersAtStreet 1:'%s' 2:'%s' 3:'%s' 4:'%s'" %(self.hands['playersAtStreet1'],self.hands['playersAtStreet2'],self.hands['playersAtStreet3'],self.hands['playersAtStreet4'])
175 self
.streetXRaises(hand
)
177 def assembleHandsPlayers(self
, hand
):
178 #street0VPI/vpip already called in Hand
179 # sawShowdown is calculated in playersAtStreetX, as that calculation gives us a convenient list of names
181 #hand.players = [[seat, name, chips],[seat, name, chips]]
182 for player
in hand
.players
:
183 self
.handsplayers
[player
[1]]['seatNo'] = player
[0]
184 self
.handsplayers
[player
[1]]['startCash'] = int(100 * Decimal(player
[2]))
185 self
.handsplayers
[player
[1]]['sitout'] = False #TODO: implement actual sitout detection
186 if hand
.gametype
["type"]=="tour":
187 self
.handsplayers
[player
[1]]['tourneyTypeId']=hand
.tourneyTypeId
188 self
.handsplayers
[player
[1]]['tourneysPlayersIds'] = hand
.tourneysPlayersIds
[player
[1]]
190 self
.handsplayers
[player
[1]]['tourneysPlayersIds'] = None
191 if player
[1] in hand
.shown
:
192 self
.handsplayers
[player
[1]]['showed'] = True
194 #### seen now processed in playersAtStreetX()
195 # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
196 #for i, street in enumerate(hand.actionStreets[2:], start=1):
197 #for i, street in enumerate(hand.actionStreets[2:]):
198 # self.seen(self.hand, i+1)
200 for i
, street
in enumerate(hand
.actionStreets
[1:]):
201 self
.aggr(self
.hand
, i
)
202 self
.calls(self
.hand
, i
)
203 self
.bets(self
.hand
, i
)
205 self
.folds(self
.hand
, i
)
207 # Winnings is a non-negative value of money collected from the pot, which already includes the
208 # rake taken out. hand.collectees is Decimal, database requires cents
209 for player
in hand
.collectees
:
210 self
.handsplayers
[player
]['winnings'] = int(100 * hand
.collectees
[player
])
211 #FIXME: This is pretty dodgy, rake = hand.rake/#collectees
212 # You can really only pay rake when you collect money, but
213 # different sites calculate rake differently.
214 # Should be fine for split-pots, but won't be accurate for multi-way pots
215 self
.handsplayers
[player
]['rake'] = int(100* hand
.rake
)/len(hand
.collectees
)
216 if self
.handsplayers
[player
]['street1Seen'] == True:
217 self
.handsplayers
[player
]['wonWhenSeenStreet1'] = 1.0
218 if self
.handsplayers
[player
]['street2Seen'] == True:
219 self
.handsplayers
[player
]['wonWhenSeenStreet2'] = 1.0
220 if self
.handsplayers
[player
]['street3Seen'] == True:
221 self
.handsplayers
[player
]['wonWhenSeenStreet3'] = 1.0
222 if self
.handsplayers
[player
]['street4Seen'] == True:
223 self
.handsplayers
[player
]['wonWhenSeenStreet4'] = 1.0
224 if self
.handsplayers
[player
]['sawShowdown'] == True:
225 self
.handsplayers
[player
]['wonAtSD'] = 1.0
227 for player
in hand
.pot
.committed
:
228 self
.handsplayers
[player
]['totalProfit'] = int(self
.handsplayers
[player
]['winnings'] - (100*hand
.pot
.committed
[player
])- (100*hand
.pot
.common
[player
]))
232 for player
in hand
.players
:
233 hcs
= hand
.join_holecards(player
[1], asList
=True)
234 hcs
= hcs
+ [u
'0x']*18
235 #for i, card in enumerate(hcs[:20, 1): #Python 2.6 syntax
236 # self.handsplayers[player[1]]['card%s' % i] = Card.encodeCard(card)
237 for i
, card
in enumerate(hcs
[:20]):
238 self
.handsplayers
[player
[1]]['card%s' % (i
+1)] = Card
.encodeCard(card
)
239 self
.handsplayers
[player
[1]]['startCards'] = Card
.calcStartCards(hand
, player
[1])
241 self
.setPositions(hand
)
242 self
.calcCheckCallRaise(hand
)
243 self
.calc34BetStreet0(hand
)
244 self
.calcSteals(hand
)
249 def assembleHandsActions(self
, hand
):
251 for i
, street
in enumerate(hand
.actionStreets
):
252 for j
, act
in enumerate(hand
.actions
[street
]):
254 self
.handsactions
[k
] = {}
256 self
.handsactions
[k
]['amount'] = 0
257 self
.handsactions
[k
]['raiseTo'] = 0
258 self
.handsactions
[k
]['amountCalled'] = 0
259 self
.handsactions
[k
]['numDiscarded'] = 0
260 self
.handsactions
[k
]['cardsDiscarded'] = None
261 self
.handsactions
[k
]['allIn'] = False
262 #Insert values from hand.actions
263 self
.handsactions
[k
]['player'] = act
[0]
264 self
.handsactions
[k
]['street'] = i
-1
265 self
.handsactions
[k
]['actionNo'] = k
266 self
.handsactions
[k
]['streetActionNo'] = (j
+1)
267 self
.handsactions
[k
]['actionId'] = hand
.ACTION
[act
[1]]
268 if act
[1] not in ('discards') and len(act
) > 2:
269 self
.handsactions
[k
]['amount'] = int(100 * act
[2])
270 if act
[1] in ('raises', 'completes'):
271 self
.handsactions
[k
]['raiseTo'] = int(100 * act
[3])
272 self
.handsactions
[k
]['amountCalled'] = int(100 * act
[4])
273 if act
[1] in ('discards'):
274 self
.handsactions
[k
]['numDiscarded'] = int(act
[2])
275 if act
[1] in ('discards') and len(act
) > 3:
276 self
.handsactions
[k
]['cardsDiscarded'] = act
[3]
277 if len(act
) > 3 and act
[1] not in ('discards'):
278 self
.handsactions
[k
]['allIn'] = act
[-1]
280 def setPositions(self
, hand
):
281 """Sets the position for each player in HandsPlayers
282 any blinds are negative values, and the last person to act on the
283 first betting round is 0
284 NOTE: HU, both values are negative for non-stud games
285 NOTE2: I've never seen a HU stud match"""
286 actions
= hand
.actions
[hand
.holeStreets
[0]]
287 # Note: pfbao list may not include big blind if all others folded
288 players
= self
.pfbao(actions
)
290 # set blinds first, then others from pfbao list, avoids problem if bb
291 # is missing from pfbao list or if there is no small blind
292 sb
, bb
, bi
= False, False, False
293 if hand
.gametype
['base'] == 'stud':
294 # Stud position is determined after cards are dealt
295 bi
= [x
[0] for x
in hand
.actions
[hand
.actionStreets
[1]] if x
[1] == 'bringin']
297 bb
= [x
[0] for x
in hand
.actions
[hand
.actionStreets
[0]] if x
[1] == 'big blind']
298 sb
= [x
[0] for x
in hand
.actions
[hand
.actionStreets
[0]] if x
[1] == 'small blind']
300 # if there are > 1 sb or bb only the first is used!
302 self
.handsplayers
[bb
[0]]['position'] = 'B'
303 if bb
[0] in players
: players
.remove(bb
[0])
305 self
.handsplayers
[sb
[0]]['position'] = 'S'
306 if sb
[0] in players
: players
.remove(sb
[0])
308 self
.handsplayers
[bi
[0]]['position'] = 'S'
309 if bi
[0] in players
: players
.remove(bi
[0])
311 #print "DEBUG: bb: '%s' sb: '%s' bi: '%s' plyrs: '%s'" %(bb, sb, bi, players)
312 for i
,player
in enumerate(reversed(players
)):
313 self
.handsplayers
[player
]['position'] = i
315 def assembleHudCache(self
, hand
):
316 # No real work to be done - HandsPlayers data already contains the correct info
319 def vpip(self
, hand
):
321 for act
in hand
.actions
[hand
.actionStreets
[1]]:
322 if act
[1] in ('calls','bets', 'raises', 'completes'):
325 self
.hands
['playersVpi'] = len(vpipers
)
327 for player
in hand
.players
:
328 if player
[1] in vpipers
:
329 self
.handsplayers
[player
[1]]['street0VPI'] = True
331 self
.handsplayers
[player
[1]]['street0VPI'] = False
333 def playersAtStreetX(self
, hand
):
334 """ playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */"""
335 # self.actions[street] is a list of all actions in a tuple, contining the player name first
336 # [ (player, action, ....), (player2, action, ...) ]
337 # The number of unique players in the list per street gives the value for playersAtStreetXXX
339 # FIXME?? - This isn't couting people that are all in - at least showdown needs to reflect this
340 # ... new code below hopefully fixes this
341 # partly fixed, allins are now set as seeing streets because they never do a fold action
343 self
.hands
['playersAtStreet1'] = 0
344 self
.hands
['playersAtStreet2'] = 0
345 self
.hands
['playersAtStreet3'] = 0
346 self
.hands
['playersAtStreet4'] = 0
347 self
.hands
['playersAtShowdown'] = 0
350 # for (i, street) in enumerate(hand.actionStreets[2:]):
352 # for action in hand.actions[street]:
353 # if len(action) > 2 and action[-1]: # allin
354 # alliners.add(action[0])
355 # actors.add(action[0])
356 # if len(actors)==0 and len(alliners)<2:
358 # self.hands['playersAtStreet%d' % (i+1)] = len(set.union(alliners, actors))
360 # actions = hand.actions[hand.actionStreets[-1]]
361 # print "p_actions:", self.pfba(actions), "p_folds:", self.pfba(actions, l=('folds',)), "alliners:", alliners
362 # pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)
364 # hand.players includes people that are sitting out on some sites for cash games
365 # actionStreets[1] is 'DEAL', 'THIRD', 'PREFLOP', so any player dealt cards
366 # must act on this street if dealt cards. Almost certainly broken for the 'all-in blind' case
367 # and right now i don't care - CG
369 p_in
= set([x
[0] for x
in hand
.actions
[hand
.actionStreets
[1]]])
372 # discover who folded on each street and remove them from p_in
374 # i values as follows 0=BLINDSANTES 1=PREFLOP 2=FLOP 3=TURN 4=RIVER
377 # At the beginning of the loop p_in contains the players with cards
378 # at the start of that street.
379 # p_in is reduced each street to become a list of players still-in
380 # e.g. when i=1 (preflop) all players who folded during preflop
381 # are found by pfba() and eliminated from p_in.
382 # Therefore at the end of the loop, p_in contains players remaining
383 # at the end of the action on that street, and can therefore be set
384 # as the value for the number of players who saw the next street
386 # note that i is 1 in advance of the actual street numbers in the db
388 # if p_in reduces to 1 player, we must bomb-out immediately
389 # because the hand is over, this will ensure playersAtStreetx
393 for (i
, street
) in enumerate(hand
.actionStreets
):
394 if (i
-1) in (1,2,3,4):
395 # p_in stores players with cards at start of this street,
396 # so can set streetxSeen & playersAtStreetx with this information
397 # This hard-coded for i-1 =1,2,3,4 because those are the only columns
398 # in the db! this code section also replaces seen() - more info log 66
399 # nb i=2=flop=street1Seen, hence i-1 term needed
400 self
.hands
['playersAtStreet%d' % (i
-1)] = len(p_in
)
401 for player_with_cards
in p_in
:
402 self
.handsplayers
[player_with_cards
]['street%sSeen' % (i
-1)] = True
404 # find out who folded, and eliminate them from p_in
406 actions
= hand
.actions
[street
]
407 p_in
= p_in
- self
.pfba(actions
, l
=('folds',))
409 # if everyone folded, we are done, so exit this method immediately
411 if len(p_in
) == 1: return None
414 # The remaining players in p_in reached showdown (including all-ins
415 # because they never did a "fold" action in pfba() above)
417 self
.hands
['playersAtShowdown'] = len(p_in
)
418 for showdown_player
in p_in
:
419 self
.handsplayers
[showdown_player
]['sawShowdown'] = True
421 def streetXRaises(self
, hand
):
422 # self.actions[street] is a list of all actions in a tuple, contining the action as the second element
423 # [ (player, action, ....), (player2, action, ...) ]
424 # No idea what this value is actually supposed to be
425 # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl
426 # Leaving empty for the moment,
428 for i
in range(5): self
.hands
['street%dRaises' % i
] = 0
430 for (i
, street
) in enumerate(hand
.actionStreets
[1:]):
431 self
.hands
['street%dRaises' % i
] = len(filter( lambda action
: action
[1] in ('raises','bets'), hand
.actions
[street
]))
433 def calcSteals(self
, hand
):
434 """Fills raiseFirstInChance|raisedFirstIn, fold(Bb|Sb)ToSteal(Chance|)
436 Steal attempt - open raise on positions 1 0 S - i.e. CO, BU, SB
437 (note: I don't think PT2 counts SB steals in HU hands, maybe we shouldn't?)
438 Fold to steal - folding blind after steal attemp wo any other callers or raisers
440 steal_attempt
= False
442 steal_positions
= (1, 0, 'S')
443 if hand
.gametype
['base'] == 'stud':
444 steal_positions
= (2, 1, 0)
445 for action
in hand
.actions
[hand
.actionStreets
[1]]:
446 pname
, act
= action
[0], action
[1]
447 posn
= self
.handsplayers
[pname
]['position']
448 #print "\naction:", action[0], posn, type(posn), steal_attempt, act
450 #NOTE: Stud games will never hit this section
452 self
.handsplayers
[pname
]['foldBbToStealChance'] = True
453 self
.handsplayers
[pname
]['raiseToStealChance'] = True
454 self
.handsplayers
[pname
]['foldedBbToSteal'] = act
== 'folds'
455 self
.handsplayers
[pname
]['raiseToStealDone'] = act
== 'raises'
456 self
.handsplayers
[stealer
]['success_Steal'] = act
== 'folds'
459 self
.handsplayers
[pname
]['raiseToStealChance'] = steal_attempt
460 self
.handsplayers
[pname
]['foldSbToStealChance'] = steal_attempt
461 self
.handsplayers
[pname
]['foldedSbToSteal'] = steal_attempt
and act
== 'folds'
462 self
.handsplayers
[pname
]['raiseToStealDone'] = steal_attempt
and act
== 'raises'
464 if steal_attempt
and act
!= 'folds':
467 if not steal_attempt
and not raised
and not act
in ('bringin'):
468 self
.handsplayers
[pname
]['raiseFirstInChance'] = True
469 if act
in ('bets', 'raises', 'completes'):
470 self
.handsplayers
[pname
]['raisedFirstIn'] = True
472 if posn
in steal_positions
:
478 if posn
not in steal_positions
and act
not in ('folds', 'bringin'):
481 def calc34BetStreet0(self
, hand
):
482 """Fills street0_(3|4)B(Chance|Done), other(3|4)BStreet0"""
483 bet_level
= 1 # bet_level after 3-bet is equal to 3
484 squeeze_chance
= False
485 for action
in hand
.actions
[hand
.actionStreets
[1]]:
486 pname
, act
, aggr
= action
[0], action
[1], action
[1] in ('raises', 'bets')
489 first_agressor
= pname
493 self
.handsplayers
[pname
]['street0_3BChance'] = True
494 self
.handsplayers
[pname
]['street0_SqueezeChance'] = squeeze_chance
495 if not squeeze_chance
and act
== 'calls':
496 squeeze_chance
= True
499 self
.handsplayers
[pname
]['street0_3BDone'] = True
500 self
.handsplayers
[pname
]['street0_SqueezeDone'] = squeeze_chance
501 second_agressor
= pname
505 if pname
== first_agressor
:
506 self
.handsplayers
[pname
]['street0_4BChance'] = True
507 self
.handsplayers
[pname
]['street0_FoldTo3BChance'] = True
509 self
.handsplayers
[pname
]['street0_4BDone'] = True
512 self
.handsplayers
[pname
]['street0_FoldTo3BDone'] = True
515 self
.handsplayers
[pname
]['street0_C4BChance'] = True
517 self
.handsplayers
[pname
]['street0_C4BDone'] = True
521 if pname
!= first_agressor
:
522 self
.handsplayers
[pname
]['street0_FoldTo4BChance'] = True
524 self
.handsplayers
[pname
]['street0_FoldTo4BDone'] = True
526 def calcCBets(self
, hand
):
527 """Fill streetXCBChance, streetXCBDone, foldToStreetXCBDone, foldToStreetXCBChance
529 Continuation Bet chance, action:
530 Had the last bet (initiative) on previous street, got called, close street action
531 Then no bets before the player with initiatives first action on current street
532 ie. if player on street-1 had initiative and no donkbets occurred
534 # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
536 #for i, street in enumerate(hand.actionStreets[2:], start=1):
537 for i
, street
in enumerate(hand
.actionStreets
[2:]):
538 name
= self
.lastBetOrRaiser(hand
.actionStreets
[i
+1])
540 chance
= self
.noBetsBefore(hand
.actionStreets
[i
+2], name
)
542 self
.handsplayers
[name
]['street%dCBChance' % (i
+1)] = True
543 self
.handsplayers
[name
]['street%dCBDone' % (i
+1)] = self
.betStreet(hand
.actionStreets
[i
+2], name
)
545 def calcCheckCallRaise(self
, hand
):
546 """Fill streetXCheckCallRaiseChance, streetXCheckCallRaiseDone
548 streetXCheckCallRaiseChance = got raise/bet after check
549 streetXCheckCallRaiseDone = checked. got raise/bet. didn't fold
551 CG: CheckCall would be a much better name for this.
553 # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
554 #for i, street in enumerate(hand.actionStreets[2:], start=1):
555 for i
, street
in enumerate(hand
.actionStreets
[2:]):
556 actions
= hand
.actions
[hand
.actionStreets
[i
+1]]
558 initial_raiser
= None
559 for action
in actions
:
560 pname
, act
= action
[0], action
[1]
561 if act
in ('bets', 'raises') and initial_raiser
is None:
562 initial_raiser
= pname
563 elif act
== 'checks' and initial_raiser
is None:
565 elif initial_raiser
is not None and pname
in checkers
:
566 self
.handsplayers
[pname
]['street%dCheckCallRaiseChance' % (i
+1)] = True
567 self
.handsplayers
[pname
]['street%dCheckCallRaiseDone' % (i
+1)] = act
!='folds'
569 def aggr(self
, hand
, i
):
572 # Growl - actionStreets contains 'BLINDSANTES', which isn't actually an action street
575 for act
in hand
.actions
[hand
.actionStreets
[i
+1]]:
578 if act
[1] in ('completes', 'bets', 'raises'):
582 for player
in hand
.players
:
583 #print "DEBUG: actionStreet[%s]: %s" %(hand.actionStreets[i+1], i)
584 if player
[1] in aggrers
:
585 self
.handsplayers
[player
[1]]['street%sAggr' % i
] = True
587 self
.handsplayers
[player
[1]]['street%sAggr' % i
] = False
589 if len(aggrers
)>0 and i
>0:
590 for playername
in others
:
591 self
.handsplayers
[playername
]['otherRaisedStreet%s' % i
] = True
592 #print "otherRaised detected on handid "+str(hand.handid)+" for "+playername+" on street "+str(i)
594 if i
> 0 and len(aggrers
) > 0:
595 for playername
in others
:
596 self
.handsplayers
[playername
]['otherRaisedStreet%s' % i
] = True
597 #print "DEBUG: otherRaised detected on handid %s for %s on actionStreet[%s]: %s"
598 # %(hand.handid, playername, hand.actionStreets[i+1], i)
600 def calls(self
, hand
, i
):
602 for act
in hand
.actions
[hand
.actionStreets
[i
+1]]:
603 if act
[1] in ('calls'):
604 self
.handsplayers
[act
[0]]['street%sCalls' % i
] = 1 + self
.handsplayers
[act
[0]]['street%sCalls' % i
]
606 # CG - I'm sure this stat is wrong
607 # Best guess is that raise = 2 bets
608 def bets(self
, hand
, i
):
609 for act
in hand
.actions
[hand
.actionStreets
[i
+1]]:
610 if act
[1] in ('bets'):
611 self
.handsplayers
[act
[0]]['street%sBets' % i
] = 1 + self
.handsplayers
[act
[0]]['street%sBets' % i
]
613 def folds(self
, hand
, i
):
614 for act
in hand
.actions
[hand
.actionStreets
[i
+1]]:
615 if act
[1] in ('folds'):
616 if self
.handsplayers
[act
[0]]['otherRaisedStreet%s' % i
] == True:
617 self
.handsplayers
[act
[0]]['foldToOtherRaisedStreet%s' % i
] = True
618 #print "DEBUG: fold detected on handid %s for %s on actionStreet[%s]: %s"
619 # %(hand.handid, act[0],hand.actionStreets[i+1], i)
621 def countPlayers(self
, hand
):
624 def pfba(self
, actions
, f
=None, l
=None):
625 """Helper method. Returns set of PlayersFilteredByActions
627 f - forbidden actions
628 l - limited to actions
631 for action
in actions
:
632 if l
is not None and action
[1] not in l
: continue
633 if f
is not None and action
[1] in f
: continue
634 players
.add(action
[0])
637 def pfbao(self
, actions
, f
=None, l
=None, unique
=True):
638 """Helper method. Returns set of PlayersFilteredByActionsOrdered
640 f - forbidden actions
641 l - limited to actions
643 # Note, this is an adaptation of function 5 from:
644 # http://www.peterbe.com/plog/uniqifiers-benchmark
647 for action
in actions
:
648 if l
is not None and action
[1] not in l
: continue
649 if f
is not None and action
[1] in f
: continue
650 if action
[0] in seen
and unique
: continue
652 players
.append(action
[0])
655 def firstsBetOrRaiser(self
, actions
):
656 """Returns player name that placed the first bet or raise.
658 None if there were no bets or raises on that street
661 if act
[1] in ('bets', 'raises'):
665 def lastBetOrRaiser(self
, street
):
666 """Returns player name that placed the last bet or raise for that street.
667 None if there were no bets or raises on that street"""
669 for act
in self
.hand
.actions
[street
]:
670 if act
[1] in ('bets', 'raises'):
675 def noBetsBefore(self
, street
, player
):
676 """Returns true if there were no bets before the specified players turn, false otherwise"""
678 for act
in self
.hand
.actions
[street
]:
679 #Must test for player first in case UTG
683 if act
[1] in ('bets', 'raises'):
688 def betStreet(self
, street
, player
):
689 """Returns true if player bet/raised the street as their first action"""
691 for act
in self
.hand
.actions
[street
]:
693 if act
[1] in ('bets', 'raises'):
696 # player found but did not bet or raise as their first action
700 # haven't found player's first action yet