import io, json, logging, os, sys, time
import requests
from bcdd.PBNFile import PBNFile
from jfrteamy.db import TeamyDB
def get_digits(t):
return int(''.join(i for i in t if i.isdigit()))
def clear():
os.system('cls' if os.name == 'nt' else 'clear')
def get_config():
with open('mojzesz.json') as config_file:
config = json.load(config_file)
return config
def setup_logging(config):
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
logging_levels = [logging.WARNING, logging.INFO, logging.DEBUG]
logging.basicConfig(
level=logging_levels[config['settings'].get('info_messages', 0)],
format= '%(levelname)s:\t%(message)s'
)
def get_pbn_source(config):
request_auth = None
if 'auth' in config:
request_auth = (config['auth'].get('user', ''), config['auth'].get('pass', ''))
request_headers = config.get('headers', {})
logging.info('Fetching %s', config['url'])
r = requests.get(config['url'], auth=request_auth, headers=request_headers)
r.raise_for_status()
remote_content = r.text
logging.info('Fetched %d bytes', len(remote_content))
with io.StringIO(remote_content) as io_stream:
f = PBNFile(io_stream)
return f
def get_team_rosters(db):
players = db.fetch_all('SELECT id, team, CONCAT(gname, " ", sname) FROM players')
rosters = {}
for player in players:
team = player[1]
if team not in rosters:
rosters[team] = {}
rosters[team][player[0]] = player[2]
return rosters
def get_round_lineup(db, round_no, segment_no):
db_tables = db.fetch_all('SELECT tabl, homet, visit FROM segments WHERE rnd = %s AND segment = %s', (
round_no, segment_no
))
round_lineup = {}
for dbt in db_tables:
round_lineup[dbt[0]] = dbt[1:]
return round_lineup
def get_pbn_lineups(pbn, round_no, board_no=None):
tables = {}
for b in pbn.boards:
if b.has_field('Round'):
if b.get_field('Round') == str(round_no):
if not board_no or (str(board_no) == b.get_field('Board')):
table = b.get_field('Table')
if table not in tables:
tables[table] = {}
if board_no:
logging.info('Fetching lineups from board no %d, table %s %s', board_no, table, b.get_field('Room'))
tables[table][b.get_field('Room')] = [
[b.get_field('North', ''), b.get_field('South', '')],
[b.get_field('East', ''), b.get_field('West', '')]
]
return tables
def fetch_lineups(pbn, db, settings):
rosters = get_team_rosters(db)
lineup_board_no = settings.get('lineup_board_no', None)
if lineup_board_no is None:
board_mapping = get_board_mapping(db, settings['teamy_round'], settings['teamy_segment'])
lineup_board_no = list(board_mapping.keys())[list(board_mapping.values()).index(1)]
logging.info('No lineup board number specified in config, reverting to first board of segment: %d', lineup_board_no)
tables = get_pbn_lineups(pbn, settings['pbn_round'], lineup_board_no)
round_lineup = get_round_lineup(db, settings['teamy_round'], settings['teamy_segment'])
for t, rooms in tables.items():
table = get_digits(t)
if table not in round_lineup:
logging.error('[Table "%s"] not in tournament for round %s-%s', table, settings['teamy_round'], settings['teamy_segment'])
continue
home_team = round_lineup[table][0]
away_team = round_lineup[table][1]
home_roster = rosters.get(home_team, {})
away_roster = rosters.get(away_team, {})
lineups = {}
positions = [['N', 'S'], ['E', 'W']]
for room, lineup in rooms.items():
room = room.lower().replace('closed', 'close')
for which_room in ['open', 'close']:
# I have no idea how to name this variable,
# it's something like "the room in which the currently processed team sits on NS if they're home and EW if away"
roster = home_roster if which_room == 'open' else away_roster
team = home_team if which_room == 'open' else away_team
for i in range(0, 2):
player = lineup[1 - (room == which_room)][i]
player_id = None
for roster_id, roster_pl in roster.items():
if player == roster_pl:
player_id = roster_id
position = room + positions[1 - (room == which_room)][i]
logging.info('Player in lineup: Table %d, position %s, #%d %s',
table, position, roster_id, roster_pl)
db.fetch(
'UPDATE segments SET '+position+' = %s WHERE rnd = %s AND segment = %s AND tabl = %s', (
player_id,
settings['teamy_round'], settings['teamy_segment'],
table
)
)
if player_id is None:
logging.warning('Player %s not found in team %d', player, team)
def get_board_mapping(db, round_no, segment_no):
board_mapping = {}
for b in db.fetch_all('SELECT brd, bno FROM boards WHERE rnd = %s AND segment = %s', (
round_no, segment_no)):
board_mapping[b[1]] = b[0]
return board_mapping
def get_current_db_score(db, round_no, segment_no, table, room, board_no):
while True:
current_score = db.fetch('SELECT declarer, contract, result, lead, score FROM scores ' +
'WHERE rnd = %s AND segment = %s AND tabl = %s AND room = %s AND board = %s', (
round_no, segment_no, table, room, board_no))
if current_score:
break
logging.info('record in scores table does not exist - creating')
db.fetch('INSERT INTO scores(rnd, segment, tabl, room, board, mecz, butler, processed, tims) VALUES(%s, %s, %s, %s, %s, 0, 0, 1, NOW())', (
round_no, segment_no, table, room, board_no))
return current_score
def get_pbn_score(b):
contract = b.get_field('Contract').replace('N', 'NT').replace('X', ' x').replace('*', ' x').replace('x x', 'xx') if b.has_field('Contract') else ''
if not contract:
return None, None, None, None, None
declarer = b.get_field('Declarer') if b.has_field('Declarer') else ''
lead = ''
if contract[0].isdigit():
contract = contract[0] + ' ' + contract[1:]
result = int(b.get_field('Result')) - get_digits(contract) - 6 if b.has_field('Result') else ''
score = int(b.get_field('Score').replace('NS ', '')) if b.has_field('Score') else '' # a co z pasami?
play_data = b.get_play_data()
if play_data:
play_data = ' '.join(play_data).split(' ')
if play_data:
lead = play_data[0].strip()
lead = lead[0:2].replace('T', '10')
else: # passed-out hand
contract = contract.upper()
result = 0
score = 0
return declarer, contract, result, score, lead
def update_score(db, pbn_board, round_no, segment_no, table, room, board_no, real_board_no=None, overwrite=False):
if real_board_no is None:
real_board_no = board_no
current_score = get_current_db_score(db, round_no, segment_no, table, room, board_no)
declarer, contract, result, score, lead = get_pbn_score(pbn_board)
if contract is None:
logging.info('no contract yet in board %d, table %d-%d',
real_board_no, table, room)
return
update_score = True
if current_score[4] or current_score == 0: # there's a score, so the result was already fully imported
if not overwrite: # we need to check if we should overwrite the score, if not
update_score = False
if score != current_score[4]: # then emit a warning if it's changed
logging.warning('result in board %d, table %d-%d changed and is NOT going to be overwritten!',
real_board_no, table, room)
else:
logging.info('not overwriting result in board %d, table %d-%d',
real_board_no, table, room)
if update_score:
params = (contract, declarer, result, lead, score)
logging.info('updating result in board %d, table %d-%d: %s',
real_board_no, table, room, params)
db.fetch('UPDATE scores SET contract = %s, declarer = %s, result = %s, lead = %s, score = %s, '+
'tims = NOW(), processed = 0, mecz = 1, butler = 1 '+
'WHERE rnd = %s AND segment = %s AND board = %s AND tabl = %s AND room = %s', (
params + (round_no, segment_no, board_no, table, room)))
def get_pbn_bidding(pbn):
bidding = pbn.get_auction()
return bidding[0], ' '.join(bidding[1:]).split(' ')
def get_lin_bidding(bidding):
lin_bidding = []
for bid in bidding:
if bid.lower() == 'pass':
lin_bidding.append('p')
continue
lin_bidding.append(bid.replace('NT', 'N'))
lin_bidding = 'mb|'.join([bid + '|' for bid in lin_bidding]) + 'pg||'
return lin_bidding
def get_html_bidding(bidding, dealer):
html_bidding = []
for bid in bidding:
if bid.lower() == 'pass':
html_bidding.append('pass')
continue
html_bid = bid.replace('NT', 'N')
for suit in ['C', 'D', 'H', 'S', 'N']:
html_bid = html_bid.replace(suit, "" % (suit))
html_bidding.append(html_bid)
players = ['W', 'N', 'E', 'S']
html_bidding = [' '] * players.index(dealer) + html_bidding + [' '] * ((4 - players.index(dealer)) % 4)
html = "
W | N | E | S |
" html += html_bidding[i] html += " | " if i % 4 == 3: html += "