From e36dd9fcbae37191983f2d60db2093813b43b7d4 Mon Sep 17 00:00:00 2001 From: MichaƂ Klichowicz Date: Wed, 2 Sep 2026 14:28:12 +0200 Subject: TXT file format: list of BBO handviewer URLs --- dealconvert/formats/txt.py | 125 +++++++++++++++++++++++++++++++++++++++++++++ tests.py | 2 +- 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 dealconvert/formats/txt.py diff --git a/dealconvert/formats/txt.py b/dealconvert/formats/txt.py new file mode 100644 index 0000000..1dabfe3 --- /dev/null +++ b/dealconvert/formats/txt.py @@ -0,0 +1,125 @@ +from collections import OrderedDict +from urlparse import urlparse, parse_qsl +from urllib import urlencode +import re, warnings + +from . import DealFormat +from .. import dto + +class TXTFormat(DealFormat): + + _url_prefix = 'https://www.bridgebase.com/tools/handviewer.html' + _hand_format = re.compile(r'([shdc])([akqjt2-9]*)', re.I) + _hand_designations = { + 'n': dto.POSITION_NORTH, + 'e': dto.POSITION_EAST, + 's': dto.POSITION_SOUTH, + 'w': dto.POSITION_WEST + } + _suit_designations = { + 's': dto.SUIT_SPADES, + 'h': dto.SUIT_HEARTS, + 'd': dto.SUIT_DIAMONDS, + 'c': dto.SUIT_CLUBS + } + + @property + def suffix(self): + return '.txt' + + def parse_content(self, content): + deal_list = [] + deal_numbers = [] + renumber_deals = False + event = '' + lines = [line.strip() for line in content.readlines()] + for line in lines: + if line.startswith(self._url_prefix): + deal = dto.Deal() + url = urlparse(line) + params = OrderedDict(parse_qsl(url.query)) + for hand in self._hand_designations.keys(): + if hand not in params: + raise RuntimeError( + 'URL %s is missing "%s" hand' % ( + line, hand + ) + ) + suits = OrderedDict( + self._hand_format.findall(params[hand])) + for suit, cards in suits.iteritems(): + cards = cards.upper() + deal.hands[ + self._hand_designations[hand] + ][ + self._suit_designations[suit] + ] = list(cards) + if 'b' in params: + try: + deal.number = int(params['b']) + except: + warnings.warn( + 'URL %s contains no deal number. ALL deals will be auto-number, maintaining their vulnerability if defined' % (line) + ) + renumber_deals = True + else: + warnings.warn( + 'URL %s contains no deal number. ALL deals will be auto-number, maintaining their vulnerability if defined' % (line) + ) + renumber_deals = True + if deal.number: + if deal.number in deal_numbers: + warnings.warn( + 'Duplicate deal number %d. ALL deals will be auto-number, maintaining their vulnerability if defined' % (deal.number) + ) + renumber_deals = True + deal_numbers.append(deal.number) + if 'v' in params: + deal.vulnerable['NS'] = params['v'].lower() in ['b', 'n'] + deal.vulnerable['EW'] = params['v'].lower() in ['b', 'e'] + else: + deal.vulnerable = None + if 'd' in params: + deal.dealer = self._hand_designations.get( + params['d'], None) + deal.event = event + event = '' + deal_list.append(deal) + else: + event = line + for idx, deal in enumerate(deal_list): + if renumber_deals: + deal.number = idx+1 + if not deal.vulnerable: + deal.vulnerable = deal.get_vulnerability(deal.number) + if not deal.dealer: + deal.dealer = deal.get_dealer(deal.number) + return deal_list + + def output_content(self, out_file, dealset): + lines = [] + dealers = {} + for designation, hand in self._hand_designations.iteritems(): + dealers[hand] = designation + suits = {} + for deal in dealset: + if deal.event: + lines.append(deal.event) + params = { + 'b': deal.number, + 'd': dealers[deal.dealer], + 'v': ['0', 'n', 'e', 'b'][ + deal.vulnerable['NS'] + 2 * deal.vulnerable['EW'] + ], + 'a': 'pppp' + } + for hand, designation in dealers.iteritems(): + params[designation] = '' + for suit, idx in self._suit_designations.iteritems(): + params[designation] += suit + params[designation] += ''.join(deal.hands[hand][idx]).lower() + url = '%s?%s' % ( + self._url_prefix, urlencode(params)) + lines.append(url) + for line in lines + ['']: + out_file.write(line + '\r\n') diff --git a/tests.py b/tests.py index ac9f260..cc7b71d 100644 --- a/tests.py +++ b/tests.py @@ -5,7 +5,7 @@ from dealconvert import DealConverter import pytest -formats = ['ber', 'bhg', 'bri', 'rzd', 'cds', 'csv', 'dge', 'dlm', 'dup', 'lin', 'pbn'] +formats = ['ber', 'bhg', 'bri', 'rzd', 'cds', 'csv', 'dge', 'dlm', 'dup', 'lin', 'pbn', 'txt'] format_files = ['test.' + f for f in formats] + ['test-jfr.pbn'] test_data = [(d[0], d[1], d[1] == 'test-jfr.pbn') for d in itertools.product(format_files, format_files)] -- cgit v1.3.1