Coverage for DerivedStats.py: 14%
989 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-28 16:41 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-28 16:41 +0000
1#!/usr/bin/env python
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.
8#
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.
13#
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.
18#fpdb modules
19from __future__ import division
21from past.utils import old_div
22#import L10n
23#_ = L10n.get_translation()
24import Card
25from decimal_wrapper import Decimal, ROUND_DOWN
27import sys
28import logging
29# logging has been set up in fpdb.py or HUD_main.py, use their settings:
30log = logging.getLogger("parser")
32try:
33 from pokereval import PokerEval
34 pokereval = PokerEval()
35except:
36 pokereval = None
38def _buildStatsInitializer():
39 init = {}
40 #Init vars that may not be used, but still need to be inserted.
41 # All stud street4 need this when importing holdem
42 init['effStack'] = 0
43 init['startBounty'] = None
44 init['endBounty'] = None
45 init['common'] = 0
46 init['committed'] = 0
47 init['winnings'] = 0
48 init['rake'] = 0
49 init['rakeDealt'] = 0
50 init['rakeContributed'] = 0
51 init['rakeWeighted'] = 0
52 init['totalProfit'] = 0
53 init['allInEV'] = 0
54 init['showdownWinnings'] = 0
55 init['nonShowdownWinnings'] = 0
56 init['sawShowdown'] = False
57 init['showed'] = False
58 init['wonAtSD'] = False
59 init['startCards'] = 170
60 init['handString'] = None
61 init['position'] = 9 #ANTE ALL IN
62 init['street0CalledRaiseChance'] = 0
63 init['street0CalledRaiseDone'] = 0
64 init['street0VPIChance'] = True
65 init['street0VPI'] = False
66 init['street0AggrChance'] = True
67 init['street0_2BChance'] = False
68 init['street0_2BDone'] = False
69 init['street0_3BChance'] = False
70 init['street0_3BDone'] = False
71 init['street0_4BChance'] = False
72 init['street0_4BDone'] = False
73 init['street0_C4BChance'] = False
74 init['street0_C4BDone'] = False
75 init['street0_FoldTo2BChance']= False
76 init['street0_FoldTo2BDone']= False
77 init['street0_FoldTo3BChance']= False
78 init['street0_FoldTo3BDone']= False
79 init['street0_FoldTo4BChance']= False
80 init['street0_FoldTo4BDone']= False
81 init['street0_SqueezeChance']= False
82 init['street0_SqueezeDone'] = False
83 init['stealChance'] = False
84 init['stealDone'] = False
85 init['success_Steal'] = False
86 init['raiseToStealChance'] = False
87 init['raiseToStealDone'] = False
88 init['raiseFirstInChance'] = False
89 init['raisedFirstIn'] = False
90 init['foldBbToStealChance'] = False
91 init['foldSbToStealChance'] = False
92 init['foldedSbToSteal'] = False
93 init['foldedBbToSteal'] = False
94 init['tourneyTypeId'] = None
95 init['street1Seen'] = False
96 init['street2Seen'] = False
97 init['street3Seen'] = False
98 init['street4Seen'] = False
99 init['otherRaisedStreet0'] = False
100 init['foldToOtherRaisedStreet0'] = False
101 init['wentAllIn'] = False
103 for i in range(5):
104 init['street%dCalls' % i] = 0
105 init['street%dBets' % i] = 0
106 init['street%dRaises' % i] = 0
107 init['street%dAggr' % i] = False
108 init['street%dInPosition' % i] = False
109 init['street%dFirstToAct' % i] = False
110 init['street%dAllIn' % i] = False
112 for i in range(1,4):
113 init['street%dDiscards' % i] = 0
115 for i in range(1,5):
116 init['street%dCBChance' %i] = False
117 init['street%dCBDone' %i] = False
118 init['street%dCheckCallRaiseChance' %i] = False
119 init['street%dCheckCallDone' %i] = False
120 init['street%dCheckRaiseDone' %i] = False
121 init['otherRaisedStreet%d' %i] = False
122 init['foldToOtherRaisedStreet%d' %i] = False
123 init['foldToStreet%dCBChance' %i] = False
124 init['foldToStreet%dCBDone' %i] = False
125 init['wonWhenSeenStreet%d' %i] = False
126 return init
128_INIT_STATS = _buildStatsInitializer()
130class DerivedStats(object):
131 def __init__(self):
132 self.hands = {}
133 self.handsplayers = {}
134 self.handsactions = {}
135 self.handsstove = []
136 self.handspots = []
138 def getStats(self, hand):
139 for player in hand.players:
140 self.handsplayers[player[1]] = _INIT_STATS.copy()
142 self.assembleHands(hand)
143 self.assembleHandsPlayers(hand)
144 self.assembleHandsActions(hand)
146 if pokereval and hand.gametype['category'] in Card.games:
147 self.assembleHandsStove(hand)
148 self.assembleHandsPots(hand)
150 def getHands(self):
151 return self.hands
153 def getHandsPlayers(self):
154 return self.handsplayers
156 def getHandsActions(self):
157 return self.handsactions
159 def getHandsStove(self):
160 return self.handsstove
162 def getHandsPots(self):
163 return self.handspots
165 def assembleHands(self, hand):
166 self.hands['tableName'] = hand.tablename
167 self.hands['siteHandNo'] = hand.handid
168 self.hands['gametypeId'] = None # Leave None, handled later after checking db
169 self.hands['sessionId'] = None # Leave None, added later if caching sessions
170 self.hands['gameId'] = None # Leave None, added later if caching sessions
171 self.hands['startTime'] = hand.startTime # format this!
172 self.hands['importTime'] = None
173 self.hands['seats'] = self.countPlayers(hand)
174 self.hands['maxPosition'] = -1
175 #self.hands['maxSeats'] = hand.maxseats
176 self.hands['texture'] = None # No calculation done for this yet.
177 self.hands['tourneyId'] = hand.tourneyId
179 self.hands['heroSeat'] = 0
180 for player in hand.players:
181 if hand.hero==player[1]:
182 self.hands['heroSeat'] = player[0]
183 # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and
184 # those values remain default in stud.
185 boardcards = []
186 if hand.board.get('FLOPET')!=None:
187 boardcards += hand.board.get('FLOPET')
188 for street in hand.communityStreets:
189 boardcards += hand.board[street]
190 boardcards += [u'0x', u'0x', u'0x', u'0x', u'0x']
191 cards = [Card.encodeCard(c) for c in boardcards[0:5]]
192 self.hands['boardcard1'] = cards[0]
193 self.hands['boardcard2'] = cards[1]
194 self.hands['boardcard3'] = cards[2]
195 self.hands['boardcard4'] = cards[3]
196 self.hands['boardcard5'] = cards[4]
198 #print "cards: ",cards
200 self.hands['boards'] = []
201 self.hands['runItTwice'] = False
202 for i in range(hand.runItTimes):
203 boardcards = []
204 for street in hand.communityStreets:
205 boardId = i+1
206 street_i = street + str(boardId)
207 if street_i in hand.board:
208 boardcards += hand.board[street_i]
209 if hand.gametype['split']:
210 boardcards = boardcards + [u'0x', u'0x', u'0x', u'0x', u'0x']
211 cards = [Card.encodeCard(c) for c in boardcards[:5]]
212 else:
213 self.hands['runItTwice'] = True
214 boardcards = [u'0x', u'0x', u'0x', u'0x', u'0x'] + boardcards
215 cards = [Card.encodeCard(c) for c in boardcards[-5:]]
216 self.hands['boards'] += [[boardId] + cards]
218 #print "DEBUG: %s self.getStreetTotals = (%s, %s, %s, %s, %s, %s)" % tuple([hand.handid] + list(hand.getStreetTotals()))
219 totals = hand.getStreetTotals()
220 totals = [int(100*i) for i in totals]
221 self.hands['street0Pot'] = totals[0]
222 self.hands['street1Pot'] = totals[1]
223 self.hands['street2Pot'] = totals[2]
224 self.hands['street3Pot'] = totals[3]
225 self.hands['street4Pot'] = totals[4]
226 self.hands['finalPot'] = totals[5]
228 self.vpip(hand) # Gives playersVpi (num of players vpip)
229 #print "DEBUG: vpip: %s" %(self.hands['playersVpi'])
230 self.playersAtStreetX(hand) # Gives playersAtStreet1..4 and Showdown
231 #print "DEBUG: playersAtStreet 1:'%s' 2:'%s' 3:'%s' 4:'%s'" %(self.hands['playersAtStreet1'],self.hands['playersAtStreet2'],self.hands['playersAtStreet3'],self.hands['playersAtStreet4'])
232 self.streetXRaises(hand)
234 def assembleHandsPlayers(self, hand):
235 #street0VPI/vpip already called in Hand
236 # sawShowdown is calculated in playersAtStreetX, as that calculation gives us a convenient list of names
238 #hand.players = [[seat, name, chips],[seat, name, chips]]
239 for player in hand.players:
240 player_name = player[1]
241 player_stats = self.handsplayers.get(player_name)
242 player_stats['seatNo'] = player[0]
243 player_stats['startCash'] = int(100 * Decimal(player[2]))
244 if player[4] != None:
245 player_stats['startBounty'] = int(100 * Decimal(player[4]))
246 player_stats['endBounty'] = int(100 * Decimal(player[4]))
247 if player_name in hand.endBounty:
248 player_stats['endBounty'] = int(hand.endBounty.get(player_name))
249 if player_name in hand.sitout:
250 player_stats['sitout'] = True
251 else:
252 player_stats['sitout'] = False
253 if hand.gametype["type"]=="tour":
254 player_stats['tourneyTypeId']=hand.tourneyTypeId
255 player_stats['tourneysPlayersId'] = hand.tourneysPlayersIds[player[1]]
256 else:
257 player_stats['tourneysPlayersId'] = None
258 if player_name in hand.shown:
259 player_stats['showed'] = True
261 #### seen now processed in playersAtStreetX()
262 # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
263 #for i, street in enumerate(hand.actionStreets[2:], start=1):
264 #for i, street in enumerate(hand.actionStreets[2:]):
265 # self.seen(self.hand, i+1)
267 for i, street in enumerate(hand.actionStreets[1:]):
268 self.aggr(hand, i)
269 self.calls(hand, i)
270 self.bets(hand, i)
271 self.raises(hand, i)
272 if i>0:
273 self.folds(hand, i)
275 # Winnings is a non-negative value of money collected from the pot, which already includes the
276 # rake taken out. hand.collectees is Decimal, database requires cents
277 num_collectees, i = len(hand.collectees), 0
278 even_split = old_div(hand.totalpot, num_collectees) if num_collectees > 0 else 0
279 unraked = [c for c in list(hand.collectees.values()) if even_split == c]
280 for player, winnings in list(hand.collectees.items()):
281 collectee_stats = self.handsplayers.get(player)
282 collectee_stats['winnings'] = int(100 * winnings)
283 # Splits evenly on split pots and gives remainder to first player
284 # Gets overwritten when calculating multi-way pots in assembleHandsPots
285 if num_collectees == 0:
286 collectee_stats['rake'] = 0
287 elif len(unraked)==0:
288 rake = old_div(int(100 * hand.rake),num_collectees)
289 remainder_1, remainder_2 = 0, 0
290 if rake > 0 and i==0:
291 leftover = int(100 * hand.rake) - (rake * num_collectees)
292 remainder_1 = int(100 * hand.rake) % rake
293 remainder_2 = leftover if remainder_1 == 0 else 0
294 collectee_stats['rake'] = rake + remainder_1 + remainder_2
295 else:
296 collectee_stats['rake'] = int(100 *(even_split - winnings))
297 if collectee_stats['street1Seen'] == True:
298 collectee_stats['wonWhenSeenStreet1'] = True
299 if collectee_stats['street2Seen'] == True:
300 collectee_stats['wonWhenSeenStreet2'] = True
301 if collectee_stats['street3Seen'] == True:
302 collectee_stats['wonWhenSeenStreet3'] = True
303 if collectee_stats['street4Seen'] == True:
304 collectee_stats['wonWhenSeenStreet4'] = True
305 if collectee_stats['sawShowdown'] == True:
306 collectee_stats['wonAtSD'] = True
307 i+=1
309 contributed, i = [], 0
310 for player, money_committed in list(hand.pot.committed.items()):
311 committed_player_stats = self.handsplayers.get(player)
312 paid = (100 * money_committed) + (100*hand.pot.common[player])
313 committed_player_stats['common'] = int(100 * hand.pot.common[player])
314 committed_player_stats['committed'] = int(100 * money_committed)
315 committed_player_stats['totalProfit'] = int(committed_player_stats['winnings'] - paid)
316 committed_player_stats['allInEV'] = committed_player_stats['totalProfit']
317 committed_player_stats['rakeDealt'] = 100 * hand.rake/len(hand.players)
318 committed_player_stats['rakeWeighted'] = 100 * hand.rake * paid/(100*hand.totalpot) if hand.rake>0 else 0
319 if paid > 0: contributed.append(player)
320 i+=1
322 for i, player in enumerate(contributed):
323 self.handsplayers[player]['rakeContributed'] = 100 * hand.rake/len(contributed)
325 self.calcCBets(hand)
327 # More inner-loop speed hackery.
328 encodeCard = Card.encodeCard
329 calcStartCards = Card.calcStartCards
330 for player in hand.players:
331 player_name = player[1]
332 hcs = hand.join_holecards(player_name, asList=True)
333 hcs = hcs + [u'0x']*18
334 #for i, card in enumerate(hcs[:20, 1): #Python 2.6 syntax
335 # self.handsplayers[player[1]]['card%s' % i] = Card.encodeCard(card)
336 player_stats = self.handsplayers.get(player_name)
337 if player_stats['sawShowdown']:
338 player_stats['showdownWinnings'] = player_stats['totalProfit']
339 else:
340 player_stats['nonShowdownWinnings'] = player_stats['totalProfit']
341 for i, card in enumerate(hcs[:20]):
342 player_stats['card%d' % (i+1)] = encodeCard(card)
343 try:
344 player_stats['startCards'] = calcStartCards(hand, player_name)
345 except IndexError:
346 log.error("IndexError: string index out of range %s %s" % (hand.handid, hand.in_path))
348 self.setPositions(hand)
349 self.calcEffectiveStack(hand)
350 self.calcCheckCallRaise(hand)
351 self.calc34BetStreet0(hand)
352 self.calcSteals(hand)
353 self.calcCalledRaiseStreet0(hand)
354 # Additional stats
355 # 3betSB, 3betBB
356 # Squeeze, Ratchet?
358 def assembleHandsActions(self, hand):
359 k = 0
360 for i, street in enumerate(hand.actionStreets):
361 for j, act in enumerate(hand.actions[street]):
362 k += 1
363 self.handsactions[k] = {}
364 #default values
365 self.handsactions[k]['amount'] = 0
366 self.handsactions[k]['raiseTo'] = 0
367 self.handsactions[k]['amountCalled'] = 0
368 self.handsactions[k]['numDiscarded'] = 0
369 self.handsactions[k]['cardsDiscarded'] = None
370 self.handsactions[k]['allIn'] = False
371 #Insert values from hand.actions
372 self.handsactions[k]['player'] = act[0]
373 self.handsactions[k]['street'] = i-1
374 self.handsactions[k]['actionNo'] = k
375 self.handsactions[k]['streetActionNo'] = (j+1)
376 self.handsactions[k]['actionId'] = hand.ACTION[act[1]]
377 if act[1] not in ('discards') and len(act) > 2:
378 self.handsactions[k]['amount'] = int(100 * act[2])
379 if act[1] in ('raises', 'completes'):
380 self.handsactions[k]['raiseTo'] = int(100 * act[3])
381 self.handsactions[k]['amountCalled'] = int(100 * act[4])
382 if act[1] in ('discards'):
383 self.handsactions[k]['numDiscarded'] = int(act[2])
384 self.handsplayers[act[0]]['street%dDiscards' %(i-1)] = int(act[2])
385 if act[1] in ('discards') and len(act) > 3:
386 self.handsactions[k]['cardsDiscarded'] = act[3]
387 if len(act) > 3 and act[1] not in ('discards'):
388 self.handsactions[k]['allIn'] = act[-1]
389 if act[-1]:
390 self.handsplayers[act[0]]['wentAllIn'] = True
391 self.handsplayers[act[0]]['street%dAllIn' %(i-1)] = True
393 def assembleHandsStove(self, hand):
394 category = hand.gametype['category']
395 holecards, holeplayers, allInStreets = {}, [], hand.allStreets[1:]
396 base, evalgame, hilo, streets, last, hrange = Card.games[category]
397 hiLoKey = {'h': [('h', 'hi')], 'l': [('l', 'low')], 's': [('h', 'hi'),('l', 'low')], 'r': [('l', 'hi')]}
398 boards = self.getBoardsDict(hand, base, streets)
399 for player in hand.players:
400 pname = player[1]
401 hp = self.handsplayers.get(pname)
402 if evalgame:
403 hcs = hand.join_holecards(pname, asList=True)
404 holecards[pname] = {}
405 holecards[pname]['cards'] = []
406 holecards[pname]['eq'] = 0
407 holecards[pname]['committed'] = 0
408 holeplayers.append(pname)
409 for street, board in list(boards.items()):
410 streetId = streets[street]
411 if streetId > 0:
412 streetSeen = hp['street%sSeen' % str(streetId)]
413 else: streetSeen = True
414 if ((pname==hand.hero and streetSeen) or (hp['showed'] and streetSeen) or hp['sawShowdown']):
415 boardId, hl, rankId, value, _cards = 0, 'n', 1, 0, None
416 for n in range(len(board['board'])):
417 streetIdx = -1 if base=='hold' else streetId
418 cards = hcs[hrange[streetIdx][0]:hrange[streetIdx][1]]
419 boardId = (n + 1) if (len(board['board']) > 1) else n
420 cards += board['board'][n] if (board['board'][n] and 'omaha' not in evalgame) else []
421 bcards = board['board'][n] if (board['board'][n] and 'omaha' in evalgame) else []
422 cards = [str(c) if Card.encodeCardList.get(c) else '0x' for c in cards]
423 bcards = [str(b) if Card.encodeCardList.get(b) else '0x' for b in bcards]
424 holecards[pname]['hole'] = cards[hrange[streetIdx][0]:hrange[streetIdx][1]]
425 holecards[pname]['cards'] += [cards]
426 notnull = ('0x' not in cards) and ('0x' not in bcards)
427 postflop = (base=='hold' and len(board['board'][n])>=3)
428 maxcards = (base!='hold' and len(cards)>=5)
429 if notnull and (postflop or maxcards):
430 for hl, side in hiLoKey[hilo]:
431 try:
432 value, rank = pokereval.best(side, cards, bcards)
433 rankId = Card.hands[rank[0]][0]
434 if rank!=None and rank[0] != 'Nothing':
435 _cards = ''.join([pokereval.card2string(i)[0] for i in rank[1:]])
436 else:
437 _cards = None
438 self.handsstove.append( [hand.dbid_hands, hand.dbid_pids[pname], streetId, boardId, hl, rankId, value, _cards, 0] )
439 except RuntimeError:
440 log.error("assembleHandsStove: error determining value and rank for hand %s %s" % (hand.handid, hand.in_path))
441 self.handsstove.append( [hand.dbid_hands, hand.dbid_pids[pname], streetId, boardId, 'n', 1, 0, None, 0] )
442 else:
443 self.handsstove.append( [hand.dbid_hands, hand.dbid_pids[pname], streetId, boardId, 'n', 1, 0, None, 0] )
444 else:
445 hl, streetId = hiLoKey[hilo][0][0], 0
446 if (hp['sawShowdown'] or hp['showed']):
447 hp['handString'] = hand.showdownStrings.get(pname)
448 streetId = streets[last]
449 self.handsstove.append( [hand.dbid_hands, hand.dbid_pids[player[1]], streetId, 0, hl, 1, 0, None, 0] )
451 if base=='hold' and evalgame:
452 self.getAllInEV(hand, evalgame, holeplayers, boards, streets, holecards)
454 def getAllInEV(self, hand, evalgame, holeplayers, boards, streets, holecards):
455 startstreet, potId, allInStreets, allplayers = None, 0, hand.allStreets[1:], []
456 for pot, players in hand.pot.pots:
457 if potId ==0: pot += (sum(hand.pot.common.values()) + hand.pot.stp)
458 potId+=1
459 for street in allInStreets:
460 board = boards[street]
461 streetId = streets[street]
462 for n in range(len(board['board'])):
463 if len(board['board']) > 1:
464 boardId = n + 1
465 else: boardId = n
466 valid = [p for p in players if self.handsplayers[p]['sawShowdown'] and u'0x' not in holecards[p]['cards'][n]]
467 if potId == 1:
468 allplayers = valid
469 deadcards, deadplayers = [], []
470 else:
471 deadplayers = [d for d in allplayers if d not in valid]
472 _deadcards = [holecards[d]['hole'] for d in deadplayers]
473 deadcards = [item for sublist in _deadcards for item in sublist]
474 if len(players) == len(valid) and (board['allin'] or hand.publicDB):
475 if board['allin'] and not startstreet: startstreet = street
476 if len(valid) > 1:
477 try:
478 evs = pokereval.poker_eval(
479 game = evalgame,
480 iterations = Card.iter[streetId],
481 pockets = [holecards[p]['hole'] for p in valid],
482 dead = deadcards,
483 board = [str(b) for b in board['board'][n]] + (5 - len(board['board'][n])) * ['__']
484 )
485 equities = [e['ev'] for e in evs['eval']]
486 except RuntimeError:
487 log.error("getAllInEV: error running poker_eval for hand %s %s" % (hand.handid, hand.in_path))
488 equities = [1000]
489 else:
490 equities = [1000]
491 remainder = old_div((1000 - sum(equities)), Decimal(len(equities)))
492 for i in range(len(equities)):
493 equities[i] += remainder
494 p = valid[i]
495 pid = hand.dbid_pids[p]
496 if street == startstreet:
497 rake = Decimal(0) if hand.cashedOut else (hand.rake * (old_div(Decimal(pot),Decimal(hand.totalpot))))
498 holecards[p]['eq'] += old_div(((pot - rake) * equities[i]),Decimal(10))
499 holecards[p]['committed'] = 100*hand.pot.committed[p] + 100*hand.pot.common[p]
500 for j in self.handsstove:
501 if [pid, streetId, boardId] == j[1:4] and len(valid) == len(hand.pot.contenders):
502 j[-1] = equities[i]
503 for p in holeplayers:
504 if holecards[p]['committed'] != 0:
505 self.handsplayers[p]['allInEV'] = holecards[p]['eq'] - holecards[p]['committed']
507 def getBoardsList(self, hand):
508 boards, community = [], []
509 if hand.gametype['base']=='hold':
510 for s in hand.communityStreets:
511 community += hand.board[s]
512 for i in range(hand.runItTimes):
513 boardcards = []
514 for street in hand.communityStreets:
515 boardId = i+1
516 street_i = street + str(boardId)
517 if street_i in hand.board:
518 boardcards += hand.board[street_i]
519 cards = [str(c) for c in community + boardcards]
520 boards.append(cards)
521 if not boards:
522 boards = [community]
523 return boards
525 def getBoardsDict(self, hand, base, streets):
526 boards, boardcards, allInStreets, showdown = {}, [], hand.allStreets[1:], False
527 for player in hand.players:
528 if (self.handsplayers[player[1]]['sawShowdown']):
529 showdown = True
530 if base == 'hold':
531 for s in allInStreets:
532 streetId = streets[s]
533 b = [x for sublist in [hand.board[k] for k in allInStreets[:streetId+1]] for x in sublist]
534 boards[s] = {'board': [b], 'allin': False}
535 boardcards += hand.board[s]
536 if not hand.actions[s] and showdown:
537 if streetId>0: boards[allInStreets[streetId-1]]['allin'] = True
538 boards[s]['allin'] = True
539 boardStreets = [[], [], []]
540 for i in range(hand.runItTimes):
541 runitcards = []
542 for street in hand.communityStreets:
543 street_i = street + str((i+1))
544 if street_i in hand.board:
545 runitcards += hand.board[street_i]
546 sId = len(boardcards + runitcards) - 3
547 boardStreets[sId].append(boardcards + runitcards)
548 for i in range(len(boardStreets)):
549 if boardStreets[i]:
550 boards[allInStreets[i+1]]['board'] = boardStreets[i]
551 else:
552 for s in allInStreets:
553 if s in streets:
554 streetId = streets[s]
555 boards[s] = {}
556 boards[s]['board'] = [[]]
557 boards[s]['allin'] = False
558 return boards
560 def awardPots(self, hand):
561 holeshow = True
562 base, evalgame, hilo, streets, last, hrange = Card.games[hand.gametype['category']]
563 for pot, players in hand.pot.pots:
564 for p in players:
565 hcs = hand.join_holecards(p, asList=True)
566 holes = [str(c) for c in hcs[hrange[-1][0]:hrange[-1][1]] if Card.encodeCardList.get(c)!=None or c=='0x']
567 #log.error((p, holes))
568 if '0x' in holes: holeshow = False
569 factor = 100
570 if ((hand.gametype["type"]=="tour" or
571 (hand.gametype["type"]=="ring" and
572 (hand.gametype["currency"]=="play" and
573 (hand.sitename not in ('Winamax', 'PacificPoker'))))) and
574 (not [n for (n,v) in hand.pot.pots if (n % Decimal('1.00'))!=0])):
575 factor = 1
576 hiLoKey = {'h':['hi'],'l':['low'],'r':['low'],'s':['hi','low']}
577 #log.error((len(hand.pot.pots)>1, evalgame, holeshow))
578 if pokereval and len(hand.pot.pots)>1 and evalgame and holeshow: #hrange
579 hand.collected = [] #list of ?
580 hand.collectees = {} # dict from player names to amounts collected (?)
581 rakes, totrake, potId = {}, 0, 0
582 totalrake = hand.rakes.get('rake')
583 if not totalrake:
584 totalpot = hand.rakes.get('pot')
585 if totalpot:
586 totalrake = hand.totalpot - totalpot
587 else:
588 totalrake = 0
589 for pot, players in hand.pot.pots:
590 if potId ==0: pot += (sum(hand.pot.common.values()) + hand.pot.stp)
591 potId+=1
592 boards, boardId, sumpot = self.getBoardsList(hand), 0, 0
593 for b in boards:
594 boardId += (hand.runItTimes>=2)
595 potBoard = Decimal(int(pot/len(boards)*factor))/factor
596 modBoard = pot - potBoard*len(boards)
597 if boardId==1:
598 potBoard+=modBoard
599 holeplayers, holecards = [], []
600 for p in players:
601 hcs = hand.join_holecards(p, asList=True)
602 holes = [str(c) for c in hcs[hrange[-1][0]:hrange[-1][1]] if Card.encodeCardList.get(c)!=None or c=='0x']
603 board = [str(c) for c in b if 'omaha' in evalgame]
604 if 'omaha' not in evalgame:
605 holes = holes + [str(c) for c in b if base=='hold']
606 if '0x' not in holes and '0x' not in board:
607 holecards.append(holes)
608 holeplayers.append(p)
609 if len(holecards)>1:
610 try:
611 win = pokereval.winners(game = evalgame, pockets = holecards, board = board)
612 except RuntimeError:
613 #log.error((evalgame, holecards, board))
614 log.error("awardPots: error evaluating winners for hand %s %s" % (hand.handid, hand.in_path))
615 win = {}
616 win[hiLoKey[hilo][0]] = [0]
617 else:
618 win = {}
619 win[hiLoKey[hilo][0]] = [0]
620 for hl in hiLoKey[hilo]:
621 if hl in win and len(win[hl])>0:
622 potHiLo = Decimal(int(potBoard/len(win)*factor))/factor
623 modHiLo = potBoard - potHiLo*len(win)
624 if len(win)==1 or hl=='hi':
625 potHiLo+=modHiLo
626 potSplit = Decimal(int(potHiLo/len(win[hl])*factor))/factor
627 modSplit = potHiLo - potSplit*len(win[hl])
628 pnames = players if len(holeplayers)==0 else [holeplayers[w] for w in win[hl]]
629 for p in pnames:
630 ppot = potSplit
631 if modSplit>0:
632 cent = (Decimal('0.01') * (100/factor))
633 ppot += cent
634 modSplit -= cent
635 rake = (totalrake * (ppot/hand.totalpot)).quantize(Decimal("0.01"), rounding=ROUND_DOWN)
636 hand.addCollectPot(player=p,pot=(ppot-rake))
638 def assembleHandsPots(self, hand):
639 # init
640 category = hand.gametype['category']
641 positions = []
642 playersPots = {}
643 potFound = {}
644 positionDict = {}
645 showdown = False
647 #debug
648 #print("start assembleHandsPots", hand.handid)
650 # Init player's pot dict
651 for p in hand.players:
652 playersPots[p[1]] = [0, []]
653 potFound[p[1]] = [0, 0]
654 position = self.handsplayers[p[1]]['position']
656 # check if player has a position
657 if position is None or position == '':
658 #print(f"warning: player {p[1]} has no position")
659 position = 'Unknown' # default
661 positionDict[str(position)] = p[1]
662 positions.append(str(position))
664 if self.handsplayers[p[1]]['sawShowdown']:
665 showdown = True
667 #debug
668 #print("positionDict:", positionDict)
669 #print("positions before sort:", positions)
671 # sort positions
672 positions.sort(reverse=True)
673 #print("positions after sort:", positions)
675 # define factor
676 factor = 100
677 if ((hand.gametype["type"] == "tour" or
678 (hand.gametype["type"] == "ring" and
679 (hand.gametype["currency"] == "play" and
680 (hand.sitename not in ('Winamax', 'PacificPoker'))))) and
681 (not [n for (n, v) in hand.pot.pots if (n % Decimal('1.00')) != 0])):
682 factor = 1
684 # Config game
685 hiLoKey = {'h': ['hi'], 'l': ['low'], 'r': ['low'], 's': ['hi', 'low']}
686 base, evalgame, hilo, streets, last, hrange = Card.games[category]
688 # process pots
689 if ((hand.sitename != 'KingsClub' or hand.adjustCollected) and
690 evalgame and
691 (len(hand.pot.pots) > 1 or (showdown and (hilo == 's' or hand.runItTimes >= 2)))):
693 rakes, totrake, potId = {}, 0, 0
695 for pot, players in hand.pot.pots:
696 if potId == 0:
697 pot += (sum(hand.pot.common.values()) + hand.pot.stp)
698 potId += 1
700 boards, boardId, sumpot = self.getBoardsList(hand), 0, 0
702 for b in boards:
703 boardId += (hand.runItTimes >= 2)
704 potBoard = Decimal(int(pot / len(boards) * factor)) / factor
705 modBoard = pot - potBoard * len(boards)
706 if boardId == 1:
707 potBoard += modBoard
709 holeplayers, holecards = [], []
710 for p in players:
711 hcs = hand.join_holecards(p, asList=True)
712 holes = [str(c) for c in hcs[hrange[-1][0]:hrange[-1][1]] if Card.encodeCardList.get(c)!=None or c=='0x']
713 board = [str(c) for c in b if 'omaha' in evalgame]
714 if 'omaha' not in evalgame:
715 holes = holes + [str(c) for c in b if base=='hold']
716 if '0x' not in holes and '0x' not in board:
717 holecards.append(holes)
718 holeplayers.append(p)
719 if len(holecards)>1:
720 try:
721 win = pokereval.winners(game = evalgame, pockets = holecards, board = board)
722 except RuntimeError:
723 log.error("assembleHandsPots: error evaluating winners for hand %s %s" % (hand.handid, hand.in_path))
724 win = {}
725 win[hiLoKey[hilo][0]] = [0]
726 else:
727 win = {}
728 win[hiLoKey[hilo][0]] = [0]
729 for hl in hiLoKey[hilo]:
730 if hl in win and len(win[hl])>0:
731 potHiLo = old_div(Decimal(int(potBoard/len(win)*factor)),factor)
732 modHiLo = potBoard - potHiLo*len(win)
733 if len(win)==1 or hl=='hi':
734 potHiLo+=modHiLo
735 potSplit = old_div(Decimal(int(potHiLo/len(win[hl])*factor)),factor)
736 modSplit = potHiLo - potSplit*len(win[hl])
737 pnames = players if len(holeplayers)==0 else [holeplayers[w] for w in win[hl]]
738 for n in positions:
739 #print(f"check position position: {n}")
740 if positionDict[n] in pnames:
741 pname = positionDict[n]
742 ppot = potSplit
743 if modSplit>0:
744 cent = (Decimal('0.01') * (old_div(100,factor)))
745 ppot += cent
746 modSplit -= cent
747 playersPots[pname][0] += ppot
748 potFound[pname][0] += ppot
749 data = {'potId': potId, 'boardId': boardId, 'hiLo': hl,'ppot':ppot, 'winners': [m for m in pnames if pname!=n], 'mod': ppot>potSplit}
750 playersPots[pname][1].append(data)
751 self.handsplayers[pname]['rake'] = 0
753 for p, (total, info) in list(playersPots.items()):
754 #log.error((p, (total, info)))
755 if hand.collectees.get(p) and info:
756 potFound[p][1] = hand.collectees.get(p)
757 for item in info:
758 #log.error((str(hand.handid)," winners: ",item['winners']))
759 split = [n for n in item['winners'] if len(playersPots[n][1])==1 and hand.collectees.get(n)!=None]
760 if len(info)==1:
761 ppot = item['ppot']
762 rake = ppot - hand.collectees[p]
763 collected = hand.collectees[p]
764 elif item==info[-1]:
765 ppot, collected = potFound[p]
766 rake = ppot - collected
767 elif len(split)>0 and not item['mod']:
768 ppot = item['ppot']
769 collected = min([hand.collectees[s] for s in split] + [ppot])
770 rake = ppot - collected
771 else:
772 ppot = item['ppot']
773 totalrake = total - hand.collectees[p]
774 rake = (totalrake * (old_div(ppot,total))).quantize(Decimal("0.01"))
775 collected = ppot - rake
776 potFound[p][0] -= ppot
777 potFound[p][1] -= collected
778 insert = [None, item['potId'], item['boardId'], item['hiLo'][0], hand.dbid_pids[p], int(item['ppot']*100), int(collected*100), int(rake*100)]
779 self.handspots.append(insert)
780 self.handsplayers[p]['rake'] += int(rake*100)
782 #debug
783 #print("end assembleHandsPots", hand.handid)
785 def setPositions(self, hand):
786 """Sets the position for each player in HandsPlayers
787 any blinds are negative values, and the last person to act on the
788 first betting round is 0
789 NOTE: HU, both values are negative for non-stud games
790 NOTE2: I've never seen a HU stud match"""
791 actions = hand.actions[hand.holeStreets[0]]
792 # Note: pfbao list may not include big blind if all others folded
793 players = self.pfbao(actions)
795 # set blinds first, then others from pfbao list, avoids problem if bb
796 # is missing from pfbao list or if there is no small blind
797 sb, bb, bi, ub, st = False, False, False, False, False
798 if hand.gametype['base'] == 'stud':
799 # Stud position is determined after cards are dealt
800 # First player to act is always the bring-in position in stud
801 # even if they decided to bet/completed
802 if len(hand.actions[hand.actionStreets[1]])>0:
803 bi = [hand.actions[hand.actionStreets[1]][0][0]]
804 #else:
805 # TODO fix: if ante all and no actions and no bring in
806 # bi = [hand.actions[hand.actionStreets[0]][0][0]]
807 else:
808 ub = [x[0] for x in hand.actions[hand.actionStreets[0]] if x[1] == 'button blind']
809 bb = [x[0] for x in hand.actions[hand.actionStreets[0]] if x[1] == 'big blind']
810 sb = [x[0] for x in hand.actions[hand.actionStreets[0]] if x[1] == 'small blind']
811 st = [x[0] for x in hand.actions[hand.actionStreets[0]] if x[1] == 'straddle']
813 # if there are > 1 sb or bb only the first is used!
814 if ub:
815 self.handsplayers[ub[0]]['street0InPosition'] = True
816 if ub[0] not in players: players.append(ub[0])
817 if bb:
818 self.handsplayers[bb[0]]['position'] = 'B'
819 self.handsplayers[bb[0]]['street0InPosition'] = True
820 if bb[0] in players: players.remove(bb[0])
821 if sb:
822 self.handsplayers[sb[0]]['position'] = 'S'
823 self.handsplayers[sb[0]]['street0FirstToAct'] = True
824 if sb[0] in players: players.remove(sb[0])
825 if bi:
826 self.handsplayers[bi[0]]['position'] = 'S'
827 self.handsplayers[bi[0]]['street0FirstToAct'] = True
828 if bi[0] in players: players.remove(bi[0])
829 if st and st[0] in players:
830 players.insert(0, players.pop())
832 #print "DEBUG: actions: '%s'" % actions
833 #print "DEBUG: ub: '%s' bb: '%s' sb: '%s' bi: '%s' plyrs: '%s'" %(ub, bb, sb, bi, players)
834 for i,player in enumerate(reversed(players)):
835 self.handsplayers[player]['position'] = i
836 self.hands['maxPosition'] = i
837 if i==0 and hand.gametype['base'] == 'stud':
838 self.handsplayers[player]['street0InPosition'] = True
839 elif (i-1)==len(players):
840 self.handsplayers[player]['street0FirstToAct'] = True
843 def assembleHudCache(self, hand):
844 # No real work to be done - HandsPlayers data already contains the correct info
845 pass
847 def vpip(self, hand):
848 vpipers = set()
849 bb = [x[0] for x in hand.actions[hand.actionStreets[0]] if x[1] in ('big blind', 'button blind')]
850 for act in hand.actions[hand.actionStreets[1]]:
851 if act[1] in ('calls','bets', 'raises', 'completes'):
852 vpipers.add(act[0])
854 self.hands['playersVpi'] = len(vpipers)
856 for player in hand.players:
857 pname = player[1]
858 player_stats = self.handsplayers.get(pname)
859 if pname in vpipers:
860 player_stats['street0VPI'] = True
861 elif pname in hand.sitout:
862 player_stats['street0VPIChance'] = False
863 player_stats['street0AggrChance'] = False
865 if len(vpipers)==0 and bb:
866 self.handsplayers[bb[0]]['street0VPIChance'] = False
867 self.handsplayers[bb[0]]['street0AggrChance'] = False
869 def playersAtStreetX(self, hand):
870 """ playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */"""
871 # self.actions[street] is a list of all actions in a tuple, contining the player name first
872 # [ (player, action, ....), (player2, action, ...) ]
873 # The number of unique players in the list per street gives the value for playersAtStreetXXX
875 # FIXME?? - This isn't couting people that are all in - at least showdown needs to reflect this
876 # ... new code below hopefully fixes this
877 # partly fixed, allins are now set as seeing streets because they never do a fold action
879 self.hands['playersAtStreet1'] = 0
880 self.hands['playersAtStreet2'] = 0
881 self.hands['playersAtStreet3'] = 0
882 self.hands['playersAtStreet4'] = 0
883 self.hands['playersAtShowdown'] = 0
885# alliners = set()
886# for (i, street) in enumerate(hand.actionStreets[2:]):
887# actors = set()
888# for action in hand.actions[street]:
889# if len(action) > 2 and action[-1]: # allin
890# alliners.add(action[0])
891# actors.add(action[0])
892# if len(actors)==0 and len(alliners)<2:
893# alliners = set()
894# self.hands['playersAtStreet%d' % (i+1)] = len(set.union(alliners, actors))
895#
896# actions = hand.actions[hand.actionStreets[-1]]
897# print "p_actions:", self.pfba(actions), "p_folds:", self.pfba(actions, l=('folds',)), "alliners:", alliners
898# pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)
900 # hand.players includes people that are sitting out on some sites for cash games
901 # actionStreets[1] is 'DEAL', 'THIRD', 'PREFLOP', so any player dealt cards
902 # must act on this street if dealt cards. Almost certainly broken for the 'all-in blind' case
903 # and right now i don't care - CG
905 p_in = set([x[0] for x in hand.actions[hand.actionStreets[1]]])
906 #Add in players who were allin blind
907 if hand.pot.pots:
908 if len(hand.pot.pots[0][1])>1: p_in = p_in.union(hand.pot.pots[0][1])
910 #
911 # discover who folded on each street and remove them from p_in
912 #
913 # i values as follows 0=BLINDSANTES 1=PREFLOP 2=FLOP 3=TURN 4=RIVER
914 # (for flop games)
915 #
916 # At the beginning of the loop p_in contains the players with cards
917 # at the start of that street.
918 # p_in is reduced each street to become a list of players still-in
919 # e.g. when i=1 (preflop) all players who folded during preflop
920 # are found by pfba() and eliminated from p_in.
921 # Therefore at the end of the loop, p_in contains players remaining
922 # at the end of the action on that street, and can therefore be set
923 # as the value for the number of players who saw the next street
924 #
925 # note that i is 1 in advance of the actual street numbers in the db
926 #
927 # if p_in reduces to 1 player, we must bomb-out immediately
928 # because the hand is over, this will ensure playersAtStreetx
929 # is accurate.
930 #
932 for (i, street) in enumerate(hand.actionStreets):
934 if (i-1) in (1,2,3,4):
935 # p_in stores players with cards at start of this street,
936 # so can set streetxSeen & playersAtStreetx with this information
937 # This hard-coded for i-1 =1,2,3,4 because those are the only columns
938 # in the db! this code section also replaces seen() - more info log 66
939 # nb i=2=flop=street1Seen, hence i-1 term needed
940 self.hands['playersAtStreet%d' % (i-1)] = len(p_in)
941 for player_with_cards in p_in:
942 self.handsplayers[player_with_cards]['street%sSeen' % (i-1)] = True
944 players = self.pfbao(hand.actions[street], f=('discards','stands pat'))
945 if len(players)>0:
946 self.handsplayers[players[0]]['street%dFirstToAct' % (i-1)] = True
947 self.handsplayers[players[-1]]['street%dInPosition' % (i-1)] = True
948 #
949 # find out who folded, and eliminate them from p_in
950 #
951 actions = hand.actions[street]
952 p_in = p_in - self.pfba(actions, l=('folds',))
953 #
954 # if everyone folded, we are done, so exit this method
955 #
956 if len(p_in) == 1:
957 if (i-1) in (1,2,3,4) and len(players)>0 and list(p_in)[0] not in players:
958 # corrects which player is "in position"
959 # if everyone folds before the last player could act
960 self.handsplayers[players[-1]]['street%dInPosition' % (i-1)] = False
961 self.handsplayers[list(p_in)[0]]['street%dInPosition' % (i-1)] = True
962 return None
964 #
965 # The remaining players in p_in reached showdown (including all-ins
966 # because they never did a "fold" action in pfba() above)
967 #
968 self.hands['playersAtShowdown'] = len(p_in)
969 for showdown_player in p_in:
970 self.handsplayers[showdown_player]['sawShowdown'] = True
972 def streetXRaises(self, hand):
973 # self.actions[street] is a list of all actions in a tuple, contining the action as the second element
974 # [ (player, action, ....), (player2, action, ...) ]
975 # No idea what this value is actually supposed to be
976 # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl
977 # Leaving empty for the moment,
979 for i in range(5): self.hands['street%dRaises' % i] = 0
981 for (i, street) in enumerate(hand.actionStreets[1:]):
982 self.hands['street%dRaises' % i] = len([action for action in hand.actions[street] if action[1] in ('raises','bets','completes')])
984 def calcSteals(self, hand):
985 """Fills raiseFirstInChance|raisedFirstIn, fold(Bb|Sb)ToSteal(Chance|)
987 Steal attempt - open raise on positions 1 0 S - i.e. CO, BU, SB
988 (note: I don't think PT2 counts SB steals in HU hands, maybe we shouldn't?)
989 Fold to steal - folding blind after steal attemp wo any other callers or raisers
990 """
991 steal_attempt = False
992 raised = False
993 if hand.gametype['base'] == 'stud':
994 steal_positions = (2, 1, 0)
995 elif len([x for x in hand.actions[hand.actionStreets[0]] if x[1] == 'button blind']) > 0:
996 steal_positions = (3, 2, 1)
997 else:
998 steal_positions = (1, 0, 'S')
999 for action in hand.actions[hand.actionStreets[1]]:
1000 pname, act = action[0], action[1]
1001 player_stats = self.handsplayers.get(pname)
1002 if player_stats['sitout']: continue
1003 posn = player_stats['position']
1004 #print "\naction:", action[0], posn, type(posn), steal_attempt, act
1005 if posn == 'B':
1006 #NOTE: Stud games will never hit this section
1007 if steal_attempt:
1008 player_stats['foldBbToStealChance'] = True
1009 player_stats['raiseToStealChance'] = True
1010 player_stats['foldedBbToSteal'] = act == 'folds'
1011 player_stats['raiseToStealDone'] = act == 'raises'
1012 self.handsplayers[stealer]['success_Steal'] = act == 'folds'
1013 break
1014 elif posn == 'S':
1015 player_stats['raiseToStealChance'] = steal_attempt
1016 player_stats['foldSbToStealChance'] = steal_attempt
1017 player_stats['foldedSbToSteal'] = steal_attempt and act == 'folds'
1018 player_stats['raiseToStealDone'] = steal_attempt and act == 'raises'
1019 if steal_attempt:
1020 self.handsplayers[stealer]['success_Steal'] = act == 'folds' and hand.gametype['base'] == 'stud'
1022 if steal_attempt and act != 'folds':
1023 break
1025 if not steal_attempt and not raised and not act in ('bringin'):
1026 player_stats['raiseFirstInChance'] = True
1027 if posn in steal_positions:
1028 player_stats['stealChance'] = True
1029 if act in ('bets', 'raises', 'completes'):
1030 player_stats['raisedFirstIn'] = True
1031 raised = True
1032 if posn in steal_positions:
1033 player_stats['stealDone'] = True
1034 steal_attempt = True
1035 stealer = pname
1036 if act == 'calls':
1037 break
1039 if posn not in steal_positions and act not in ('folds', 'bringin'):
1040 break
1042 def calc34BetStreet0(self, hand):
1043 """Fills street0_(3|4)B(Chance|Done), other(3|4)BStreet0"""
1044 if hand.gametype['base'] == 'stud':
1045 bet_level = 0 # bet_level after 3-bet is equal to 3
1046 else:
1047 bet_level = 1 # bet_level after 3-bet is equal to 3
1048 squeeze_chance, raise_chance, action_cnt, first_agressor = False, True, {}, None
1049 p0_in = set([x[0] for x in hand.actions[hand.actionStreets[0]] if not x[-1]])
1050 p1_in = set([x[0] for x in hand.actions[hand.actionStreets[1]]])
1051 p_in = p1_in.union(p0_in)
1052 for p in p_in: action_cnt[p] = 0
1053 for action in hand.actions[hand.actionStreets[1]]:
1054 pname, act, aggr, allin = action[0], action[1], action[1] in ('raises', 'bets', 'completes'), False
1055 player_stats = self.handsplayers.get(pname)
1056 action_cnt[pname] += 1
1057 if len(action) > 3 and act != 'discards':
1058 allin = action[-1]
1059 if len(p_in)==1 and action_cnt[pname]==1:
1060 raise_chance = False
1061 player_stats['street0AggrChance'] = raise_chance
1062 if act == 'folds' or allin or player_stats['sitout']:
1063 p_in.discard(pname)
1064 if player_stats['sitout']: continue
1065 if bet_level == 0:
1066 if aggr:
1067 if first_agressor == None:
1068 first_agressor = pname
1069 bet_level += 1
1070 continue
1071 elif bet_level == 1:
1072 player_stats['street0_2BChance'] = raise_chance
1073 if aggr:
1074 if first_agressor == None:
1075 first_agressor = pname
1076 player_stats['street0_2BDone'] = True
1077 bet_level += 1
1078 continue
1079 elif bet_level == 2:
1080 player_stats['street0_3BChance'] = raise_chance
1081 player_stats['street0_SqueezeChance'] = squeeze_chance
1082 if pname == first_agressor:
1083 player_stats['street0_FoldTo2BChance'] = True
1084 if act == 'folds':
1085 player_stats['street0_FoldTo2BDone'] = True
1086 if not squeeze_chance and act == 'calls':
1087 squeeze_chance = True
1088 continue
1089 if aggr:
1090 player_stats['street0_3BDone'] = True
1091 player_stats['street0_SqueezeDone'] = squeeze_chance
1092 second_agressor = pname
1093 bet_level += 1
1094 continue
1095 elif bet_level == 3:
1096 if pname == first_agressor:
1097 player_stats['street0_4BChance'] = raise_chance
1098 player_stats['street0_FoldTo3BChance'] = True
1099 if aggr:
1100 player_stats['street0_4BDone'] = raise_chance
1101 bet_level += 1
1102 elif act == 'folds':
1103 player_stats['street0_FoldTo3BDone'] = True
1104 break
1105 else:
1106 player_stats['street0_C4BChance'] = raise_chance
1107 if aggr:
1108 player_stats['street0_C4BDone'] = raise_chance
1109 bet_level += 1
1110 continue
1111 elif bet_level == 4:
1112 if pname != first_agressor:
1113 player_stats['street0_FoldTo4BChance'] = True
1114 if act == 'folds':
1115 player_stats['street0_FoldTo4BDone'] = True
1117 def calcCBets(self, hand):
1118 """Fill streetXCBChance, streetXCBDone, foldToStreetXCBDone, foldToStreetXCBChance
1120 Continuation Bet chance, action:
1121 Had the last bet (initiative) on previous street, got called, close street action
1122 Then no bets before the player with initiatives first action on current street
1123 ie. if player on street-1 had initiative and no donkbets occurred
1124 """
1125 # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
1126 # came there
1127 #for i, street in enumerate(hand.actionStreets[2:], start=1):
1128 for i, street in enumerate(hand.actionStreets[2:]):
1129 name = self.lastBetOrRaiser(hand.actions, hand.actionStreets[i+1]) # previous street
1130 if name:
1131 chance = self.noBetsBefore(hand.actions, hand.actionStreets[i+2], name) # this street
1132 if chance == True:
1133 player_stats = self.handsplayers.get(name)
1134 player_stats['street%dCBChance' % (i+1)] = True
1135 player_stats['street%dCBDone' % (i+1)] = self.betStreet(hand.actions, hand.actionStreets[i+2], name)
1136 if player_stats['street%dCBDone' % (i+1)]:
1137 for pname, folds in list(self.foldTofirstsBetOrRaiser(hand.actions, street, name).items()):
1138 #print "DEBUG:", hand.handid, pname.encode('utf8'), street, folds, '--', name, 'lastbet on ', hand.actionStreets[i+1]
1139 self.handsplayers[pname]['foldToStreet%sCBChance' % (i+1)] = True
1140 self.handsplayers[pname]['foldToStreet%sCBDone' % (i+1)] = folds
1142 def calcCalledRaiseStreet0(self, hand):
1143 """
1144 Fill street0CalledRaiseChance, street0CalledRaiseDone
1145 For flop games, go through the preflop actions:
1146 skip through first raise
1147 For each subsequent action:
1148 if the next action is fold :
1149 player chance + 1
1150 if the next action is raise :
1151 player chance + 1
1152 if the next non-fold action is call :
1153 player chance + 1
1154 player done + 1
1155 skip through list to the next raise action
1156 """
1158 fast_forward = True
1159 for tupleread in hand.actions[hand.actionStreets[1]]:
1160 action = tupleread[1]
1161 if fast_forward:
1162 if action in ('raises', 'completes'):
1163 fast_forward = False # raisefound, end fast-forward
1164 else:
1165 player = tupleread[0]
1166 player_stats = self.handsplayers.get(player)
1167 player_stats['street0CalledRaiseChance'] += 1
1168 if action == 'calls':
1169 player_stats['street0CalledRaiseDone'] += 1
1170 fast_forward = True
1172 def calcCheckCallRaise(self, hand):
1173 """Fill streetXCheckCallRaiseChance, streetXCheckCallRaiseDone
1175 streetXCheckCallRaiseChance = got raise/bet after check
1176 streetXCheckCallRaiseDone = checked. got raise/bet. didn't fold
1178 CG: CheckCall would be a much better name for this.
1179 """
1180 # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
1181 #for i, street in enumerate(hand.actionStreets[2:], start=1):
1182 for i, street in enumerate(hand.actionStreets[2:]):
1183 actions = hand.actions[street]
1184 checkers = set()
1185 acted = set()
1186 initial_raiser = None
1187 for action in actions:
1188 pname, act = action[0], action[1]
1189 if act in ('bets', 'raises') and initial_raiser is None:
1190 initial_raiser = pname
1191 elif act == 'checks' and initial_raiser is None:
1192 checkers.add(pname)
1193 elif initial_raiser is not None and pname in checkers and pname not in acted:
1194 player_stats = self.handsplayers.get(pname)
1195 player_stats['street%dCheckCallRaiseChance' % (i+1)] = True
1196 player_stats['street%dCheckCallDone' % (i+1)] = act=='calls'
1197 player_stats['street%dCheckRaiseDone' % (i+1)] = act=='raises'
1198 acted.add(pname)
1200 def aggr(self, hand, i):
1201 aggrers = set()
1202 others = set()
1203 # Growl - actionStreets contains 'BLINDSANTES', which isn't actually an action street
1205 firstAggrMade=False
1206 for act in hand.actions[hand.actionStreets[i+1]]:
1207 if firstAggrMade:
1208 others.add(act[0])
1209 if act[1] in ('completes', 'bets', 'raises'):
1210 aggrers.add(act[0])
1211 firstAggrMade=True
1213 for player in hand.players:
1214 if player[1] in aggrers:
1215 self.handsplayers[player[1]]['street%sAggr' % i] = True
1217 if len(aggrers)>0 and i>0:
1218 for playername in others:
1219 self.handsplayers[playername]['otherRaisedStreet%s' % i] = True
1220 #print "otherRaised detected on handid "+str(hand.handid)+" for "+playername+" on street "+str(i)
1222 if i > 0 and len(aggrers) > 0:
1223 for playername in others:
1224 self.handsplayers[playername]['otherRaisedStreet%s' % i] = True
1225 #print "DEBUG: otherRaised detected on handid %s for %s on actionStreet[%s]: %s"
1226 # %(hand.handid, playername, hand.actionStreets[i+1], i)
1228 def calls(self, hand, i):
1229 callers = []
1230 for act in hand.actions[hand.actionStreets[i+1]]:
1231 if act[1] in ('calls'):
1232 player_stats = self.handsplayers.get(act[0])
1233 player_stats['street%sCalls' % i] = 1 + player_stats['street%sCalls' % i]
1235 def bets(self, hand, i):
1236 for act in hand.actions[hand.actionStreets[i+1]]:
1237 if act[1] in ('bets'):
1238 player_stats = self.handsplayers.get(act[0])
1239 player_stats['street%sBets' % i] = 1 + player_stats['street%sBets' % i]
1241 def raises(self, hand, i):
1242 for act in hand.actions[hand.actionStreets[i+1]]:
1243 if act[1] in ('completes', 'raises'):
1244 player_stats = self.handsplayers.get(act[0])
1245 player_stats['street%sRaises' % i] = 1 + player_stats['street%sRaises' % i]
1247 def folds(self, hand, i):
1248 for act in hand.actions[hand.actionStreets[i+1]]:
1249 if act[1] in ('folds'):
1250 player_stats = self.handsplayers.get(act[0])
1251 if player_stats['otherRaisedStreet%s' % i] == True:
1252 player_stats['foldToOtherRaisedStreet%s' % i] = True
1253 #print "DEBUG: fold detected on handid %s for %s on actionStreet[%s]: %s"
1254 # %(hand.handid, act[0],hand.actionStreets[i+1], i)
1256 def countPlayers(self, hand):
1257 pass
1259 def pfba(self, actions, f=None, l=None):
1260 """Helper method. Returns set of PlayersFilteredByActions
1262 f - forbidden actions
1263 l - limited to actions
1264 """
1265 players = set()
1266 for action in actions:
1267 if l is not None and action[1] not in l: continue
1268 if f is not None and action[1] in f: continue
1269 players.add(action[0])
1270 return players
1272 def pfbao(self, actions, f=None, l=None, unique=True):
1273 """Helper method. Returns set of PlayersFilteredByActionsOrdered
1275 f - forbidden actions
1276 l - limited to actions
1277 """
1278 # Note, this is an adaptation of function 5 from:
1279 # http://www.peterbe.com/plog/uniqifiers-benchmark
1280 seen = {}
1281 players = []
1282 for action in actions:
1283 if l is not None and action[1] not in l: continue
1284 if f is not None and action[1] in f: continue
1285 if action[0] in seen and unique: continue
1286 seen[action[0]] = 1
1287 players.append(action[0])
1288 return players
1290 def calcEffectiveStack(self,hand):
1291 """Calculates the effective stack for each player on street 1
1292 """
1293 seen = {}
1294 pstacks = {}
1295 actions = hand.actions[hand.holeStreets[0]]
1296 for p in hand.players:
1297 if p[1] not in hand.sitout:
1298 pstacks[p[1]] = int(100 * Decimal(p[2]))
1299 for action in actions:
1300 if action[0] in seen: continue
1301 if action[0] not in pstacks: continue
1302 seen[action[0]] = 1
1303 oppstacks = [v for (k,v) in list(pstacks.items()) if k != action[0]]
1304 if oppstacks:
1305 if pstacks[action[0]] > max(oppstacks):
1306 self.handsplayers[action[0]]['effStack'] = max(oppstacks)
1307 else:
1308 self.handsplayers[action[0]]['effStack'] = pstacks[action[0]]
1309 if action[1] == 'folds':
1310 pstacks[action[0]] = 0
1312 def firstsBetOrRaiser(self, actions):
1313 """Returns player name that placed the first bet or raise.
1315 None if there were no bets or raises on that street
1316 """
1317 for act in actions:
1318 if act[1] in ('bets', 'raises', 'completes'):
1319 return act[0]
1320 return None
1322 def foldTofirstsBetOrRaiser(self, actions, street, aggressor):
1323 """Returns player name that placed the first bet or raise.
1325 None if there were no bets or raises on that street
1326 """
1327 i, players = 0, {}
1328 for act in actions[street]:
1329 if i>1: break
1330 if act[0] != aggressor:
1331 if act[1] == 'folds':
1332 players[act[0]] = True
1333 else:
1334 players[act[0]] = False
1335 if act[1] == 'raises' or act[1] == 'completes':
1336 break
1337 elif act[1] not in ('discards', 'stands pat'):
1338 i += 1
1339 return players
1341 def lastBetOrRaiser(self, actions, street):
1342 """Returns player name that placed the last bet or raise for that street.
1343 None if there were no bets or raises on that street"""
1344 lastbet = None
1345 for act in actions[street]:
1346 if act[1] in ('bets', 'raises', 'completes'):
1347 lastbet = act[0]
1348 return lastbet
1351 def noBetsBefore(self, actions, street, player):
1352 """Returns true if there were no bets before the specified players turn, false otherwise"""
1353 noBetsBefore = False
1354 for act in actions[street]:
1355 #Must test for player first in case UTG
1356 if act[0] == player:
1357 noBetsBefore = True
1358 break
1359 if act[1] in ('bets', 'raises', 'completes'):
1360 break
1361 return noBetsBefore
1364 def betStreet(self, actions, street, player):
1365 """Returns true if player bet/raised the street as their first action"""
1366 betOrRaise = False
1367 for act in actions[street]:
1368 if act[0] == player and act[1] not in ('discards', 'stands pat'):
1369 if act[1] in ('bets', 'raises', 'completes'):
1370 betOrRaise = True
1371 else:
1372 # player found but did not bet or raise as their first action
1373 pass
1374 break
1375 #else:
1376 # haven't found player's first action yet
1377 return betOrRaise