2008-12-12 15:29:45 +01:00
#!/usr/bin/python
#Copyright 2008 Carl Gherardi
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in
#agpl-3.0.txt in the docs folder of the package.
2009-07-13 06:37:51 +02:00
# TODO: get writehand() encoding correct
2008-12-12 15:29:45 +01:00
import re
import sys
import traceback
2009-03-04 17:46:01 +01:00
import logging
2008-12-12 15:29:45 +01:00
import os
import os . path
from decimal import Decimal
import operator
2009-06-07 22:57:13 +02:00
import time , datetime
2008-12-16 05:29:11 +01:00
from copy import deepcopy
2009-02-27 19:42:53 +01:00
from Exceptions import *
2009-07-04 00:59:50 +02:00
import pprint
2009-03-14 12:40:27 +01:00
import DerivedStats
2009-06-07 22:57:13 +02:00
import Card
2009-03-14 12:40:27 +01:00
2009-07-15 17:50:27 +02:00
class Hand ( object ) :
2009-07-13 22:22:23 +02:00
###############################################################3
# Class Variables
2008-12-17 01:30:31 +01:00
UPS = { ' a ' : ' A ' , ' t ' : ' T ' , ' j ' : ' J ' , ' q ' : ' Q ' , ' k ' : ' K ' , ' S ' : ' s ' , ' C ' : ' c ' , ' H ' : ' h ' , ' D ' : ' d ' }
2009-03-13 18:51:10 +01:00
LCS = { ' H ' : ' h ' , ' D ' : ' d ' , ' C ' : ' c ' , ' S ' : ' s ' }
2009-07-16 07:54:41 +02:00
SYMBOL = { ' USD ' : ' $ ' , ' EUR ' : u ' $ ' , ' T$ ' : ' ' , ' play ' : ' ' }
2009-07-13 22:22:23 +02:00
MS = { ' horse ' : ' HORSE ' , ' 8game ' : ' 8-Game ' , ' hose ' : ' HOSE ' }
2009-03-14 12:40:27 +01:00
def __init__ ( self , sitename , gametype , handText , builtFrom = " HHC " ) :
2008-12-12 15:29:45 +01:00
self . sitename = sitename
2009-03-14 12:40:27 +01:00
self . stats = DerivedStats . DerivedStats ( self )
2008-12-12 15:29:45 +01:00
self . gametype = gametype
2009-06-06 13:26:33 +02:00
self . starttime = 0
2009-03-04 16:10:08 +01:00
self . handText = handText
2008-12-12 15:29:45 +01:00
self . handid = 0
2009-06-19 08:21:35 +02:00
self . tablename = " "
self . hero = " "
2008-12-12 15:29:45 +01:00
self . maxseats = 10
self . counted_seats = 0
self . buttonpos = 0
2009-07-11 19:44:32 +02:00
self . tourNo = None
self . buyin = None
self . level = None
2009-07-13 22:22:23 +02:00
self . mixed = None
2008-12-12 15:29:45 +01:00
self . seating = [ ]
self . players = [ ]
self . posted = [ ]
# Collections indexed by street names
2009-03-02 00:22:47 +01:00
self . bets = { }
self . lastBet = { }
self . streets = { }
self . actions = { } # [['mct','bets','$10'],['mika','folds'],['carlg','raises','$20']]
2009-03-03 19:45:02 +01:00
self . board = { } # dict from street names to community cards
2009-06-19 08:21:35 +02:00
self . holecards = { }
2009-07-11 19:44:32 +02:00
self . discards = { }
2009-06-19 08:21:35 +02:00
for street in self . allStreets :
2009-03-02 00:22:47 +01:00
self . streets [ street ] = " " # portions of the handText, filled by markStreets()
2009-07-11 19:44:32 +02:00
self . actions [ street ] = [ ]
for street in self . actionStreets :
2009-03-02 00:22:47 +01:00
self . bets [ street ] = { }
self . lastBet [ street ] = 0
2009-03-03 19:45:02 +01:00
self . board [ street ] = [ ]
2009-07-11 19:44:32 +02:00
for street in self . holeStreets :
2009-06-19 08:21:35 +02:00
self . holecards [ street ] = { } # dict from player names to holecards
2009-07-11 19:44:32 +02:00
self . discards [ street ] = { } # dict from player names to dicts by street ... of tuples ... of discarded holecards
2008-12-12 15:29:45 +01:00
# Collections indexed by player names
2008-12-16 05:29:11 +01:00
self . stacks = { }
2009-03-07 16:43:33 +01:00
self . collected = [ ] #list of ?
2009-03-02 00:22:47 +01:00
self . collectees = { } # dict from player names to amounts collected (?)
2008-12-12 15:29:45 +01:00
# Sets of players
self . folded = set ( )
2009-06-19 08:21:35 +02:00
self . dealt = set ( ) # 'dealt to' line to be printed
self . shown = set ( ) # cards were shown
2009-07-04 00:59:50 +02:00
self . mucked = set ( ) # cards were mucked at showdown
2008-12-12 15:29:45 +01:00
2009-03-02 22:48:30 +01:00
# Things to do with money
self . pot = Pot ( )
2008-12-12 15:29:45 +01:00
self . totalpot = None
2008-12-14 20:25:04 +01:00
self . totalcollected = None
2008-12-12 15:29:45 +01:00
self . rake = None
2009-07-16 18:13:24 +02:00
# currency symbol for this hand
self . sym = self . SYMBOL [ self . gametype [ ' currency ' ] ] # save typing! delete this attr when done
self . pot . setSym ( self . sym )
2008-12-12 15:29:45 +01:00
2009-06-12 18:29:17 +02:00
def __str__ ( self ) :
2009-07-04 00:59:50 +02:00
vars = ( ( " BB " , self . bb ) ,
( " SB " , self . sb ) ,
( " BUTTONPOS " , self . buttonpos ) ,
( " HAND NO. " , self . handid ) ,
( " SITE " , self . sitename ) ,
( " TABLE NAME " , self . tablename ) ,
( " HERO " , self . hero ) ,
( " MAXSEATS " , self . maxseats ) ,
2009-07-11 19:44:32 +02:00
( " TOURNAMENT NO " , self . tourNo ) ,
( " BUYIN " , self . buyin ) ,
( " LEVEL " , self . level ) ,
2009-07-13 22:22:23 +02:00
( " MIXED " , self . mixed ) ,
2009-07-04 00:59:50 +02:00
( " LASTBET " , self . lastBet ) ,
( " ACTION STREETS " , self . actionStreets ) ,
( " STREETS " , self . streets ) ,
( " ALL STREETS " , self . allStreets ) ,
( " COMMUNITY STREETS " , self . communityStreets ) ,
( " HOLE STREETS " , self . holeStreets ) ,
( " COUNTED SEATS " , self . counted_seats ) ,
( " DEALT " , self . dealt ) ,
( " SHOWN " , self . shown ) ,
( " MUCKED " , self . mucked ) ,
( " TOTAL POT " , self . totalpot ) ,
( " TOTAL COLLECTED " , self . totalcollected ) ,
( " RAKE " , self . rake ) ,
( " START TIME " , self . starttime ) ,
)
structs = ( ( " PLAYERS " , self . players ) ,
( " STACKS " , self . stacks ) ,
( " POSTED " , self . posted ) ,
( " POT " , self . pot ) ,
( " SEATING " , self . seating ) ,
( " GAMETYPE " , self . gametype ) ,
( " ACTION " , self . actions ) ,
( " COLLECTEES " , self . collectees ) ,
( " BETS " , self . bets ) ,
( " BOARD " , self . board ) ,
( " DISCARDS " , self . discards ) ,
( " HOLECARDS " , self . holecards ) ,
)
2009-06-12 18:29:17 +02:00
str = ' '
2009-07-04 00:59:50 +02:00
for ( name , var ) in vars :
str = str + " \n %s = " % name + pprint . pformat ( var )
for ( name , struct ) in structs :
str = str + " \n %s = \n " % name + pprint . pformat ( struct , 4 )
2009-06-12 18:29:17 +02:00
return str
2008-12-12 15:29:45 +01:00
2009-07-12 22:01:02 +02:00
def addHoleCards ( self , street , player , open = [ ] , closed = [ ] , shown = False , mucked = False , dealt = False ) :
""" \
Assigns observed holecards to a player .
cards list of card bigrams e . g . [ ' 2h ' , ' Jc ' ]
player ( string ) name of player
shown whether they were revealed at showdown
mucked whether they were mucked at showdown
dealt whether they were seen in a ' dealt to ' line
"""
2009-07-13 06:37:51 +02:00
# logging.debug("addHoleCards %s %s" % (open + closed, player))
2009-07-12 22:01:02 +02:00
try :
self . checkPlayerExists ( player )
except FpdbParseError , e :
print " [ERROR] Tried to add holecards for unknown player: %s " % ( player , )
return
if dealt : self . dealt . add ( player )
if shown : self . shown . add ( player )
if mucked : self . mucked . add ( player )
self . holecards [ street ] [ player ] = [ open , closed ]
2009-07-18 13:02:55 +02:00
def prepInsert ( self , db ) :
pass
2009-03-14 13:19:20 +01:00
def insert ( self , db ) :
""" Function to insert Hand into database
Should not commit , and do minimal selects . Callers may want to cache commits
db : a connected fpdb_db object """
# TODO:
# Players - base playerid and siteid tuple
2009-06-01 14:53:42 +02:00
sqlids = db . getSqlPlayerIDs ( [ p [ 1 ] for p in self . players ] , self . siteId )
2009-03-14 13:19:20 +01:00
# HudCache data to come from DerivedStats class
# HandsActions - all actions for all players for all streets - self.actions
2009-06-19 08:21:35 +02:00
# BoardCards - Skip - no longer necessary
2009-03-14 13:19:20 +01:00
# Hands - Summary information of hand indexed by handId - gameinfo
2009-06-08 16:13:42 +02:00
#hh['siteHandNo'] = self.handid
2009-06-06 13:26:33 +02:00
# gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
#
2009-06-08 16:13:42 +02:00
#hh['handStart'] = self.starttime
2009-06-06 13:26:33 +02:00
# seats TINYINT NOT NULL,
#
2009-06-08 16:13:42 +02:00
#hh['tableName'] = self.tablenam
#hh['maxSeats'] = self.maxseats
2009-06-06 13:26:33 +02:00
# boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
# boardcard2 smallint,
# boardcard3 smallint,
# boardcard4 smallint,
# boardcard5 smallint,
2009-06-20 01:58:53 +02:00
# Flop turn and river may all be empty - add (likely) too many elements and trim with range
# boardcards = board['FLOP'] + board['TURN'] + board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x']
# cards = [Card.cardFromValueSuit(v,s) for v,s in boardcards[0:4]]
# hh['boardcard1'] = cards[0]
# hh['boardcard2'] = cards[1]
# hh['boardcard3'] = cards[2]
# hh['boardcard4'] = cards[3]
# hh['boardcard5'] = cards[4]
2009-06-06 13:26:33 +02:00
# texture smallint,
# playersVpi SMALLINT NOT NULL, /* num of players vpi */
# Needs to be recorded
# playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */
# Needs to be recorded
# playersAtStreet2 SMALLINT NOT NULL,
# Needs to be recorded
# playersAtStreet3 SMALLINT NOT NULL,
# Needs to be recorded
# playersAtStreet4 SMALLINT NOT NULL,
# Needs to be recorded
# playersAtShowdown SMALLINT NOT NULL,
# Needs to be recorded
# street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */
# Needs to be recorded
# street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */
# Needs to be recorded
# street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */
# Needs to be recorded
# street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */
# Needs to be recorded
# street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */
# Needs to be recorded
# street1Pot INT, /* pot size at flop/street4 */
# Needs to be recorded
# street2Pot INT, /* pot size at turn/street5 */
# Needs to be recorded
# street3Pot INT, /* pot size at river/street6 */
# Needs to be recorded
# street4Pot INT, /* pot size at sd/street7 */
# Needs to be recorded
# showdownPot INT, /* pot size at sd/street7 */
# comment TEXT,
# commentTs DATETIME
2009-06-08 16:13:42 +02:00
# handid = db.storeHand(hh)
2009-03-14 13:19:20 +01:00
# HandsPlayers - ? ... Do we fix winnings?
# Tourneys ?
# TourneysPlayers
pass
def select ( self , handId ) :
""" Function to create Hand object from database """
2009-06-07 22:57:13 +02:00
2009-03-14 13:19:20 +01:00
2008-12-12 15:29:45 +01:00
def addPlayer ( self , seat , name , chips ) :
""" \
Adds a player to the hand , and initialises data structures indexed by player .
seat ( int ) indicating the seat
name ( string ) player name
chips ( string ) the chips the player has at the start of the hand ( can be None )
If a player has None chips he won ' t be added. " " "
2009-03-06 02:24:38 +01:00
logging . debug ( " addPlayer: %s %s ( %s ) " % ( seat , name , chips ) )
2008-12-12 15:29:45 +01:00
if chips is not None :
2009-07-19 03:31:39 +02:00
chips = re . sub ( u ' , ' , u ' ' , chips ) #some sites have commas
2008-12-12 15:29:45 +01:00
self . players . append ( [ seat , name , chips ] )
2008-12-16 05:29:11 +01:00
self . stacks [ name ] = Decimal ( chips )
2008-12-20 17:48:25 +01:00
self . pot . addPlayer ( name )
2009-07-11 19:44:32 +02:00
for street in self . actionStreets :
2008-12-12 15:29:45 +01:00
self . bets [ street ] [ name ] = [ ]
2009-06-19 08:21:35 +02:00
#self.holecards[name] = {} # dict from street names.
2009-07-11 19:44:32 +02:00
#self.discards[name] = {} # dict from street names.
2008-12-12 15:29:45 +01:00
2008-12-14 23:05:51 +01:00
def addStreets ( self , match ) :
# go through m and initialise actions to empty list for each street.
2009-03-04 17:46:01 +01:00
if match :
2009-03-02 00:22:47 +01:00
self . streets . update ( match . groupdict ( ) )
2009-03-03 19:45:02 +01:00
logging . debug ( " markStreets: \n " + str ( self . streets ) )
2008-12-14 23:05:51 +01:00
else :
2009-03-04 17:46:01 +01:00
logging . error ( " markstreets didn ' t match " )
2008-12-14 23:05:51 +01:00
2008-12-12 15:29:45 +01:00
def checkPlayerExists ( self , player ) :
if player not in [ p [ 1 ] for p in self . players ] :
2009-02-20 08:44:06 +01:00
print " checkPlayerExists " , player , " fail "
2008-12-12 15:29:45 +01:00
raise FpdbParseError
2009-03-06 02:24:38 +01:00
2008-12-12 15:29:45 +01:00
def setCommunityCards ( self , street , cards ) :
2009-03-04 17:46:01 +01:00
logging . debug ( " setCommunityCards %s %s " % ( street , cards ) )
2008-12-12 15:29:45 +01:00
self . board [ street ] = [ self . card ( c ) for c in cards ]
2009-07-16 03:22:07 +02:00
# print "DEBUG: self.board: %s" % self.board
2008-12-12 15:29:45 +01:00
def card ( self , c ) :
""" upper case the ranks but not suits, ' atjqk ' => ' ATJQK ' """
for k , v in self . UPS . items ( ) :
c = c . replace ( k , v )
return c
2009-02-25 16:45:46 +01:00
def addAnte ( self , player , ante ) :
2009-03-11 19:40:17 +01:00
logging . debug ( " %s %s antes %s " % ( ' ANTES ' , player , ante ) )
2009-02-25 16:45:46 +01:00
if player is not None :
2009-07-19 03:31:39 +02:00
ante = re . sub ( u ' , ' , u ' ' , ante ) #some sites have commas
2009-02-25 16:45:46 +01:00
self . bets [ ' ANTES ' ] [ player ] . append ( Decimal ( ante ) )
self . stacks [ player ] - = Decimal ( ante )
act = ( player , ' posts ' , " ante " , ante , self . stacks [ player ] == 0 )
self . actions [ ' ANTES ' ] . append ( act )
2009-03-11 17:51:58 +01:00
#~ self.lastBet['ANTES'] = Decimal(ante)
2009-02-25 16:45:46 +01:00
self . pot . addMoney ( player , Decimal ( ante ) )
2008-12-14 23:05:51 +01:00
def addBlind ( self , player , blindtype , amount ) :
2008-12-12 15:29:45 +01:00
# if player is None, it's a missing small blind.
2008-12-20 17:48:25 +01:00
# The situation we need to cover are:
# Player in small blind posts
# - this is a bet of 1 sb, as yet uncalled.
# Player in the big blind posts
2009-03-02 00:22:47 +01:00
# - this is a call of 1 sb and a raise to 1 bb
2009-03-14 11:48:34 +01:00
#
2009-03-04 17:46:01 +01:00
logging . debug ( " addBlind: %s posts %s , %s " % ( player , blindtype , amount ) )
2008-12-12 15:29:45 +01:00
if player is not None :
2009-07-19 03:31:39 +02:00
amount = re . sub ( u ' , ' , u ' ' , amount ) #some sites have commas
2008-12-12 15:29:45 +01:00
self . bets [ ' PREFLOP ' ] [ player ] . append ( Decimal ( amount ) )
2008-12-16 05:29:11 +01:00
self . stacks [ player ] - = Decimal ( amount )
2008-12-16 22:08:10 +01:00
#print "DEBUG %s posts, stack %s" % (player, self.stacks[player])
2008-12-20 17:48:25 +01:00
act = ( player , ' posts ' , blindtype , amount , self . stacks [ player ] == 0 )
2009-03-02 00:22:47 +01:00
self . actions [ ' BLINDSANTES ' ] . append ( act )
2008-12-20 17:48:25 +01:00
self . pot . addMoney ( player , Decimal ( amount ) )
2008-12-14 23:05:51 +01:00
if blindtype == ' big blind ' :
2009-03-14 11:48:34 +01:00
self . lastBet [ ' PREFLOP ' ] = Decimal ( amount )
2009-02-21 15:26:37 +01:00
elif blindtype == ' both ' :
2008-12-14 23:05:51 +01:00
# extra small blind is 'dead'
self . lastBet [ ' PREFLOP ' ] = Decimal ( self . bb )
2009-03-14 13:44:14 +01:00
self . posted = self . posted + [ [ player , blindtype ] ]
2009-02-22 06:37:38 +01:00
#print "DEBUG: self.posted: %s" %(self.posted)
2008-12-12 15:29:45 +01:00
2009-02-25 17:23:46 +01:00
2008-12-12 15:29:45 +01:00
def addCall ( self , street , player = None , amount = None ) :
2009-07-19 03:31:39 +02:00
if amount :
amount = re . sub ( u ' , ' , u ' ' , amount ) #some sites have commas
2009-03-11 19:40:17 +01:00
logging . debug ( " %s %s calls %s " % ( street , player , amount ) )
2008-12-12 15:29:45 +01:00
# Potentially calculate the amount of the call if not supplied
# corner cases include if player would be all in
if amount is not None :
self . bets [ street ] [ player ] . append ( Decimal ( amount ) )
#self.lastBet[street] = Decimal(amount)
2008-12-16 05:29:11 +01:00
self . stacks [ player ] - = Decimal ( amount )
2009-02-22 06:37:38 +01:00
#print "DEBUG %s calls %s, stack %s" % (player, amount, self.stacks[player])
2008-12-20 17:48:25 +01:00
act = ( player , ' calls ' , amount , self . stacks [ player ] == 0 )
self . actions [ street ] . append ( act )
self . pot . addMoney ( player , Decimal ( amount ) )
2008-12-16 05:29:11 +01:00
2008-12-17 12:54:26 +01:00
def addRaiseBy ( self , street , player , amountBy ) :
2008-12-12 15:29:45 +01:00
""" \
2008-12-17 12:54:26 +01:00
Add a raise by amountBy on [ street ] by [ player ]
2008-12-12 15:29:45 +01:00
"""
2008-12-17 12:54:26 +01:00
#Given only the amount raised by, the amount of the raise can be calculated by
2008-12-12 15:29:45 +01:00
# working out how much this player has already in the pot
# (which is the sum of self.bets[street][player])
# and how much he needs to call to match the previous player
# (which is tracked by self.lastBet)
2008-12-17 12:54:26 +01:00
# let Bp = previous bet
# Bc = amount player has committed so far
# Rb = raise by
# then: C = Bp - Bc (amount to call)
# Rt = Bp + Rb (raise to)
#
2009-07-19 03:31:39 +02:00
amountBy = re . sub ( u ' , ' , u ' ' , amountBy ) #some sites have commas
2008-12-17 12:54:26 +01:00
self . checkPlayerExists ( player )
Rb = Decimal ( amountBy )
Bp = self . lastBet [ street ]
Bc = reduce ( operator . add , self . bets [ street ] [ player ] , 0 )
C = Bp - Bc
Rt = Bp + Rb
2009-03-11 19:40:17 +01:00
self . _addRaise ( street , player , C , Rb , Rt )
#~ self.bets[street][player].append(C + Rb)
#~ self.stacks[player] -= (C + Rb)
#~ self.actions[street] += [(player, 'raises', Rb, Rt, C, self.stacks[player]==0)]
#~ self.lastBet[street] = Rt
2008-12-17 12:54:26 +01:00
def addCallandRaise ( self , street , player , amount ) :
""" \
For sites which by " raises x " mean " calls and raises putting a total of x in the por " . """
self . checkPlayerExists ( player )
2009-07-19 03:31:39 +02:00
amount = re . sub ( u ' , ' , u ' ' , amount ) #some sites have commas
2008-12-17 12:54:26 +01:00
CRb = Decimal ( amount )
Bp = self . lastBet [ street ]
Bc = reduce ( operator . add , self . bets [ street ] [ player ] , 0 )
C = Bp - Bc
Rb = CRb - C
Rt = Bp + Rb
self . _addRaise ( street , player , C , Rb , Rt )
2008-12-20 17:48:25 +01:00
2008-12-17 12:54:26 +01:00
def addRaiseTo ( self , street , player , amountTo ) :
""" \
Add a raise on [ street ] by [ player ] to [ amountTo ]
"""
2009-02-19 18:26:29 +01:00
#CG - No idea if this function has been test/verified
2008-12-12 15:29:45 +01:00
self . checkPlayerExists ( player )
2009-07-19 03:31:39 +02:00
amountTo = re . sub ( u ' , ' , u ' ' , amountTo ) #some sites have commas
2009-02-19 17:37:48 +01:00
Bp = self . lastBet [ street ]
2008-12-17 12:54:26 +01:00
Bc = reduce ( operator . add , self . bets [ street ] [ player ] , 0 )
Rt = Decimal ( amountTo )
C = Bp - Bc
Rb = Rt - C
self . _addRaise ( street , player , C , Rb , Rt )
2008-12-20 17:48:25 +01:00
def _addRaise ( self , street , player , C , Rb , Rt ) :
2009-03-11 19:40:17 +01:00
logging . debug ( " %s %s raise %s " % ( street , player , Rt ) )
2008-12-20 17:48:25 +01:00
self . bets [ street ] [ player ] . append ( C + Rb )
self . stacks [ player ] - = ( C + Rb )
act = ( player , ' raises ' , Rb , Rt , C , self . stacks [ player ] == 0 )
self . actions [ street ] . append ( act )
self . lastBet [ street ] = Rt # TODO check this is correct
self . pot . addMoney ( player , C + Rb )
2008-12-16 05:29:11 +01:00
2008-12-12 15:29:45 +01:00
def addBet ( self , street , player , amount ) :
2009-03-11 19:40:17 +01:00
logging . debug ( " %s %s bets %s " % ( street , player , amount ) )
2009-07-19 03:31:39 +02:00
amount = re . sub ( u ' , ' , u ' ' , amount ) #some sites have commas
2008-12-12 15:29:45 +01:00
self . checkPlayerExists ( player )
self . bets [ street ] [ player ] . append ( Decimal ( amount ) )
2008-12-16 05:29:11 +01:00
self . stacks [ player ] - = Decimal ( amount )
2009-02-22 06:37:38 +01:00
#print "DEBUG %s bets %s, stack %s" % (player, amount, self.stacks[player])
2008-12-20 17:48:25 +01:00
act = ( player , ' bets ' , amount , self . stacks [ player ] == 0 )
self . actions [ street ] . append ( act )
2008-12-14 23:05:51 +01:00
self . lastBet [ street ] = Decimal ( amount )
2008-12-20 17:48:25 +01:00
self . pot . addMoney ( player , Decimal ( amount ) )
2009-03-14 11:48:34 +01:00
def addStandsPat ( self , street , player ) :
self . checkPlayerExists ( player )
act = ( player , ' stands pat ' )
self . actions [ street ] . append ( act )
2008-12-16 05:29:11 +01:00
2008-12-12 15:29:45 +01:00
def addFold ( self , street , player ) :
2009-03-11 19:40:17 +01:00
logging . debug ( " %s %s folds " % ( street , player ) )
2008-12-12 15:29:45 +01:00
self . checkPlayerExists ( player )
self . folded . add ( player )
2008-12-20 17:48:25 +01:00
self . pot . addFold ( player )
self . actions [ street ] . append ( ( player , ' folds ' ) )
2008-12-12 15:29:45 +01:00
def addCheck ( self , street , player ) :
2009-02-22 06:37:38 +01:00
#print "DEBUG: %s %s checked" % (street, player)
2008-12-12 15:29:45 +01:00
self . checkPlayerExists ( player )
2008-12-20 17:48:25 +01:00
self . actions [ street ] . append ( ( player , ' checks ' ) )
2008-12-12 15:29:45 +01:00
2009-02-20 09:33:25 +01:00
2008-12-12 15:29:45 +01:00
def addCollectPot ( self , player , pot ) :
2009-03-11 19:40:17 +01:00
logging . debug ( " %s collected %s " % ( player , pot ) )
2008-12-12 15:29:45 +01:00
self . checkPlayerExists ( player )
2009-02-21 17:17:06 +01:00
self . collected = self . collected + [ [ player , pot ] ]
if player not in self . collectees :
self . collectees [ player ] = Decimal ( pot )
2008-12-12 15:29:45 +01:00
else :
2009-02-21 17:17:06 +01:00
self . collectees [ player ] + = Decimal ( pot )
2008-12-12 15:29:45 +01:00
2009-07-04 20:35:20 +02:00
def addShownCards ( self , cards , player , holeandboard = None , shown = True , mucked = False ) :
""" \
For when a player shows cards for any reason ( for showdown or out of choice ) .
Card ranks will be uppercased
"""
logging . debug ( " addShownCards %s hole= %s all= %s " % ( player , cards , holeandboard ) )
if cards is not None :
self . addHoleCards ( cards , player , shown , mucked )
elif holeandboard is not None :
holeandboard = set ( [ self . card ( c ) for c in holeandboard ] )
board = set ( [ c for s in self . board . values ( ) for c in s ] )
self . addHoleCards ( holeandboard . difference ( board ) , player , shown , mucked )
2008-12-12 15:29:45 +01:00
def totalPot ( self ) :
2008-12-16 00:56:19 +01:00
""" If all bets and blinds have been added, totals up the total pot size """
2008-12-20 17:57:12 +01:00
# This gives us the total amount put in the pot
2008-12-12 15:29:45 +01:00
if self . totalpot is None :
2008-12-20 17:48:25 +01:00
self . pot . end ( )
2008-12-20 17:57:12 +01:00
self . totalpot = self . pot . total
# This gives us the amount collected, i.e. after rake
2008-12-14 20:25:04 +01:00
if self . totalcollected is None :
self . totalcollected = 0 ;
2009-02-21 17:17:06 +01:00
#self.collected looks like [[p1,amount][px,amount]]
for entry in self . collected :
self . totalcollected + = Decimal ( entry [ 1 ] )
2008-12-14 20:25:04 +01:00
2008-12-14 23:05:51 +01:00
2008-12-14 20:25:04 +01:00
2008-12-12 15:29:45 +01:00
def getGameTypeAsString ( self ) :
""" \
Map the tuple self . gametype onto the pokerstars string describing it
"""
# currently it appears to be something like ["ring", "hold", "nl", sb, bb]:
2009-07-13 22:22:23 +02:00
gs = { " holdem " : " Hold ' em " ,
2009-02-22 10:07:11 +01:00
" omahahi " : " Omaha " ,
2009-03-14 14:45:09 +01:00
" omahahilo " : " Omaha Hi/Lo " ,
2008-12-12 15:29:45 +01:00
" razz " : " Razz " ,
2009-03-06 02:24:38 +01:00
" studhi " : " 7 Card Stud " ,
2009-06-12 18:29:17 +02:00
" studhilo " : " 7 Card Stud Hi/Lo " ,
2008-12-12 15:29:45 +01:00
" fivedraw " : " 5 Card Draw " ,
" 27_1draw " : " FIXME " ,
" 27_3draw " : " Triple Draw 2-7 Lowball " ,
2009-03-14 11:48:34 +01:00
" badugi " : " Badugi "
2008-12-12 15:29:45 +01:00
}
ls = { " nl " : " No Limit " ,
" pl " : " Pot Limit " ,
" fl " : " Limit " ,
" cn " : " Cap No Limit " ,
" cp " : " Cap Pot Limit "
}
2009-03-04 17:46:01 +01:00
logging . debug ( " gametype: %s " % ( self . gametype ) )
2009-03-10 17:17:54 +01:00
retstring = " %s %s " % ( gs [ self . gametype [ ' category ' ] ] , ls [ self . gametype [ ' limitType ' ] ] )
2009-03-04 17:46:01 +01:00
return retstring
2008-12-12 15:29:45 +01:00
2009-03-01 17:52:52 +01:00
2008-12-16 00:56:19 +01:00
def writeHand ( self , fh = sys . __stdout__ ) :
2009-02-27 19:42:53 +01:00
print >> fh , " Override me "
def printHand ( self ) :
self . writeHand ( sys . stdout )
2009-06-19 08:21:35 +02:00
def actionString ( self , act ) :
2009-02-27 19:42:53 +01:00
if act [ 1 ] == ' folds ' :
2009-06-19 08:21:35 +02:00
return ( " %s : folds " % ( act [ 0 ] ) )
2009-02-27 19:42:53 +01:00
elif act [ 1 ] == ' checks ' :
2009-06-19 08:21:35 +02:00
return ( " %s : checks " % ( act [ 0 ] ) )
2009-03-02 00:22:47 +01:00
elif act [ 1 ] == ' calls ' :
2009-07-16 05:04:16 +02:00
return ( " %s : calls %s %s %s " % ( act [ 0 ] , self . sym , act [ 2 ] , ' and is all-in ' if act [ 3 ] else ' ' ) )
2009-03-02 00:22:47 +01:00
elif act [ 1 ] == ' bets ' :
2009-07-16 05:04:16 +02:00
return ( " %s : bets %s %s %s " % ( act [ 0 ] , self . sym , act [ 2 ] , ' and is all-in ' if act [ 3 ] else ' ' ) )
2009-03-02 00:22:47 +01:00
elif act [ 1 ] == ' raises ' :
2009-07-16 05:04:16 +02:00
return ( " %s : raises %s %s to %s %s %s " % ( act [ 0 ] , self . sym , act [ 2 ] , self . sym , act [ 3 ] , ' and is all-in ' if act [ 5 ] else ' ' ) )
2009-03-11 17:51:58 +01:00
elif act [ 1 ] == ' completea ' :
2009-07-16 05:04:16 +02:00
return ( " %s : completes to %s %s %s " % ( act [ 0 ] , self . sym , act [ 2 ] , ' and is all-in ' if act [ 3 ] else ' ' ) )
2009-03-02 00:22:47 +01:00
elif act [ 1 ] == ' posts ' :
if ( act [ 2 ] == " small blind " ) :
2009-07-16 05:04:16 +02:00
return ( " %s : posts small blind %s %s %s " % ( act [ 0 ] , self . sym , act [ 3 ] , ' and is all-in ' if act [ 4 ] else ' ' ) )
2009-03-02 00:22:47 +01:00
elif ( act [ 2 ] == " big blind " ) :
2009-07-16 05:04:16 +02:00
return ( " %s : posts big blind %s %s %s " % ( act [ 0 ] , self . sym , act [ 3 ] , ' and is all-in ' if act [ 4 ] else ' ' ) )
2009-03-02 00:22:47 +01:00
elif ( act [ 2 ] == " both " ) :
2009-07-16 05:04:16 +02:00
return ( " %s : posts small & big blinds %s %s %s " % ( act [ 0 ] , self . sym , act [ 3 ] , ' and is all-in ' if act [ 4 ] else ' ' ) )
2009-03-11 17:51:58 +01:00
elif act [ 1 ] == ' bringin ' :
2009-07-16 05:04:16 +02:00
return ( " %s : brings in for %s %s %s " % ( act [ 0 ] , self . sym , act [ 2 ] , ' and is all-in ' if act [ 3 ] else ' ' ) )
2009-03-14 11:48:34 +01:00
elif act [ 1 ] == ' discards ' :
2009-06-19 08:21:35 +02:00
return ( " %s : discards %s %s %s " % ( act [ 0 ] , act [ 2 ] , ' card ' if act [ 2 ] == 1 else ' cards ' , " [ " + " " . join ( self . discards [ act [ 0 ] ] [ ' DRAWONE ' ] ) + " ] " if self . hero == act [ 0 ] else ' ' ) )
2009-03-14 11:48:34 +01:00
elif act [ 1 ] == ' stands pat ' :
2009-06-19 08:21:35 +02:00
return ( " %s : stands pat " % ( act [ 0 ] ) )
2009-03-14 11:48:34 +01:00
2009-07-13 22:22:23 +02:00
def getStakesAsString ( self ) :
2009-07-15 01:18:38 +02:00
""" Return a string of the stakes of the current hand. """
return " %s %s / %s %s " % ( self . sym , self . sb , self . sym , self . bb )
2009-07-13 22:22:23 +02:00
def writeGameLine ( self ) :
2009-07-15 01:18:38 +02:00
""" Return the first HH line for the current hand. """
gs = " PokerStars Game # %s : " % self . handid
if self . tourNo != None and self . mixed != None : # mixed tournament
gs = gs + " Tournament # %s , %s %s ( %s ) - Level %s ( %s ) - " % ( self . tourNo , self . buyin , self . MS [ self . mixed ] , self . getGameTypeAsString ( ) , self . level , self . getStakesAsString ( ) )
elif self . tourNo != None : # all other tournaments
gs = gs + " Tournament # %s , %s %s - Level %s ( %s ) - " % ( self . tourNo ,
2009-07-13 22:22:23 +02:00
self . buyin , self . getGameTypeAsString ( ) , self . level , self . getStakesAsString ( ) )
2009-07-15 01:18:38 +02:00
elif self . mixed != None : # all other mixed games
gs = gs + " %s ( %s , %s ) - " % ( self . MS [ self . mixed ] ,
2009-07-13 22:22:23 +02:00
self . getGameTypeAsString ( ) , self . getStakesAsString ( ) )
2009-07-15 01:18:38 +02:00
else : # non-mixed cash games
gs = gs + " %s ( %s ) - " % ( self . getGameTypeAsString ( ) , self . getStakesAsString ( ) )
return gs + datetime . datetime . strftime ( self . starttime , ' % Y/ % m/ %d % H: % M: % S ET ' )
2009-07-13 22:22:23 +02:00
def writeTableLine ( self ) :
table_string = " Table \' %s \' %s -max " % ( self . tablename , self . maxseats )
if self . gametype [ ' currency ' ] == ' play ' :
table_string = table_string + " (Play Money) "
if self . buttonpos != None :
table_string = table_string + " Seat # %s is the button " % self . buttonpos
return table_string
2009-03-14 11:48:34 +01:00
2009-07-15 17:50:27 +02:00
def writeHand ( self , fh = sys . __stdout__ ) :
# PokerStars format.
print >> fh , self . writeGameLine ( )
print >> fh , self . writeTableLine ( )
2009-02-27 19:42:53 +01:00
class HoldemOmahaHand ( Hand ) :
2009-06-07 22:57:13 +02:00
def __init__ ( self , hhc , sitename , gametype , handText , builtFrom = " HHC " , handid = None ) :
2009-03-10 17:17:54 +01:00
if gametype [ ' base ' ] != ' hold ' :
2009-02-27 19:42:53 +01:00
pass # or indeed don't pass and complain instead
2009-03-03 19:45:02 +01:00
logging . debug ( " HoldemOmahaHand " )
2009-06-19 08:21:35 +02:00
self . allStreets = [ ' BLINDSANTES ' , ' PREFLOP ' , ' FLOP ' , ' TURN ' , ' RIVER ' ]
self . holeStreets = [ ' PREFLOP ' ]
2009-03-02 00:22:47 +01:00
self . communityStreets = [ ' FLOP ' , ' TURN ' , ' RIVER ' ]
2009-06-19 08:21:35 +02:00
self . actionStreets = [ ' BLINDSANTES ' , ' PREFLOP ' , ' FLOP ' , ' TURN ' , ' RIVER ' ]
2009-03-14 12:40:27 +01:00
Hand . __init__ ( self , sitename , gametype , handText , builtFrom = " HHC " )
2009-03-06 19:10:04 +01:00
self . sb = gametype [ ' sb ' ]
self . bb = gametype [ ' bb ' ]
2009-02-27 19:42:53 +01:00
2009-03-02 22:48:30 +01:00
#Populate a HoldemOmahaHand
#Generally, we call 'read' methods here, which get the info according to the particular filter (hhc)
# which then invokes a 'addXXX' callback
2009-03-14 15:01:40 +01:00
if builtFrom == " HHC " :
hhc . readHandInfo ( self )
hhc . readPlayerStacks ( self )
hhc . compilePlayerRegexs ( self )
hhc . markStreets ( self )
hhc . readBlinds ( self )
hhc . readButton ( self )
hhc . readHeroCards ( self )
hhc . readShowdownActions ( self )
# Read actions in street order
for street in self . communityStreets :
if self . streets [ street ] :
hhc . readCommunityCards ( self , street )
for street in self . actionStreets :
if self . streets [ street ] :
hhc . readAction ( self , street )
hhc . readCollectPot ( self )
hhc . readShownCards ( self )
self . totalPot ( ) # finalise it (total the pot)
hhc . getRake ( self )
elif builtFrom == " DB " :
2009-06-07 22:57:13 +02:00
if handid is not None :
self . select ( handid ) # Will need a handId
else :
logging . warning ( " HoldemOmahaHand.__init__:Can ' t assemble hand from db without a handid " )
else :
logging . warning ( " HoldemOmahaHand.__init__:Neither HHC nor DB+handid provided " )
pass
2009-03-07 16:43:33 +01:00
2009-07-12 22:01:02 +02:00
def addShownCards ( self , cards , player , shown = True , mucked = False , dealt = False ) :
if player == self . hero : # we have hero's cards just update shown/mucked
if shown : self . shown . add ( player )
if mucked : self . mucked . add ( player )
2009-06-19 08:21:35 +02:00
else :
2009-07-12 22:01:02 +02:00
self . addHoleCards ( ' PREFLOP ' , player , open = [ ] , closed = cards , shown = shown , mucked = mucked , dealt = dealt )
2009-03-02 22:48:30 +01:00
2009-06-16 01:29:44 +02:00
def writeHTMLHand ( self , fh = sys . __stdout__ ) :
from nevow import tags as T
from nevow import flat
players_who_act_preflop = ( ( [ x [ 0 ] for x in self . actions [ ' PREFLOP ' ] ] + [ x [ 0 ] for x in self . actions [ ' BLINDSANTES ' ] ] ) )
players_stacks = [ x for x in self . players if x [ 1 ] in players_who_act_preflop ]
action_streets = [ x for x in self . actionStreets if len ( self . actions [ x ] ) > 0 ]
def render_stack ( context , data ) :
pat = context . tag . patternGenerator ( ' list_item ' )
for player in data :
2009-07-16 05:04:16 +02:00
x = " Seat %s : %s ( %s %s in chips) " % ( player [ 0 ] , player [ 1 ] ,
self . sym , player [ 2 ] )
2009-06-16 01:29:44 +02:00
context . tag [ pat ( ) . fillSlots ( ' playerStack ' , x ) ]
return context . tag
def render_street ( context , data ) :
pat = context . tag . patternGenerator ( ' list_item ' )
for street in data :
2009-06-19 08:21:35 +02:00
lines = [ ]
if street in self . holeStreets and self . holecards [ street ] :
lines . append (
T . ol ( class_ = ' dealclosed ' , data = street ,
render = render_deal ) [
T . li ( pattern = ' list_item ' ) [ T . slot ( name = ' deal ' ) ]
]
)
if street in self . communityStreets and self . board [ street ] :
lines . append (
T . ol ( class_ = ' community ' , data = street ,
render = render_deal_community ) [
T . li ( pattern = ' list_item ' ) [ T . slot ( name = ' deal ' ) ]
]
)
if street in self . actionStreets and self . actions [ street ] :
lines . append (
T . ol ( class_ = ' actions ' , data = self . actions [ street ] , render = render_action ) [
T . li ( pattern = ' list_item ' ) [ T . slot ( name = ' action ' ) ]
]
)
if lines :
context . tag [ pat ( ) . fillSlots ( ' street ' , [ T . h3 [ street ] ] + lines ) ]
return context . tag
def render_deal ( context , data ) :
# data is streetname
# we can have open+closed, or just open, or just closed.
if self . holecards [ data ] :
for player in self . holecards [ data ] :
somestuff = ' dealt to %s %s ' % ( player , self . holecards [ data ] [ player ] )
pat = context . tag . patternGenerator ( ' list_item ' )
context . tag [ pat ( ) . fillSlots ( ' deal ' , somestuff ) ]
2009-06-16 01:29:44 +02:00
return context . tag
2009-06-19 08:21:35 +02:00
def render_deal_community ( context , data ) :
# data is streetname
if self . board [ data ] :
somestuff = ' [ ' + ' ' . join ( self . board [ data ] ) + ' ] '
pat = context . tag . patternGenerator ( ' list_item ' )
context . tag [ pat ( ) . fillSlots ( ' deal ' , somestuff ) ]
return context . tag
2009-06-16 01:29:44 +02:00
def render_action ( context , data ) :
pat = context . tag . patternGenerator ( ' list_item ' )
for act in data :
2009-06-19 08:21:35 +02:00
x = self . actionString ( act )
2009-06-16 01:29:44 +02:00
context . tag [ pat ( ) . fillSlots ( ' action ' , x ) ]
return context . tag
s = T . p [
2009-06-19 08:21:35 +02:00
T . h1 [
T . span ( class_ = ' site ' ) [ " %s Game # %s ] " % ( ' PokerStars ' , self . handid ) ] ,
T . span ( class_ = ' type_limit ' ) [ " %s ($ %s /$ %s ) " % ( self . getGameTypeAsString ( ) , self . sb , self . bb ) ] ,
T . span ( class_ = ' date ' ) [ datetime . datetime . strftime ( self . starttime , ' % Y/ % m/ %d - % H: % M: % S ET ' ) ]
2009-06-16 01:29:44 +02:00
] ,
T . h2 [ " Table ' %s ' %d -max Seat # %s is the button " % ( self . tablename ,
self . maxseats , self . buttonpos ) ] ,
T . ol ( class_ = ' stacks ' , data = players_stacks , render = render_stack ) [
T . li ( pattern = ' list_item ' ) [ T . slot ( name = ' playerStack ' ) ]
] ,
2009-06-19 08:21:35 +02:00
T . ol ( class_ = ' streets ' , data = self . allStreets ,
2009-06-16 01:29:44 +02:00
render = render_street ) [
T . li ( pattern = ' list_item ' ) [ T . slot ( name = ' street ' ) ]
]
]
2009-06-19 08:21:35 +02:00
import tidy
options = dict ( input_xml = True ,
output_xhtml = True ,
add_xml_decl = False ,
doctype = ' omit ' ,
indent = ' auto ' ,
tidy_mark = False )
return str ( tidy . parseString ( flat . flatten ( s ) , * * options ) )
2009-06-16 01:29:44 +02:00
2009-02-27 19:42:53 +01:00
def writeHand ( self , fh = sys . __stdout__ ) :
2008-12-12 15:29:45 +01:00
# PokerStars format.
2009-07-15 17:50:27 +02:00
super ( HoldemOmahaHand , self ) . writeHand ( fh )
2009-07-13 22:22:23 +02:00
2009-03-11 15:07:38 +01:00
players_who_act_preflop = set ( ( [ x [ 0 ] for x in self . actions [ ' PREFLOP ' ] ] + [ x [ 0 ] for x in self . actions [ ' BLINDSANTES ' ] ] ) )
2009-03-11 15:05:38 +01:00
logging . debug ( self . actions [ ' PREFLOP ' ] )
2008-12-16 00:56:19 +01:00
for player in [ x for x in self . players if x [ 1 ] in players_who_act_preflop ] :
#Only print stacks of players who do something preflop
2009-06-07 22:57:13 +02:00
print >> fh , ( " Seat %s : %s ($ %s in chips) " % ( player [ 0 ] , player [ 1 ] , player [ 2 ] ) )
2008-12-12 15:29:45 +01:00
2009-03-02 00:22:47 +01:00
if self . actions [ ' BLINDSANTES ' ] :
for act in self . actions [ ' BLINDSANTES ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-03-02 00:22:47 +01:00
2009-06-07 22:57:13 +02:00
print >> fh , ( " *** HOLE CARDS *** " )
2009-06-19 08:21:35 +02:00
for player in self . dealt :
2009-07-12 22:01:02 +02:00
print >> fh , ( " Dealt to %s [ %s ] " % ( player , " " . join ( self . holecards [ ' PREFLOP ' ] [ player ] [ 1 ] ) ) )
2009-06-19 08:21:35 +02:00
if self . hero == " " :
for player in self . shown . difference ( self . dealt ) :
2009-07-12 22:01:02 +02:00
print >> fh , ( " Dealt to %s [ %s ] " % ( player , " " . join ( self . holecards [ ' PREFLOP ' ] [ player ] [ 1 ] ) ) )
2008-12-12 15:29:45 +01:00
2009-03-02 00:22:47 +01:00
if self . actions [ ' PREFLOP ' ] :
2008-12-12 15:29:45 +01:00
for act in self . actions [ ' PREFLOP ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2008-12-12 15:29:45 +01:00
2009-03-03 19:45:02 +01:00
if self . board [ ' FLOP ' ] :
2009-06-07 22:57:13 +02:00
print >> fh , ( " *** FLOP *** [ %s ] " % ( " " . join ( self . board [ ' FLOP ' ] ) ) )
2009-03-03 19:45:02 +01:00
if self . actions [ ' FLOP ' ] :
2008-12-12 15:29:45 +01:00
for act in self . actions [ ' FLOP ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2008-12-12 15:29:45 +01:00
2009-03-03 19:45:02 +01:00
if self . board [ ' TURN ' ] :
2009-06-07 22:57:13 +02:00
print >> fh , ( " *** TURN *** [ %s ] [ %s ] " % ( " " . join ( self . board [ ' FLOP ' ] ) , " " . join ( self . board [ ' TURN ' ] ) ) )
2009-03-03 19:45:02 +01:00
if self . actions [ ' TURN ' ] :
2008-12-12 15:29:45 +01:00
for act in self . actions [ ' TURN ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2008-12-12 15:29:45 +01:00
2009-03-03 19:45:02 +01:00
if self . board [ ' RIVER ' ] :
2009-06-07 22:57:13 +02:00
print >> fh , ( " *** RIVER *** [ %s ] [ %s ] " % ( " " . join ( self . board [ ' FLOP ' ] + self . board [ ' TURN ' ] ) , " " . join ( self . board [ ' RIVER ' ] ) ) )
2009-03-03 19:45:02 +01:00
if self . actions [ ' RIVER ' ] :
2008-12-12 15:29:45 +01:00
for act in self . actions [ ' RIVER ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2008-12-12 15:29:45 +01:00
#Some sites don't have a showdown section so we have to figure out if there should be one
# The logic for a showdown is: at the end of river action there are at least two players in the hand
# we probably don't need a showdown section in pseudo stars format for our filtering purposes
2009-03-14 16:02:23 +01:00
if self . shown :
2009-06-07 22:57:13 +02:00
print >> fh , ( " *** SHOW DOWN *** " )
2009-03-14 16:02:23 +01:00
for name in self . shown :
2009-03-15 17:51:50 +01:00
# TODO: legacy importer can't handle only one holecard here, make sure there are 2 for holdem, 4 for omaha
# TOOD: If HoldHand subclass supports more than omahahi, omahahilo, holdem, add them here
numOfHoleCardsNeeded = None
if self . gametype [ ' category ' ] in ( ' omahahi ' , ' omahahilo ' ) :
numOfHoleCardsNeeded = 4
elif self . gametype [ ' category ' ] in ( ' holdem ' ) :
numOfHoleCardsNeeded = 2
2009-06-19 08:21:35 +02:00
if len ( self . holecards [ ' PREFLOP ' ] [ name ] ) == numOfHoleCardsNeeded :
2009-07-12 22:01:02 +02:00
print >> fh , ( " %s shows [ %s ] (a hand...) " % ( name , " " . join ( self . holecards [ ' PREFLOP ' ] [ name ] [ 1 ] ) ) )
2009-03-14 16:02:23 +01:00
2009-02-21 12:24:11 +01:00
# Current PS format has the lines:
2009-02-21 13:37:47 +01:00
# Uncalled bet ($111.25) returned to s0rrow
2009-02-21 12:24:11 +01:00
# s0rrow collected $5.15 from side pot
# stervels: shows [Ks Qs] (two pair, Kings and Queens)
# stervels collected $45.35 from main pot
# Immediately before the summary.
# The current importer uses those lines for importing winning rather than the summary
2009-02-21 13:37:47 +01:00
for name in self . pot . returned :
2009-07-16 05:04:16 +02:00
print >> fh , ( " Uncalled bet ( %s %s ) returned to %s " % ( self . sym , self . pot . returned [ name ] , name ) )
2009-02-21 17:17:06 +01:00
for entry in self . collected :
2009-07-16 05:04:16 +02:00
print >> fh , ( " %s collected %s %s from x pot " % ( entry [ 0 ] , self . sym , entry [ 1 ] ) )
2009-02-21 12:24:11 +01:00
2009-06-07 22:57:13 +02:00
print >> fh , ( " *** SUMMARY *** " )
2009-07-16 05:04:16 +02:00
print >> fh , " %s | Rake %s %.2f " % ( self . pot , self . sym , self . rake )
2008-12-14 23:05:51 +01:00
2008-12-12 15:29:45 +01:00
board = [ ]
2009-07-16 04:30:41 +02:00
for street in [ " FLOP " , " TURN " , " RIVER " ] :
board + = self . board [ street ]
2008-12-12 15:29:45 +01:00
if board : # sometimes hand ends preflop without a board
2009-06-07 22:57:13 +02:00
print >> fh , ( " Board [ %s ] " % ( " " . join ( board ) ) )
2008-12-12 15:29:45 +01:00
2008-12-16 22:49:04 +01:00
for player in [ x for x in self . players if x [ 1 ] in players_who_act_preflop ] :
2008-12-12 15:29:45 +01:00
seatnum = player [ 0 ]
name = player [ 1 ]
2009-02-21 17:17:06 +01:00
if name in self . collectees and name in self . shown :
2009-07-16 05:04:16 +02:00
print >> fh , ( " Seat %d : %s showed [ %s ] and won ( %s %s ) " % ( seatnum , name , " " . join ( self . holecards [ ' PREFLOP ' ] [ name ] [ 1 ] ) , self . sym , self . collectees [ name ] ) )
2009-02-21 17:17:06 +01:00
elif name in self . collectees :
2009-07-16 05:04:16 +02:00
print >> fh , ( " Seat %d : %s collected ( %s %s ) " % ( seatnum , name , self . sym , self . collectees [ name ] ) )
2009-03-13 17:50:46 +01:00
#~ elif name in self.shown:
#~ print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name]['PREFLOP'])))
2009-02-25 13:34:05 +01:00
elif name in self . folded :
2009-06-07 22:57:13 +02:00
print >> fh , ( " Seat %d : %s folded " % ( seatnum , name ) )
2009-02-25 13:34:05 +01:00
else :
2009-03-13 17:50:46 +01:00
if name in self . shown :
2009-07-12 22:01:02 +02:00
print >> fh , ( " Seat %d : %s showed [ %s ] and lost with... " % ( seatnum , name , " " . join ( self . holecards [ ' PREFLOP ' ] [ name ] [ 1 ] ) ) )
2009-07-04 21:28:20 +02:00
elif name in self . mucked :
2009-07-12 22:01:02 +02:00
print >> fh , ( " Seat %d : %s mucked [ %s ] " % ( seatnum , name , " " . join ( self . holecards [ ' PREFLOP ' ] [ name ] [ 1 ] ) ) )
2009-03-13 17:50:46 +01:00
else :
2009-06-07 22:57:13 +02:00
print >> fh , ( " Seat %d : %s mucked " % ( seatnum , name ) )
2009-02-25 13:34:05 +01:00
print >> fh , " \n \n "
2009-03-06 02:24:38 +01:00
class DrawHand ( Hand ) :
2009-03-14 12:40:27 +01:00
def __init__ ( self , hhc , sitename , gametype , handText , builtFrom = " HHC " ) :
2009-03-10 17:17:54 +01:00
if gametype [ ' base ' ] != ' draw ' :
2009-03-06 02:24:38 +01:00
pass # or indeed don't pass and complain instead
2009-03-14 11:48:34 +01:00
self . streetList = [ ' BLINDSANTES ' , ' DEAL ' , ' DRAWONE ' , ' DRAWTWO ' , ' DRAWTHREE ' ]
2009-07-11 19:44:32 +02:00
self . allStreets = [ ' BLINDSANTES ' , ' DEAL ' , ' DRAWONE ' , ' DRAWTWO ' , ' DRAWTHREE ' ]
2009-03-14 11:48:34 +01:00
self . holeStreets = [ ' DEAL ' , ' DRAWONE ' , ' DRAWTWO ' , ' DRAWTHREE ' ]
self . actionStreets = [ ' PREDEAL ' , ' DEAL ' , ' DRAWONE ' , ' DRAWTWO ' , ' DRAWTHREE ' ]
2009-07-11 19:44:32 +02:00
self . communityStreets = [ ]
2009-03-14 11:48:34 +01:00
Hand . __init__ ( self , sitename , gametype , handText )
self . sb = gametype [ ' sb ' ]
self . bb = gametype [ ' bb ' ]
# Populate the draw hand.
2009-03-14 15:01:40 +01:00
if builtFrom == " HHC " :
hhc . readHandInfo ( self )
hhc . readPlayerStacks ( self )
hhc . compilePlayerRegexs ( self )
hhc . markStreets ( self )
hhc . readBlinds ( self )
hhc . readButton ( self )
2009-07-13 06:37:51 +02:00
hhc . readHeroCards ( self )
2009-03-14 15:01:40 +01:00
hhc . readShowdownActions ( self )
# Read actions in street order
for street in self . streetList :
if self . streets [ street ] :
hhc . readAction ( self , street )
hhc . readCollectPot ( self )
hhc . readShownCards ( self )
self . totalPot ( ) # finalise it (total the pot)
hhc . getRake ( self )
elif builtFrom == " DB " :
self . select ( " dummy " ) # Will need a handId
2009-03-14 11:48:34 +01:00
# Draw games (at least Badugi has blinds - override default Holdem addBlind
def addBlind ( self , player , blindtype , amount ) :
# if player is None, it's a missing small blind.
# The situation we need to cover are:
# Player in small blind posts
# - this is a bet of 1 sb, as yet uncalled.
# Player in the big blind posts
# - this is a call of 1 sb and a raise to 1 bb
#
logging . debug ( " addBlind: %s posts %s , %s " % ( player , blindtype , amount ) )
if player is not None :
self . bets [ ' DEAL ' ] [ player ] . append ( Decimal ( amount ) )
self . stacks [ player ] - = Decimal ( amount )
#print "DEBUG %s posts, stack %s" % (player, self.stacks[player])
act = ( player , ' posts ' , blindtype , amount , self . stacks [ player ] == 0 )
self . actions [ ' BLINDSANTES ' ] . append ( act )
self . pot . addMoney ( player , Decimal ( amount ) )
if blindtype == ' big blind ' :
self . lastBet [ ' DEAL ' ] = Decimal ( amount )
elif blindtype == ' both ' :
# extra small blind is 'dead'
self . lastBet [ ' DEAL ' ] = Decimal ( self . bb )
self . posted = self . posted + [ [ player , blindtype ] ]
#print "DEBUG: self.posted: %s" %(self.posted)
2009-07-13 06:37:51 +02:00
def addShownCards ( self , cards , player , shown = True , mucked = False , dealt = False ) :
if player == self . hero : # we have hero's cards just update shown/mucked
if shown : self . shown . add ( player )
if mucked : self . mucked . add ( player )
else :
# TODO: Probably better to find the last street with action and add the hole cards to that street
self . addHoleCards ( ' DRAWTHREE ' , player , open = [ ] , closed = cards , shown = shown , mucked = mucked , dealt = dealt )
2009-03-14 11:48:34 +01:00
2009-07-13 06:37:51 +02:00
2009-03-14 11:48:34 +01:00
def discardDrawHoleCards ( self , cards , player , street ) :
logging . debug ( " discardDrawHoleCards ' %s ' ' %s ' ' %s ' " % ( cards , player , street ) )
2009-07-11 19:44:32 +02:00
self . discards [ street ] [ player ] = set ( [ cards ] )
2009-03-14 11:48:34 +01:00
2009-03-14 14:23:30 +01:00
def addDiscard ( self , street , player , num , cards ) :
self . checkPlayerExists ( player )
if cards :
act = ( player , ' discards ' , num , cards )
self . discardDrawHoleCards ( cards , player , street )
else :
act = ( player , ' discards ' , num )
self . actions [ street ] . append ( act )
2009-03-14 11:48:34 +01:00
def writeHand ( self , fh = sys . __stdout__ ) :
# PokerStars format.
2009-07-15 17:50:27 +02:00
super ( DrawHand , self ) . writeHand ( fh )
2009-03-14 11:48:34 +01:00
players_who_act_ondeal = set ( ( [ x [ 0 ] for x in self . actions [ ' DEAL ' ] ] + [ x [ 0 ] for x in self . actions [ ' BLINDSANTES ' ] ] ) )
for player in [ x for x in self . players if x [ 1 ] in players_who_act_ondeal ] :
#Only print stacks of players who do something on deal
2009-07-16 05:04:16 +02:00
print >> fh , _ ( " Seat %s : %s ( %s %s in chips) " % ( player [ 0 ] , player [ 1 ] , self . sym , player [ 2 ] ) )
2009-03-14 11:48:34 +01:00
if ' BLINDSANTES ' in self . actions :
for act in self . actions [ ' BLINDSANTES ' ] :
2009-07-16 05:04:16 +02:00
print >> fh , _ ( " %s : %s %s %s %s " % ( act [ 0 ] , act [ 1 ] , act [ 2 ] , self . sym , act [ 3 ] ) )
2009-03-14 11:48:34 +01:00
if ' DEAL ' in self . actions :
print >> fh , _ ( " *** DEALING HANDS *** " )
for player in [ x [ 1 ] for x in self . players if x [ 1 ] in players_who_act_ondeal ] :
if ' DEAL ' in self . holecards [ player ] :
( nc , oc ) = self . holecards [ player ] [ ' DEAL ' ]
print >> fh , _ ( " Dealt to %s : [ %s ] " ) % ( player , " " . join ( nc ) )
for act in self . actions [ ' DEAL ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-03-14 11:48:34 +01:00
if ' DRAWONE ' in self . actions :
print >> fh , _ ( " *** FIRST DRAW *** " )
for act in self . actions [ ' DRAWONE ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-03-14 11:48:34 +01:00
if act [ 0 ] == self . hero and act [ 1 ] == ' discards ' :
2009-07-11 19:44:32 +02:00
( nc , oc ) = self . holecards [ ' DRAWONE ' ] [ act [ 0 ] ]
dc = self . discards [ ' DRAWONE ' ] [ act [ 0 ] ]
2009-03-14 11:48:34 +01:00
kc = oc - dc
print >> fh , _ ( " Dealt to %s [ %s ] [ %s ] " % ( act [ 0 ] , " " . join ( kc ) , " " . join ( nc ) ) )
if ' DRAWTWO ' in self . actions :
print >> fh , _ ( " *** SECOND DRAW *** " )
for act in self . actions [ ' DRAWTWO ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-03-14 11:48:34 +01:00
if act [ 0 ] == self . hero and act [ 1 ] == ' discards ' :
2009-07-11 19:44:32 +02:00
( nc , oc ) = self . holecards [ ' DRAWTWO ' ] [ act [ 0 ] ]
dc = self . discards [ ' DRAWTWO ' ] [ act [ 0 ] ]
2009-03-14 11:48:34 +01:00
kc = oc - dc
print >> fh , _ ( " Dealt to %s [ %s ] [ %s ] " % ( act [ 0 ] , " " . join ( kc ) , " " . join ( nc ) ) )
if ' DRAWTHREE ' in self . actions :
print >> fh , _ ( " *** THIRD DRAW *** " )
for act in self . actions [ ' DRAWTHREE ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-03-14 11:48:34 +01:00
if act [ 0 ] == self . hero and act [ 1 ] == ' discards ' :
2009-07-11 19:44:32 +02:00
( nc , oc ) = self . holecards [ ' DRAWTHREE ' ] [ act [ 0 ] ]
dc = self . discards [ ' DRAWTHREE ' ] [ act [ 0 ] ]
2009-03-14 11:48:34 +01:00
kc = oc - dc
print >> fh , _ ( " Dealt to %s [ %s ] [ %s ] " % ( act [ 0 ] , " " . join ( kc ) , " " . join ( nc ) ) )
if ' SHOWDOWN ' in self . actions :
print >> fh , _ ( " *** SHOW DOWN *** " )
#TODO: Complete SHOWDOWN
# Current PS format has the lines:
# Uncalled bet ($111.25) returned to s0rrow
# s0rrow collected $5.15 from side pot
# stervels: shows [Ks Qs] (two pair, Kings and Queens)
# stervels collected $45.35 from main pot
# Immediately before the summary.
# The current importer uses those lines for importing winning rather than the summary
for name in self . pot . returned :
2009-07-16 05:04:16 +02:00
print >> fh , _ ( " Uncalled bet ( %s %s ) returned to %s " % ( self . sym , self . pot . returned [ name ] , name ) )
2009-03-14 11:48:34 +01:00
for entry in self . collected :
2009-07-16 05:04:16 +02:00
print >> fh , _ ( " %s collected %s %s from x pot " % ( entry [ 0 ] , self . sym , entry [ 1 ] ) )
2009-03-14 11:48:34 +01:00
print >> fh , _ ( " *** SUMMARY *** " )
2009-07-16 05:04:16 +02:00
print >> fh , " %s | Rake %s %.2f " % ( self . pot , self . sym , self . rake )
2009-03-14 11:48:34 +01:00
print >> fh , " \n \n "
2009-02-27 19:42:53 +01:00
class StudHand ( Hand ) :
2009-03-14 12:40:27 +01:00
def __init__ ( self , hhc , sitename , gametype , handText , builtFrom = " HHC " ) :
2009-03-10 17:17:54 +01:00
if gametype [ ' base ' ] != ' stud ' :
2009-02-27 19:42:53 +01:00
pass # or indeed don't pass and complain instead
2009-07-01 19:53:30 +02:00
self . allStreets = [ ' ANTES ' , ' THIRD ' , ' FOURTH ' , ' FIFTH ' , ' SIXTH ' , ' SEVENTH ' ]
self . communityStreets = [ ]
self . actionStreets = [ ' ANTES ' , ' THIRD ' , ' FOURTH ' , ' FIFTH ' , ' SIXTH ' , ' SEVENTH ' ]
2009-02-27 19:42:53 +01:00
self . streetList = [ ' ANTES ' , ' THIRD ' , ' FOURTH ' , ' FIFTH ' , ' SIXTH ' , ' SEVENTH ' ] # a list of the observed street names in order
2009-07-16 03:22:07 +02:00
self . holeStreets = [ ' THIRD ' , ' FOURTH ' , ' FIFTH ' , ' SIXTH ' , ' SEVENTH ' ]
2009-03-02 00:22:47 +01:00
Hand . __init__ ( self , sitename , gametype , handText )
2009-03-06 19:10:04 +01:00
self . sb = gametype [ ' sb ' ]
self . bb = gametype [ ' bb ' ]
2009-03-02 22:48:30 +01:00
#Populate the StudHand
#Generally, we call a 'read' method here, which gets the info according to the particular filter (hhc)
# which then invokes a 'addXXX' callback
2009-03-14 15:01:40 +01:00
if builtFrom == " HHC " :
hhc . readHandInfo ( self )
hhc . readPlayerStacks ( self )
hhc . compilePlayerRegexs ( self )
hhc . markStreets ( self )
hhc . readAntes ( self )
hhc . readBringIn ( self )
2009-07-13 06:37:51 +02:00
hhc . readHeroCards ( self )
2009-03-14 15:01:40 +01:00
# Read actions in street order
for street in self . streetList :
if self . streets [ street ] :
logging . debug ( street )
logging . debug ( self . streets [ street ] )
hhc . readAction ( self , street )
hhc . readCollectPot ( self )
2009-07-04 20:35:20 +02:00
hhc . readShownCards ( self ) # not done yet
2009-03-14 15:01:40 +01:00
self . totalPot ( ) # finalise it (total the pot)
hhc . getRake ( self )
elif builtFrom == " DB " :
self . select ( " dummy " ) # Will need a handId
2009-03-02 00:22:47 +01:00
2009-07-13 06:37:51 +02:00
def addShownCards ( self , cards , player , shown = True , mucked = False , dealt = False ) :
if player == self . hero : # we have hero's cards just update shown/mucked
if shown : self . shown . add ( player )
if mucked : self . mucked . add ( player )
else :
self . addHoleCards ( ' THIRD ' , player , open = [ cards [ 2 ] ] , closed = cards [ 0 : 2 ] , shown = shown , mucked = mucked )
2009-07-16 03:22:07 +02:00
self . addHoleCards ( ' FOURTH ' , player , open = [ cards [ 3 ] ] , closed = [ cards [ 2 ] ] , shown = shown , mucked = mucked )
self . addHoleCards ( ' FIFTH ' , player , open = [ cards [ 4 ] ] , closed = cards [ 2 : 4 ] , shown = shown , mucked = mucked )
self . addHoleCards ( ' SIXTH ' , player , open = [ cards [ 5 ] ] , closed = cards [ 2 : 5 ] , shown = shown , mucked = mucked )
2009-07-13 06:37:51 +02:00
self . addHoleCards ( ' SEVENTH ' , player , open = [ ] , closed = [ cards [ 6 ] ] , shown = shown , mucked = mucked )
2009-03-02 22:48:30 +01:00
def addPlayerCards ( self , player , street , open = [ ] , closed = [ ] ) :
""" \
Assigns observed cards to a player .
player ( string ) name of player
street ( string ) the street name ( in streetList )
open list of card bigrams e . g . [ ' 2h ' , ' Jc ' ] , dealt face up
closed likewise , but known only to player
"""
logging . debug ( " addPlayerCards %s , o %s x %s " % ( player , open , closed ) )
try :
self . checkPlayerExists ( player )
2009-07-01 19:53:30 +02:00
self . holecards [ street ] [ player ] = ( open , closed )
2009-03-02 22:48:30 +01:00
except FpdbParseError , e :
print " [ERROR] Tried to add holecards for unknown player: %s " % ( player , )
2009-03-11 17:51:58 +01:00
# TODO: def addComplete(self, player, amount):
def addComplete ( self , street , player , amountTo ) :
# assert street=='THIRD'
# This needs to be called instead of addRaiseTo, and it needs to take account of self.lastBet['THIRD'] to determine the raise-by size
""" \
Add a complete on [ street ] by [ player ] to [ amountTo ]
"""
2009-03-11 19:40:17 +01:00
logging . debug ( " %s %s completes %s " % ( street , player , amountTo ) )
2009-03-11 17:51:58 +01:00
self . checkPlayerExists ( player )
Bp = self . lastBet [ ' THIRD ' ]
Bc = reduce ( operator . add , self . bets [ street ] [ player ] , 0 )
Rt = Decimal ( amountTo )
C = Bp - Bc
Rb = Rt - C
self . _addRaise ( street , player , C , Rb , Rt )
#~ self.bets[street][player].append(C + Rb)
#~ self.stacks[player] -= (C + Rb)
#~ act = (player, 'raises', Rb, Rt, C, self.stacks[player]==0)
#~ self.actions[street].append(act)
#~ self.lastBet[street] = Rt # TODO check this is correct
#~ self.pot.addMoney(player, C+Rb)
2009-03-02 22:48:30 +01:00
def addBringIn ( self , player , bringin ) :
2009-03-02 00:22:47 +01:00
if player is not None :
2009-03-02 22:48:30 +01:00
logging . debug ( " Bringin: %s , %s " % ( player , bringin ) )
self . bets [ ' THIRD ' ] [ player ] . append ( Decimal ( bringin ) )
self . stacks [ player ] - = Decimal ( bringin )
2009-03-11 17:51:58 +01:00
act = ( player , ' bringin ' , bringin , self . stacks [ player ] == 0 )
2009-03-02 00:22:47 +01:00
self . actions [ ' THIRD ' ] . append ( act )
2009-03-11 17:51:58 +01:00
self . lastBet [ ' THIRD ' ] = Decimal ( bringin )
2009-03-02 22:48:30 +01:00
self . pot . addMoney ( player , Decimal ( bringin ) )
2009-07-04 20:35:20 +02:00
2009-02-27 19:42:53 +01:00
2009-03-02 22:48:30 +01:00
def writeHand ( self , fh = sys . __stdout__ ) :
2009-02-25 13:34:05 +01:00
# PokerStars format.
2009-07-07 19:48:43 +02:00
2009-07-15 17:50:27 +02:00
super ( StudHand , self ) . writeHand ( fh )
2009-02-25 13:34:05 +01:00
players_who_post_antes = set ( [ x [ 0 ] for x in self . actions [ ' ANTES ' ] ] )
for player in [ x for x in self . players if x [ 1 ] in players_who_post_antes ] :
#Only print stacks of players who do something preflop
2009-07-16 05:40:07 +02:00
print >> fh , _ ( " Seat %s : %s ( %s %s in chips) " % ( player [ 0 ] , player [ 1 ] , self . sym , player [ 2 ] ) )
2009-02-25 13:34:05 +01:00
2009-02-25 16:45:46 +01:00
if ' ANTES ' in self . actions :
for act in self . actions [ ' ANTES ' ] :
2009-07-16 05:04:16 +02:00
print >> fh , _ ( " %s : posts the ante %s %s " % ( act [ 0 ] , self . sym , act [ 3 ] ) )
2009-02-25 16:45:46 +01:00
2009-02-25 13:34:05 +01:00
if ' THIRD ' in self . actions :
2009-03-11 17:51:58 +01:00
dealt = 0
#~ print >>fh, _("*** 3RD STREET ***")
2009-03-02 22:48:30 +01:00
for player in [ x [ 1 ] for x in self . players if x [ 1 ] in players_who_post_antes ] :
2009-07-01 19:53:30 +02:00
if self . holecards [ ' THIRD ' ] . has_key ( player ) :
( open , closed ) = self . holecards [ ' THIRD ' ] [ player ]
2009-03-11 17:51:58 +01:00
dealt + = 1
if dealt == 1 :
print >> fh , _ ( " *** 3RD STREET *** " )
2009-07-16 03:22:07 +02:00
# print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(closed) + "] " if closed else " ", "[" + " ".join(open) + "]" if open else "")
print >> fh , self . writeHoleCards ( ' THIRD ' , player )
2009-02-25 13:34:05 +01:00
for act in self . actions [ ' THIRD ' ] :
2009-02-25 17:23:46 +01:00
#FIXME: Need some logic here for bringin vs completes
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-02-25 13:34:05 +01:00
if ' FOURTH ' in self . actions :
2009-03-11 17:51:58 +01:00
dealt = 0
#~ print >>fh, _("*** 4TH STREET ***")
for player in [ x [ 1 ] for x in self . players if x [ 1 ] in players_who_post_antes ] :
2009-07-01 19:53:30 +02:00
if player in self . holecards [ ' FOURTH ' ] :
2009-03-11 17:51:58 +01:00
dealt + = 1
if dealt == 1 :
print >> fh , _ ( " *** 4TH STREET *** " )
2009-07-16 03:22:07 +02:00
print >> fh , self . writeHoleCards ( ' FOURTH ' , player )
2009-02-25 13:34:05 +01:00
for act in self . actions [ ' FOURTH ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-02-25 13:34:05 +01:00
if ' FIFTH ' in self . actions :
2009-03-11 17:51:58 +01:00
dealt = 0
#~ print >>fh, _("*** 5TH STREET ***")
for player in [ x [ 1 ] for x in self . players if x [ 1 ] in players_who_post_antes ] :
2009-07-01 19:53:30 +02:00
if self . holecards [ ' FIFTH ' ] . has_key ( player ) :
2009-03-11 17:51:58 +01:00
dealt + = 1
if dealt == 1 :
print >> fh , _ ( " *** 5TH STREET *** " )
2009-07-16 03:22:07 +02:00
print >> fh , self . writeHoleCards ( ' FIFTH ' , player )
2009-02-25 13:34:05 +01:00
for act in self . actions [ ' FIFTH ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-02-25 13:34:05 +01:00
if ' SIXTH ' in self . actions :
2009-03-11 17:51:58 +01:00
dealt = 0
#~ print >>fh, _("*** 6TH STREET ***")
for player in [ x [ 1 ] for x in self . players if x [ 1 ] in players_who_post_antes ] :
2009-07-01 19:53:30 +02:00
if self . holecards [ ' SIXTH ' ] . has_key ( player ) :
2009-03-11 17:51:58 +01:00
dealt + = 1
if dealt == 1 :
print >> fh , _ ( " *** 6TH STREET *** " )
2009-07-16 03:22:07 +02:00
print >> fh , self . writeHoleCards ( ' SIXTH ' , player )
2009-02-25 13:34:05 +01:00
for act in self . actions [ ' SIXTH ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-02-25 13:34:05 +01:00
if ' SEVENTH ' in self . actions :
2009-03-11 17:51:58 +01:00
# OK. It's possible that they're all in at an earlier street, but only closed cards are dealt.
# Then we have no 'dealt to' lines, no action lines, but still 7th street should appear.
# The only way I can see to know whether to print this line is by knowing the state of the hand
# i.e. are all but one players folded; is there an allin showdown; and all that.
2009-07-16 03:22:07 +02:00
print >> fh , _ ( " *** RIVER *** " )
2009-03-11 17:51:58 +01:00
for player in [ x [ 1 ] for x in self . players if x [ 1 ] in players_who_post_antes ] :
2009-07-01 19:53:30 +02:00
if self . holecards [ ' SEVENTH ' ] . has_key ( player ) :
2009-07-16 03:22:07 +02:00
if self . writeHoleCards ( ' SEVENTH ' , player ) :
print >> fh , self . writeHoleCards ( ' SEVENTH ' , player )
2009-02-25 13:34:05 +01:00
for act in self . actions [ ' SEVENTH ' ] :
2009-06-19 08:21:35 +02:00
print >> fh , self . actionString ( act )
2009-02-25 13:34:05 +01:00
#Some sites don't have a showdown section so we have to figure out if there should be one
# The logic for a showdown is: at the end of river action there are at least two players in the hand
# we probably don't need a showdown section in pseudo stars format for our filtering purposes
if ' SHOWDOWN ' in self . actions :
print >> fh , _ ( " *** SHOW DOWN *** " )
2009-03-04 15:29:13 +01:00
# TODO: print showdown lines.
2009-02-25 13:34:05 +01:00
# Current PS format has the lines:
# Uncalled bet ($111.25) returned to s0rrow
# s0rrow collected $5.15 from side pot
# stervels: shows [Ks Qs] (two pair, Kings and Queens)
# stervels collected $45.35 from main pot
# Immediately before the summary.
# The current importer uses those lines for importing winning rather than the summary
for name in self . pot . returned :
2009-07-16 05:04:16 +02:00
print >> fh , _ ( " Uncalled bet ( %s %s ) returned to %s " % ( self . sym , self . pot . returned [ name ] , name ) )
2009-02-25 13:34:05 +01:00
for entry in self . collected :
2009-07-16 05:04:16 +02:00
print >> fh , _ ( " %s collected %s %s from x pot " % ( entry [ 0 ] , self . sym , entry [ 1 ] ) )
2009-02-25 13:34:05 +01:00
print >> fh , _ ( " *** SUMMARY *** " )
2009-07-16 05:04:16 +02:00
print >> fh , " %s | Rake %s %.2f " % ( self . pot , self . sym , self . rake )
2009-07-16 05:40:07 +02:00
# TODO: side pots
2009-02-25 13:34:05 +01:00
board = [ ]
for s in self . board . values ( ) :
board + = s
if board : # sometimes hand ends preflop without a board
print >> fh , _ ( " Board [ %s ] " % ( " " . join ( board ) ) )
for player in [ x for x in self . players if x [ 1 ] in players_who_post_antes ] :
seatnum = player [ 0 ]
name = player [ 1 ]
if name in self . collectees and name in self . shown :
2009-07-16 05:04:16 +02:00
print >> fh , _ ( " Seat %d : %s showed [ %s ] and won ( %s %s ) " % ( seatnum , name , self . join_holecards ( name ) , self . sym , self . collectees [ name ] ) )
2009-02-25 13:34:05 +01:00
elif name in self . collectees :
2009-07-16 05:04:16 +02:00
print >> fh , _ ( " Seat %d : %s collected ( %s %s ) " % ( seatnum , name , self . sym , self . collectees [ name ] ) )
2008-12-16 22:08:10 +01:00
elif name in self . shown :
2009-07-04 21:19:46 +02:00
print >> fh , _ ( " Seat %d : %s showed [ %s ] " % ( seatnum , name , self . join_holecards ( name ) ) )
elif name in self . mucked :
print >> fh , _ ( " Seat %d : %s mucked [ %s ] " % ( seatnum , name , self . join_holecards ( name ) ) )
2008-12-16 22:08:10 +01:00
elif name in self . folded :
2008-12-16 00:56:19 +01:00
print >> fh , _ ( " Seat %d : %s folded " % ( seatnum , name ) )
2008-12-12 15:29:45 +01:00
else :
2008-12-16 00:56:19 +01:00
print >> fh , _ ( " Seat %d : %s mucked " % ( seatnum , name ) )
2008-12-12 15:29:45 +01:00
2008-12-16 00:56:19 +01:00
print >> fh , " \n \n "
2008-12-12 15:29:45 +01:00
2009-07-16 03:22:07 +02:00
def writeHoleCards ( self , street , player ) :
hc = " Dealt to %s [ " % player
if street == ' THIRD ' :
if player == self . hero :
return hc + " " . join ( self . holecards [ street ] [ player ] [ 1 ] ) + " " + " " . join ( self . holecards [ street ] [ player ] [ 0 ] ) + ' ] '
else :
return hc + " " . join ( self . holecards [ street ] [ player ] [ 0 ] ) + ' ] '
if street == ' SEVENTH ' and player != self . hero : return # only write 7th st line for hero, LDO
2009-07-16 03:46:45 +02:00
return hc + " " . join ( self . holecards [ street ] [ player ] [ 1 ] ) + " ] [ " + " " . join ( self . holecards [ street ] [ player ] [ 0 ] ) + " ] "
2009-07-16 03:22:07 +02:00
2009-07-04 21:19:46 +02:00
def join_holecards ( self , player ) :
holecards = [ ]
for street in self . holeStreets :
if self . holecards [ street ] . has_key ( player ) :
2009-07-16 04:11:23 +02:00
if street == ' THIRD ' :
holecards = holecards + self . holecards [ street ] [ player ] [ 1 ] + self . holecards [ street ] [ player ] [ 0 ]
elif street == ' SEVENTH ' :
if player == self . hero :
holecards = holecards + self . holecards [ street ] [ player ] [ 0 ]
else :
holecards = holecards + self . holecards [ street ] [ player ] [ 1 ]
else :
holecards = holecards + self . holecards [ street ] [ player ] [ 0 ]
2009-07-04 21:19:46 +02:00
return " " . join ( holecards )
2008-12-19 04:01:45 +01:00
class Pot ( object ) :
2008-12-20 17:48:25 +01:00
def __init__ ( self ) :
self . contenders = set ( )
self . committed = { }
self . total = None
2009-02-21 13:37:47 +01:00
self . returned = { }
2009-07-16 18:13:24 +02:00
self . sym = u ' $ ' # this is the default currency symbol
def setSym ( self , sym ) :
self . sym = sym
2008-12-20 17:48:25 +01:00
def addPlayer ( self , player ) :
self . committed [ player ] = Decimal ( 0 )
2008-12-19 04:01:45 +01:00
def addFold ( self , player ) :
2008-12-20 17:48:25 +01:00
# addFold must be called when a player folds
self . contenders . discard ( player )
2008-12-19 04:01:45 +01:00
def addMoney ( self , player , amount ) :
2008-12-20 17:48:25 +01:00
# addMoney must be called for any actions that put money in the pot, in the order they occur
self . contenders . add ( player )
2008-12-19 04:01:45 +01:00
self . committed [ player ] + = amount
2008-12-20 17:48:25 +01:00
def end ( self ) :
2008-12-19 04:01:45 +01:00
self . total = sum ( self . committed . values ( ) )
2008-12-20 17:48:25 +01:00
# Return any uncalled bet.
2008-12-19 04:01:45 +01:00
committed = sorted ( [ ( v , k ) for ( k , v ) in self . committed . items ( ) ] )
lastbet = committed [ - 1 ] [ 0 ] - committed [ - 2 ] [ 0 ]
if lastbet > 0 : # uncalled
returnto = committed [ - 1 ] [ 1 ]
2009-02-21 13:37:47 +01:00
#print "DEBUG: returning %f to %s" % (lastbet, returnto)
2008-12-19 04:01:45 +01:00
self . total - = lastbet
self . committed [ returnto ] - = lastbet
2009-02-21 13:37:47 +01:00
self . returned [ returnto ] = lastbet
2009-02-20 09:22:58 +01:00
2008-12-20 17:48:25 +01:00
# Work out side pots
2008-12-19 04:01:45 +01:00
commitsall = sorted ( [ ( v , k ) for ( k , v ) in self . committed . items ( ) if v > 0 ] )
2009-02-20 09:22:58 +01:00
2008-12-20 17:48:25 +01:00
self . pots = [ ]
2008-12-19 04:01:45 +01:00
while len ( commitsall ) > 0 :
commitslive = [ ( v , k ) for ( v , k ) in commitsall if k in self . contenders ]
v1 = commitslive [ 0 ] [ 0 ]
2008-12-20 17:48:25 +01:00
self . pots + = [ sum ( [ min ( v , v1 ) for ( v , k ) in commitsall ] ) ]
2008-12-19 04:01:45 +01:00
commitsall = [ ( ( v - v1 ) , k ) for ( v , k ) in commitsall if v - v1 > 0 ]
# TODO: I think rake gets taken out of the pots.
# so it goes:
# total pot x. main pot y, side pot z. | rake r
# and y+z+r = x
# for example:
# Total pot $124.30 Main pot $98.90. Side pot $23.40. | Rake $2
2008-12-20 17:48:25 +01:00
def __str__ ( self ) :
if self . total is None :
print " call Pot.end() before printing pot total "
# NB if I'm sure end() is idempotent, call it here.
raise FpdbParseError
2009-07-16 18:13:24 +02:00
# TODO: This really neeads to be a loop to handle multiple side pots
2008-12-20 17:48:25 +01:00
if len ( self . pots ) == 1 : # (only use Total pot)
2009-07-16 18:13:24 +02:00
return " Total pot %s %.2f " % ( self . sym , self . total , )
2008-12-20 17:48:25 +01:00
elif len ( self . pots ) == 2 :
2009-07-16 18:13:24 +02:00
return " Total pot %s %.2f Main pot %s %.2f . Side pot %s % 2.f. " % ( self . sym , self . total , self . sym , self . pots [ 0 ] , self . sym , self . pots [ 1 ] )
2008-12-20 17:48:25 +01:00
elif len ( self . pots ) == 3 :
2009-07-16 18:13:24 +02:00
return " Total pot %s %.2f Main pot $ %.2f . Side pot-1 %s %2.2f . Side pot-2 %s %.2f . " % ( self . sym , self . total , self . sym , self . pots [ 0 ] , self . sym , self . pots [ 1 ] , self . sym , self . pots [ 2 ] )
2009-02-21 14:31:57 +01:00
elif len ( self . pots ) == 0 :
# no small blind and walk in bb (hopefully)
2009-07-16 18:13:24 +02:00
return " Total pot %s %.2f " % ( self . sym , self . total , )
2008-12-19 04:01:45 +01:00
else :
2009-06-07 22:57:13 +02:00
return ( " too many pots.. no small blind and walk in bb?. self.pots: %s " % ( self . pots ) )
2008-12-20 23:52:47 +01:00
# I don't know stars format for a walk in the bb when sb doesn't post.
# The thing to do here is raise a Hand error like fpdb import does and file it into errors.txt
2009-06-07 22:57:13 +02:00
def assemble ( cnxn , handid ) :
c = cnxn . cursor ( )
2009-06-19 08:21:35 +02:00
# We need at least sitename, gametype, handid
# for the Hand.__init__
2009-06-07 22:57:13 +02:00
c . execute ( """
select
s . name ,
g . category ,
g . base ,
g . type ,
g . limitType ,
g . hilo ,
2009-06-15 23:30:58 +02:00
round ( g . smallBlind / 100.0 , 2 ) ,
round ( g . bigBlind / 100.0 , 2 ) ,
round ( g . smallBet / 100.0 , 2 ) ,
round ( g . bigBet / 100.0 , 2 ) ,
2009-06-07 22:57:13 +02:00
s . currency ,
2009-06-19 08:21:35 +02:00
h . boardcard1 ,
h . boardcard2 ,
h . boardcard3 ,
h . boardcard4 ,
h . boardcard5
2009-06-07 22:57:13 +02:00
from
hands as h ,
sites as s ,
gametypes as g ,
handsplayers as hp ,
players as p
where
h . id = % ( handid ) s
and g . id = h . gametypeid
and hp . handid = h . id
and p . id = hp . playerid
and s . id = p . siteid
limit 1 """ , { ' handid ' :handid})
#TODO: siteid should be in hands table - we took the scenic route through players here.
res = c . fetchone ( )
gametype = { ' category ' : res [ 1 ] , ' base ' : res [ 2 ] , ' type ' : res [ 3 ] , ' limitType ' : res [ 4 ] , ' hilo ' : res [ 5 ] , ' sb ' : res [ 6 ] , ' bb ' : res [ 7 ] , ' currency ' : res [ 10 ] }
h = HoldemOmahaHand ( hhc = None , sitename = res [ 0 ] , gametype = gametype , handText = None , builtFrom = " DB " , handid = handid )
2009-06-19 08:21:35 +02:00
cards = map ( Card . valueSuitFromCard , res [ 11 : 16 ] )
if cards [ 0 ] :
2009-06-07 23:44:50 +02:00
h . setCommunityCards ( ' FLOP ' , cards [ 0 : 3 ] )
2009-06-19 08:21:35 +02:00
if cards [ 3 ] :
2009-06-15 23:21:27 +02:00
h . setCommunityCards ( ' TURN ' , [ cards [ 3 ] ] )
2009-06-19 08:21:35 +02:00
if cards [ 4 ] :
2009-06-15 23:21:27 +02:00
h . setCommunityCards ( ' RIVER ' , [ cards [ 4 ] ] )
2009-06-07 22:57:13 +02:00
#[Card.valueSuitFromCard(x) for x in cards]
# HandInfo : HID, TABLE
# BUTTON - why is this treated specially in Hand?
# answer: it is written out in hand histories
# still, I think we should record all the active seat positions in a seat_order array
c . execute ( """
SELECT
h . sitehandno as hid ,
h . tablename as table ,
h . handstart as starttime
FROM
hands as h
WHERE h . id = % ( handid ) s
""" , { ' handid ' :handid})
res = c . fetchone ( )
h . handid = res [ 0 ]
h . tablename = res [ 1 ]
h . starttime = res [ 2 ] # automatically a datetime
# PlayerStacks
c . execute ( """
SELECT
hp . seatno ,
2009-06-15 23:30:58 +02:00
round ( hp . winnings / 100.0 , 2 ) as winnings ,
2009-06-07 22:57:13 +02:00
p . name ,
round ( hp . startcash / 100.0 , 2 ) as chips ,
2009-06-19 08:21:35 +02:00
hp . card1 , hp . card2 ,
hp . position
2009-06-07 22:57:13 +02:00
FROM
handsplayers as hp ,
players as p
WHERE
hp . handid = % ( handid ) s
and p . id = hp . playerid
""" , { ' handid ' :handid})
2009-06-19 08:21:35 +02:00
for ( seat , winnings , name , chips , card1 , card2 , position ) in c . fetchall ( ) :
2009-06-07 22:57:13 +02:00
h . addPlayer ( seat , name , chips )
2009-06-19 08:21:35 +02:00
if card1 and card2 :
h . addHoleCards ( map ( Card . valueSuitFromCard , ( card1 , card2 ) ) , name , dealt = True )
2009-06-15 23:21:27 +02:00
if winnings > 0 :
h . addCollectPot ( name , winnings )
2009-06-19 08:21:35 +02:00
if position == ' B ' :
h . buttonpos = seat
2009-06-07 22:57:13 +02:00
2009-06-19 08:21:35 +02:00
2009-06-07 22:57:13 +02:00
# actions
c . execute ( """
SELECT
( ha . street , ha . actionno ) as actnum ,
p . name ,
ha . street ,
ha . action ,
ha . allin ,
2009-06-15 23:30:58 +02:00
round ( ha . amount / 100.0 , 2 )
2009-06-07 22:57:13 +02:00
FROM
handsplayers as hp ,
handsactions as ha ,
players as p
WHERE
hp . handid = % ( handid ) s
and ha . handsplayerid = hp . id
and p . id = hp . playerid
ORDER BY
ha . street , ha . actionno
""" , { ' handid ' :handid})
res = c . fetchall ( )
for ( actnum , player , streetnum , act , allin , amount ) in res :
act = act . strip ( )
2009-06-19 08:21:35 +02:00
street = h . allStreets [ streetnum + 1 ]
2009-06-07 22:57:13 +02:00
if act == u ' blind ' :
h . addBlind ( player , ' big blind ' , amount )
# TODO: The type of blind is not recorded in the DB.
# TODO: preflop street name anomalies in Hand
elif act == u ' fold ' :
h . addFold ( street , player )
elif act == u ' call ' :
h . addCall ( street , player , amount )
elif act == u ' bet ' :
h . addBet ( street , player , amount )
elif act == u ' check ' :
h . addCheck ( street , player )
elif act == u ' unbet ' :
pass
else :
print act , player , streetnum , allin , amount
# TODO : other actions
2009-06-15 23:21:27 +02:00
2009-06-07 22:57:13 +02:00
#hhc.readShowdownActions(self)
#hc.readShownCards(self)
h . totalPot ( )
h . rake = h . totalpot - h . totalcollected
return h