summaryrefslogtreecommitdiff
path: root/dealconvert/formats/lin.py
blob: 57a5205bfae823d783773d61eed75c001a84029c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
from collections import OrderedDict
import re

from . import DealFormat
from .. import dto

class LINFormat(DealFormat):

    _qx_format = re.compile(r'^[oc](\d+)$')
    _ah_format = re.compile(r'^[A-Za-z ]* (\d+)$')
    _md_hand_format = re.compile(r'^S(.*)H(.*)D(.*)C(.*)$')
    _suit_cards = 'AKQJT98765432'

    @property
    def suffix(self):
        return '.lin'

    def parse_content(self, content):
        deals = OrderedDict()
        event = ''
        lines = [line.strip() for line in content.readlines()]
        for line in lines:
            chunks = line.split('|')
            fields = {}
            while len(chunks) > 1:
                field_name = chunks.pop(0)
                field_value = chunks.pop(0)
                if field_name not in fields:
                    fields[field_name] = []
                fields[field_name].append(field_value)
            if 'vg' in fields:
                event = fields['vg'][0].split(',')[0]
            if 'md' in fields:
                deal_number = None
                for field in ['qx', 'ah']:
                    if field in fields:
                        match = getattr(
                            self, '_%s_format' % (field)).match(
                                fields[field][0])
                        if match:
                            deal_number = int(match.group(1))
                            break
                if deal_number is not None:
                    layout = self._parse_md_field(fields['md'][0])
                    if layout:
                        if deal_number in deals:
                            if deals[deal_number] != layout:
                                raise RuntimeError('multiple boards #%d with different layouts' % (deal_number))
                        deals[deal_number] = layout
                    else:
                        print('layout not parsed: ' + fields['md'][0])
        dealset = []
        for number, layout in deals.items():
            deal = dto.Deal()
            deal.event = event
            deal.number = number
            deal.hands = layout
            deal.dealer = deal.get_dealer(deal.number)
            deal.vulnerable = deal.get_vulnerability(deal.number)
            dealset.append(deal)
        return dealset

    def _parse_md_field(self, value):
        try:
            hands = value[1:].split(',')
            layout = [[[], [], [], []],
                      [[], [], [], []],
                      [[], [], [], []],
                      [[], [], [], []]]
            for i, hand in enumerate(hands):
                layout[(i+2)%4] = self._parse_md_hand(hand) # hands always start from S
            for j, single_hand in enumerate(layout):
                if not sum([len(suit) for suit in single_hand]): # fill 4th hand if necessary
                    for k, suit in enumerate(single_hand):
                        layout[j][k] = ''.join([
                            c for c in self._suit_cards
                            if c not in ''.join([layout[h][k] for h in range(0, 4) if h != j])
                        ])
            for j, single_hand in enumerate(layout):
                for k, suit in enumerate(single_hand):
                    layout[j][k] = list(suit)
            return layout
        except:
            return None

    def _parse_md_hand(self, hand):
        match = self._md_hand_format.match(hand)
        if match:
            return [''.join(sorted(
                list(match.group(i)),
                key=lambda c: self._suit_cards.index(c)))
                    for i in range(1, 5)]
        return ['', '', '', '']

    def output_content(self, out_file, dealset):
        event_name = ([deal.event for deal in dealset if deal.event] or [''])[0]
        first_deal = min([deal.number for deal in dealset])
        last_deal = max([deal.number for deal in dealset])
        lines = [
            'vg|%s,SEGMENT 1,I,%d,%d,HOME,0,AWAY,0|' % (event_name, first_deal, last_deal),
            'rs|,,,,,,,,,,,|',
            'pn|,,,,,,,|pg||'
        ]
        for deal in dealset:
            dealer = (deal.dealer + 3) % 4 or 4
            layout = ''
            for i in range(0, 4):
                for s, suit in enumerate(deal.hands[(i+2) % 4]):
                    layout += 'SHDC'[s]
                    layout += ''.join(suit)
                if i < 3:
                    layout += ','
            vulnerability = ('b' if deal.vulnerable['EW'] else 'n') \
                if deal.vulnerable['NS'] \
                   else ('e' if deal.vulnerable['EW'] else '0')
            for room in ['o', 'c']:
                lines.append(
                    'qx|%s%d|pn|,,,,,,,|md|%d%s|sv|%s|pg||' % (
                        room, deal.number,
                        dealer, layout,
                        vulnerability
                    )
                )
        for line in lines:
            out_file.write(line + '\r\n')