Coverage for BetfairToFpdb.py: 0%

140 statements  

« 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 -*- 

3# 

4# Copyright 2008-2011, Carl Gherardi 

5#  

6# This program is free software; you can redistribute it and/or modify 

7# it under the terms of the GNU General Public License as published by 

8# the Free Software Foundation; either version 2 of the License, or 

9# (at your option) any later version. 

10#  

11# This program is distributed in the hope that it will be useful, 

12# but WITHOUT ANY WARRANTY; without even the implied warranty of 

13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

14# GNU General Public License for more details. 

15#  

16# You should have received a copy of the GNU General Public License 

17# along with this program; if not, write to the Free Software 

18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

19######################################################################## 

20 

21 

22#import L10n 

23#_ = L10n.get_translation() 

24 

25import sys 

26from HandHistoryConverter import * 

27 

28# Betfair HH format 

29 

30class Betfair(HandHistoryConverter): 

31 

32 sitename = 'Betfair' 

33 filetype = "text" 

34 codepage = "cp1252" 

35 siteId = 7 # Needs to match id entry in Sites database 

36 

37 # Static regexes 

38 re_GameInfo = re.compile("^(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAME>(Texas Hold\'em|Omaha Hi|Omaha|Razz))", re.MULTILINE) 

39 re_Identify = re.compile(u'\*{5}\sBetfair\sPoker\sHand\sHistory\sfor\sGame\s\d+\s') 

40 re_SplitHands = re.compile(r'\n\n+') 

41 re_HandInfo = re.compile("\*\*\*\*\* Betfair Poker Hand History for Game (?P<HID>[0-9]+) \*\*\*\*\*\n(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>(Texas Hold\'em|Omaha|Razz)) - (?P<DATETIME>[a-zA-Z]+, [a-zA-Z]+ \d+, \d\d:\d\d:\d\d GMT \d\d\d\d)\nTable (?P<TABLE>[ a-zA-Z0-9]+) \d-max \(Real Money\)\nSeat (?P<BUTTON>[0-9]+)", re.MULTILINE) 

