Merge branch 'master' of git://git.assembla.com/fpdboz.git
This commit is contained in:
commit
8673cc3437
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# Copyright 2008, Carl Gherardi
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright 2010, Matthew Boss
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,93 +19,286 @@
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
|
|
||||||
# Standard Library modules
|
# This code is based heavily on EverleafToFpdb.py, by Carl Gherardi
|
||||||
import Configuration
|
#
|
||||||
import traceback
|
# OUTSTANDING MATTERS
|
||||||
|
#
|
||||||
|
# -- No siteID assigned
|
||||||
|
# -- No support for games other than NL hold 'em cash. Hand histories for other
|
||||||
|
# games required
|
||||||
|
# -- No support for limit hold 'em yet, though this would be easy to add
|
||||||
|
# -- No support for tournaments (see also the last item below)
|
||||||
|
# -- Assumes that the currency of ring games is USD
|
||||||
|
# -- Only works for 'gametype="2"'. What is 'gametype'?
|
||||||
|
# -- Only accepts 'realmoney="true"'
|
||||||
|
# -- A hand's time-stamp does not record seconds past the minute (a
|
||||||
|
# limitation of the history format)
|
||||||
|
# -- No support for a bring-in or for antes (is the latter in fact unnecessary
|
||||||
|
# for hold 'em on Carbon?)
|
||||||
|
# -- hand.maxseats can only be guessed at
|
||||||
|
# -- The last hand in a history file will often be incomplete and is therefore
|
||||||
|
# rejected
|
||||||
|
# -- Is behaviour currently correct when someone shows an uncalled hand?
|
||||||
|
# -- Information may be lost when the hand ID is converted from the native form
|
||||||
|
# xxxxxxxx-yyy(y*) to xxxxxxxxyyy(y*) (in principle this should be stored as
|
||||||
|
# a string, but the database does not support this). Is there a possibility
|
||||||
|
# of collision between hand IDs that ought to be distinct?
|
||||||
|
# -- Cannot parse tables that run it twice (nor is this likely ever to be
|
||||||
|
# possible)
|
||||||
|
# -- Cannot parse hands in which someone is all in in one of the blinds. Until
|
||||||
|
# this is corrected tournaments will be unparseable
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import re
|
import logging
|
||||||
import xml.dom.minidom
|
from HandHistoryConverter import *
|
||||||
from xml.dom.minidom import Node
|
from decimal import Decimal
|
||||||
from HandHistoryConverter import HandHistoryConverter
|
|
||||||
|
|
||||||
# Carbon format looks like:
|
class Carbon(HandHistoryConverter):
|
||||||
|
|
||||||
# 1) <description type="Holdem" stakes="No Limit ($0.25/$0.50)"/>
|
sitename = "Carbon"
|
||||||
# 2) <game id="14902583-5578" starttime="20081006145401" numholecards="2" gametype="2" realmoney="true" data="20081006|Niagara Falls (14902583)|14902583|14902583-5578|false">
|
filetype = "text"
|
||||||
# 3) <players dealer="8">
|
codepage = "cp1252"
|
||||||
# <player seat="3" nickname="PlayerInSeat3" balance="$43.29" dealtin="true" />
|
siteID = 11
|
||||||
# ...
|
|
||||||
# 4) <round id="BLINDS" sequence="1">
|
|
||||||
# <event sequence="1" type="SMALL_BLIND" player="0" amount="0.25"/>
|
|
||||||
# <event sequence="2" type="BIG_BLIND" player="1" amount="0.50"/>
|
|
||||||
# 5) <round id="PREFLOP" sequence="2">
|
|
||||||
# <event sequence="3" type="CALL" player="2" amount="0.50"/>
|
|
||||||
# 6) <round id="POSTFLOP" sequence="3">
|
|
||||||
# <event sequence="16" type="BET" player="3" amount="1.00"/>
|
|
||||||
# ....
|
|
||||||
# <cards type="COMMUNITY" cards="7d,Jd,Jh"/>
|
|
||||||
|
|
||||||
# The full sequence for a NHLE cash game is:
|
# Static regexes
|
||||||
# BLINDS, PREFLOP, POSTFLOP, POSTTURN, POSTRIVER, SHOWDOWN, END_OF_GAME
|
re_SplitHands = re.compile(r'</game>\n+(?=<game)')
|
||||||
# This sequence can be terminated after BLINDS at any time by END_OF_FOLDED_GAME
|
re_TailSplitHands = re.compile(r'(</game>)')
|
||||||
|
re_GameInfo = re.compile(r'<description type="(?P<GAME>[a-zA-Z ]+)" stakes="(?P<LIMIT>[a-zA-Z ]+) \(\$(?P<SB>[.0-9]+)/\$(?P<BB>[.0-9]+)\)"/>', re.MULTILINE)
|
||||||
|
re_HandInfo = re.compile(r'<game id="(?P<HID1>[0-9]+)-(?P<HID2>[0-9]+)" starttime="(?P<DATETIME>[0-9]+)" numholecards="2" gametype="2" realmoney="true" data="[0-9]+\|(?P<TABLE>[^\(]+)', re.MULTILINE)
|
||||||
|
re_Button = re.compile(r'<players dealer="(?P<BUTTON>[0-9]+)">')
|
||||||
|
re_PlayerInfo = re.compile(r'<player seat="(?P<SEAT>[0-9]+)" nickname="(?P<PNAME>.+)" balance="\$(?P<CASH>[.0-9]+)" dealtin="(?P<DEALTIN>(true|false))" />', re.MULTILINE)
|
||||||
|
re_Board = re.compile(r'<cards type="COMMUNITY" cards="(?P<CARDS>[^"]+)"', re.MULTILINE)
|
||||||
|
re_EndOfHand = re.compile(r'<round id="END_OF_GAME"', re.MULTILINE)
|
||||||
|
|
||||||
|
# The following are also static regexes: there is no need to call
|
||||||
|
# compilePlayerRegexes (which does nothing), since players are identified
|
||||||
|
# not by name but by seat number
|
||||||
|
re_PostSB = re.compile(r'<event sequence="[0-9]+" type="(SMALL_BLIND|RETURN_BLIND)" player="(?P<PSEAT>[0-9])" amount="(?P<SB>[.0-9]+)"/>', re.MULTILINE)
|
||||||
|
re_PostBB = re.compile(r'<event sequence="[0-9]+" type="(BIG_BLIND|INITIAL_BLIND)" player="(?P<PSEAT>[0-9])" amount="(?P<BB>[.0-9]+)"/>', re.MULTILINE)
|
||||||
|
re_PostBoth = re.compile(r'<event sequence="[0-9]+" type="(RETURN_BLIND)" player="(?P<PSEAT>[0-9])" amount="(?P<SBBB>[.0-9]+)"/>', re.MULTILINE)
|
||||||
|
#re_Antes = ???
|
||||||
|
#re_BringIn = ???
|
||||||
|
re_HeroCards = re.compile(r'<cards type="HOLE" cards="(?P<CARDS>.+)" player="(?P<PSEAT>[0-9])"', re.MULTILINE)
|
||||||
|
re_Action = re.compile(r'<event sequence="[0-9]+" type="(?P<ATYPE>FOLD|CHECK|CALL|BET|RAISE|ALL_IN|SIT_OUT)" player="(?P<PSEAT>[0-9])"( amount="(?P<BET>[.0-9]+)")?/>', re.MULTILINE)
|
||||||
|
re_ShowdownAction = re.compile(r'<cards type="SHOWN" cards="(?P<CARDS>..,..)" player="(?P<PSEAT>[0-9])"/>', re.MULTILINE)
|
||||||
|
re_CollectPot = re.compile(r'<winner amount="(?P<POT>[.0-9]+)" uncalled="(true|false)" potnumber="[0-9]+" player="(?P<PSEAT>[0-9])"', re.MULTILINE)
|
||||||
|
re_SitsOut = re.compile(r'<event sequence="[0-9]+" type="SIT_OUT" player="(?P<PSEAT>[0-9])"/>', re.MULTILINE)
|
||||||
|
re_ShownCards = re.compile(r'<cards type="(SHOWN|MUCKED)" cards="(?P<CARDS>..,..)" player="(?P<PSEAT>[0-9])"/>', re.MULTILINE)
|
||||||
|
|
||||||
class CarbonPoker(HandHistoryConverter):
|
def compilePlayerRegexs(self, hand):
|
||||||
def __init__(self, config, filename):
|
pass
|
||||||
print "Initialising Carbon Poker converter class"
|
|
||||||
HandHistoryConverter.__init__(self, config, filename, "Carbon") # Call super class init
|
|
||||||
self.setFileType("xml")
|
|
||||||
self.siteId = 4 # Needs to match id entry in Sites database
|
|
||||||
|
|
||||||
def readSupportedGames(self):
|
def playerNameFromSeatNo(self, seatNo, hand):
|
||||||
pass
|
# This special function is required because Carbon Poker records
|
||||||
def determineGameType(self):
|
# actions by seat number, not by the player's name
|
||||||
gametype = []
|
for p in hand.players:
|
||||||
desc_node = self.doc.getElementsByTagName("description")
|
if p[0] == int(seatNo):
|
||||||
#TODO: no examples of non ring type yet
|
return p[1]
|
||||||
gametype = gametype + ["ring"]
|
|
||||||
type = desc_node[0].getAttribute("type")
|
|
||||||
if(type == "Holdem"):
|
|
||||||
gametype = gametype + ["hold"]
|
|
||||||
else:
|
|
||||||
print "Carbon: Unknown gametype: '%s'" % (type)
|
|
||||||
|
|
||||||
stakes = desc_node[0].getAttribute("stakes")
|
def readSupportedGames(self):
|
||||||
#TODO: no examples of anything except nlhe
|
return [["ring", "hold", "nl"],
|
||||||
m = re.match('(?P<LIMIT>No Limit)\s\(\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\)', stakes)
|
["tour", "hold", "nl"]]
|
||||||
|
|
||||||
if(m.group('LIMIT') == "No Limit"):
|
def determineGameType(self, handText):
|
||||||
gametype = gametype + ["nl"]
|
"""return dict with keys/values:
|
||||||
|
'type' in ('ring', 'tour')
|
||||||
|
'limitType' in ('nl', 'cn', 'pl', 'cp', 'fl')
|
||||||
|
'base' in ('hold', 'stud', 'draw')
|
||||||
|
'category' in ('holdem', 'omahahi', omahahilo', 'razz', 'studhi', 'studhilo', 'fivedraw', '27_1draw', '27_3draw', 'badugi')
|
||||||
|
'hilo' in ('h','l','s')
|
||||||
|
'smallBlind' int?
|
||||||
|
'bigBlind' int?
|
||||||
|
'smallBet'
|
||||||
|
'bigBet'
|
||||||
|
'currency' in ('USD', 'EUR', 'T$', <countrycode>)
|
||||||
|
or None if we fail to get the info """
|
||||||
|
|
||||||
gametype = gametype + [self.float2int(m.group('SB'))]
|
m = self.re_GameInfo.search(handText)
|
||||||
gametype = gametype + [self.float2int(m.group('BB'))]
|
if not m:
|
||||||
|
# Information about the game type appears only at the beginning of
|
||||||
|
# a hand history file; hence it is not supplied with the second
|
||||||
|
# and subsequent hands. In these cases we use the value previously
|
||||||
|
# stored.
|
||||||
|
return self.info
|
||||||
|
self.info = {}
|
||||||
|
mg = m.groupdict()
|
||||||
|
|
||||||
return gametype
|
limits = { 'No Limit':'nl', 'Limit':'fl' }
|
||||||
|
games = { # base, category
|
||||||
|
'Holdem' : ('hold','holdem'),
|
||||||
|
'Holdem Tournament' : ('hold','holdem') }
|
||||||
|
|
||||||
def readPlayerStacks(self):
|
if 'LIMIT' in mg:
|
||||||
pass
|
self.info['limitType'] = limits[mg['LIMIT']]
|
||||||
def readBlinds(self):
|
if 'GAME' in mg:
|
||||||
pass
|
(self.info['base'], self.info['category']) = games[mg['GAME']]
|
||||||
def readAction(self):
|
if 'SB' in mg:
|
||||||
pass
|
self.info['sb'] = mg['SB']
|
||||||
|
if 'BB' in mg:
|
||||||
|
self.info['bb'] = mg['BB']
|
||||||
|
if mg['GAME'] == 'Holdem Tournament':
|
||||||
|
self.info['type'] = 'tour'
|
||||||
|
self.info['currency'] = 'T$'
|
||||||
|
else:
|
||||||
|
self.info['type'] = 'ring'
|
||||||
|
self.info['currency'] = 'USD'
|
||||||
|
|
||||||
# Override read function as xml.minidom barfs on the Carbon layout
|
return self.info
|
||||||
# This is pretty dodgy
|
|
||||||
def readFile(self, filename):
|
def readHandInfo(self, hand):
|
||||||
print "Carbon: Reading file: '%s'" %(filename)
|
m = self.re_HandInfo.search(hand.handText)
|
||||||
infile=open(filename, "rU")
|
if m is None:
|
||||||
self.obs = infile.read()
|
logging.info("Didn't match re_HandInfo")
|
||||||
infile.close()
|
logging.info(hand.handText)
|
||||||
self.obs = "<CarbonHHFile>\n" + self.obs + "</CarbonHHFile>"
|
return None
|
||||||
try:
|
logging.debug("HID %s-%s, Table %s" % (m.group('HID1'),
|
||||||
doc = xml.dom.minidom.parseString(self.obs)
|
m.group('HID2'), m.group('TABLE')[:-1]))
|
||||||
self.doc = doc
|
hand.handid = m.group('HID1') + m.group('HID2')
|
||||||
except:
|
hand.tablename = m.group('TABLE')[:-1]
|
||||||
traceback.print_exc(file=sys.stderr)
|
hand.maxseats = 2 # This value may be increased as necessary
|
||||||
|
hand.starttime = datetime.datetime.strptime(m.group('DATETIME')[:12],
|
||||||
|
'%Y%m%d%H%M')
|
||||||
|
# Check that the hand is complete up to the awarding of the pot; if
|
||||||
|
# not, the hand is unparseable
|
||||||
|
if self.re_EndOfHand.search(hand.handText) is None:
|
||||||
|
raise FpdbParseError(hid=m.group('HID1') + "-" + m.group('HID2'))
|
||||||
|
|
||||||
|
def readPlayerStacks(self, hand):
|
||||||
|
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||||
|
for a in m:
|
||||||
|
seatno = int(a.group('SEAT'))
|
||||||
|
# It may be necessary to adjust 'hand.maxseats', which is an
|
||||||
|
# educated guess, starting with 2 (indicating a heads-up table) and
|
||||||
|
# adjusted upwards in steps to 6, then 9, then 10. An adjustment is
|
||||||
|
# made whenever a player is discovered whose seat number is
|
||||||
|
# currently above the maximum allowable for the table.
|
||||||
|
if seatno >= hand.maxseats:
|
||||||
|
if seatno > 8:
|
||||||
|
hand.maxseats = 10
|
||||||
|
elif seatno > 5:
|
||||||
|
hand.maxseats = 9
|
||||||
|
else:
|
||||||
|
hand.maxseats = 6
|
||||||
|
if a.group('DEALTIN') == "true":
|
||||||
|
hand.addPlayer(seatno, a.group('PNAME'), a.group('CASH'))
|
||||||
|
|
||||||
|
def markStreets(self, hand):
|
||||||
|
#if hand.gametype['base'] == 'hold':
|
||||||
|
m = re.search(r'<round id="PREFLOP" sequence="[0-9]+">(?P<PREFLOP>.+(?=<round id="POSTFLOP")|.+)(<round id="POSTFLOP" sequence="[0-9]+">(?P<FLOP>.+(?=<round id="POSTTURN")|.+))?(<round id="POSTTURN" sequence="[0-9]+">(?P<TURN>.+(?=<round id="POSTRIVER")|.+))?(<round id="POSTRIVER" sequence="[0-9]+">(?P<RIVER>.+))?', hand.handText, re.DOTALL)
|
||||||
|
hand.addStreets(m)
|
||||||
|
|
||||||
|
def readCommunityCards(self, hand, street):
|
||||||
|
m = self.re_Board.search(hand.streets[street])
|
||||||
|
if street == 'FLOP':
|
||||||
|
hand.setCommunityCards(street, m.group('CARDS').split(','))
|
||||||
|
elif street in ('TURN','RIVER'):
|
||||||
|
hand.setCommunityCards(street, [m.group('CARDS').split(',')[-1]])
|
||||||
|
|
||||||
|
def readAntes(self, hand):
|
||||||
|
pass # ???
|
||||||
|
|
||||||
|
def readBringIn(self, hand):
|
||||||
|
pass # ???
|
||||||
|
|
||||||
|
def readBlinds(self, hand):
|
||||||
|
try:
|
||||||
|
m = self.re_PostSB.search(hand.handText)
|
||||||
|
hand.addBlind(self.playerNameFromSeatNo(m.group('PSEAT'), hand),
|
||||||
|
'small blind', m.group('SB'))
|
||||||
|
except: # no small blind
|
||||||
|
hand.addBlind(None, None, None)
|
||||||
|
for a in self.re_PostBB.finditer(hand.handText):
|
||||||
|
hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), hand),
|
||||||
|
'big blind', a.group('BB'))
|
||||||
|
for a in self.re_PostBoth.finditer(hand.handText):
|
||||||
|
bb = Decimal(self.info['bb'])
|
||||||
|
amount = Decimal(a.group('SBBB'))
|
||||||
|
if amount < bb:
|
||||||
|
hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'),
|
||||||
|
hand), 'small blind', a.group('SBBB'))
|
||||||
|
elif amount == bb:
|
||||||
|
hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'),
|
||||||
|
hand), 'big blind', a.group('SBBB'))
|
||||||
|
else:
|
||||||
|
hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'),
|
||||||
|
hand), 'both', a.group('SBBB'))
|
||||||
|
|
||||||
|
def readButton(self, hand):
|
||||||
|
hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
|
||||||
|
|
||||||
|
def readHeroCards(self, hand):
|
||||||
|
m = self.re_HeroCards.search(hand.handText)
|
||||||
|
if m:
|
||||||
|
hand.hero = self.playerNameFromSeatNo(m.group('PSEAT'), hand)
|
||||||
|
cards = m.group('CARDS').split(',')
|
||||||
|
hand.addHoleCards('PREFLOP', hand.hero, closed=cards, shown=False,
|
||||||
|
mucked=False, dealt=True)
|
||||||
|
|
||||||
|
def readAction(self, hand, street):
|
||||||
|
logging.debug("readAction (%s)" % street)
|
||||||
|
m = self.re_Action.finditer(hand.streets[street])
|
||||||
|
for action in m:
|
||||||
|
logging.debug("%s %s" % (action.group('ATYPE'),
|
||||||
|
action.groupdict()))
|
||||||
|
player = self.playerNameFromSeatNo(action.group('PSEAT'), hand)
|
||||||
|
if action.group('ATYPE') == 'RAISE':
|
||||||
|
hand.addCallandRaise(street, player, action.group('BET'))
|
||||||
|
elif action.group('ATYPE') == 'CALL':
|
||||||
|
hand.addCall(street, player, action.group('BET'))
|
||||||
|
elif action.group('ATYPE') == 'BET':
|
||||||
|
hand.addBet(street, player, action.group('BET'))
|
||||||
|
elif action.group('ATYPE') in ('FOLD', 'SIT_OUT'):
|
||||||
|
hand.addFold(street, player)
|
||||||
|
elif action.group('ATYPE') == 'CHECK':
|
||||||
|
hand.addCheck(street, player)
|
||||||
|
elif action.group('ATYPE') == 'ALL_IN':
|
||||||
|
hand.addAllIn(street, player, action.group('BET'))
|
||||||
|
else:
|
||||||
|
logging.debug("Unimplemented readAction: %s %s"
|
||||||
|
% (action.group('PSEAT'),action.group('ATYPE'),))
|
||||||
|
|
||||||
|
def readShowdownActions(self, hand):
|
||||||
|
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||||
|
cards = shows.group('CARDS').split(',')
|
||||||
|
hand.addShownCards(cards,
|
||||||
|
self.playerNameFromSeatNo(shows.group('PSEAT'),
|
||||||
|
hand))
|
||||||
|
|
||||||
|
def readCollectPot(self, hand):
|
||||||
|
pots = [Decimal(0) for n in range(hand.maxseats)]
|
||||||
|
for m in self.re_CollectPot.finditer(hand.handText):
|
||||||
|
pots[int(m.group('PSEAT'))] += Decimal(m.group('POT'))
|
||||||
|
# Regarding the processing logic for "committed", see Pot.end() in
|
||||||
|
# Hand.py
|
||||||
|
committed = sorted([(v,k) for (k,v) in hand.pot.committed.items()])
|
||||||
|
for p in range(hand.maxseats):
|
||||||
|
pname = self.playerNameFromSeatNo(p, hand)
|
||||||
|
if committed[-1][1] == pname:
|
||||||
|
pots[p] -= committed[-1][0] - committed[-2][0]
|
||||||
|
if pots[p] > 0:
|
||||||
|
hand.addCollectPot(player=pname, pot=pots[p])
|
||||||
|
|
||||||
|
def readShownCards(self, hand):
|
||||||
|
for m in self.re_ShownCards.finditer(hand.handText):
|
||||||
|
cards = m.group('CARDS').split(',')
|
||||||
|
hand.addShownCards(cards=cards, player=self.playerNameFromSeatNo(m.group('PSEAT'), hand))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
c = Configuration.Config()
|
parser = OptionParser()
|
||||||
e = CarbonPoker(c, "regression-test-files/carbon-poker/Niagara Falls (15245216).xml")
|
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="-")
|
||||||
e.processFile()
|
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
|
||||||
print str(e)
|
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||||
|
parser.add_option("-q", "--quiet", action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||||
|
parser.add_option("-v", "--verbose", action="store_const", const=logging.INFO, dest="verbosity")
|
||||||
|
parser.add_option("--vv", action="store_const", const=logging.DEBUG, dest="verbosity")
|
||||||
|
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
LOG_FILENAME = './logging.out'
|
||||||
|
logging.basicConfig(filename=LOG_FILENAME, level=options.verbosity)
|
||||||
|
|
||||||
|
e = Carbon(in_path = options.ipath,
|
||||||
|
out_path = options.opath,
|
||||||
|
follow = options.follow,
|
||||||
|
autostart = True)
|
||||||
|
|
||||||
|
|
|
@ -1311,6 +1311,7 @@ class Database:
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')")
|
c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
|
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')")
|
c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')")
|
||||||
|
c.execute("INSERT INTO Sites (name,currency) VALUES ('Carbon', 'USD')")
|
||||||
if self.backend == self.SQLITE:
|
if self.backend == self.SQLITE:
|
||||||
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
|
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
|
||||||
elif self.backend == self.PGSQL:
|
elif self.backend == self.PGSQL:
|
||||||
|
|
|
@ -65,8 +65,8 @@ class Fulltilt(HandHistoryConverter):
|
||||||
(\s\((?P<TURBO>Turbo)\))?)|(?P<UNREADABLE_INFO>.+))
|
(\s\((?P<TURBO>Turbo)\))?)|(?P<UNREADABLE_INFO>.+))
|
||||||
''', re.VERBOSE)
|
''', re.VERBOSE)
|
||||||
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
||||||
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) (?! collected )?\(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
|
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{3,15}) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
|
||||||
re_TourneyPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) (?! collected )?\(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE)
|
re_TourneyPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{3,15}) \(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE)
|
||||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||||
|
|
||||||
#static regex for tourney purpose
|
#static regex for tourney purpose
|
||||||
|
@ -112,7 +112,6 @@ class Fulltilt(HandHistoryConverter):
|
||||||
# These regexes are for FTP only
|
# These regexes are for FTP only
|
||||||
re_Mixed = re.compile(r'\s\-\s(?P<MIXED>HA|HORSE|HOSE)\s\-\s', re.VERBOSE)
|
re_Mixed = re.compile(r'\s\-\s(?P<MIXED>HA|HORSE|HOSE)\s\-\s', re.VERBOSE)
|
||||||
re_Max = re.compile("(?P<MAX>\d+)( max)?", re.MULTILINE)
|
re_Max = re.compile("(?P<MAX>\d+)( max)?", re.MULTILINE)
|
||||||
re_Collected = re.compile(" collected")
|
|
||||||
# NB: if we ever match "Full Tilt Poker" we should also match "FullTiltPoker", which PT Stud erroneously exports.
|
# NB: if we ever match "Full Tilt Poker" we should also match "FullTiltPoker", which PT Stud erroneously exports.
|
||||||
|
|
||||||
|
|
||||||
|
@ -258,10 +257,13 @@ class Fulltilt(HandHistoryConverter):
|
||||||
##int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
|
##int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
|
||||||
|
|
||||||
def readPlayerStacks(self, hand):
|
def readPlayerStacks(self, hand):
|
||||||
|
# Split hand text for FTP, as the regex matches the player names incorrectly
|
||||||
|
# in the summary section
|
||||||
|
pre, post = hand.handText.split('SUMMARY')
|
||||||
if hand.gametype['type'] == "ring" :
|
if hand.gametype['type'] == "ring" :
|
||||||
m = self.re_PlayerInfo.finditer(hand.handText)
|
m = self.re_PlayerInfo.finditer(pre)
|
||||||
else: #if hand.gametype['type'] == "tour"
|
else: #if hand.gametype['type'] == "tour"
|
||||||
m = self.re_TourneyPlayerInfo.finditer(hand.handText)
|
m = self.re_TourneyPlayerInfo.finditer(pre)
|
||||||
|
|
||||||
for a in m:
|
for a in m:
|
||||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||||
|
|
|
@ -445,6 +445,43 @@ Left-Drag to Move"
|
||||||
<location seat="9" x="70" y="53"> </location>
|
<location seat="9" x="70" y="53"> </location>
|
||||||
</layout>
|
</layout>
|
||||||
</site>
|
</site>
|
||||||
|
|
||||||
|
|
||||||
|
<site HH_path="C:/Program Files/Carbon Poker/HandHistory/YOUR SCREEN NAME HERE/" converter="CarbonToFpdb" decoder="everleaf_decode_table" enabled="True" screen_name="YOUR SCREEN NAME HERE" site_name="Carbon" site_path="C:/Program Files/Carbin/" supported_games="holdem" table_finder="Carbon Poker.exe">
|
||||||
|
<layout fav_seat="0" height="547" max="8" width="794">
|
||||||
|
<location seat="1" x="640" y="64"> </location>
|
||||||
|
<location seat="2" x="650" y="230"> </location>
|
||||||
|
<location seat="3" x="650" y="385"> </location>
|
||||||
|
<location seat="4" x="588" y="425"> </location>
|
||||||
|
<location seat="5" x="92" y="425"> </location>
|
||||||
|
<location seat="6" x="0" y="373"> </location>
|
||||||
|
<location seat="7" x="0" y="223"> </location>
|
||||||
|
<location seat="8" x="25" y="50"> </location>
|
||||||
|
</layout>
|
||||||
|
<layout fav_seat="0" height="547" max="6" width="794">
|
||||||
|
<location seat="1" x="640" y="58"> </location>
|
||||||
|
<location seat="2" x="654" y="288"> </location>
|
||||||
|
<location seat="3" x="615" y="424"> </location>
|
||||||
|
<location seat="4" x="70" y="421"> </location>
|
||||||
|
<location seat="5" x="0" y="280"> </location>
|
||||||
|
<location seat="6" x="70" y="58"> </location>
|
||||||
|
</layout>
|
||||||
|
<layout fav_seat="0" height="547" max="2" width="794">
|
||||||
|
<location seat="1" x="651" y="288"> </location>
|
||||||
|
<location seat="2" x="10" y="288"> </location>
|
||||||
|
</layout>
|
||||||
|
<layout fav_seat="0" height="547" max="9" width="794">
|
||||||
|
<location seat="1" x="634" y="38"> </location>
|
||||||
|
<location seat="2" x="667" y="184"> </location>
|
||||||
|
<location seat="3" x="667" y="321"> </location>
|
||||||
|
<location seat="4" x="667" y="445"> </location>
|
||||||
|
<location seat="5" x="337" y="459"> </location>
|
||||||
|
<location seat="6" x="0" y="400"> </location>
|
||||||
|
<location seat="7" x="0" y="322"> </location>
|
||||||
|
<location seat="8" x="0" y="181"> </location>
|
||||||
|
<location seat="9" x="70" y="53"> </location>
|
||||||
|
</layout>
|
||||||
|
</site>
|
||||||
</supported_sites>
|
</supported_sites>
|
||||||
|
|
||||||
<supported_games>
|
<supported_games>
|
||||||
|
@ -585,6 +622,7 @@ Left-Drag to Move"
|
||||||
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
|
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
|
||||||
<hhc site="Betfair" converter="BetfairToFpdb"/>
|
<hhc site="Betfair" converter="BetfairToFpdb"/>
|
||||||
<hhc site="Partouche" converter="PartoucheToFpdb"/>
|
<hhc site="Partouche" converter="PartoucheToFpdb"/>
|
||||||
|
<hhc site="Carbon" converter="CarbonToFpdb"/>
|
||||||
</hhcs>
|
</hhcs>
|
||||||
|
|
||||||
<supported_databases>
|
<supported_databases>
|
||||||
|
|
|
@ -43,7 +43,7 @@ class Hand(object):
|
||||||
LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'}
|
LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'}
|
||||||
SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''}
|
SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''}
|
||||||
MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE', 'ha': 'HA'}
|
MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE', 'ha': 'HA'}
|
||||||
SITEIDS = {'Fulltilt':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7, 'Absolute':8, 'PartyPoker':9 }
|
SITEIDS = {'Fulltilt':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7, 'Absolute':8, 'PartyPoker':9, 'Partouche':10, 'Carbon':11 }
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, sitename, gametype, handText, builtFrom = "HHC"):
|
def __init__(self, sitename, gametype, handText, builtFrom = "HHC"):
|
||||||
|
@ -288,6 +288,24 @@ If a player has None chips he won't be added."""
|
||||||
c = c.replace(k,v)
|
c = c.replace(k,v)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
def addAllIn(self, street, player, amount):
|
||||||
|
"""\
|
||||||
|
For sites (currently only Carbon Poker) which record "all in" as a special action, which can mean either "calls and is all in" or "raises all in".
|
||||||
|
"""
|
||||||
|
self.checkPlayerExists(player)
|
||||||
|
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||||
|
Ai = Decimal(amount)
|
||||||
|
Bp = self.lastBet[street]
|
||||||
|
Bc = reduce(operator.add, self.bets[street][player], 0)
|
||||||
|
C = Bp - Bc
|
||||||
|
if Ai <= C:
|
||||||
|
self.addCall(street, player, amount)
|
||||||
|
elif Bp == 0:
|
||||||
|
self.addBet(street, player, amount)
|
||||||
|
else:
|
||||||
|
Rb = Ai - C
|
||||||
|
self._addRaise(street, player, C, Rb, Ai)
|
||||||
|
|
||||||
def addAnte(self, player, ante):
|
def addAnte(self, player, ante):
|
||||||
log.debug("%s %s antes %s" % ('BLINDSANTES', player, ante))
|
log.debug("%s %s antes %s" % ('BLINDSANTES', player, ante))
|
||||||
if player is not None:
|
if player is not None:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user