Merge branch 'master' of git://git.assembla.com/fpdboz.git
This commit is contained in:
commit
9be7f308a6
116
pyfpdb/AlchemyFacilities.py
Normal file
116
pyfpdb/AlchemyFacilities.py
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from sqlalchemy import types
|
||||||
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
|
||||||
|
import Card
|
||||||
|
|
||||||
|
class CardColumn(types.TypeDecorator):
|
||||||
|
"""Stores cards as smallints
|
||||||
|
|
||||||
|
Automatically converts values like '9h' to smallint
|
||||||
|
|
||||||
|
>>> CardColumn().process_bind_param( 'Td', '' )
|
||||||
|
22
|
||||||
|
>>> CardColumn().process_bind_param( u'Td', '' )
|
||||||
|
22
|
||||||
|
>>> CardColumn().process_bind_param( 22, '' )
|
||||||
|
22
|
||||||
|
>>> CardColumn().process_result_value( 22, '' )
|
||||||
|
'Td'
|
||||||
|
"""
|
||||||
|
|
||||||
|
impl = types.SmallInteger
|
||||||
|
|
||||||
|
def process_bind_param(self, value, dialect):
|
||||||
|
if value is None or isinstance(value, int):
|
||||||
|
return value
|
||||||
|
elif isinstance(value, basestring) and len(value) == 2:
|
||||||
|
return Card.encodeCard(str(value))
|
||||||
|
else:
|
||||||
|
raise Exception, "Incorrect card value: " + repr(value)
|
||||||
|
|
||||||
|
def process_result_value(self, value, dialect):
|
||||||
|
return Card.valueSuitFromCard( value )
|
||||||
|
|
||||||
|
|
||||||
|
class MoneyColumn(types.TypeDecorator):
|
||||||
|
"""Stores money: bets, pots, etc
|
||||||
|
|
||||||
|
Understands:
|
||||||
|
Decimal as real amount
|
||||||
|
int as amount mupliplied by 100
|
||||||
|
string as decimal
|
||||||
|
Returns Decimal
|
||||||
|
>>> MoneyColumn().process_bind_param( 230, '' )
|
||||||
|
230
|
||||||
|
>>> MoneyColumn().process_bind_param( Decimal('2.30'), '' )
|
||||||
|
230
|
||||||
|
>>> MoneyColumn().process_bind_param( '2.30', '' )
|
||||||
|
230
|
||||||
|
>>> MoneyColumn().process_result_value( 230, '' )
|
||||||
|
Decimal('2.3')
|
||||||
|
"""
|
||||||
|
|
||||||
|
impl = types.Integer
|
||||||
|
|
||||||
|
def process_bind_param(self, value, dialect):
|
||||||
|
if value is None or isinstance(value, int):
|
||||||
|
return value
|
||||||
|
elif isinstance(value, basestring) or isinstance(value, Decimal):
|
||||||
|
return int(Decimal(value)*100)
|
||||||
|
else:
|
||||||
|
raise Exception, "Incorrect amount:" + repr(value)
|
||||||
|
|
||||||
|
def process_result_value(self, value, dialect):
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
return Decimal(value)/100
|
||||||
|
|
||||||
|
|
||||||
|
class BigIntColumn(types.TypeDecorator, types.Integer):
|
||||||
|
"""Representing db-independent big integer """
|
||||||
|
# Integer inheritance required for auto_increment flag
|
||||||
|
|
||||||
|
impl = types.Integer
|
||||||
|
|
||||||
|
def load_dialect_impl(self, dialect):
|
||||||
|
from sqlalchemy import databases
|
||||||
|
if dialect.name == 'mysql':
|
||||||
|
return databases.mysql.MSBigInteger()
|
||||||
|
elif dialect.name == 'postgres':
|
||||||
|
return databases.mysql.PGBigInteger()
|
||||||
|
return types.Integer()
|
||||||
|
|
||||||
|
|
||||||
|
class MappedBase(object):
|
||||||
|
"""Provide dummy contrcutor"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
for k, v in kwargs.iteritems():
|
||||||
|
setattr(self, k, v)
|
||||||
|
|
||||||
|
def get_columns_names(self):
|
||||||
|
return [i.name for i in self._sa_class_manager.mapper.c]
|
||||||
|
|
||||||
|
def get_or_create(klass, session, **kwargs):
|
||||||
|
"""
|
||||||
|
Looks up an object with the given kwargs, creating one if necessary.
|
||||||
|
Returns a tuple of (object, created), where created is a boolean
|
||||||
|
specifying whether an object was created.
|
||||||
|
"""
|
||||||
|
assert kwargs, \
|
||||||
|
'get_or_create() must be passed at least one keyword argument'
|
||||||
|
try:
|
||||||
|
return session.query(klass).filter_by(**kwargs).one(), False
|
||||||
|
except NoResultFound:
|
||||||
|
try:
|
||||||
|
obj = klass(**kwargs)
|
||||||
|
session.add(obj)
|
||||||
|
session.flush()
|
||||||
|
return obj, True
|
||||||
|
except IntegrityError:
|
||||||
|
return session.query(klass).filter_by(**kwargs).one(), False
|
||||||
|
|
464
pyfpdb/AlchemyMappings.py
Normal file
464
pyfpdb/AlchemyMappings.py
Normal file
|
@ -0,0 +1,464 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""@package AlchemyMappings
|
||||||
|
This package contains all classes to be mapped and mappers themselves
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
from decimal import Decimal
|
||||||
|
from sqlalchemy.orm import mapper, relation, reconstructor
|
||||||
|
from sqlalchemy.sql import select
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
from AlchemyTables import *
|
||||||
|
from AlchemyFacilities import get_or_create, MappedBase
|
||||||
|
from DerivedStats import DerivedStats
|
||||||
|
from Exceptions import IncompleteHandError, FpdbError
|
||||||
|
|
||||||
|
|
||||||
|
class Player(MappedBase):
|
||||||
|
"""Class reflecting Players db table"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_or_create(session, siteId, name):
|
||||||
|
return get_or_create(Player, session, siteId=siteId, name=name)[0]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '<Player "%s" on %s>' % (self.name, self.site and self.site.name)
|
||||||
|
|
||||||
|
|
||||||
|
class Gametype(MappedBase):
|
||||||
|
"""Class reflecting Gametypes db table"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_or_create(session, siteId, gametype):
|
||||||
|
map = zip(
|
||||||
|
['type', 'base', 'category', 'limitType', 'smallBlind', 'bigBlind', 'smallBet', 'bigBet'],
|
||||||
|
['type', 'base', 'category', 'limitType', 'sb', 'bb', 'dummy', 'dummy', ])
|
||||||
|
gametype = dict([(new, gametype.get(old)) for new, old in map ])
|
||||||
|
|
||||||
|
hilo = "h"
|
||||||
|
if gametype['category'] in ('studhilo', 'omahahilo'):
|
||||||
|
hilo = "s"
|
||||||
|
elif gametype['category'] in ('razz','27_3draw','badugi'):
|
||||||
|
hilo = "l"
|
||||||
|
gametype['hiLo'] = hilo
|
||||||
|
|
||||||
|
for f in ['smallBlind', 'bigBlind', 'smallBet', 'bigBet']:
|
||||||
|
if gametype[f] is None:
|
||||||
|
gametype[f] = 0
|
||||||
|
gametype[f] = int(Decimal(gametype[f])*100)
|
||||||
|
|
||||||
|
gametype['siteId'] = siteId
|
||||||
|
return get_or_create(Gametype, session, **gametype)[0]
|
||||||
|
|
||||||
|
|
||||||
|
class HandActions(object):
|
||||||
|
"""Class reflecting HandsActions db table"""
|
||||||
|
def initFromImportedHand(self, hand, actions):
|
||||||
|
self.hand = hand
|
||||||
|
self.actions = {}
|
||||||
|
for street, street_actions in actions.iteritems():
|
||||||
|
self.actions[street] = []
|
||||||
|
for v in street_actions:
|
||||||
|
hp = hand.handplayers_by_name[v[0]]
|
||||||
|
self.actions[street].append({'street': street, 'pid': hp.id, 'seat': hp.seatNo, 'action':v})
|
||||||
|
|
||||||
|
@property
|
||||||
|
def flat_actions(self):
|
||||||
|
actions = []
|
||||||
|
for street in self.hand.allStreets:
|
||||||
|
actions += self.actions[street]
|
||||||
|
return actions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class HandInternal(DerivedStats):
|
||||||
|
"""Class reflecting Hands db table"""
|
||||||
|
|
||||||
|
def parseImportedHandStep1(self, hand):
|
||||||
|
"""Extracts values to insert into from hand returned by HHC. No db is needed he"""
|
||||||
|
hand.players = hand.getAlivePlayers()
|
||||||
|
|
||||||
|
# also save some data for step2. Those fields aren't in Hands table
|
||||||
|
self.siteId = hand.siteId
|
||||||
|
self.gametype_dict = hand.gametype
|
||||||
|
|
||||||
|
self.attachHandPlayers(hand)
|
||||||
|
self.attachActions(hand)
|
||||||
|
|
||||||
|
self.assembleHands(hand)
|
||||||
|
self.assembleHandsPlayers(hand)
|
||||||
|
|
||||||
|
def parseImportedHandStep2(self, session):
|
||||||
|
"""Fetching ids for gametypes and players"""
|
||||||
|
gametype = Gametype.get_or_create(session, self.siteId, self.gametype_dict)
|
||||||
|
self.gametypeId = gametype.id
|
||||||
|
for hp in self.handPlayers:
|
||||||
|
hp.playerId = Player.get_or_create(session, self.siteId, hp.name).id
|
||||||
|
|
||||||
|
def getPlayerByName(self, name):
|
||||||
|
if not hasattr(self, 'handplayers_by_name'):
|
||||||
|
self.handplayers_by_name = {}
|
||||||
|
for hp in self.handPlayers:
|
||||||
|
pname = getattr(hp, 'name', None) or hp.player.name
|
||||||
|
self.handplayers_by_name[pname] = hp
|
||||||
|
return self.handplayers_by_name[name]
|
||||||
|
|
||||||
|
def attachHandPlayers(self, hand):
|
||||||
|
"""Fill HandInternal.handPlayers list. Create self.handplayers_by_name"""
|
||||||
|
hand.noSb = getattr(hand, 'noSb', None)
|
||||||
|
if hand.noSb is None and self.gametype_dict['base']=='hold':
|
||||||
|
saw_sb = False
|
||||||
|
for action in hand.actions[hand.actionStreets[0]]: # blindsantes
|
||||||
|
if action[1] == 'posts' and action[2] == 'small blind' and action[0] is not None:
|
||||||
|
saw_sb = True
|
||||||
|
hand.noSb = saw_sb
|
||||||
|
|
||||||
|
self.handplayers_by_name = {}
|
||||||
|
for seat, name, chips in hand.players:
|
||||||
|
p = HandPlayer(hand = self, imported_hand=hand, seatNo=seat,
|
||||||
|
name=name, startCash=chips)
|
||||||
|
self.handplayers_by_name[name] = p
|
||||||
|
|
||||||
|
def attachActions(self, hand):
|
||||||
|
"""Create HandActions object"""
|
||||||
|
a = HandActions()
|
||||||
|
a.initFromImportedHand(self, hand.actions)
|
||||||
|
|
||||||
|
def parseImportedTournament(self, hand, session):
|
||||||
|
"""Fetching tourney, its type and players
|
||||||
|
|
||||||
|
Must be called after Step2
|
||||||
|
"""
|
||||||
|
if self.gametype_dict['type'] != 'tour': return
|
||||||
|
|
||||||
|
# check for consistense
|
||||||
|
for i in ('buyin', 'tourNo'):
|
||||||
|
if not hasattr(hand, i):
|
||||||
|
raise IncompleteHandError(
|
||||||
|
"Field '%s' required for tournaments" % i, self.id, hand )
|
||||||
|
|
||||||
|
# repair old-style buyin value
|
||||||
|
m = re.match('\$(\d+)\+\$(\d+)', hand.buyin)
|
||||||
|
if m is not None:
|
||||||
|
hand.buyin, self.fee = m.groups()
|
||||||
|
|
||||||
|
# fetch tourney type
|
||||||
|
tour_type_hand2db = {
|
||||||
|
'buyin': 'buyin',
|
||||||
|
'fee': 'fee',
|
||||||
|
'speed': 'speed',
|
||||||
|
'maxSeats': 'maxseats',
|
||||||
|
'knockout': 'isKO',
|
||||||
|
'rebuyOrAddon': 'isRebuy',
|
||||||
|
'headsUp': 'isHU',
|
||||||
|
'shootout': 'isShootout',
|
||||||
|
'matrix': 'isMatrix',
|
||||||
|
'sng': 'isSNG',
|
||||||
|
}
|
||||||
|
tour_type_index = dict([
|
||||||
|
( i_db, getattr(hand, i_hand, None) )
|
||||||
|
for i_db, i_hand in tour_type_hand2db.iteritems()
|
||||||
|
])
|
||||||
|
tour_type_index['siteId'] = self.siteId
|
||||||
|
tour_type = TourneyType.get_or_create(session, **tour_type_index)
|
||||||
|
|
||||||
|
# fetch and update tourney
|
||||||
|
tour = Tourney.get_or_create(session, hand.tourNo, tour_type.id)
|
||||||
|
cols = tour.get_columns_names()
|
||||||
|
for col in cols:
|
||||||
|
hand_val = getattr(hand, col, None)
|
||||||
|
if col in ('id', 'tourneyTypeId', 'comment', 'commentTs') or hand_val is None:
|
||||||
|
continue
|
||||||
|
db_val = getattr(tour, col, None)
|
||||||
|
if db_val is None:
|
||||||
|
setattr(tour, col, hand_val)
|
||||||
|
elif col == 'koBounty':
|
||||||
|
setattr(tour, col, max(db_val, hand_val))
|
||||||
|
elif col == 'tourStartTime' and hand.handStart:
|
||||||
|
setattr(tour, col, min(db_val, hand.handStart))
|
||||||
|
|
||||||
|
if tour.entries is None and tour_type.sng:
|
||||||
|
tour.entries = tour_type.maxSeats
|
||||||
|
|
||||||
|
# fetch and update tourney players
|
||||||
|
for hp in self.handPlayers:
|
||||||
|
tp = TourneyPlayer.get_or_create(session, tour.id, hp.playerId)
|
||||||
|
# FIXME: other TourneysPlayers should be added here
|
||||||
|
|
||||||
|
session.flush()
|
||||||
|
|
||||||
|
def isDuplicate(self, session):
|
||||||
|
"""Checks if current hand already exists in db
|
||||||
|
|
||||||
|
siteHandNo ans gameTypeId have to be setted
|
||||||
|
"""
|
||||||
|
return session.query(HandInternal).filter_by(
|
||||||
|
siteHandNo=self.siteHandNo, gametypeId=self.gametypeId).count()!=0
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = list()
|
||||||
|
for i in self._sa_class_manager.mapper.c:
|
||||||
|
s.append('%25s %s' % (i, getattr(self, i.name)))
|
||||||
|
|
||||||
|
s+=['', '']
|
||||||
|
for i,p in enumerate(self.handPlayers):
|
||||||
|
s.append('%d. %s' % (i, p.name or '???'))
|
||||||
|
s.append(str(p))
|
||||||
|
return '\n'.join(s)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def boardcards(self):
|
||||||
|
cards = []
|
||||||
|
for i in range(5):
|
||||||
|
cards.append(getattr(self, 'boardcard%d' % (i+1), None))
|
||||||
|
return filter(bool, cards)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HandClass(self):
|
||||||
|
"""Return HoldemOmahaHand or something like this"""
|
||||||
|
import Hand
|
||||||
|
if self.gametype.base == 'hold':
|
||||||
|
return Hand.HoldemOmahaHand
|
||||||
|
elif self.gametype.base == 'draw':
|
||||||
|
return Hand.DrawHand
|
||||||
|
elif self.gametype.base == 'stud':
|
||||||
|
return Hand.StudHand
|
||||||
|
raise Exception("Unknow gametype.base: '%s'" % self.gametype.base)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def allStreets(self):
|
||||||
|
return self.HandClass.allStreets
|
||||||
|
|
||||||
|
@property
|
||||||
|
def actionStreets(self):
|
||||||
|
return self.HandClass.actionStreets
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class HandPlayer(MappedBase):
|
||||||
|
"""Class reflecting HandsPlayers db table"""
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
if 'imported_hand' in kwargs and 'seatNo' in kwargs:
|
||||||
|
imported_hand = kwargs.pop('imported_hand')
|
||||||
|
self.position = self.getPosition(imported_hand, kwargs['seatNo'])
|
||||||
|
super(HandPlayer, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
@reconstructor
|
||||||
|
def init_on_load(self):
|
||||||
|
self.name = self.player.name
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getPosition(hand, seat):
|
||||||
|
"""Returns position value like 'B', 'S', '0', '1', ...
|
||||||
|
|
||||||
|
>>> class A(object): pass
|
||||||
|
...
|
||||||
|
>>> A.noSb = False
|
||||||
|
>>> A.maxseats = 6
|
||||||
|
>>> A.buttonpos = 2
|
||||||
|
>>> A.gametype = {'base': 'hold'}
|
||||||
|
>>> A.players = [(i, None, None) for i in (2, 4, 5, 6)]
|
||||||
|
>>> HandPlayer.getPosition(A, 6) # cut off
|
||||||
|
'1'
|
||||||
|
>>> HandPlayer.getPosition(A, 2) # button
|
||||||
|
'0'
|
||||||
|
>>> HandPlayer.getPosition(A, 4) # SB
|
||||||
|
'S'
|
||||||
|
>>> HandPlayer.getPosition(A, 5) # BB
|
||||||
|
'B'
|
||||||
|
>>> A.noSb = True
|
||||||
|
>>> HandPlayer.getPosition(A, 5) # MP3
|
||||||
|
'2'
|
||||||
|
>>> HandPlayer.getPosition(A, 6) # cut off
|
||||||
|
'1'
|
||||||
|
>>> HandPlayer.getPosition(A, 2) # button
|
||||||
|
'0'
|
||||||
|
>>> HandPlayer.getPosition(A, 4) # BB
|
||||||
|
'B'
|
||||||
|
"""
|
||||||
|
from itertools import chain
|
||||||
|
if hand.gametype['base'] == 'stud':
|
||||||
|
# FIXME: i've never played stud so plz check & del comment \\grindi
|
||||||
|
bringin = None
|
||||||
|
for action in chain(*[self.actions[street] for street in hand.allStreets]):
|
||||||
|
if action[1]=='bringin':
|
||||||
|
bringin = action[0]
|
||||||
|
break
|
||||||
|
if bringin is None:
|
||||||
|
raise Exception, "Cannot find bringin"
|
||||||
|
# name -> seat
|
||||||
|
bringin = int(filter(lambda p: p[1]==bringin, bringin)[0])
|
||||||
|
seat = (int(seat) - int(bringin))%int(hand.maxseats)
|
||||||
|
return str(seat)
|
||||||
|
else:
|
||||||
|
seats_occupied = sorted([seat_ for seat_, name, chips in hand.players], key=int)
|
||||||
|
if hand.buttonpos not in seats_occupied:
|
||||||
|
# i.e. something like
|
||||||
|
# Seat 3: PlayerX ($0), is sitting out
|
||||||
|
# The button is in seat #3
|
||||||
|
hand.buttonpos = max(seats_occupied,
|
||||||
|
key = lambda s: int(s)
|
||||||
|
if int(s) <= int(hand.buttonpos)
|
||||||
|
else int(s) - int(hand.maxseats)
|
||||||
|
)
|
||||||
|
seats_occupied = sorted(seats_occupied,
|
||||||
|
key = lambda seat_: (
|
||||||
|
- seats_occupied.index(seat_)
|
||||||
|
+ seats_occupied.index(hand.buttonpos)
|
||||||
|
+ 2) % len(seats_occupied)
|
||||||
|
)
|
||||||
|
# now (if SB presents) seats_occupied contains seats in order: BB, SB, BU, CO, MP3, ...
|
||||||
|
if hand.noSb:
|
||||||
|
# fix order in the case nosb
|
||||||
|
seats_occupied = seats_occupied[1:] + seats_occupied[0:1]
|
||||||
|
seats_occupied.insert(1, -1)
|
||||||
|
seat = seats_occupied.index(seat)
|
||||||
|
if seat == 0:
|
||||||
|
return 'B'
|
||||||
|
elif seat == 1:
|
||||||
|
return 'S'
|
||||||
|
else:
|
||||||
|
return str(seat-2)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cards(self):
|
||||||
|
cards = []
|
||||||
|
for i in range(7):
|
||||||
|
cards.append(getattr(self, 'card%d' % (i+1), None))
|
||||||
|
return filter(bool, cards)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = list()
|
||||||
|
for i in self._sa_class_manager.mapper.c:
|
||||||
|
s.append('%45s %s' % (i, getattr(self, i.name)))
|
||||||
|
return '\n'.join(s)
|
||||||
|
|
||||||
|
|
||||||
|
class Site(object):
|
||||||
|
"""Class reflecting Players db table"""
|
||||||
|
INITIAL_DATA = [
|
||||||
|
(1 , 'Full Tilt Poker','USD'),
|
||||||
|
(2 , 'PokerStars', 'USD'),
|
||||||
|
(3 , 'Everleaf', 'USD'),
|
||||||
|
(4 , 'Win2day', 'USD'),
|
||||||
|
(5 , 'OnGame', 'USD'),
|
||||||
|
(6 , 'UltimateBet', 'USD'),
|
||||||
|
(7 , 'Betfair', 'USD'),
|
||||||
|
(8 , 'Absolute', 'USD'),
|
||||||
|
(9 , 'PartyPoker', 'USD'),
|
||||||
|
(10, 'Partouche', 'EUR'),
|
||||||
|
]
|
||||||
|
INITIAL_DATA_KEYS = ('id', 'name', 'currency')
|
||||||
|
|
||||||
|
INITIAL_DATA_DICTS = [ dict(zip(INITIAL_DATA_KEYS, datum)) for datum in INITIAL_DATA ]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def insert_initial(cls, connection):
|
||||||
|
connection.execute(sites_table.insert(), cls.INITIAL_DATA_DICTS)
|
||||||
|
|
||||||
|
|
||||||
|
class Tourney(MappedBase):
|
||||||
|
"""Class reflecting Tourneys db table"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_or_create(cls, session, siteTourneyNo, tourneyTypeId):
|
||||||
|
"""Fetch tourney by index or creates one if none. """
|
||||||
|
return get_or_create(cls, session, siteTourneyNo=siteTourneyNo,
|
||||||
|
tourneyTypeId=tourneyTypeId)[0]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TourneyType(MappedBase):
|
||||||
|
"""Class reflecting TourneysType db table"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_or_create(cls, session, **kwargs):
|
||||||
|
"""Fetch tourney type by index or creates one if none
|
||||||
|
|
||||||
|
Required kwargs:
|
||||||
|
buyin fee speed maxSeats knockout
|
||||||
|
rebuyOrAddon headsUp shootout matrix sng
|
||||||
|
"""
|
||||||
|
return get_or_create(cls, session, **kwargs)[0]
|
||||||
|
|
||||||
|
|
||||||
|
class TourneyPlayer(MappedBase):
|
||||||
|
"""Class reflecting TourneysPlayers db table"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_or_create(cls, session, tourneyId, playerId):
|
||||||
|
"""Fetch tourney player by index or creates one if none """
|
||||||
|
return get_or_create(cls, session, tourneyId=tourneyId, playerId=playerId)
|
||||||
|
|
||||||
|
|
||||||
|
class Version(object):
|
||||||
|
"""Provides read/write access for version var"""
|
||||||
|
CURRENT_VERSION = 120 # db version for current release
|
||||||
|
# 119 - first alchemy version
|
||||||
|
# 120 - add m_factor
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
ver = None
|
||||||
|
def __init__(self, connection=None):
|
||||||
|
if self.__class__.conn is None:
|
||||||
|
self.__class__.conn = connection
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_wrong(cls):
|
||||||
|
return cls.get() != cls.CURRENT_VERSION
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get(cls):
|
||||||
|
if cls.ver is None:
|
||||||
|
try:
|
||||||
|
cls.ver = cls.conn.execute(select(['version'], settings_table)).fetchone()[0]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
return cls.ver
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set(cls, value):
|
||||||
|
if cls.conn.execute(settings_table.select()).rowcount==0:
|
||||||
|
cls.conn.execute(settings_table.insert(), version=value)
|
||||||
|
else:
|
||||||
|
cls.conn.execute(settings_table.update().values(version=value))
|
||||||
|
cls.ver = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_initial(cls):
|
||||||
|
cls.set(cls.CURRENT_VERSION)
|
||||||
|
|
||||||
|
|
||||||
|
mapper (Gametype, gametypes_table, properties={
|
||||||
|
'hands': relation(HandInternal, backref='gametype'),
|
||||||
|
})
|
||||||
|
mapper (Player, players_table, properties={
|
||||||
|
'playerHands': relation(HandPlayer, backref='player'),
|
||||||
|
'playerTourney': relation(TourneyPlayer, backref='player'),
|
||||||
|
})
|
||||||
|
mapper (Site, sites_table, properties={
|
||||||
|
'gametypes': relation(Gametype, backref = 'site'),
|
||||||
|
'players': relation(Player, backref = 'site'),
|
||||||
|
'tourneyTypes': relation(TourneyType, backref = 'site'),
|
||||||
|
})
|
||||||
|
mapper (HandActions, hands_actions_table, properties={})
|
||||||
|
mapper (HandInternal, hands_table, properties={
|
||||||
|
'handPlayers': relation(HandPlayer, backref='hand'),
|
||||||
|
'actions_all': relation(HandActions, backref='hand', uselist=False),
|
||||||
|
})
|
||||||
|
mapper (HandPlayer, hands_players_table, properties={})
|
||||||
|
|
||||||
|
mapper (Tourney, tourneys_table)
|
||||||
|
mapper (TourneyType, tourney_types_table, properties={
|
||||||
|
'tourneys': relation(Tourney, backref='type'),
|
||||||
|
})
|
||||||
|
mapper (TourneyPlayer, tourneys_players_table)
|
||||||
|
|
||||||
|
class LambdaKeyDict(defaultdict):
|
||||||
|
"""Operates like defaultdict but passes key argument to the factory function"""
|
||||||
|
def __missing__(key):
|
||||||
|
return self.default_factory(key)
|
||||||
|
|
438
pyfpdb/AlchemyTables.py
Normal file
438
pyfpdb/AlchemyTables.py
Normal file
|
@ -0,0 +1,438 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""@package AlchemyTables
|
||||||
|
Contains all sqlalchemy tables
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sqlalchemy import Table, Float, Column, Integer, String, MetaData, \
|
||||||
|
ForeignKey, Boolean, SmallInteger, DateTime, Text, Index, CHAR, \
|
||||||
|
PickleType, Unicode
|
||||||
|
|
||||||
|
from AlchemyFacilities import CardColumn, MoneyColumn, BigIntColumn
|
||||||
|
|
||||||
|
|
||||||
|
metadata = MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
autorates_table = Table('Autorates', metadata,
|
||||||
|
Column('id', Integer, primary_key=True, nullable=False),
|
||||||
|
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False),
|
||||||
|
Column('gametypeId', SmallInteger, ForeignKey("Gametypes.id"), nullable=False),
|
||||||
|
Column('description', String(50), nullable=False),
|
||||||
|
Column('shortDesc', CHAR(8), nullable=False),
|
||||||
|
Column('ratingTime', DateTime, nullable=False),
|
||||||
|
Column('handCount', Integer, nullable=False),
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
gametypes_table = Table('Gametypes', metadata,
|
||||||
|
Column('id', SmallInteger, primary_key=True),
|
||||||
|
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False), # SMALLINT
|
||||||
|
Column('type', String(4), nullable=False), # char(4) NOT NULL
|
||||||
|
Column('base', String(4), nullable=False), # char(4) NOT NULL
|
||||||
|
Column('category', String(9), nullable=False), # varchar(9) NOT NULL
|
||||||
|
Column('limitType', CHAR(2), nullable=False), # char(2) NOT NULL
|
||||||
|
Column('hiLo', CHAR(1), nullable=False), # char(1) NOT NULL
|
||||||
|
Column('smallBlind', Integer(3)), # int
|
||||||
|
Column('bigBlind', Integer(3)), # int
|
||||||
|
Column('smallBet', Integer(3), nullable=False), # int NOT NULL
|
||||||
|
Column('bigBet', Integer(3), nullable=False), # int NOT NULL
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
hands_table = Table('Hands', metadata,
|
||||||
|
Column('id', BigIntColumn, primary_key=True),
|
||||||
|
Column('tableName', String(30), nullable=False),
|
||||||
|
Column('siteHandNo', BigIntColumn, nullable=False),
|
||||||
|
Column('gametypeId', SmallInteger, ForeignKey('Gametypes.id'), nullable=False),
|
||||||
|
Column('handStart', DateTime, nullable=False),
|
||||||
|
Column('importTime', DateTime, nullable=False),
|
||||||
|
Column('seats', SmallInteger, nullable=False),
|
||||||
|
Column('maxSeats', SmallInteger, nullable=False),
|
||||||
|
|
||||||
|
Column('boardcard1', CardColumn),
|
||||||
|
Column('boardcard2', CardColumn),
|
||||||
|
Column('boardcard3', CardColumn),
|
||||||
|
Column('boardcard4', CardColumn),
|
||||||
|
Column('boardcard5', CardColumn),
|
||||||
|
Column('texture', SmallInteger),
|
||||||
|
Column('playersVpi', SmallInteger, nullable=False),
|
||||||
|
Column('playersAtStreet1', SmallInteger, nullable=False, default=0),
|
||||||
|
Column('playersAtStreet2', SmallInteger, nullable=False, default=0),
|
||||||
|
Column('playersAtStreet3', SmallInteger, nullable=False, default=0),
|
||||||
|
Column('playersAtStreet4', SmallInteger, nullable=False, default=0),
|
||||||
|
Column('playersAtShowdown',SmallInteger, nullable=False),
|
||||||
|
Column('street0Raises', SmallInteger, nullable=False),
|
||||||
|
Column('street1Raises', SmallInteger, nullable=False),
|
||||||
|
Column('street2Raises', SmallInteger, nullable=False),
|
||||||
|
Column('street3Raises', SmallInteger, nullable=False),
|
||||||
|
Column('street4Raises', SmallInteger, nullable=False),
|
||||||
|
Column('street1Pot', MoneyColumn),
|
||||||
|
Column('street2Pot', MoneyColumn),
|
||||||
|
Column('street3Pot', MoneyColumn),
|
||||||
|
Column('street4Pot', MoneyColumn),
|
||||||
|
Column('showdownPot', MoneyColumn),
|
||||||
|
Column('comment', Text),
|
||||||
|
Column('commentTs', DateTime),
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
Index('siteHandNo', hands_table.c.siteHandNo, hands_table.c.gametypeId, unique=True)
|
||||||
|
|
||||||
|
|
||||||
|
hands_actions_table = Table('HandsActions', metadata,
|
||||||
|
Column('id', BigIntColumn, primary_key=True, nullable=False),
|
||||||
|
Column('handId', BigIntColumn, ForeignKey("Hands.id"), nullable=False),
|
||||||
|
Column('actions', PickleType, nullable=False),
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
hands_players_table = Table('HandsPlayers', metadata,
|
||||||
|
Column('id', BigIntColumn, primary_key=True),
|
||||||
|
Column('handId', BigIntColumn, ForeignKey("Hands.id"), nullable=False),
|
||||||
|
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False),
|
||||||
|
Column('startCash', MoneyColumn),
|
||||||
|
Column('position', CHAR(1)), #CHAR(1)
|
||||||
|
Column('seatNo', SmallInteger, nullable=False), #SMALLINT NOT NULL
|
||||||
|
|
||||||
|
Column('card1', CardColumn), #smallint NOT NULL,
|
||||||
|
Column('card2', CardColumn), #smallint NOT NULL
|
||||||
|
Column('card3', CardColumn), #smallint
|
||||||
|
Column('card4', CardColumn), #smallint
|
||||||
|
Column('card5', CardColumn), #smallint
|
||||||
|
Column('card6', CardColumn), #smallint
|
||||||
|
Column('card7', CardColumn), #smallint
|
||||||
|
Column('startCards', SmallInteger), #smallint
|
||||||
|
|
||||||
|
Column('m_factor', Integer), # null for ring games
|
||||||
|
Column('ante', MoneyColumn), #INT
|
||||||
|
Column('winnings', MoneyColumn, nullable=False, default=0), #int NOT NULL
|
||||||
|
Column('rake', MoneyColumn, nullable=False, default=0), #int NOT NULL
|
||||||
|
Column('totalProfit', MoneyColumn), #INT
|
||||||
|
Column('comment', Text), #text
|
||||||
|
Column('commentTs', DateTime), #DATETIME
|
||||||
|
Column('tourneysPlayersId', BigIntColumn, ForeignKey("TourneysPlayers.id"),), #BIGINT UNSIGNED
|
||||||
|
Column('tourneyTypeId', Integer, ForeignKey("TourneyTypes.id"),), #SMALLINT UNSIGNED
|
||||||
|
|
||||||
|
Column('wonWhenSeenStreet1',Float), #FLOAT
|
||||||
|
Column('wonWhenSeenStreet2',Float), #FLOAT
|
||||||
|
Column('wonWhenSeenStreet3',Float), #FLOAT
|
||||||
|
Column('wonWhenSeenStreet4',Float), #FLOAT
|
||||||
|
Column('wonAtSD', Float), #FLOAT
|
||||||
|
|
||||||
|
Column('street0VPI', Boolean), #BOOLEAN
|
||||||
|
Column('street0Aggr', Boolean), #BOOLEAN
|
||||||
|
Column('street0_3BChance', Boolean), #BOOLEAN
|
||||||
|
Column('street0_3BDone', Boolean), #BOOLEAN
|
||||||
|
Column('street0_4BChance', Boolean), #BOOLEAN
|
||||||
|
Column('street0_4BDone', Boolean), #BOOLEAN
|
||||||
|
Column('other3BStreet0', Boolean), #BOOLEAN
|
||||||
|
Column('other4BStreet0', Boolean), #BOOLEAN
|
||||||
|
|
||||||
|
Column('street1Seen', Boolean), #BOOLEAN
|
||||||
|
Column('street2Seen', Boolean), #BOOLEAN
|
||||||
|
Column('street3Seen', Boolean), #BOOLEAN
|
||||||
|
Column('street4Seen', Boolean), #BOOLEAN
|
||||||
|
Column('sawShowdown', Boolean), #BOOLEAN
|
||||||
|
|
||||||
|
Column('street1Aggr', Boolean), #BOOLEAN
|
||||||
|
Column('street2Aggr', Boolean), #BOOLEAN
|
||||||
|
Column('street3Aggr', Boolean), #BOOLEAN
|
||||||
|
Column('street4Aggr', Boolean), #BOOLEAN
|
||||||
|
|
||||||
|
Column('otherRaisedStreet0',Boolean), #BOOLEAN
|
||||||
|
Column('otherRaisedStreet1',Boolean), #BOOLEAN
|
||||||
|
Column('otherRaisedStreet2',Boolean), #BOOLEAN
|
||||||
|
Column('otherRaisedStreet3',Boolean), #BOOLEAN
|
||||||
|
Column('otherRaisedStreet4',Boolean), #BOOLEAN
|
||||||
|
Column('foldToOtherRaisedStreet0', Boolean), #BOOLEAN
|
||||||
|
Column('foldToOtherRaisedStreet1', Boolean), #BOOLEAN
|
||||||
|
Column('foldToOtherRaisedStreet2', Boolean), #BOOLEAN
|
||||||
|
Column('foldToOtherRaisedStreet3', Boolean), #BOOLEAN
|
||||||
|
Column('foldToOtherRaisedStreet4', Boolean), #BOOLEAN
|
||||||
|
|
||||||
|
Column('stealAttemptChance', Boolean), #BOOLEAN
|
||||||
|
Column('stealAttempted', Boolean), #BOOLEAN
|
||||||
|
Column('foldBbToStealChance', Boolean), #BOOLEAN
|
||||||
|
Column('foldedBbToSteal', Boolean), #BOOLEAN
|
||||||
|
Column('foldSbToStealChance', Boolean), #BOOLEAN
|
||||||
|
Column('foldedSbToSteal', Boolean), #BOOLEAN
|
||||||
|
|
||||||
|
Column('street1CBChance', Boolean), #BOOLEAN
|
||||||
|
Column('street1CBDone', Boolean), #BOOLEAN
|
||||||
|
Column('street2CBChance', Boolean), #BOOLEAN
|
||||||
|
Column('street2CBDone', Boolean), #BOOLEAN
|
||||||
|
Column('street3CBChance', Boolean), #BOOLEAN
|
||||||
|
Column('street3CBDone', Boolean), #BOOLEAN
|
||||||
|
Column('street4CBChance', Boolean), #BOOLEAN
|
||||||
|
Column('street4CBDone', Boolean), #BOOLEAN
|
||||||
|
|
||||||
|
Column('foldToStreet1CBChance', Boolean), #BOOLEAN
|
||||||
|
Column('foldToStreet1CBDone', Boolean), #BOOLEAN
|
||||||
|
Column('foldToStreet2CBChance', Boolean), #BOOLEAN
|
||||||
|
Column('foldToStreet2CBDone', Boolean), #BOOLEAN
|
||||||
|
Column('foldToStreet3CBChance', Boolean), #BOOLEAN
|
||||||
|
Column('foldToStreet3CBDone', Boolean), #BOOLEAN
|
||||||
|
Column('foldToStreet4CBChance', Boolean), #BOOLEAN
|
||||||
|
Column('foldToStreet4CBDone', Boolean), #BOOLEAN
|
||||||
|
|
||||||
|
Column('street1CheckCallRaiseChance',Boolean), #BOOLEAN
|
||||||
|
Column('street1CheckCallRaiseDone', Boolean), #BOOLEAN
|
||||||
|
Column('street2CheckCallRaiseChance',Boolean), #BOOLEAN
|
||||||
|
Column('street2CheckCallRaiseDone', Boolean), #BOOLEAN
|
||||||
|
Column('street3CheckCallRaiseChance',Boolean), #BOOLEAN
|
||||||
|
Column('street3CheckCallRaiseDone', Boolean), #BOOLEAN
|
||||||
|
Column('street4CheckCallRaiseChance',Boolean), #BOOLEAN
|
||||||
|
Column('street4CheckCallRaiseDone', Boolean), #BOOLEAN
|
||||||
|
|
||||||
|
Column('street0Calls', SmallInteger), #TINYINT
|
||||||
|
Column('street1Calls', SmallInteger), #TINYINT
|
||||||
|
Column('street2Calls', SmallInteger), #TINYINT
|
||||||
|
Column('street3Calls', SmallInteger), #TINYINT
|
||||||
|
Column('street4Calls', SmallInteger), #TINYINT
|
||||||
|
Column('street0Bets', SmallInteger), #TINYINT
|
||||||
|
Column('street1Bets', SmallInteger), #TINYINT
|
||||||
|
Column('street2Bets', SmallInteger), #TINYINT
|
||||||
|
Column('street3Bets', SmallInteger), #TINYINT
|
||||||
|
Column('street4Bets', SmallInteger), #TINYINT
|
||||||
|
Column('street0Raises', SmallInteger), #TINYINT
|
||||||
|
Column('street1Raises', SmallInteger), #TINYINT
|
||||||
|
Column('street2Raises', SmallInteger), #TINYINT
|
||||||
|
Column('street3Raises', SmallInteger), #TINYINT
|
||||||
|
Column('street4Raises', SmallInteger), #TINYINT
|
||||||
|
|
||||||
|
Column('actionString', String(15)), #VARCHAR(15)
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
hud_cache_table = Table('HudCache', metadata,
|
||||||
|
Column('id', BigIntColumn, primary_key=True),
|
||||||
|
Column('gametypeId', SmallInteger, ForeignKey("Gametypes.id"), nullable=False), # SMALLINT
|
||||||
|
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False), # SMALLINT
|
||||||
|
Column('activeSeats', SmallInteger, nullable=False), # SMALLINT NOT NULL
|
||||||
|
Column('position', CHAR(1)), # CHAR(1)
|
||||||
|
Column('tourneyTypeId', Integer, ForeignKey("TourneyTypes.id") ), # SMALLINT
|
||||||
|
Column('styleKey', CHAR(7), nullable=False), # CHAR(7) NOT NULL
|
||||||
|
Column('m_factor', Integer),
|
||||||
|
Column('HDs', Integer, nullable=False), # INT NOT NULL
|
||||||
|
|
||||||
|
Column('wonWhenSeenStreet1', Float), # FLOAT
|
||||||
|
Column('wonWhenSeenStreet2', Float), # FLOAT
|
||||||
|
Column('wonWhenSeenStreet3', Float), # FLOAT
|
||||||
|
Column('wonWhenSeenStreet4', Float), # FLOAT
|
||||||
|
Column('wonAtSD', Float), # FLOAT
|
||||||
|
|
||||||
|
Column('street0VPI', Integer), # INT
|
||||||
|
Column('street0Aggr', Integer), # INT
|
||||||
|
Column('street0_3BChance', Integer), # INT
|
||||||
|
Column('street0_3BDone', Integer), # INT
|
||||||
|
Column('street0_4BChance', Integer), # INT
|
||||||
|
Column('street0_4BDone', Integer), # INT
|
||||||
|
Column('other3BStreet0', Integer), # INT
|
||||||
|
Column('other4BStreet0', Integer), # INT
|
||||||
|
|
||||||
|
Column('street1Seen', Integer), # INT
|
||||||
|
Column('street2Seen', Integer), # INT
|
||||||
|
Column('street3Seen', Integer), # INT
|
||||||
|
Column('street4Seen', Integer), # INT
|
||||||
|
Column('sawShowdown', Integer), # INT
|
||||||
|
|
||||||
|
Column('street1Aggr', Integer), # INT
|
||||||
|
Column('street2Aggr', Integer), # INT
|
||||||
|
Column('street3Aggr', Integer), # INT
|
||||||
|
Column('street4Aggr', Integer), # INT
|
||||||
|
|
||||||
|
Column('otherRaisedStreet0', Integer), # INT
|
||||||
|
Column('otherRaisedStreet1', Integer), # INT
|
||||||
|
Column('otherRaisedStreet2', Integer), # INT
|
||||||
|
Column('otherRaisedStreet3', Integer), # INT
|
||||||
|
Column('otherRaisedStreet4', Integer), # INT
|
||||||
|
Column('foldToOtherRaisedStreet0', Integer), # INT
|
||||||
|
Column('foldToOtherRaisedStreet1', Integer), # INT
|
||||||
|
Column('foldToOtherRaisedStreet2', Integer), # INT
|
||||||
|
Column('foldToOtherRaisedStreet3', Integer), # INT
|
||||||
|
Column('foldToOtherRaisedStreet4', Integer), # INT
|
||||||
|
|
||||||
|
Column('stealAttemptChance', Integer), # INT
|
||||||
|
Column('stealAttempted', Integer), # INT
|
||||||
|
Column('foldBbToStealChance', Integer), # INT
|
||||||
|
Column('foldedBbToSteal', Integer), # INT
|
||||||
|
Column('foldSbToStealChance', Integer), # INT
|
||||||
|
Column('foldedSbToSteal', Integer), # INT
|
||||||
|
|
||||||
|
Column('street1CBChance', Integer), # INT
|
||||||
|
Column('street1CBDone', Integer), # INT
|
||||||
|
Column('street2CBChance', Integer), # INT
|
||||||
|
Column('street2CBDone', Integer), # INT
|
||||||
|
Column('street3CBChance', Integer), # INT
|
||||||
|
Column('street3CBDone', Integer), # INT
|
||||||
|
Column('street4CBChance', Integer), # INT
|
||||||
|
Column('street4CBDone', Integer), # INT
|
||||||
|
|
||||||
|
Column('foldToStreet1CBChance', Integer), # INT
|
||||||
|
Column('foldToStreet1CBDone', Integer), # INT
|
||||||
|
Column('foldToStreet2CBChance', Integer), # INT
|
||||||
|
Column('foldToStreet2CBDone', Integer), # INT
|
||||||
|
Column('foldToStreet3CBChance', Integer), # INT
|
||||||
|
Column('foldToStreet3CBDone', Integer), # INT
|
||||||
|
Column('foldToStreet4CBChance', Integer), # INT
|
||||||
|
Column('foldToStreet4CBDone', Integer), # INT
|
||||||
|
|
||||||
|
Column('totalProfit', Integer), # INT
|
||||||
|
|
||||||
|
Column('street1CheckCallRaiseChance', Integer), # INT
|
||||||
|
Column('street1CheckCallRaiseDone', Integer), # INT
|
||||||
|
Column('street2CheckCallRaiseChance', Integer), # INT
|
||||||
|
Column('street2CheckCallRaiseDone', Integer), # INT
|
||||||
|
Column('street3CheckCallRaiseChance', Integer), # INT
|
||||||
|
Column('street3CheckCallRaiseDone', Integer), # INT
|
||||||
|
Column('street4CheckCallRaiseChance', Integer), # INT
|
||||||
|
Column('street4CheckCallRaiseDone', Integer), # INT
|
||||||
|
|
||||||
|
Column('street0Calls', Integer), # INT
|
||||||
|
Column('street1Calls', Integer), # INT
|
||||||
|
Column('street2Calls', Integer), # INT
|
||||||
|
Column('street3Calls', Integer), # INT
|
||||||
|
Column('street4Calls', Integer), # INT
|
||||||
|
Column('street0Bets', Integer), # INT
|
||||||
|
Column('street1Bets', Integer), # INT
|
||||||
|
Column('street2Bets', Integer), # INT
|
||||||
|
Column('street3Bets', Integer), # INT
|
||||||
|
Column('street4Bets', Integer), # INT
|
||||||
|
Column('street0Raises', Integer), # INT
|
||||||
|
Column('street1Raises', Integer), # INT
|
||||||
|
Column('street2Raises', Integer), # INT
|
||||||
|
Column('street3Raises', Integer), # INT
|
||||||
|
Column('street4Raises', Integer), # INT
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
players_table = Table('Players', metadata,
|
||||||
|
Column('id', Integer, primary_key=True),
|
||||||
|
Column('name', Unicode(32), nullable=False), # VARCHAR(32) CHARACTER SET utf8 NOT NULL
|
||||||
|
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False), # SMALLINT
|
||||||
|
Column('comment', Text), # text
|
||||||
|
Column('commentTs', DateTime), # DATETIME
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
Index('name', players_table.c.name, players_table.c.siteId, unique=True)
|
||||||
|
|
||||||
|
|
||||||
|
settings_table = Table('Settings', metadata,
|
||||||
|
Column('version', SmallInteger, nullable=False),
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
sites_table = Table('Sites', metadata,
|
||||||
|
Column('id', SmallInteger, primary_key=True),
|
||||||
|
Column('name', String(32), nullable=False), # varchar(32) NOT NULL
|
||||||
|
Column('currency', String(3), nullable=False), # char(3) NOT NULL
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
tourneys_table = Table('Tourneys', metadata,
|
||||||
|
Column('id', Integer, primary_key=True),
|
||||||
|
Column('tourneyTypeId', Integer, ForeignKey("TourneyTypes.id"), nullable=False, default=1),
|
||||||
|
Column('siteTourneyNo', BigIntColumn, nullable=False), # BIGINT NOT NULL
|
||||||
|
Column('entries', Integer), # INT NOT NULL
|
||||||
|
Column('prizepool', Integer), # INT NOT NULL
|
||||||
|
Column('tourStartTime', DateTime), # DATETIME NOT NULL
|
||||||
|
Column('tourEndTime', DateTime), # DATETIME
|
||||||
|
Column('buyinChips', Integer), # INT
|
||||||
|
Column('tourneyName', String(40)), # varchar(40)
|
||||||
|
# Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn
|
||||||
|
Column('matrixIdProcessed',SmallInteger, default=0), # TINYINT UNSIGNED DEFAULT 0
|
||||||
|
Column('rebuyChips', Integer, default=0), # INT DEFAULT 0
|
||||||
|
Column('addonChips', Integer, default=0), # INT DEFAULT 0
|
||||||
|
Column('rebuyAmount', MoneyColumn, default=0), # INT DEFAULT 0
|
||||||
|
Column('addonAmount', MoneyColumn, default=0), # INT DEFAULT 0
|
||||||
|
Column('totalRebuys', Integer, default=0), # INT DEFAULT 0
|
||||||
|
Column('totalAddons', Integer, default=0), # INT DEFAULT 0
|
||||||
|
Column('koBounty', Integer, default=0), # INT DEFAULT 0
|
||||||
|
Column('comment', Text), # TEXT
|
||||||
|
Column('commentTs', DateTime), # DATETIME
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
Index('siteTourneyNo', tourneys_table.c.siteTourneyNo, tourneys_table.c.tourneyTypeId, unique=True)
|
||||||
|
|
||||||
|
|
||||||
|
tourney_types_table = Table('TourneyTypes', metadata,
|
||||||
|
Column('id', Integer, primary_key=True),
|
||||||
|
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False),
|
||||||
|
Column('buyin', Integer, nullable=False), # INT NOT NULL
|
||||||
|
Column('fee', Integer, nullable=False, default=0), # INT NOT NULL
|
||||||
|
Column('maxSeats', Boolean, nullable=False, default=-1), # INT NOT NULL DEFAULT -1
|
||||||
|
Column('knockout', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('rebuyOrAddon', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('speed', String(10)), # varchar(10)
|
||||||
|
Column('headsUp', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('shootout', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('matrix', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('sng', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
Index('tourneyTypes_all',
|
||||||
|
tourney_types_table.c.siteId, tourney_types_table.c.buyin, tourney_types_table.c.fee,
|
||||||
|
tourney_types_table.c.maxSeats, tourney_types_table.c.knockout, tourney_types_table.c.rebuyOrAddon,
|
||||||
|
tourney_types_table.c.speed, tourney_types_table.c.headsUp, tourney_types_table.c.shootout,
|
||||||
|
tourney_types_table.c.matrix, tourney_types_table.c.sng)
|
||||||
|
|
||||||
|
|
||||||
|
tourneys_players_table = Table('TourneysPlayers', metadata,
|
||||||
|
Column('id', BigIntColumn, primary_key=True),
|
||||||
|
Column('tourneyId', Integer, ForeignKey("Tourneys.id"), nullable=False),
|
||||||
|
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False),
|
||||||
|
Column('payinAmount', Integer), # INT NOT NULL
|
||||||
|
Column('rank', Integer), # INT NOT NULL
|
||||||
|
Column('winnings', Integer), # INT NOT NULL
|
||||||
|
Column('nbRebuys', Integer, default=0), # INT DEFAULT 0
|
||||||
|
Column('nbAddons', Integer, default=0), # INT DEFAULT 0
|
||||||
|
Column('nbKO', Integer, default=0), # INT DEFAULT 0
|
||||||
|
Column('comment', Text), # TEXT
|
||||||
|
Column('commentTs', DateTime), # DATETIME
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
Index('tourneyId', tourneys_players_table.c.tourneyId, tourneys_players_table.c.playerId, unique=True)
|
||||||
|
|
||||||
|
|
||||||
|
def sss():
|
||||||
|
"Debug function. Returns (config, sql, db)"
|
||||||
|
|
||||||
|
import Configuration, SQL, Database, os
|
||||||
|
class Dummy(object):
|
||||||
|
pass
|
||||||
|
self = Dummy()
|
||||||
|
self.config = Configuration.Config()
|
||||||
|
self.settings = {}
|
||||||
|
if (os.sep=="/"):
|
||||||
|
self.settings['os']="linuxmac"
|
||||||
|
else:
|
||||||
|
self.settings['os']="windows"
|
||||||
|
|
||||||
|
self.settings.update(self.config.get_db_parameters())
|
||||||
|
self.settings.update(self.config.get_tv_parameters())
|
||||||
|
self.settings.update(self.config.get_import_parameters())
|
||||||
|
self.settings.update(self.config.get_default_paths())
|
||||||
|
|
||||||
|
self.sql = SQL.Sql( db_server = self.settings['db-server'])
|
||||||
|
self.db = Database.Database(self.config, sql = self.sql)
|
||||||
|
|
||||||
|
return self.config, self.sql, self.db
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
#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 Affero General Public License as published by
|
#it under the terms of the GNU Affero General Public License as published by
|
||||||
#the Free Software Foundation, version 3 of the License.
|
#the Free Software Foundation, version 3 of the License.
|
||||||
#
|
#
|
||||||
#This program is distributed in the hope that it will be useful,
|
#This program is distributed in the hope that it will be useful,
|
||||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
#GNU General Public License for more details.
|
#GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
#You should have received a copy of the GNU Affero General Public License
|
#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/>.
|
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#In the "official" distribution you can find the license in
|
#In the "official" distribution you can find the license in
|
||||||
|
@ -39,24 +39,37 @@ def calcStartCards(hand, player):
|
||||||
|
|
||||||
def twoStartCards(value1, suit1, value2, suit2):
|
def twoStartCards(value1, suit1, value2, suit2):
|
||||||
""" Function to convert 2 value,suit pairs into a Holdem style starting hand e.g. AQo
|
""" Function to convert 2 value,suit pairs into a Holdem style starting hand e.g. AQo
|
||||||
Hand is stored as an int 13 * x + y where (x+2) represents rank of 1st card and
|
Incoming values should be ints 2-14 (2,3,...K,A), suits are 'd'/'h'/'c'/'s'
|
||||||
|
Hand is stored as an int 13 * x + y + 1 where (x+2) represents rank of 1st card and
|
||||||
(y+2) represents rank of second card (2=2 .. 14=Ace)
|
(y+2) represents rank of second card (2=2 .. 14=Ace)
|
||||||
If x > y then pair is suited, if x < y then unsuited"""
|
If x > y then pair is suited, if x < y then unsuited
|
||||||
if value1 < 2 or value2 < 2:
|
Examples:
|
||||||
|
0 Unknown / Illegal cards
|
||||||
|
1 22
|
||||||
|
2 32o
|
||||||
|
3 42o
|
||||||
|
...
|
||||||
|
14 32s
|
||||||
|
15 33
|
||||||
|
16 42o
|
||||||
|
...
|
||||||
|
170 AA
|
||||||
|
"""
|
||||||
|
if value1 is None or value1 < 2 or value1 > 14 or value2 is None or value2 < 2 or value2 > 14:
|
||||||
ret = 0
|
ret = 0
|
||||||
if value1 == value2: # pairs
|
elif value1 == value2: # pairs
|
||||||
ret = (13 * (value2-2) + (value2-2) )
|
ret = (13 * (value2-2) + (value2-2) ) + 1
|
||||||
elif suit1 == suit2:
|
elif suit1 == suit2:
|
||||||
if value1 > value2:
|
if value1 > value2:
|
||||||
ret = 13 * (value1-2) + (value2-2)
|
ret = 13 * (value1-2) + (value2-2) + 1
|
||||||
else:
|
else:
|
||||||
ret = 13 * (value2-2) + (value1-2)
|
ret = 13 * (value2-2) + (value1-2) + 1
|
||||||
else:
|
else:
|
||||||
if value1 > value2:
|
if value1 > value2:
|
||||||
ret = 13 * (value2-2) + (value1-2)
|
ret = 13 * (value2-2) + (value1-2) + 1
|
||||||
else:
|
else:
|
||||||
ret = 13 * (value1-2) + (value2-2)
|
ret = 13 * (value1-2) + (value2-2) + 1
|
||||||
|
|
||||||
# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret
|
# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -66,8 +79,8 @@ def twoStartCardString(card):
|
||||||
ret = 'xx'
|
ret = 'xx'
|
||||||
if card > 0:
|
if card > 0:
|
||||||
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
|
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
|
||||||
x = card / 13
|
x = (card-1) / 13
|
||||||
y = card - 13 * x
|
y = (card-1) - 13 * x
|
||||||
if x == y: ret = s[x] + s[y]
|
if x == y: ret = s[x] + s[y]
|
||||||
elif x > y: ret = s[x] + s[y] + 's'
|
elif x > y: ret = s[x] + s[y] + 's'
|
||||||
else: ret = s[y] + s[x] + 'o'
|
else: ret = s[y] + s[x] + 'o'
|
||||||
|
@ -95,7 +108,7 @@ def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4):
|
||||||
# SSSS (K, J, 6, 3)
|
# SSSS (K, J, 6, 3)
|
||||||
# - 13C4 = 715 possibilities
|
# - 13C4 = 715 possibilities
|
||||||
# SSSx (K, J, 6),(3)
|
# SSSx (K, J, 6),(3)
|
||||||
# - 13C3 * 13 = 3718 possibilities
|
# - 13C3 * 13 = 3718 possibilities
|
||||||
# SSxy (K, J),(6),(3)
|
# SSxy (K, J),(6),(3)
|
||||||
# - 13C2 * 13*13 = 13182 possibilities
|
# - 13C2 * 13*13 = 13182 possibilities
|
||||||
# SSHH (K, J),(6, 3)
|
# SSHH (K, J),(6, 3)
|
||||||
|
@ -118,7 +131,7 @@ suitFromCardList = ['', '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', 'Th', 'J
|
||||||
, '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As'
|
, '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As'
|
||||||
]
|
]
|
||||||
def valueSuitFromCard(card):
|
def valueSuitFromCard(card):
|
||||||
""" Function to convert a card stored in the database (int 0-52) into value
|
""" Function to convert a card stored in the database (int 0-52) into value
|
||||||
and suit like 9s, 4c etc """
|
and suit like 9s, 4c etc """
|
||||||
global suitFromCardList
|
global suitFromCardList
|
||||||
if card < 0 or card > 52 or not card:
|
if card < 0 or card > 52 or not card:
|
||||||
|
@ -145,5 +158,5 @@ if __name__ == '__main__':
|
||||||
print "card %2d = %s card %2d = %s card %2d = %s card %2d = %s" % \
|
print "card %2d = %s card %2d = %s card %2d = %s card %2d = %s" % \
|
||||||
(i, valueSuitFromCard(i), i+13, valueSuitFromCard(i+13), i+26, valueSuitFromCard(i+26), i+39, valueSuitFromCard(i+39))
|
(i, valueSuitFromCard(i), i+13, valueSuitFromCard(i+13), i+26, valueSuitFromCard(i+26), i+39, valueSuitFromCard(i+39))
|
||||||
|
|
||||||
print
|
print
|
||||||
print encodeCard('7c')
|
print encodeCard('7c')
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
#Copyright 2008 Steffen Jobbagy-Felso
|
|
||||||
#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.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import fpdb_simple
|
|
||||||
from optparse import OptionParser
|
|
||||||
|
|
||||||
try:
|
|
||||||
import MySQLdb
|
|
||||||
except:
|
|
||||||
diaSQLLibMissing = gtk.Dialog(title="Fatal Error - SQL interface library missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK))
|
|
||||||
|
|
||||||
print "Please note that the CLI importer only works with MySQL, if you use PostgreSQL this error is expected."
|
|
||||||
|
|
||||||
import fpdb_import
|
|
||||||
import fpdb_db
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
#process CLI parameters
|
|
||||||
parser = OptionParser()
|
|
||||||
parser.add_option("-c", "--handCount", default="0", type="int",
|
|
||||||
help="Number of hands to import (default 0 means unlimited)")
|
|
||||||
parser.add_option("-d", "--database", default="fpdb", help="The MySQL database to use (default fpdb)")
|
|
||||||
parser.add_option("-e", "--errorFile", default="failed.txt",
|
|
||||||
help="File to store failed hands into. (default: failed.txt) Not implemented.")
|
|
||||||
parser.add_option("-f", "--inputFile", "--file", "--inputfile", default="stdin",
|
|
||||||
help="The file you want to import (remember to use quotes if necessary)")
|
|
||||||
parser.add_option("-m", "--minPrint", "--status", default="50", type="int",
|
|
||||||
help="How often to print a one-line status report (0 means never, default is 50)")
|
|
||||||
parser.add_option("-p", "--password", help="The password for the MySQL user")
|
|
||||||
parser.add_option("-q", "--quiet", action="store_true",
|
|
||||||
help="If this is passed it doesn't print a total at the end nor the opening line. Note that this purposely does NOT change --minPrint")
|
|
||||||
parser.add_option("-s", "--server", default="localhost",
|
|
||||||
help="Hostname/IP of the MySQL server (default localhost)")
|
|
||||||
parser.add_option("-u", "--user", default="fpdb", help="The MySQL username (default fpdb)")
|
|
||||||
parser.add_option("-x", "--failOnError", action="store_true",
|
|
||||||
help="If this option is passed it quits when it encounters any error")
|
|
||||||
|
|
||||||
(options, argv) = parser.parse_args()
|
|
||||||
|
|
||||||
settings={'callFpdbHud':False, 'db-backend':2}
|
|
||||||
settings['db-host']=options.server
|
|
||||||
settings['db-user']=options.user
|
|
||||||
settings['db-password']=options.password
|
|
||||||
settings['db-databaseName']=options.database
|
|
||||||
settings['handCount']=options.handCount
|
|
||||||
settings['failOnError']=options.failOnError
|
|
||||||
|
|
||||||
importer = fpdb_import.Importer(options, settings)
|
|
||||||
importer.addImportFile(options.inputFile)
|
|
||||||
importer.runImport()
|
|
|
@ -31,6 +31,7 @@ import inspect
|
||||||
import string
|
import string
|
||||||
import traceback
|
import traceback
|
||||||
import shutil
|
import shutil
|
||||||
|
import locale
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
from xml.dom.minidom import Node
|
from xml.dom.minidom import Node
|
||||||
|
|
||||||
|
@ -125,7 +126,8 @@ DATABASE_TYPES = (
|
||||||
DATABASE_TYPE_MYSQL,
|
DATABASE_TYPE_MYSQL,
|
||||||
)
|
)
|
||||||
|
|
||||||
NEWIMPORT = False
|
NEWIMPORT = True
|
||||||
|
LOCALE_ENCODING = locale.getdefaultlocale()[1]
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
def string_to_bool(string, default=True):
|
def string_to_bool(string, default=True):
|
||||||
|
|
1186
pyfpdb/Database.py
1186
pyfpdb/Database.py
File diff suppressed because it is too large
Load Diff
|
@ -48,18 +48,11 @@ class DerivedStats():
|
||||||
self.handsplayers[player[1]]['sawShowdown'] = False
|
self.handsplayers[player[1]]['sawShowdown'] = False
|
||||||
self.handsplayers[player[1]]['wonAtSD'] = 0.0
|
self.handsplayers[player[1]]['wonAtSD'] = 0.0
|
||||||
self.handsplayers[player[1]]['startCards'] = 0
|
self.handsplayers[player[1]]['startCards'] = 0
|
||||||
for i in range(5):
|
|
||||||
self.handsplayers[player[1]]['street%dCalls' % i] = 0
|
|
||||||
self.handsplayers[player[1]]['street%dBets' % i] = 0
|
|
||||||
for i in range(1,5):
|
|
||||||
self.handsplayers[player[1]]['street%dCBChance' %i] = False
|
|
||||||
self.handsplayers[player[1]]['street%dCBDone' %i] = False
|
|
||||||
|
|
||||||
#FIXME - Everything below this point is incomplete.
|
|
||||||
self.handsplayers[player[1]]['position'] = 2
|
self.handsplayers[player[1]]['position'] = 2
|
||||||
self.handsplayers[player[1]]['tourneyTypeId'] = 1
|
|
||||||
self.handsplayers[player[1]]['street0_3BChance'] = False
|
self.handsplayers[player[1]]['street0_3BChance'] = False
|
||||||
self.handsplayers[player[1]]['street0_3BDone'] = False
|
self.handsplayers[player[1]]['street0_3BDone'] = False
|
||||||
|
self.handsplayers[player[1]]['street0_4BChance'] = False
|
||||||
|
self.handsplayers[player[1]]['street0_4BDone'] = False
|
||||||
self.handsplayers[player[1]]['stealAttemptChance'] = False
|
self.handsplayers[player[1]]['stealAttemptChance'] = False
|
||||||
self.handsplayers[player[1]]['stealAttempted'] = False
|
self.handsplayers[player[1]]['stealAttempted'] = False
|
||||||
self.handsplayers[player[1]]['foldBbToStealChance'] = False
|
self.handsplayers[player[1]]['foldBbToStealChance'] = False
|
||||||
|
@ -67,13 +60,22 @@ class DerivedStats():
|
||||||
self.handsplayers[player[1]]['foldSbToStealChance'] = False
|
self.handsplayers[player[1]]['foldSbToStealChance'] = False
|
||||||
self.handsplayers[player[1]]['foldedSbToSteal'] = False
|
self.handsplayers[player[1]]['foldedSbToSteal'] = False
|
||||||
self.handsplayers[player[1]]['foldedBbToSteal'] = False
|
self.handsplayers[player[1]]['foldedBbToSteal'] = False
|
||||||
|
for i in range(5):
|
||||||
|
self.handsplayers[player[1]]['street%dCalls' % i] = 0
|
||||||
|
self.handsplayers[player[1]]['street%dBets' % i] = 0
|
||||||
|
for i in range(1,5):
|
||||||
|
self.handsplayers[player[1]]['street%dCBChance' %i] = False
|
||||||
|
self.handsplayers[player[1]]['street%dCBDone' %i] = False
|
||||||
|
self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False
|
||||||
|
self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False
|
||||||
|
|
||||||
|
#FIXME - Everything below this point is incomplete.
|
||||||
|
self.handsplayers[player[1]]['tourneyTypeId'] = 1
|
||||||
for i in range(1,5):
|
for i in range(1,5):
|
||||||
self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False
|
self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False
|
||||||
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
|
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
|
||||||
self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False
|
self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False
|
||||||
self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False
|
self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False
|
||||||
self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False
|
|
||||||
self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False
|
|
||||||
|
|
||||||
self.assembleHands(self.hand)
|
self.assembleHands(self.hand)
|
||||||
self.assembleHandsPlayers(self.hand)
|
self.assembleHandsPlayers(self.hand)
|
||||||
|
@ -174,33 +176,47 @@ class DerivedStats():
|
||||||
self.handsplayers[player[1]]['card%s' % (i+1)] = Card.encodeCard(card)
|
self.handsplayers[player[1]]['card%s' % (i+1)] = Card.encodeCard(card)
|
||||||
self.handsplayers[player[1]]['startCards'] = Card.calcStartCards(hand, player[1])
|
self.handsplayers[player[1]]['startCards'] = Card.calcStartCards(hand, player[1])
|
||||||
|
|
||||||
# position,
|
self.setPositions(hand)
|
||||||
#Stud 3rd street card test
|
self.calcCheckCallRaise(hand)
|
||||||
# denny501: brings in for $0.02
|
self.calc34BetStreet0(hand)
|
||||||
# s0rrow: calls $0.02
|
self.calcSteals(hand)
|
||||||
# TomSludge: folds
|
|
||||||
# Soroka69: calls $0.02
|
|
||||||
# rdiezchang: calls $0.02 (Seat 8)
|
|
||||||
# u.pressure: folds (Seat 1)
|
|
||||||
# 123smoothie: calls $0.02
|
|
||||||
# gashpor: calls $0.02
|
|
||||||
|
|
||||||
# Additional stats
|
# Additional stats
|
||||||
# 3betSB, 3betBB
|
# 3betSB, 3betBB
|
||||||
# Squeeze, Ratchet?
|
# Squeeze, Ratchet?
|
||||||
|
|
||||||
|
|
||||||
def getPosition(hand, seat):
|
def setPositions(self, hand):
|
||||||
"""Returns position value like 'B', 'S', 0, 1, ..."""
|
"""Sets the position for each player in HandsPlayers
|
||||||
# Flop/Draw games with blinds
|
any blinds are negative values, and the last person to act on the
|
||||||
# Need a better system???
|
first betting round is 0
|
||||||
# -2 BB - B (all)
|
NOTE: HU, both values are negative for non-stud games
|
||||||
# -1 SB - S (all)
|
NOTE2: I've never seen a HU stud match"""
|
||||||
# 0 Button
|
# The position calculation must be done differently for Stud and other games as
|
||||||
# 1 Cutoff
|
# Stud the 'blind' acts first - in all other games they act last.
|
||||||
# 2 Hijack
|
#
|
||||||
|
#This function is going to get it wrong when there in situations where there
|
||||||
|
# is no small blind. I can live with that.
|
||||||
|
positions = [7, 6, 5, 4, 3, 2, 1, 0, 'S', 'B']
|
||||||
|
actions = hand.actions[hand.holeStreets[0]]
|
||||||
|
players = self.pfbao(actions)
|
||||||
|
seats = len(players)
|
||||||
|
map = []
|
||||||
|
if hand.gametype['base'] == 'stud':
|
||||||
|
# Could posibly change this to be either -2 or -1 depending if they complete or bring-in
|
||||||
|
# First player to act is -1, last player is 0 for 6 players it should look like:
|
||||||
|
# ['S', 4, 3, 2, 1, 0]
|
||||||
|
map = positions[-seats-1:-1] # Copy required positions from postions array anding in -1
|
||||||
|
map = map[-1:] + map[0:-1] # and move the -1 to the start of that array
|
||||||
|
else:
|
||||||
|
# For 6 players is should look like:
|
||||||
|
# [3, 2, 1, 0, 'S', 'B']
|
||||||
|
map = positions[-seats:] # Copy required positions from array ending in -2
|
||||||
|
|
||||||
|
for i, player in enumerate(players):
|
||||||
|
self.handsplayers[player]['position'] = map[i]
|
||||||
|
|
||||||
def assembleHudCache(self, hand):
|
def assembleHudCache(self, hand):
|
||||||
|
# No real work to be done - HandsPlayers data already contains the correct info
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def vpip(self, hand):
|
def vpip(self, hand):
|
||||||
|
@ -262,13 +278,59 @@ class DerivedStats():
|
||||||
for (i, street) in enumerate(hand.actionStreets[1:]):
|
for (i, street) in enumerate(hand.actionStreets[1:]):
|
||||||
self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street]))
|
self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street]))
|
||||||
|
|
||||||
def calcCBets(self, hand):
|
def calcSteals(self, hand):
|
||||||
# Continuation Bet chance, action:
|
"""Fills stealAttempt(Chance|ed, fold(Bb|Sb)ToSteal(Chance|)
|
||||||
# Had the last bet (initiative) on previous street, got called, close street action
|
|
||||||
# Then no bets before the player with initiatives first action on current street
|
|
||||||
# ie. if player on street-1 had initiative
|
|
||||||
# and no donkbets occurred
|
|
||||||
|
|
||||||
|
Steal attemp - open raise on positions 2 1 0 S - i.e. MP3, CO, BU, SB
|
||||||
|
Fold to steal - folding blind after steal attemp wo any other callers or raisers
|
||||||
|
"""
|
||||||
|
steal_attemp = False
|
||||||
|
steal_positions = ('2', '1', '0', 'S')
|
||||||
|
if hand.gametype['base'] == 'stud':
|
||||||
|
steal_positions = ('2', '1', '0')
|
||||||
|
for action in hand.actions[hand.actionStreets[1]]:
|
||||||
|
pname, act = action[0], action[1]
|
||||||
|
#print action[0], hp.position, steal_attemp, act
|
||||||
|
if self.handsplayers[pname]['position'] == 'B':
|
||||||
|
#NOTE: Stud games will never hit this section
|
||||||
|
self.handsplayers[pname]['foldBbToStealChance'] = steal_attemp
|
||||||
|
self.handsplayers[pname]['foldBbToSteal'] = self.handsplayers[pname]['foldBbToStealChance'] and act == 'folds'
|
||||||
|
break
|
||||||
|
elif self.handsplayers[pname]['position'] == 'S':
|
||||||
|
self.handsplayers[pname]['foldSbToStealChance'] = steal_attemp
|
||||||
|
self.handsplayers[pname]['foldSbToSteal'] = self.handsplayers[pname]['foldSbToStealChance'] and act == 'folds'
|
||||||
|
|
||||||
|
if steal_attemp and act != 'folds':
|
||||||
|
break
|
||||||
|
|
||||||
|
if self.handsplayers[pname]['position'] in steal_positions and not steal_attemp:
|
||||||
|
self.handsplayers[pname]['stealAttemptChance'] = True
|
||||||
|
if act in ('bets', 'raises'):
|
||||||
|
self.handsplayers[pname]['stealAttempted'] = True
|
||||||
|
steal_attemp = True
|
||||||
|
|
||||||
|
def calc34BetStreet0(self, hand):
|
||||||
|
"""Fills street0_(3|4)B(Chance|Done), other(3|4)BStreet0"""
|
||||||
|
bet_level = 1 # bet_level after 3-bet is equal to 3
|
||||||
|
for action in hand.actions[hand.actionStreets[1]]:
|
||||||
|
# FIXME: fill other(3|4)BStreet0 - i have no idea what does it mean
|
||||||
|
pname, aggr = action[0], action[1] in ('raises', 'bets')
|
||||||
|
self.handsplayers[pname]['street0_3BChance'] = bet_level == 2
|
||||||
|
self.handsplayers[pname]['street0_4BChance'] = bet_level == 3
|
||||||
|
self.handsplayers[pname]['street0_3BDone'] = aggr and (self.handsplayers[pname]['street0_3BChance'])
|
||||||
|
self.handsplayers[pname]['street0_4BDone'] = aggr and (self.handsplayers[pname]['street0_4BChance'])
|
||||||
|
if aggr:
|
||||||
|
bet_level += 1
|
||||||
|
|
||||||
|
|
||||||
|
def calcCBets(self, hand):
|
||||||
|
"""Fill streetXCBChance, streetXCBDone, foldToStreetXCBDone, foldToStreetXCBChance
|
||||||
|
|
||||||
|
Continuation Bet chance, action:
|
||||||
|
Had the last bet (initiative) on previous street, got called, close street action
|
||||||
|
Then no bets before the player with initiatives first action on current street
|
||||||
|
ie. if player on street-1 had initiative and no donkbets occurred
|
||||||
|
"""
|
||||||
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
|
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
|
||||||
# came there
|
# came there
|
||||||
#for i, street in enumerate(hand.actionStreets[2:], start=1):
|
#for i, street in enumerate(hand.actionStreets[2:], start=1):
|
||||||
|
@ -280,6 +342,29 @@ class DerivedStats():
|
||||||
if chance == True:
|
if chance == True:
|
||||||
self.handsplayers[name]['street%dCBDone' % (i+1)] = self.betStreet(hand.actionStreets[i+2], name)
|
self.handsplayers[name]['street%dCBDone' % (i+1)] = self.betStreet(hand.actionStreets[i+2], name)
|
||||||
|
|
||||||
|
def calcCheckCallRaise(self, hand):
|
||||||
|
"""Fill streetXCheckCallRaiseChance, streetXCheckCallRaiseDone
|
||||||
|
|
||||||
|
streetXCheckCallRaiseChance = got raise/bet after check
|
||||||
|
streetXCheckCallRaiseDone = checked. got raise/bet. didn't fold
|
||||||
|
|
||||||
|
CG: CheckCall would be a much better name for this.
|
||||||
|
"""
|
||||||
|
#for i, street in enumerate(hand.actionStreets[2:], start=1):
|
||||||
|
for i, street in enumerate(hand.actionStreets[2:]):
|
||||||
|
actions = hand.actions[hand.actionStreets[i+1]]
|
||||||
|
checkers = set()
|
||||||
|
initial_raiser = None
|
||||||
|
for action in actions:
|
||||||
|
pname, act = action[0], action[1]
|
||||||
|
if act in ('bets', 'raises') and initial_raiser is None:
|
||||||
|
initial_raiser = pname
|
||||||
|
elif act == 'checks' and initial_raiser is None:
|
||||||
|
checkers.add(pname)
|
||||||
|
elif initial_raiser is not None and pname in checkers:
|
||||||
|
self.handsplayers[pname]['street%dCheckCallRaiseChance' % (i+1)] = True
|
||||||
|
self.handsplayers[pname]['street%dCheckCallRaiseDone' % (i+1)] = act!='folds'
|
||||||
|
|
||||||
def seen(self, hand, i):
|
def seen(self, hand, i):
|
||||||
pas = set()
|
pas = set()
|
||||||
for act in hand.actions[hand.actionStreets[i+1]]:
|
for act in hand.actions[hand.actionStreets[i+1]]:
|
||||||
|
@ -293,11 +378,13 @@ class DerivedStats():
|
||||||
|
|
||||||
def aggr(self, hand, i):
|
def aggr(self, hand, i):
|
||||||
aggrers = set()
|
aggrers = set()
|
||||||
for act in hand.actions[hand.actionStreets[i]]:
|
# Growl - actionStreets contains 'BLINDSANTES', which isn't actually an action street
|
||||||
if act[1] in ('completes', 'raises'):
|
for act in hand.actions[hand.actionStreets[i+1]]:
|
||||||
|
if act[1] in ('completes', 'bets', 'raises'):
|
||||||
aggrers.add(act[0])
|
aggrers.add(act[0])
|
||||||
|
|
||||||
for player in hand.players:
|
for player in hand.players:
|
||||||
|
#print "DEBUG: actionStreet[%s]: %s" %(hand.actionStreets[i+1], i)
|
||||||
if player[1] in aggrers:
|
if player[1] in aggrers:
|
||||||
self.handsplayers[player[1]]['street%sAggr' % i] = True
|
self.handsplayers[player[1]]['street%sAggr' % i] = True
|
||||||
else:
|
else:
|
||||||
|
@ -333,6 +420,44 @@ class DerivedStats():
|
||||||
players.add(action[0])
|
players.add(action[0])
|
||||||
return players
|
return players
|
||||||
|
|
||||||
|
def pfbao(self, actions, f=None, l=None, unique=True):
|
||||||
|
"""Helper method. Returns set of PlayersFilteredByActionsOrdered
|
||||||
|
|
||||||
|
f - forbidden actions
|
||||||
|
l - limited to actions
|
||||||
|
"""
|
||||||
|
# Note, this is an adaptation of function 5 from:
|
||||||
|
# http://www.peterbe.com/plog/uniqifiers-benchmark
|
||||||
|
seen = {}
|
||||||
|
players = []
|
||||||
|
for action in actions:
|
||||||
|
if l is not None and action[1] not in l: continue
|
||||||
|
if f is not None and action[1] in f: continue
|
||||||
|
if action[0] in seen and unique: continue
|
||||||
|
seen[action[0]] = 1
|
||||||
|
players.append(action[0])
|
||||||
|
return players
|
||||||
|
|
||||||
|
def firstsBetOrRaiser(self, actions):
|
||||||
|
"""Returns player name that placed the first bet or raise.
|
||||||
|
|
||||||
|
None if there were no bets or raises on that street
|
||||||
|
"""
|
||||||
|
for act in actions:
|
||||||
|
if act[1] in ('bets', 'raises'):
|
||||||
|
return act[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def lastBetOrRaiser(self, street):
|
||||||
|
"""Returns player name that placed the last bet or raise for that street.
|
||||||
|
None if there were no bets or raises on that street"""
|
||||||
|
lastbet = None
|
||||||
|
for act in self.hand.actions[street]:
|
||||||
|
if act[1] in ('bets', 'raises'):
|
||||||
|
lastbet = act[0]
|
||||||
|
return lastbet
|
||||||
|
|
||||||
|
|
||||||
def noBetsBefore(self, street, player):
|
def noBetsBefore(self, street, player):
|
||||||
"""Returns true if there were no bets before the specified players turn, false otherwise"""
|
"""Returns true if there were no bets before the specified players turn, false otherwise"""
|
||||||
betOrRaise = False
|
betOrRaise = False
|
||||||
|
@ -345,6 +470,7 @@ class DerivedStats():
|
||||||
break
|
break
|
||||||
return betOrRaise
|
return betOrRaise
|
||||||
|
|
||||||
|
|
||||||
def betStreet(self, street, player):
|
def betStreet(self, street, player):
|
||||||
"""Returns true if player bet/raised the street as their first action"""
|
"""Returns true if player bet/raised the street as their first action"""
|
||||||
betOrRaise = False
|
betOrRaise = False
|
||||||
|
@ -355,12 +481,3 @@ class DerivedStats():
|
||||||
break
|
break
|
||||||
return betOrRaise
|
return betOrRaise
|
||||||
|
|
||||||
|
|
||||||
def lastBetOrRaiser(self, street):
|
|
||||||
"""Returns player name that placed the last bet or raise for that street.
|
|
||||||
None if there were no bets or raises on that street"""
|
|
||||||
lastbet = None
|
|
||||||
for act in self.hand.actions[street]:
|
|
||||||
if act[1] in ('bets', 'raises'):
|
|
||||||
lastbet = act[0]
|
|
||||||
return lastbet
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ class Filters(threading.Thread):
|
||||||
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
|
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
|
||||||
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
|
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
|
||||||
,'groupsall':'All Players'
|
,'groupsall':'All Players'
|
||||||
,'limitsFL':'FL', 'limitsNL':'NL', 'ring':'Ring', 'tour':'Tourney'
|
,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney'
|
||||||
}
|
}
|
||||||
|
|
||||||
# For use in date ranges.
|
# For use in date ranges.
|
||||||
|
@ -107,6 +107,7 @@ class Filters(threading.Thread):
|
||||||
self.cbAllLimits = None
|
self.cbAllLimits = None
|
||||||
self.cbFL = None
|
self.cbFL = None
|
||||||
self.cbNL = None
|
self.cbNL = None
|
||||||
|
self.cbPL = None
|
||||||
self.rb = {} # radio buttons for ring/tour
|
self.rb = {} # radio buttons for ring/tour
|
||||||
self.type = None # ring/tour
|
self.type = None # ring/tour
|
||||||
self.types = {} # list of all ring/tour values
|
self.types = {} # list of all ring/tour values
|
||||||
|
@ -191,6 +192,9 @@ class Filters(threading.Thread):
|
||||||
def getSites(self):
|
def getSites(self):
|
||||||
return self.sites
|
return self.sites
|
||||||
|
|
||||||
|
def getGames(self):
|
||||||
|
return self.games
|
||||||
|
|
||||||
def getSiteIds(self):
|
def getSiteIds(self):
|
||||||
return self.siteid
|
return self.siteid
|
||||||
|
|
||||||
|
@ -303,7 +307,7 @@ class Filters(threading.Thread):
|
||||||
#print w.get_active()
|
#print w.get_active()
|
||||||
self.limits[limit] = w.get_active()
|
self.limits[limit] = w.get_active()
|
||||||
print "self.limit[%s] set to %s" %(limit, self.limits[limit])
|
print "self.limit[%s] set to %s" %(limit, self.limits[limit])
|
||||||
if limit.isdigit() or (len(limit) > 2 and limit[-2:] == 'nl'):
|
if limit.isdigit() or (len(limit) > 2 and (limit[-2:] == 'nl' or limit[-2:] == 'fl' or limit[-2:] == 'pl')):
|
||||||
if self.limits[limit]:
|
if self.limits[limit]:
|
||||||
if self.cbNoLimits is not None:
|
if self.cbNoLimits is not None:
|
||||||
self.cbNoLimits.set_active(False)
|
self.cbNoLimits.set_active(False)
|
||||||
|
@ -314,9 +318,12 @@ class Filters(threading.Thread):
|
||||||
if limit.isdigit():
|
if limit.isdigit():
|
||||||
if self.cbFL is not None:
|
if self.cbFL is not None:
|
||||||
self.cbFL.set_active(False)
|
self.cbFL.set_active(False)
|
||||||
else:
|
elif (len(limit) > 2 and (limit[-2:] == 'nl')):
|
||||||
if self.cbNL is not None:
|
if self.cbNL is not None:
|
||||||
self.cbNL.set_active(False)
|
self.cbNL.set_active(False)
|
||||||
|
else:
|
||||||
|
if self.cbPL is not None:
|
||||||
|
self.cbPL.set_active(False)
|
||||||
elif limit == "all":
|
elif limit == "all":
|
||||||
if self.limits[limit]:
|
if self.limits[limit]:
|
||||||
#for cb in self.cbLimits.values():
|
#for cb in self.cbLimits.values():
|
||||||
|
@ -325,6 +332,8 @@ class Filters(threading.Thread):
|
||||||
self.cbFL.set_active(True)
|
self.cbFL.set_active(True)
|
||||||
if self.cbNL is not None:
|
if self.cbNL is not None:
|
||||||
self.cbNL.set_active(True)
|
self.cbNL.set_active(True)
|
||||||
|
if self.cbPL is not None:
|
||||||
|
self.cbPL.set_active(True)
|
||||||
elif limit == "none":
|
elif limit == "none":
|
||||||
if self.limits[limit]:
|
if self.limits[limit]:
|
||||||
for cb in self.cbLimits.values():
|
for cb in self.cbLimits.values():
|
||||||
|
@ -333,6 +342,8 @@ class Filters(threading.Thread):
|
||||||
self.cbNL.set_active(False)
|
self.cbNL.set_active(False)
|
||||||
if self.cbFL is not None:
|
if self.cbFL is not None:
|
||||||
self.cbFL.set_active(False)
|
self.cbFL.set_active(False)
|
||||||
|
if self.cbPL is not None:
|
||||||
|
self.cbPL.set_active(False)
|
||||||
elif limit == "fl":
|
elif limit == "fl":
|
||||||
if not self.limits[limit]:
|
if not self.limits[limit]:
|
||||||
# only toggle all fl limits off if they are all currently on
|
# only toggle all fl limits off if they are all currently on
|
||||||
|
@ -384,6 +395,30 @@ class Filters(threading.Thread):
|
||||||
self.rb['tour'].set_active(True)
|
self.rb['tour'].set_active(True)
|
||||||
elif self.type == 'tour':
|
elif self.type == 'tour':
|
||||||
self.rb['ring'].set_active(True)
|
self.rb['ring'].set_active(True)
|
||||||
|
elif limit == "pl":
|
||||||
|
if not self.limits[limit]:
|
||||||
|
# only toggle all nl limits off if they are all currently on
|
||||||
|
# this stops turning one off from cascading into 'nl' box off
|
||||||
|
# and then all nl limits being turned off
|
||||||
|
all_nl_on = True
|
||||||
|
for cb in self.cbLimits.values():
|
||||||
|
t = cb.get_children()[0].get_text()
|
||||||
|
if "pl" in t and len(t) > 2:
|
||||||
|
if not cb.get_active():
|
||||||
|
all_nl_on = False
|
||||||
|
found = {'ring':False, 'tour':False}
|
||||||
|
for cb in self.cbLimits.values():
|
||||||
|
t = cb.get_children()[0].get_text()
|
||||||
|
if "pl" in t and len(t) > 2:
|
||||||
|
if self.limits[limit] or all_nl_on:
|
||||||
|
cb.set_active(self.limits[limit])
|
||||||
|
found[self.types[t]] = True
|
||||||
|
if self.limits[limit]:
|
||||||
|
if not found[self.type]:
|
||||||
|
if self.type == 'ring':
|
||||||
|
self.rb['tour'].set_active(True)
|
||||||
|
elif self.type == 'tour':
|
||||||
|
self.rb['ring'].set_active(True)
|
||||||
elif limit == "ring":
|
elif limit == "ring":
|
||||||
print "set", limit, "to", self.limits[limit]
|
print "set", limit, "to", self.limits[limit]
|
||||||
if self.limits[limit]:
|
if self.limits[limit]:
|
||||||
|
@ -479,7 +514,7 @@ class Filters(threading.Thread):
|
||||||
self.cursor.execute(self.sql.query['getLimits2'])
|
self.cursor.execute(self.sql.query['getLimits2'])
|
||||||
# selects limitType, bigBlind
|
# selects limitType, bigBlind
|
||||||
result = self.db.cursor.fetchall()
|
result = self.db.cursor.fetchall()
|
||||||
found = {'nl':False, 'fl':False, 'ring':False, 'tour':False}
|
found = {'nl':False, 'fl':False, 'pl':False, 'ring':False, 'tour':False}
|
||||||
|
|
||||||
if len(result) >= 1:
|
if len(result) >= 1:
|
||||||
hbox = gtk.HBox(True, 0)
|
hbox = gtk.HBox(True, 0)
|
||||||
|
@ -497,14 +532,18 @@ class Filters(threading.Thread):
|
||||||
vbox2.pack_start(hbox, False, False, 0)
|
vbox2.pack_start(hbox, False, False, 0)
|
||||||
else:
|
else:
|
||||||
vbox3.pack_start(hbox, False, False, 0)
|
vbox3.pack_start(hbox, False, False, 0)
|
||||||
if line[1] == 'fl':
|
if line[0] == 'ring':
|
||||||
name = str(line[2])
|
if line[1] == 'fl':
|
||||||
found['fl'] = True
|
name = str(line[2])
|
||||||
else:
|
found['fl'] = True
|
||||||
name = str(line[2])+line[1]
|
elif line[1] == 'pl':
|
||||||
found['nl'] = True
|
name = str(line[2])+line[1]
|
||||||
self.cbLimits[name] = self.createLimitLine(hbox, name, name)
|
found['pl'] = True
|
||||||
self.types[name] = line[0]
|
else:
|
||||||
|
name = str(line[2])+line[1]
|
||||||
|
found['nl'] = True
|
||||||
|
self.cbLimits[name] = self.createLimitLine(hbox, name, name)
|
||||||
|
self.types[name] = line[0]
|
||||||
found[line[0]] = True # type is ring/tour
|
found[line[0]] = True # type is ring/tour
|
||||||
self.type = line[0] # if only one type, set it now
|
self.type = line[0] # if only one type, set it now
|
||||||
if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2:
|
if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2:
|
||||||
|
@ -532,6 +571,9 @@ class Filters(threading.Thread):
|
||||||
hbox = gtk.HBox(False, 0)
|
hbox = gtk.HBox(False, 0)
|
||||||
vbox3.pack_start(hbox, False, False, 0)
|
vbox3.pack_start(hbox, False, False, 0)
|
||||||
self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL'])
|
self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL'])
|
||||||
|
hbox = gtk.HBox(False, 0)
|
||||||
|
vbox3.pack_start(hbox, False, False, 0)
|
||||||
|
self.cbPL = self.createLimitLine(hbox, 'pl', self.filterText['limitsPL'])
|
||||||
dest = vbox2 # for ring/tour buttons
|
dest = vbox2 # for ring/tour buttons
|
||||||
else:
|
else:
|
||||||
print "INFO: No games returned from database"
|
print "INFO: No games returned from database"
|
||||||
|
|
|
@ -30,7 +30,6 @@ import gtk
|
||||||
import gobject
|
import gobject
|
||||||
|
|
||||||
# fpdb/FreePokerTools modules
|
# fpdb/FreePokerTools modules
|
||||||
import fpdb_simple
|
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import Configuration
|
import Configuration
|
||||||
import Exceptions
|
import Exceptions
|
||||||
|
|
|
@ -64,7 +64,7 @@ class GuiPlayerStats (threading.Thread):
|
||||||
|
|
||||||
filters_display = { "Heroes" : True,
|
filters_display = { "Heroes" : True,
|
||||||
"Sites" : True,
|
"Sites" : True,
|
||||||
"Games" : False,
|
"Games" : True,
|
||||||
"Limits" : True,
|
"Limits" : True,
|
||||||
"LimitSep" : True,
|
"LimitSep" : True,
|
||||||
"LimitType" : True,
|
"LimitType" : True,
|
||||||
|
@ -180,6 +180,7 @@ class GuiPlayerStats (threading.Thread):
|
||||||
seats = self.filters.getSeats()
|
seats = self.filters.getSeats()
|
||||||
groups = self.filters.getGroups()
|
groups = self.filters.getGroups()
|
||||||
dates = self.filters.getDates()
|
dates = self.filters.getDates()
|
||||||
|
games = self.filters.getGames()
|
||||||
sitenos = []
|
sitenos = []
|
||||||
playerids = []
|
playerids = []
|
||||||
|
|
||||||
|
@ -205,9 +206,9 @@ class GuiPlayerStats (threading.Thread):
|
||||||
print "No limits found"
|
print "No limits found"
|
||||||
return
|
return
|
||||||
|
|
||||||
self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates)
|
self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates, games)
|
||||||
|
|
||||||
def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates):
|
def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates, games):
|
||||||
starttime = time()
|
starttime = time()
|
||||||
|
|
||||||
# Scrolled window for summary table
|
# Scrolled window for summary table
|
||||||
|
@ -223,7 +224,7 @@ class GuiPlayerStats (threading.Thread):
|
||||||
# gridnum - index for grid data structures
|
# gridnum - index for grid data structures
|
||||||
flags = [False, self.filters.getNumHands(), 0]
|
flags = [False, self.filters.getNumHands(), 0]
|
||||||
self.addGrid(swin, 'playerDetailedStats', flags, playerids
|
self.addGrid(swin, 'playerDetailedStats', flags, playerids
|
||||||
,sitenos, limits, type, seats, groups, dates)
|
,sitenos, limits, type, seats, groups, dates, games)
|
||||||
|
|
||||||
# Separator
|
# Separator
|
||||||
vbox2 = gtk.VBox(False, 0)
|
vbox2 = gtk.VBox(False, 0)
|
||||||
|
@ -243,7 +244,7 @@ class GuiPlayerStats (threading.Thread):
|
||||||
flags[0] = True
|
flags[0] = True
|
||||||
flags[2] = 1
|
flags[2] = 1
|
||||||
self.addGrid(swin, 'playerDetailedStats', flags, playerids
|
self.addGrid(swin, 'playerDetailedStats', flags, playerids
|
||||||
,sitenos, limits, type, seats, groups, dates)
|
,sitenos, limits, type, seats, groups, dates, games)
|
||||||
|
|
||||||
self.db.rollback()
|
self.db.rollback()
|
||||||
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
|
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||||
|
@ -317,7 +318,7 @@ class GuiPlayerStats (threading.Thread):
|
||||||
print "***sortcols error: " + str(sys.exc_info()[1])
|
print "***sortcols error: " + str(sys.exc_info()[1])
|
||||||
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
|
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
|
||||||
|
|
||||||
def addGrid(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates):
|
def addGrid(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
|
||||||
counter = 0
|
counter = 0
|
||||||
row = 0
|
row = 0
|
||||||
sqlrow = 0
|
sqlrow = 0
|
||||||
|
@ -325,7 +326,7 @@ class GuiPlayerStats (threading.Thread):
|
||||||
else: holecards,grid = flags[0],flags[2]
|
else: holecards,grid = flags[0],flags[2]
|
||||||
|
|
||||||
tmp = self.sql.query[query]
|
tmp = self.sql.query[query]
|
||||||
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates)
|
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates, games)
|
||||||
self.cursor.execute(tmp)
|
self.cursor.execute(tmp)
|
||||||
result = self.cursor.fetchall()
|
result = self.cursor.fetchall()
|
||||||
colnames = [desc[0].lower() for desc in self.cursor.description]
|
colnames = [desc[0].lower() for desc in self.cursor.description]
|
||||||
|
@ -428,7 +429,7 @@ class GuiPlayerStats (threading.Thread):
|
||||||
|
|
||||||
#end def addGrid(self, query, vars, playerids, sitenos, limits, type, seats, groups, dates):
|
#end def addGrid(self, query, vars, playerids, sitenos, limits, type, seats, groups, dates):
|
||||||
|
|
||||||
def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates):
|
def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
|
||||||
having = ''
|
having = ''
|
||||||
if not flags:
|
if not flags:
|
||||||
holecards = False
|
holecards = False
|
||||||
|
@ -466,6 +467,20 @@ class GuiPlayerStats (threading.Thread):
|
||||||
query = query.replace("<playerName>", pname)
|
query = query.replace("<playerName>", pname)
|
||||||
query = query.replace("<havingclause>", having)
|
query = query.replace("<havingclause>", having)
|
||||||
|
|
||||||
|
gametest = ""
|
||||||
|
q = []
|
||||||
|
for m in self.filters.display.items():
|
||||||
|
if m[0] == 'Games' and m[1]:
|
||||||
|
for n in games:
|
||||||
|
if games[n]:
|
||||||
|
q.append(n)
|
||||||
|
gametest = str(tuple(q))
|
||||||
|
gametest = gametest.replace("L", "")
|
||||||
|
gametest = gametest.replace(",)",")")
|
||||||
|
gametest = gametest.replace("u'","'")
|
||||||
|
gametest = "and gt.category in %s" % gametest
|
||||||
|
query = query.replace("<game_test>", gametest)
|
||||||
|
|
||||||
if seats:
|
if seats:
|
||||||
query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to']))
|
query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to']))
|
||||||
if 'show' in seats and seats['show']:
|
if 'show' in seats and seats['show']:
|
||||||
|
@ -516,8 +531,8 @@ class GuiPlayerStats (threading.Thread):
|
||||||
if holecards: # re-use level variables for hole card query
|
if holecards: # re-use level variables for hole card query
|
||||||
query = query.replace("<hgameTypeId>", "hp.startcards")
|
query = query.replace("<hgameTypeId>", "hp.startcards")
|
||||||
query = query.replace("<orderbyhgameTypeId>"
|
query = query.replace("<orderbyhgameTypeId>"
|
||||||
, ",case when floor(hp.startcards/13) >= mod(hp.startcards,13) then hp.startcards + 0.1 "
|
, ",case when floor((hp.startcards-1)/13) >= mod((hp.startcards-1),13) then hp.startcards + 0.1 "
|
||||||
+ " else 13*mod(hp.startcards,13) + floor(hp.startcards/13) "
|
+ " else 13*mod((hp.startcards-1),13) + floor((hp.startcards-1)/13) + 1 "
|
||||||
+ " end desc ")
|
+ " end desc ")
|
||||||
else:
|
else:
|
||||||
query = query.replace("<orderbyhgameTypeId>", "")
|
query = query.replace("<orderbyhgameTypeId>", "")
|
||||||
|
|
|
@ -20,7 +20,6 @@ import pygtk
|
||||||
pygtk.require('2.0')
|
pygtk.require('2.0')
|
||||||
import gtk
|
import gtk
|
||||||
import os
|
import os
|
||||||
import fpdb_simple
|
|
||||||
|
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import fpdb_db
|
import fpdb_db
|
||||||
|
|
|
@ -232,6 +232,9 @@ db: a connected fpdb_db object"""
|
||||||
#Raise Duplicate exception?
|
#Raise Duplicate exception?
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def updateHudCache(self, db):
|
||||||
|
db.storeHudCache(self.dbid_gt, self.dbid_pids, self.starttime, self.stats.getHandsPlayers())
|
||||||
|
|
||||||
def select(self, handId):
|
def select(self, handId):
|
||||||
""" Function to create Hand object from database """
|
""" Function to create Hand object from database """
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ follow : whether to tail -f the input"""
|
||||||
|
|
||||||
log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) )
|
log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) )
|
||||||
|
|
||||||
self.index = 0
|
self.index = index
|
||||||
self.starsArchive = starsArchive
|
self.starsArchive = starsArchive
|
||||||
|
|
||||||
self.in_path = in_path
|
self.in_path = in_path
|
||||||
|
|
|
@ -606,6 +606,7 @@ class Hud:
|
||||||
if self.update_table_position() == False: # we got killed by finding our table was gone
|
if self.update_table_position() == False: # we got killed by finding our table was gone
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
|
||||||
for s in self.stat_dict:
|
for s in self.stat_dict:
|
||||||
try:
|
try:
|
||||||
statd = self.stat_dict[s]
|
statd = self.stat_dict[s]
|
||||||
|
@ -629,20 +630,16 @@ class Hud:
|
||||||
window = self.stat_windows[statd['seat']]
|
window = self.stat_windows[statd['seat']]
|
||||||
|
|
||||||
if this_stat.hudcolor != "":
|
if this_stat.hudcolor != "":
|
||||||
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
|
|
||||||
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.hudcolor))
|
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.hudcolor))
|
||||||
else:
|
else:
|
||||||
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
|
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
|
||||||
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#FFFFFF"))
|
|
||||||
|
|
||||||
if this_stat.stat_loth != "":
|
if this_stat.stat_loth != "":
|
||||||
if number[0] < (float(this_stat.stat_loth)/100):
|
if number[0] < (float(this_stat.stat_loth)/100):
|
||||||
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
|
|
||||||
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.stat_locolor))
|
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.stat_locolor))
|
||||||
|
|
||||||
if this_stat.stat_hith != "":
|
if this_stat.stat_hith != "":
|
||||||
if number[0] > (float(this_stat.stat_hith)/100):
|
if number[0] > (float(this_stat.stat_hith)/100):
|
||||||
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
|
|
||||||
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.stat_hicolor))
|
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.stat_hicolor))
|
||||||
|
|
||||||
window.label[r][c].set_text(statstring)
|
window.label[r][c].set_text(statstring)
|
||||||
|
|
|
@ -81,6 +81,7 @@ class PokerStars(HandHistoryConverter):
|
||||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||||
# self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
|
# self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
|
||||||
|
|
||||||
|
re_DateTime = re.compile("""(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)""", re.MULTILINE)
|
||||||
|
|
||||||
def compilePlayerRegexs(self, hand):
|
def compilePlayerRegexs(self, hand):
|
||||||
players = set([player[1] for player in hand.players])
|
players = set([player[1] for player in hand.players])
|
||||||
|
@ -97,7 +98,7 @@ class PokerStars(HandHistoryConverter):
|
||||||
self.re_PostBB = re.compile(r"^%(PLYR)s: posts big blind %(CUR)s(?P<BB>[.0-9]+)" % subst, re.MULTILINE)
|
self.re_PostBB = re.compile(r"^%(PLYR)s: posts big blind %(CUR)s(?P<BB>[.0-9]+)" % subst, re.MULTILINE)
|
||||||
self.re_Antes = re.compile(r"^%(PLYR)s: posts the ante %(CUR)s(?P<ANTE>[.0-9]+)" % subst, re.MULTILINE)
|
self.re_Antes = re.compile(r"^%(PLYR)s: posts the ante %(CUR)s(?P<ANTE>[.0-9]+)" % subst, re.MULTILINE)
|
||||||
self.re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.0-9]+)" % subst, re.MULTILINE)
|
self.re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.0-9]+)" % subst, re.MULTILINE)
|
||||||
self.re_PostBoth = re.compile(r"^%(PLYR)s: posts small \& big blinds \[%(CUR)s (?P<SBBB>[.0-9]+)" % subst, re.MULTILINE)
|
self.re_PostBoth = re.compile(r"^%(PLYR)s: posts small \& big blinds %(CUR)s(?P<SBBB>[.0-9]+)" % subst, re.MULTILINE)
|
||||||
self.re_HeroCards = re.compile(r"^Dealt to %(PLYR)s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % subst, re.MULTILINE)
|
self.re_HeroCards = re.compile(r"^Dealt to %(PLYR)s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % subst, re.MULTILINE)
|
||||||
self.re_Action = re.compile(r"""
|
self.re_Action = re.compile(r"""
|
||||||
^%(PLYR)s:(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat)
|
^%(PLYR)s:(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat)
|
||||||
|
@ -105,7 +106,7 @@ class PokerStars(HandHistoryConverter):
|
||||||
(\scards?(\s\[(?P<DISCARDED>.+?)\])?)?"""
|
(\scards?(\s\[(?P<DISCARDED>.+?)\])?)?"""
|
||||||
% subst, re.MULTILINE|re.VERBOSE)
|
% subst, re.MULTILINE|re.VERBOSE)
|
||||||
self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
|
self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
|
||||||
self.re_CollectPot = re.compile(r"Seat (?P<SEAT>[0-9]+): %(PLYR)s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(%(CUR)s(?P<POT>[.\d]+)\)(, mucked| with.*|)" % subst, re.MULTILINE)
|
self.re_CollectPot = re.compile(r"Seat (?P<SEAT>[0-9]+): %(PLYR)s (\(button\) |\(small blind\) |\(big blind\) |\(button\) \(small blind\) )?(collected|showed \[.*\] and won) \(%(CUR)s(?P<POT>[.\d]+)\)(, mucked| with.*|)" % subst, re.MULTILINE)
|
||||||
self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE)
|
self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE)
|
||||||
self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %s (\(.*\) )?(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
|
self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %s (\(.*\) )?(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
|
||||||
|
|
||||||
|
@ -194,12 +195,13 @@ class PokerStars(HandHistoryConverter):
|
||||||
#2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET]
|
#2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET]
|
||||||
#2008/08/17 - 01:14:43 (ET)
|
#2008/08/17 - 01:14:43 (ET)
|
||||||
#2008/09/07 06:23:14 ET
|
#2008/09/07 06:23:14 ET
|
||||||
m2 = re.search("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)", info[key])
|
m1 = self.re_DateTime.finditer(info[key])
|
||||||
datetimestr = "%s/%s/%s %s:%s:%s" % (m2.group('Y'), m2.group('M'),m2.group('D'),m2.group('H'),m2.group('MIN'),m2.group('S'))
|
# m2 = re.search("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)", info[key])
|
||||||
|
for a in m1:
|
||||||
|
datetimestr = "%s/%s/%s %s:%s:%s" % (a.group('Y'), a.group('M'),a.group('D'),a.group('H'),a.group('MIN'),a.group('S'))
|
||||||
hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")
|
hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")
|
||||||
if key == 'HID':
|
if key == 'HID':
|
||||||
hand.handid = info[key]
|
hand.handid = info[key]
|
||||||
|
|
||||||
if key == 'TOURNO':
|
if key == 'TOURNO':
|
||||||
hand.tourNo = info[key]
|
hand.tourNo = info[key]
|
||||||
if key == 'BUYIN':
|
if key == 'BUYIN':
|
||||||
|
|
144
pyfpdb/SQL.py
144
pyfpdb/SQL.py
|
@ -1881,6 +1881,7 @@ class Sql:
|
||||||
inner join Sites s on (s.Id = gt.siteId)
|
inner join Sites s on (s.Id = gt.siteId)
|
||||||
inner join Players p on (p.Id = hp.playerId)
|
inner join Players p on (p.Id = hp.playerId)
|
||||||
where hp.playerId in <player_test>
|
where hp.playerId in <player_test>
|
||||||
|
<game_test>
|
||||||
/*and hp.tourneysPlayersId IS NULL*/
|
/*and hp.tourneysPlayersId IS NULL*/
|
||||||
and h.seats <seats_test>
|
and h.seats <seats_test>
|
||||||
<flagtest>
|
<flagtest>
|
||||||
|
@ -1964,6 +1965,7 @@ class Sql:
|
||||||
inner join Sites s on (s.Id = gt.siteId)
|
inner join Sites s on (s.Id = gt.siteId)
|
||||||
inner join Players p on (p.Id = hp.playerId)
|
inner join Players p on (p.Id = hp.playerId)
|
||||||
where hp.playerId in <player_test>
|
where hp.playerId in <player_test>
|
||||||
|
<game_test>
|
||||||
/*and hp.tourneysPlayersId IS NULL*/
|
/*and hp.tourneysPlayersId IS NULL*/
|
||||||
and h.seats <seats_test>
|
and h.seats <seats_test>
|
||||||
<flagtest>
|
<flagtest>
|
||||||
|
@ -2047,6 +2049,7 @@ class Sql:
|
||||||
inner join Gametypes gt on (gt.Id = h.gameTypeId)
|
inner join Gametypes gt on (gt.Id = h.gameTypeId)
|
||||||
inner join Sites s on (s.Id = gt.siteId)
|
inner join Sites s on (s.Id = gt.siteId)
|
||||||
where hp.playerId in <player_test>
|
where hp.playerId in <player_test>
|
||||||
|
<game_test>
|
||||||
/*and hp.tourneysPlayersId IS NULL*/
|
/*and hp.tourneysPlayersId IS NULL*/
|
||||||
and h.seats <seats_test>
|
and h.seats <seats_test>
|
||||||
<flagtest>
|
<flagtest>
|
||||||
|
@ -3088,6 +3091,147 @@ class Sql:
|
||||||
,'d' || substr(strftime('%Y%m%d', h.handStart),3,7)
|
,'d' || substr(strftime('%Y%m%d', h.handStart),3,7)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.query['insert_hudcache'] = """
|
||||||
|
INSERT INTO HudCache (
|
||||||
|
gametypeId,
|
||||||
|
playerId,
|
||||||
|
activeSeats,
|
||||||
|
position,
|
||||||
|
tourneyTypeId,
|
||||||
|
styleKey,
|
||||||
|
HDs,
|
||||||
|
street0VPI,
|
||||||
|
street0Aggr,
|
||||||
|
street0_3BChance,
|
||||||
|
street0_3BDone,
|
||||||
|
street1Seen,
|
||||||
|
street2Seen,
|
||||||
|
street3Seen,
|
||||||
|
street4Seen,
|
||||||
|
sawShowdown,
|
||||||
|
street1Aggr,
|
||||||
|
street2Aggr,
|
||||||
|
street3Aggr,
|
||||||
|
street4Aggr,
|
||||||
|
otherRaisedStreet1,
|
||||||
|
otherRaisedStreet2,
|
||||||
|
otherRaisedStreet3,
|
||||||
|
otherRaisedStreet4,
|
||||||
|
foldToOtherRaisedStreet1,
|
||||||
|
foldToOtherRaisedStreet2,
|
||||||
|
foldToOtherRaisedStreet3,
|
||||||
|
foldToOtherRaisedStreet4,
|
||||||
|
wonWhenSeenStreet1,
|
||||||
|
wonAtSD,
|
||||||
|
stealAttemptChance,
|
||||||
|
stealAttempted,
|
||||||
|
foldBbToStealChance,
|
||||||
|
foldedBbToSteal,
|
||||||
|
foldSbToStealChance,
|
||||||
|
foldedSbToSteal,
|
||||||
|
street1CBChance,
|
||||||
|
street1CBDone,
|
||||||
|
street2CBChance,
|
||||||
|
street2CBDone,
|
||||||
|
street3CBChance,
|
||||||
|
street3CBDone,
|
||||||
|
street4CBChance,
|
||||||
|
street4CBDone,
|
||||||
|
foldToStreet1CBChance,
|
||||||
|
foldToStreet1CBDone,
|
||||||
|
foldToStreet2CBChance,
|
||||||
|
foldToStreet2CBDone,
|
||||||
|
foldToStreet3CBChance,
|
||||||
|
foldToStreet3CBDone,
|
||||||
|
foldToStreet4CBChance,
|
||||||
|
foldToStreet4CBDone,
|
||||||
|
totalProfit,
|
||||||
|
street1CheckCallRaiseChance,
|
||||||
|
street1CheckCallRaiseDone,
|
||||||
|
street2CheckCallRaiseChance,
|
||||||
|
street2CheckCallRaiseDone,
|
||||||
|
street3CheckCallRaiseChance,
|
||||||
|
street3CheckCallRaiseDone,
|
||||||
|
street4CheckCallRaiseChance,
|
||||||
|
street4CheckCallRaiseDone)
|
||||||
|
VALUES (%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s,
|
||||||
|
%s)"""
|
||||||
|
|
||||||
|
self.query['update_hudcache'] = """
|
||||||
|
UPDATE HudCache SET
|
||||||
|
HDs=HDs+%s,
|
||||||
|
street0VPI=street0VPI+%s,
|
||||||
|
street0Aggr=street0Aggr+%s,
|
||||||
|
street0_3BChance=street0_3BChance+%s,
|
||||||
|
street0_3BDone=street0_3BDone+%s,
|
||||||
|
street1Seen=street1Seen+%s,
|
||||||
|
street2Seen=street2Seen+%s,
|
||||||
|
street3Seen=street3Seen+%s,
|
||||||
|
street4Seen=street4Seen+%s,
|
||||||
|
sawShowdown=sawShowdown+%s,
|
||||||
|
street1Aggr=street1Aggr+%s,
|
||||||
|
street2Aggr=street2Aggr+%s,
|
||||||
|
street3Aggr=street3Aggr+%s,
|
||||||
|
street4Aggr=street4Aggr+%s,
|
||||||
|
otherRaisedStreet1=otherRaisedStreet1+%s,
|
||||||
|
otherRaisedStreet2=otherRaisedStreet2+%s,
|
||||||
|
otherRaisedStreet3=otherRaisedStreet3+%s,
|
||||||
|
otherRaisedStreet4=otherRaisedStreet4+%s,
|
||||||
|
foldToOtherRaisedStreet1=foldToOtherRaisedStreet1+%s,
|
||||||
|
foldToOtherRaisedStreet2=foldToOtherRaisedStreet2+%s,
|
||||||
|
foldToOtherRaisedStreet3=foldToOtherRaisedStreet3+%s,
|
||||||
|
foldToOtherRaisedStreet4=foldToOtherRaisedStreet4+%s,
|
||||||
|
wonWhenSeenStreet1=wonWhenSeenStreet1+%s,
|
||||||
|
wonAtSD=wonAtSD+%s,
|
||||||
|
stealAttemptChance=stealAttemptChance+%s,
|
||||||
|
stealAttempted=stealAttempted+%s,
|
||||||
|
foldBbToStealChance=foldBbToStealChance+%s,
|
||||||
|
foldedBbToSteal=foldedBbToSteal+%s,
|
||||||
|
foldSbToStealChance=foldSbToStealChance+%s,
|
||||||
|
foldedSbToSteal=foldedSbToSteal+%s,
|
||||||
|
street1CBChance=street1CBChance+%s,
|
||||||
|
street1CBDone=street1CBDone+%s,
|
||||||
|
street2CBChance=street2CBChance+%s,
|
||||||
|
street2CBDone=street2CBDone+%s,
|
||||||
|
street3CBChance=street3CBChance+%s,
|
||||||
|
street3CBDone=street3CBDone+%s,
|
||||||
|
street4CBChance=street4CBChance+%s,
|
||||||
|
street4CBDone=street4CBDone+%s,
|
||||||
|
foldToStreet1CBChance=foldToStreet1CBChance+%s,
|
||||||
|
foldToStreet1CBDone=foldToStreet1CBDone+%s,
|
||||||
|
foldToStreet2CBChance=foldToStreet2CBChance+%s,
|
||||||
|
foldToStreet2CBDone=foldToStreet2CBDone+%s,
|
||||||
|
foldToStreet3CBChance=foldToStreet3CBChance+%s,
|
||||||
|
foldToStreet3CBDone=foldToStreet3CBDone+%s,
|
||||||
|
foldToStreet4CBChance=foldToStreet4CBChance+%s,
|
||||||
|
foldToStreet4CBDone=foldToStreet4CBDone+%s,
|
||||||
|
totalProfit=totalProfit+%s,
|
||||||
|
street1CheckCallRaiseChance=street1CheckCallRaiseChance+%s,
|
||||||
|
street1CheckCallRaiseDone=street1CheckCallRaiseDone+%s,
|
||||||
|
street2CheckCallRaiseChance=street2CheckCallRaiseChance+%s,
|
||||||
|
street2CheckCallRaiseDone=street2CheckCallRaiseDone+%s,
|
||||||
|
street3CheckCallRaiseChance=street3CheckCallRaiseChance+%s,
|
||||||
|
street3CheckCallRaiseDone=street3CheckCallRaiseDone+%s,
|
||||||
|
street4CheckCallRaiseChance=street4CheckCallRaiseChance+%s,
|
||||||
|
street4CheckCallRaiseDone=street4CheckCallRaiseDone+%s
|
||||||
|
WHERE gametypeId+0=%s
|
||||||
|
AND playerId=%s
|
||||||
|
AND activeSeats=%s
|
||||||
|
AND position=%s
|
||||||
|
AND tourneyTypeId+0=%s
|
||||||
|
AND styleKey=%s"""
|
||||||
|
|
||||||
self.query['get_hero_hudcache_start'] = """select min(hc.styleKey)
|
self.query['get_hero_hudcache_start'] = """select min(hc.styleKey)
|
||||||
from HudCache hc
|
from HudCache hc
|
||||||
where hc.playerId in <playerid_list>
|
where hc.playerId in <playerid_list>
|
||||||
|
|
|
@ -62,9 +62,13 @@ import Database
|
||||||
re_Places = re.compile("_[0-9]$")
|
re_Places = re.compile("_[0-9]$")
|
||||||
re_Percent = re.compile("%$")
|
re_Percent = re.compile("%$")
|
||||||
|
|
||||||
|
# String manipulation
|
||||||
|
import codecs
|
||||||
|
encoder = codecs.lookup(Configuration.LOCALE_ENCODING)
|
||||||
|
|
||||||
def do_tip(widget, tip):
|
def do_tip(widget, tip):
|
||||||
widget.set_tooltip_text(tip)
|
(_tip, _len) = encoder.encode(tip)
|
||||||
|
widget.set_tooltip_text(_tip)
|
||||||
|
|
||||||
def do_stat(stat_dict, player = 24, stat = 'vpip'):
|
def do_stat(stat_dict, player = 24, stat = 'vpip'):
|
||||||
match = re_Places.search(stat)
|
match = re_Places.search(stat)
|
||||||
|
|
|
@ -39,7 +39,6 @@ if os.name == 'nt':
|
||||||
|
|
||||||
# FreePokerTools modules
|
# FreePokerTools modules
|
||||||
import Configuration
|
import Configuration
|
||||||
from fpdb_simple import LOCALE_ENCODING
|
|
||||||
|
|
||||||
# Each TableWindow object must have the following attributes correctly populated:
|
# Each TableWindow object must have the following attributes correctly populated:
|
||||||
# tw.name = the table name from the title bar, which must to match the table name
|
# tw.name = the table name from the title bar, which must to match the table name
|
||||||
|
@ -238,7 +237,7 @@ def discover_nt_by_name(c, tablename):
|
||||||
try:
|
try:
|
||||||
# maybe it's better to make global titles[hwnd] decoding?
|
# maybe it's better to make global titles[hwnd] decoding?
|
||||||
# this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html
|
# this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html
|
||||||
if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower():
|
if not tablename.lower() in titles[hwnd].decode(Configuration.LOCALE_ENCODING).lower():
|
||||||
continue
|
continue
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -38,7 +38,6 @@ except ImportError:
|
||||||
logging.info("Not using numpy to define variance in sqlite.")
|
logging.info("Not using numpy to define variance in sqlite.")
|
||||||
use_numpy = False
|
use_numpy = False
|
||||||
|
|
||||||
import fpdb_simple
|
|
||||||
import FpdbSQLQueries
|
import FpdbSQLQueries
|
||||||
import Configuration
|
import Configuration
|
||||||
|
|
||||||
|
|
|
@ -35,10 +35,8 @@ import gtk
|
||||||
|
|
||||||
# fpdb/FreePokerTools modules
|
# fpdb/FreePokerTools modules
|
||||||
|
|
||||||
import fpdb_simple
|
|
||||||
import fpdb_db
|
import fpdb_db
|
||||||
import Database
|
import Database
|
||||||
import fpdb_parse_logic
|
|
||||||
import Configuration
|
import Configuration
|
||||||
import Exceptions
|
import Exceptions
|
||||||
|
|
||||||
|
@ -409,7 +407,7 @@ class Importer:
|
||||||
conv = None
|
conv = None
|
||||||
(stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0)
|
(stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0)
|
||||||
|
|
||||||
file = file.decode(fpdb_simple.LOCALE_ENCODING)
|
file = file.decode(Configuration.LOCALE_ENCODING)
|
||||||
|
|
||||||
# Load filter, process file, pass returned filename to import_fpdb_file
|
# Load filter, process file, pass returned filename to import_fpdb_file
|
||||||
if self.settings['threads'] > 0 and self.writeq is not None:
|
if self.settings['threads'] > 0 and self.writeq is not None:
|
||||||
|
@ -429,11 +427,13 @@ class Importer:
|
||||||
mod = __import__(filter)
|
mod = __import__(filter)
|
||||||
obj = getattr(mod, filter_name, None)
|
obj = getattr(mod, filter_name, None)
|
||||||
if callable(obj):
|
if callable(obj):
|
||||||
hhc = obj(in_path = file, out_path = out_path, index = 0, starsArchive = self.settings['starsArchive']) # Index into file 0 until changeover
|
idx = 0
|
||||||
if hhc.getStatus() and self.NEWIMPORT == False:
|
if file in self.pos_in_file:
|
||||||
(stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(db, out_path, site, q)
|
idx = self.pos_in_file[file]
|
||||||
elif hhc.getStatus() and self.NEWIMPORT == True:
|
else:
|
||||||
#This code doesn't do anything yet
|
self.pos_in_file[file] = 0
|
||||||
|
hhc = obj(in_path = file, out_path = out_path, index = idx, starsArchive = self.settings['starsArchive'])
|
||||||
|
if hhc.getStatus() and self.NEWIMPORT == True:
|
||||||
handlist = hhc.getProcessedHands()
|
handlist = hhc.getProcessedHands()
|
||||||
self.pos_in_file[file] = hhc.getLastCharacterRead()
|
self.pos_in_file[file] = hhc.getLastCharacterRead()
|
||||||
to_hud = []
|
to_hud = []
|
||||||
|
@ -448,6 +448,11 @@ class Importer:
|
||||||
else:
|
else:
|
||||||
log.error("Hand processed but empty")
|
log.error("Hand processed but empty")
|
||||||
self.database.commit()
|
self.database.commit()
|
||||||
|
# Call hudcache update if not in bulk import mode
|
||||||
|
# FIXME: Need to test for bulk import that isn't rebuilding the cache
|
||||||
|
if self.callHud:
|
||||||
|
hand.updateHudCache(self.database)
|
||||||
|
self.database.commit()
|
||||||
|
|
||||||
#pipe the Hands.id out to the HUD
|
#pipe the Hands.id out to the HUD
|
||||||
for hid in to_hud:
|
for hid in to_hud:
|
||||||
|
@ -468,162 +473,6 @@ class Importer:
|
||||||
return (stored, duplicates, partial, errors, ttime)
|
return (stored, duplicates, partial, errors, ttime)
|
||||||
|
|
||||||
|
|
||||||
def import_fpdb_file(self, db, file, site, q):
|
|
||||||
starttime = time()
|
|
||||||
last_read_hand = 0
|
|
||||||
loc = 0
|
|
||||||
(stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0)
|
|
||||||
# print "file =", file
|
|
||||||
if file == "stdin":
|
|
||||||
inputFile = sys.stdin
|
|
||||||
else:
|
|
||||||
if os.path.exists(file):
|
|
||||||
inputFile = open(file, "rU")
|
|
||||||
else:
|
|
||||||
self.removeFromFileList[file] = True
|
|
||||||
return (0, 0, 0, 1, 0)
|
|
||||||
try:
|
|
||||||
loc = self.pos_in_file[file]
|
|
||||||
#size = os.path.getsize(file)
|
|
||||||
#print "loc =", loc, 'size =', size
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
# Read input file into class and close file
|
|
||||||
inputFile.seek(loc)
|
|
||||||
#tmplines = inputFile.readlines()
|
|
||||||
#if tmplines == None or tmplines == []:
|
|
||||||
# print "tmplines = ", tmplines
|
|
||||||
#else:
|
|
||||||
# print "tmplines[0] =", tmplines[0]
|
|
||||||
self.lines = fpdb_simple.removeTrailingEOL(inputFile.readlines())
|
|
||||||
self.pos_in_file[file] = inputFile.tell()
|
|
||||||
inputFile.close()
|
|
||||||
|
|
||||||
x = clock()
|
|
||||||
(stored, duplicates, partial, errors, ttime, handsId) = self.import_fpdb_lines(db, self.lines, starttime, file, site, q)
|
|
||||||
|
|
||||||
db.commit()
|
|
||||||
y = clock()
|
|
||||||
ttime = y - x
|
|
||||||
#ttime = time() - starttime
|
|
||||||
if q is None:
|
|
||||||
log.info("Total stored: %(stored)d\tduplicates:%(duplicates)d\terrors:%(errors)d\ttime:%(ttime)s" % locals())
|
|
||||||
|
|
||||||
if not stored:
|
|
||||||
if duplicates:
|
|
||||||
for line_no in xrange(len(self.lines)):
|
|
||||||
if self.lines[line_no].find("Game #") != -1:
|
|
||||||
final_game_line = self.lines[line_no]
|
|
||||||
handsId=fpdb_simple.parseSiteHandNo(final_game_line)
|
|
||||||
else:
|
|
||||||
print "failed to read a single hand from file:", inputFile
|
|
||||||
handsId = 0
|
|
||||||
#todo: this will cause return of an unstored hand number if the last hand was error
|
|
||||||
self.handsId = handsId
|
|
||||||
|
|
||||||
return (stored, duplicates, partial, errors, ttime)
|
|
||||||
# end def import_fpdb_file
|
|
||||||
|
|
||||||
|
|
||||||
def import_fpdb_lines(self, db, lines, starttime, file, site, q = None):
|
|
||||||
"""Import an fpdb hand history held in the list lines, could be one hand or many"""
|
|
||||||
|
|
||||||
#db.lock_for_insert() # should be ok when using one thread, but doesn't help??
|
|
||||||
while gtk.events_pending():
|
|
||||||
gtk.main_iteration(False)
|
|
||||||
|
|
||||||
try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return.
|
|
||||||
firstline = lines[0]
|
|
||||||
except:
|
|
||||||
# just skip the debug message and return silently:
|
|
||||||
#print "DEBUG: import_fpdb_file: failed on lines[0]: '%s' '%s' '%s' '%s' " %( file, site, lines, loc)
|
|
||||||
return (0,0,0,1,0,0)
|
|
||||||
|
|
||||||
if "Tournament Summary" in firstline:
|
|
||||||
print "TODO: implement importing tournament summaries"
|
|
||||||
#self.faobs = readfile(inputFile)
|
|
||||||
#self.parseTourneyHistory()
|
|
||||||
return (0,0,0,1,0,0)
|
|
||||||
|
|
||||||
category = fpdb_simple.recogniseCategory(firstline)
|
|
||||||
|
|
||||||
startpos = 0
|
|
||||||
stored = 0 #counter
|
|
||||||
duplicates = 0 #counter
|
|
||||||
partial = 0 #counter
|
|
||||||
errors = 0 #counter
|
|
||||||
ttime = 0
|
|
||||||
handsId = 0
|
|
||||||
|
|
||||||
for i in xrange(len(lines)):
|
|
||||||
if len(lines[i]) < 2: #Wierd way to detect for '\r\n' or '\n'
|
|
||||||
endpos = i
|
|
||||||
hand = lines[startpos:endpos]
|
|
||||||
|
|
||||||
if len(hand[0]) < 2:
|
|
||||||
hand=hand[1:]
|
|
||||||
|
|
||||||
if len(hand) < 3:
|
|
||||||
pass
|
|
||||||
#TODO: This is ugly - we didn't actually find the start of the
|
|
||||||
# hand with the outer loop so we test again...
|
|
||||||
else:
|
|
||||||
isTourney = fpdb_simple.isTourney(hand[0])
|
|
||||||
if not isTourney:
|
|
||||||
hand = fpdb_simple.filterAnteBlindFold(hand)
|
|
||||||
self.hand = hand
|
|
||||||
|
|
||||||
try:
|
|
||||||
handsId = fpdb_parse_logic.mainParser( self.settings, self.siteIds[site]
|
|
||||||
, category, hand, self.config
|
|
||||||
, db, q )
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
stored += 1
|
|
||||||
if self.callHud:
|
|
||||||
#print "call to HUD here. handsId:",handsId
|
|
||||||
#pipe the Hands.id out to the HUD
|
|
||||||
# print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
|
|
||||||
try:
|
|
||||||
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
|
|
||||||
except IOError: # hud closed
|
|
||||||
self.callHud = False
|
|
||||||
pass # continue import without hud
|
|
||||||
except Exceptions.DuplicateError:
|
|
||||||
duplicates += 1
|
|
||||||
db.rollback()
|
|
||||||
except (ValueError), fe:
|
|
||||||
errors += 1
|
|
||||||
self.printEmailErrorMessage(errors, file, hand)
|
|
||||||
|
|
||||||
if (self.settings['failOnError']):
|
|
||||||
db.commit() #dont remove this, in case hand processing was cancelled.
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
db.rollback()
|
|
||||||
except (fpdb_simple.FpdbError), fe:
|
|
||||||
errors += 1
|
|
||||||
self.printEmailErrorMessage(errors, file, hand)
|
|
||||||
db.rollback()
|
|
||||||
|
|
||||||
if self.settings['failOnError']:
|
|
||||||
db.commit() #dont remove this, in case hand processing was cancelled.
|
|
||||||
raise
|
|
||||||
|
|
||||||
if self.settings['minPrint']:
|
|
||||||
if not ((stored+duplicates+errors) % self.settings['minPrint']):
|
|
||||||
print "stored:", stored, " duplicates:", duplicates, "errors:", errors
|
|
||||||
|
|
||||||
if self.settings['handCount']:
|
|
||||||
if ((stored+duplicates+errors) >= self.settings['handCount']):
|
|
||||||
if not self.settings['quiet']:
|
|
||||||
print "quitting due to reaching the amount of hands to be imported"
|
|
||||||
print "Total stored:", stored, "duplicates:", duplicates, "errors:", errors, " time:", (time() - starttime)
|
|
||||||
sys.exit(0)
|
|
||||||
startpos = endpos
|
|
||||||
return (stored, duplicates, partial, errors, ttime, handsId)
|
|
||||||
# end def import_fpdb_lines
|
|
||||||
|
|
||||||
def printEmailErrorMessage(self, errors, filename, line):
|
def printEmailErrorMessage(self, errors, filename, line):
|
||||||
traceback.print_exc(file=sys.stderr)
|
traceback.print_exc(file=sys.stderr)
|
||||||
print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it."
|
print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it."
|
||||||
|
|
|
@ -1,235 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
#Copyright 2008 Steffen Jobbagy-Felso
|
|
||||||
#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.
|
|
||||||
|
|
||||||
#parses an in-memory fpdb hand history and calls db routine to store it
|
|
||||||
|
|
||||||
import sys
|
|
||||||
from time import time, strftime
|
|
||||||
from Exceptions import *
|
|
||||||
|
|
||||||
import fpdb_simple
|
|
||||||
import Database
|
|
||||||
|
|
||||||
def mainParser(settings, siteID, category, hand, config, db = None, writeq = None):
|
|
||||||
""" mainParser for Holdem Hands """
|
|
||||||
t0 = time()
|
|
||||||
backend = settings['db-backend']
|
|
||||||
# Ideally db connection is passed in, if not use sql list if passed in,
|
|
||||||
# otherwise start from scratch
|
|
||||||
if db is None:
|
|
||||||
db = Database.Database(c = config, sql = None)
|
|
||||||
category = fpdb_simple.recogniseCategory(hand[0])
|
|
||||||
|
|
||||||
base = "hold" if (category == "holdem" or category == "omahahi" or
|
|
||||||
category == "omahahilo") else "stud"
|
|
||||||
|
|
||||||
#part 0: create the empty arrays
|
|
||||||
# lineTypes valid values: header, name, cards, action, win, rake, ignore
|
|
||||||
# lineStreets valid values: predeal, preflop, flop, turn, river
|
|
||||||
lineTypes = []
|
|
||||||
lineStreets = []
|
|
||||||
cardValues = []
|
|
||||||
cardSuits = []
|
|
||||||
boardValues = []
|
|
||||||
boardSuits = []
|
|
||||||
antes = []
|
|
||||||
allIns = []
|
|
||||||
actionAmounts = []
|
|
||||||
actionNos = []
|
|
||||||
actionTypes = []
|
|
||||||
actionTypeByNo = []
|
|
||||||
seatLines = []
|
|
||||||
winnings = []
|
|
||||||
rakes = []
|
|
||||||
|
|
||||||
#part 1: read hand no and check for duplicate
|
|
||||||
siteHandNo = fpdb_simple.parseSiteHandNo(hand[0])
|
|
||||||
handStartTime = fpdb_simple.parseHandStartTime(hand[0])
|
|
||||||
isTourney = fpdb_simple.isTourney(hand[0])
|
|
||||||
|
|
||||||
smallBlindLine = None
|
|
||||||
for i, line in enumerate(hand):
|
|
||||||
if 'posts small blind' in line or 'posts the small blind' in line:
|
|
||||||
if line[-2:] == "$0": continue
|
|
||||||
smallBlindLine = i
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
smallBlindLine = 0
|
|
||||||
# If we did not find a small blind line, what happens?
|
|
||||||
# if we leave it at None, it errors two lines down.
|
|
||||||
|
|
||||||
gametypeID = fpdb_simple.recogniseGametypeID(backend, db, db.get_cursor(),
|
|
||||||
hand[0], hand[smallBlindLine],
|
|
||||||
siteID, category, isTourney)
|
|
||||||
if isTourney:
|
|
||||||
siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0])
|
|
||||||
buyin = fpdb_simple.parseBuyin(hand[0])
|
|
||||||
fee = fpdb_simple.parseFee(hand[0])
|
|
||||||
entries = -1 #todo: parse this
|
|
||||||
prizepool = -1 #todo: parse this
|
|
||||||
knockout = False
|
|
||||||
tourneyStartTime= handStartTime #todo: read tourney start time
|
|
||||||
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
|
|
||||||
|
|
||||||
# The tourney site id has to be searched because it may already be in
|
|
||||||
# db with a TourneyTypeId which is different from the one automatically
|
|
||||||
# calculated (Summary import first)
|
|
||||||
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(db, siteID,
|
|
||||||
siteTourneyNo,
|
|
||||||
buyin, fee,
|
|
||||||
knockout,
|
|
||||||
rebuyOrAddon)
|
|
||||||
else:
|
|
||||||
siteTourneyNo = -1
|
|
||||||
buyin = -1
|
|
||||||
fee = -1
|
|
||||||
entries = -1
|
|
||||||
prizepool = -1
|
|
||||||
knockout = 0
|
|
||||||
tourneyStartTime= None
|
|
||||||
rebuyOrAddon = -1
|
|
||||||
|
|
||||||
tourneyTypeId = 1
|
|
||||||
fpdb_simple.isAlreadyInDB(db, gametypeID, siteHandNo)
|
|
||||||
|
|
||||||
hand = fpdb_simple.filterCrap(hand, isTourney)
|
|
||||||
|
|
||||||
#part 2: classify lines by type (e.g. cards, action, win, sectionchange) and street
|
|
||||||
fpdb_simple.classifyLines(hand, category, lineTypes, lineStreets)
|
|
||||||
|
|
||||||
#part 3: read basic player info
|
|
||||||
#3a read player names, startcashes
|
|
||||||
for i, line in enumerate(hand):
|
|
||||||
if lineTypes[i] == "name":
|
|
||||||
seatLines.append(line)
|
|
||||||
|
|
||||||
names = fpdb_simple.parseNames(seatLines)
|
|
||||||
playerIDs = db.recognisePlayerIDs(names, siteID) # inserts players as needed
|
|
||||||
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
|
|
||||||
startCashes = tmp['startCashes']
|
|
||||||
seatNos = tmp['seatNos']
|
|
||||||
|
|
||||||
fpdb_simple.createArrays(category, len(names), cardValues, cardSuits, antes,
|
|
||||||
winnings, rakes, actionTypes, allIns,
|
|
||||||
actionAmounts, actionNos, actionTypeByNo)
|
|
||||||
|
|
||||||
#3b read positions
|
|
||||||
if base == "hold":
|
|
||||||
positions = fpdb_simple.parsePositions(hand, names)
|
|
||||||
|
|
||||||
#part 4: take appropriate action for each line based on linetype
|
|
||||||
for i, line in enumerate(hand):
|
|
||||||
if lineTypes[i] == "cards":
|
|
||||||
fpdb_simple.parseCardLine(category, lineStreets[i], line, names,
|
|
||||||
cardValues, cardSuits, boardValues,
|
|
||||||
boardSuits)
|
|
||||||
#if category=="studhilo":
|
|
||||||
# print "hand[i]:", hand[i]
|
|
||||||
# print "cardValues:", cardValues
|
|
||||||
# print "cardSuits:", cardSuits
|
|
||||||
elif lineTypes[i] == "action":
|
|
||||||
fpdb_simple.parseActionLine(base, isTourney, line, lineStreets[i],
|
|
||||||
playerIDs, names, actionTypes, allIns,
|
|
||||||
actionAmounts, actionNos, actionTypeByNo)
|
|
||||||
elif lineTypes[i] == "win":
|
|
||||||
fpdb_simple.parseWinLine(line, names, winnings, isTourney)
|
|
||||||
elif lineTypes[i] == "rake":
|
|
||||||
totalRake = 0 if isTourney else fpdb_simple.parseRake(line)
|
|
||||||
fpdb_simple.splitRake(winnings, rakes, totalRake)
|
|
||||||
elif (lineTypes[i] == "header" or lineTypes[i] == "rake" or
|
|
||||||
lineTypes[i] == "name" or lineTypes[i] == "ignore"):
|
|
||||||
pass
|
|
||||||
elif lineTypes[i] == "ante":
|
|
||||||
fpdb_simple.parseAnteLine(line, isTourney, names, antes)
|
|
||||||
elif lineTypes[i] == "table":
|
|
||||||
tableResult=fpdb_simple.parseTableLine(base, line)
|
|
||||||
else:
|
|
||||||
raise FpdbError("unrecognised lineType:" + lineTypes[i])
|
|
||||||
|
|
||||||
maxSeats = tableResult['maxSeats']
|
|
||||||
tableName = tableResult['tableName']
|
|
||||||
#print "before part5, antes:", antes
|
|
||||||
|
|
||||||
#part 5: final preparations, then call Database.* with
|
|
||||||
# the arrays as they are - that file will fill them.
|
|
||||||
fpdb_simple.convertCardValues(cardValues)
|
|
||||||
if base == "hold":
|
|
||||||
fpdb_simple.convertCardValuesBoard(boardValues)
|
|
||||||
fpdb_simple.convertBlindBet(actionTypes, actionAmounts)
|
|
||||||
fpdb_simple.checkPositions(positions)
|
|
||||||
|
|
||||||
c = db.get_cursor()
|
|
||||||
c.execute("SELECT limitType FROM Gametypes WHERE id=%s" % (db.sql.query['placeholder'],), (gametypeID, ))
|
|
||||||
limit_type = c.fetchone()[0]
|
|
||||||
fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts)
|
|
||||||
|
|
||||||
totalWinnings = sum(winnings)
|
|
||||||
|
|
||||||
# if hold'em, use positions and not antes, if stud do not use positions, use antes
|
|
||||||
# this is used for handsplayers inserts, so still needed even if hudcache update is being skipped
|
|
||||||
if base == "hold":
|
|
||||||
hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base,
|
|
||||||
category, actionTypes,
|
|
||||||
allIns, actionTypeByNo,
|
|
||||||
winnings,
|
|
||||||
totalWinnings,
|
|
||||||
positions, actionTypes,
|
|
||||||
actionAmounts, None)
|
|
||||||
else:
|
|
||||||
hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base,
|
|
||||||
category, actionTypes,
|
|
||||||
allIns, actionTypeByNo,
|
|
||||||
winnings,
|
|
||||||
totalWinnings, None,
|
|
||||||
actionTypes,
|
|
||||||
actionAmounts, antes)
|
|
||||||
|
|
||||||
try:
|
|
||||||
db.commit() # need to commit new players as different db connection used
|
|
||||||
# for other writes. maybe this will change maybe not ...
|
|
||||||
except: # TODO: this really needs to be narrowed down
|
|
||||||
print "parse: error during commit: " + str(sys.exc_value)
|
|
||||||
|
|
||||||
# HERE's an ugly kludge to keep from failing when positions is undef
|
|
||||||
# We'll fix this by getting rid of the legacy importer. REB
|
|
||||||
try:
|
|
||||||
if positions:
|
|
||||||
pass
|
|
||||||
except NameError:
|
|
||||||
positions = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
||||||
# save data structures in a HandToWrite instance and then insert into database:
|
|
||||||
htw = Database.HandToWrite()
|
|
||||||
htw.set_all( config, settings, base, category, siteTourneyNo, buyin
|
|
||||||
, fee, knockout, entries, prizepool, tourneyStartTime
|
|
||||||
, isTourney, tourneyTypeId, siteID, siteHandNo
|
|
||||||
, gametypeID, handStartTime, names, playerIDs, startCashes
|
|
||||||
, positions, antes, cardValues, cardSuits, boardValues, boardSuits
|
|
||||||
, winnings, rakes, actionTypes, allIns, actionAmounts
|
|
||||||
, actionNos, hudImportData, maxSeats, tableName, seatNos)
|
|
||||||
|
|
||||||
# save hand in db via direct call or via q if in a thread
|
|
||||||
if writeq is None:
|
|
||||||
result = db.store_the_hand(htw)
|
|
||||||
else:
|
|
||||||
writeq.put(htw)
|
|
||||||
result = -999 # meaning unknown
|
|
||||||
|
|
||||||
t9 = time()
|
|
||||||
#print "parse and save=(%4.3f)" % (t9-t0)
|
|
||||||
return result
|
|
||||||
#end def mainParser
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -89,13 +89,14 @@ def testFlopImport():
|
||||||
print "DEBUG: stored: %s dups: %s partial: %s errs: %s ttime: %s" %(stored, dups, partial, errs, ttime)
|
print "DEBUG: stored: %s dups: %s partial: %s errs: %s ttime: %s" %(stored, dups, partial, errs, ttime)
|
||||||
importer.clearFileList()
|
importer.clearFileList()
|
||||||
|
|
||||||
col = { 'sawShowdown': 2
|
col = { 'sawShowdown': 2, 'street0Aggr':3
|
||||||
}
|
}
|
||||||
|
|
||||||
q = """SELECT
|
q = """SELECT
|
||||||
s.name,
|
s.name,
|
||||||
p.name,
|
p.name,
|
||||||
hp.sawShowdown
|
hp.sawShowdown,
|
||||||
|
hp.street0Aggr
|
||||||
FROM
|
FROM
|
||||||
Hands as h,
|
Hands as h,
|
||||||
Sites as s,
|
Sites as s,
|
||||||
|
@ -119,7 +120,8 @@ and s.id = p.siteid"""
|
||||||
q = """SELECT
|
q = """SELECT
|
||||||
s.name,
|
s.name,
|
||||||
p.name,
|
p.name,
|
||||||
hp.sawShowdown
|
hp.sawShowdown,
|
||||||
|
hp.street0Aggr
|
||||||
FROM
|
FROM
|
||||||
Hands as h,
|
Hands as h,
|
||||||
Sites as s,
|
Sites as s,
|
||||||
|
@ -135,10 +137,10 @@ and s.id = p.siteid"""
|
||||||
c = db.get_cursor()
|
c = db.get_cursor()
|
||||||
c.execute(q)
|
c.execute(q)
|
||||||
result = c.fetchall()
|
result = c.fetchall()
|
||||||
|
pstats = { u'Kinewma':0, u'Arbaz':0, u's0rrow':1, u'bys7':0, u'AAALISAAAA':1, u'Bl\xe5veis':0 }
|
||||||
for row, data in enumerate(result):
|
for row, data in enumerate(result):
|
||||||
print "DEBUG: result[%s]: %s" %(row, result[row])
|
print "DEBUG: result[%s]: %s == %s" %(row, result[row], pstats[data[1]])
|
||||||
# Assert if any sawShowdown = True
|
assert result[row][col['sawShowdown']] == pstats[data[1]]
|
||||||
assert result[row][col['sawShowdown']] == 1
|
|
||||||
|
|
||||||
assert 0 == 1
|
assert 0 == 1
|
||||||
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import fpdb_simple
|
|
||||||
import datetime
|
|
||||||
import py
|
|
||||||
|
|
||||||
def checkDateParse(header, site, result):
|
|
||||||
assert fpdb_simple.parseHandStartTime(header, site) == result
|
|
||||||
|
|
||||||
def testPokerStarsHHDate():
|
|
||||||
tuples = (
|
|
||||||
("PokerStars Game #21969660557: Hold'em No Limit ($0.50/$1.00) - 2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET]", "ps",
|
|
||||||
datetime.datetime(2008,11,12,15,00,48)),
|
|
||||||
("PokerStars Game #21969660557: Hold'em No Limit ($0.50/$1.00) - 2008/08/17 - 01:14:43 (ET)", "ps",
|
|
||||||
datetime.datetime(2008,8,17,6,14,43)),
|
|
||||||
("PokerStars Game #21969660557: Hold'em No Limit ($0.50/$1.00) - 2008/09/07 06:23:14 ET", "ps",
|
|
||||||
datetime.datetime(2008,9,7,11,23,14))
|
|
||||||
)
|
|
||||||
|
|
||||||
#def testTableDetection():
|
|
||||||
# result = Tables.clean_title("French (deep)")
|
|
||||||
# assert result == "French"
|
|
||||||
# result = Tables.clean_title("French (deep) - $0.25/$0.50 - No Limit Hold'em - Logged In As xxxx")
|
|
||||||
# assert result == "French"
|
|
||||||
#
|
|
||||||
# for (header, site, result) in tuples:
|
|
||||||
# yield checkDateParse, header, site, result
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user