42 re_Button = re.compile(r"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE) 

43 re_PlayerInfo = re.compile("Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*)\s\(\s(\$(?P<CASH>[.0-9]+)) \)") 

44 re_Board = re.compile(r"\[ (?P<CARDS>.+) \]") 

45 

46 

47 def compilePlayerRegexs(self, hand): 

48 players = set([player[1] for player in hand.players]) 

49 if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' 

50 # we need to recompile the player regexs. 

51 self.compiledPlayers = players 

52 player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")" 

53 log.debug("player_re: " + player_re) 

54 self.re_PostSB = re.compile("^%s posts small blind \[\$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE) 

55 self.re_PostBB = re.compile("^%s posts big blind \[\$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE) 

56 self.re_Antes = re.compile("^%s antes asdf sadf sadf" % player_re, re.MULTILINE) 

57 self.re_BringIn = re.compile("^%s antes asdf sadf sadf" % player_re, re.MULTILINE) 

58 self.re_PostBoth = re.compile("^%s posts small \& big blinds \[\$?(?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE) 

59 self.re_HeroCards = re.compile("^Dealt to %s \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE) 

60 self.re_Action = re.compile("^%s (?P<ATYPE>bets|checks|raises to|raises|calls|folds)(\s\[\$(?P<BET>[.\d]+)\])?" % player_re, re.MULTILINE) 

61 self.re_ShowdownAction = re.compile("^%s shows \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE) 

62 self.re_CollectPot = re.compile("^%s wins \$(?P<POT>[.\d]+) (.*?\[ (?P<CARDS>.*?) \])?" % player_re, re.MULTILINE) 

63 self.re_SitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE) 

64 self.re_ShownCards = re.compile(r"%s (?P<SEAT>[0-9]+) (?P<CARDS>adsfasdf)" % player_re, re.MULTILINE) 

65 

66 def readSupportedGames(self): 

67 return [["ring", "hold", "nl"], 

68 ["ring", "hold", "pl"] 

69 ] 

70 

71 def determineGameType(self, handText): 

72 info = {'type':'ring'} 

73 

74 m = self.re_GameInfo.search(handText) 

75 if not m: 

76 tmp = handText[0:200] 

77 log.error(("BetfairToFpdb.determineGameType: '%s'") % tmp) 

78 raise FpdbParseError 

79 

80 mg = m.groupdict() 

81 

82 # translations from captured groups to our info strings 

83 limits = { 'NL':'nl', 'PL':'pl', 'Limit':'fl' } 

84 games = { # base, category 

85 "Texas Hold'em" : ('hold','holdem'), 

86 'Omaha Hi' : ('hold','omahahi'), 

87 'Omaha' : ('hold','omahahi'), 

88 'Razz' : ('stud','razz'), 

89 '7 Card Stud' : ('stud','studhi') 

90 } 

91 currencies = { u' €':'EUR', '$':'USD', '':'T$' } 

92 if 'LIMIT' in mg: 

93 info['limitType'] = limits[mg['LIMIT']] 

94 if 'GAME' in mg: 

95 (info['base'], info['category']) = games[mg['GAME']] 

96 if 'SB' in mg: 

97 info['sb'] = mg['SB'] 

98 if 'BB' in mg: 

99 info['bb'] = mg['BB'] 

100 if 'CURRENCY' in mg: 

101 info['currency'] = currencies[mg['CURRENCY']] 

102 

103 return info 

104 

105 def readHandInfo(self, hand): 

106 m = self.re_HandInfo.search(hand.handText) 

107 if(m == None): 

108 tmp = hand.handText[0:200] 

109 log.error(("BetfairToFpdb.readHandInfo: '%s'") % tmp) 

110 raise FpdbParseError 

111 log.debug("HID %s, Table %s" % (m.group('HID'), m.group('TABLE'))) 

112 hand.handid = m.group('HID') 

113 hand.tablename = m.group('TABLE') 

114 hand.startTime = datetime.datetime.strptime(m.group('DATETIME'), "%A, %B %d, %H:%M:%S GMT %Y") 

115 #hand.buttonpos = int(m.group('BUTTON')) 

116 

117 def readPlayerStacks(self, hand): 

118 m = self.re_PlayerInfo.finditer(hand.handText) 

119 for a in m: 

120 hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH')) 

121 

122 #Shouldn't really dip into the Hand object, but i've no idea how to tell the length of iter m 

123 if len(hand.players) < 2: 

124 log.info(("Less than 2 players found in hand %s.") % hand.handid) 

125 

126 def markStreets(self, hand): 

127 m = re.search(r"\*\* Dealing down cards \*\*(?P<PREFLOP>.+(?=\*\* Dealing Flop \*\*)|.+)" 

128 r"(\*\* Dealing Flop \*\*(?P<FLOP> \[ \S\S, \S\S, \S\S \].+(?=\*\* Dealing Turn \*\*)|.+))?" 

129 r"(\*\* Dealing Turn \*\*(?P<TURN> \[ \S\S \].+(?=\*\* Dealing River \*\*)|.+))?" 

130 r"(\*\* Dealing River \*\*(?P<RIVER> \[ \S\S \].+))?", hand.handText,re.DOTALL) 

131 

132 hand.addStreets(m) 

133 

134 

135 def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand 

136 if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP) 

137 m = self.re_Board.search(hand.streets[street]) 

138 hand.setCommunityCards(street, m.group('CARDS').split(', ')) 

139 

140 def readBlinds(self, hand): 

141 try: 

142 m = self.re_PostSB.search(hand.handText) 

143 hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) 

144 except: # no small blind 

145 hand.addBlind(None, None, None) 

146 for a in self.re_PostBB.finditer(hand.handText): 

147 hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) 

148 for a in self.re_PostBoth.finditer(hand.handText): 

149 hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB')) 

150 

151 def readAntes(self, hand): 

152 log.debug("reading antes") 

153 m = self.re_Antes.finditer(hand.handText) 

154 for player in m: 

155 log.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE'))) 

156 hand.addAnte(player.group('PNAME'), player.group('ANTE')) 

157 

158 def readBringIn(self, hand): 

159 m = self.re_BringIn.search(hand.handText,re.DOTALL) 

160 if m: 

161 log.debug(("Player bringing in: %s for %s") % (m.group('PNAME'), m.group('BRINGIN'))) 

162 hand.addBringIn(m.group('PNAME'), m.group('BRINGIN')) 

163 else: 

164 log.warning(("No bringin found")) 

165 

166 def readButton(self, hand): 

167 hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON')) 

168 

169 def readHoleCards(self, hand): 

170 # streets PREFLOP, PREDRAW, and THIRD are special cases beacause 

171 # we need to grab hero's cards 

172 for street in ('PREFLOP', 'DEAL'): 

173 if street in list(hand.streets.keys()): 

174 m = self.re_HeroCards.finditer(hand.streets[street]) 

175 for found in m: 

176 hand.hero = found.group('PNAME') 

177 newcards = [c.strip() for c in found.group('CARDS').split(',')] 

178 hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True) 

179 

180 def readStudPlayerCards(self, hand, street): 

181 # balh blah blah 

182 pass 

183 

184 def readAction(self, hand, street): 

185 m = self.re_Action.finditer(hand.streets[street]) 

186 for action in m: 

187 if action.group('ATYPE') == 'folds': 

188 hand.addFold( street, action.group('PNAME')) 

189 elif action.group('ATYPE') == 'checks': 

190 hand.addCheck( street, action.group('PNAME')) 

191 elif action.group('ATYPE') == 'calls': 

192 hand.addCall( street, action.group('PNAME'), action.group('BET') ) 

193 elif action.group('ATYPE') == 'bets': 

194 hand.addBet( street, action.group('PNAME'), action.group('BET') ) 

195 elif action.group('ATYPE') == 'raises to': 

196 hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') ) 

197 else: 

198 log.debug(("DEBUG:") + " " + ("Unimplemented %s: '%s' '%s'") % ("readAction", action.group('PNAME'), action.group('ATYPE'))) 

199 

200 

201 def readShowdownActions(self, hand): 

202 for shows in self.re_ShowdownAction.finditer(hand.handText): 

203 cards = shows.group('CARDS') 

204 cards = cards.split(', ') 

205 hand.addShownCards(cards, shows.group('PNAME')) 

206 

207 def readCollectPot(self,hand): 

208 for m in self.re_CollectPot.finditer(hand.handText): 

209 hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT')) 

210 

211 def readShownCards(self,hand): 

212 for m in self.re_ShownCards.finditer(hand.handText): 

213 if m.group('CARDS') is not None: 

214 cards = m.group('CARDS') 

215 cards = cards.split(', ') 

216 hand.addShownCards(cards=None, player=m.group('PNAME'), holeandboard=cards)