This file is indexed.

/usr/share/pyshared/pybridge/bridge/pbn.py is in pybridge-common 0.3.0-7.2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# PyBridge -- online contract bridge made easy.
# Copyright (C) 2004-2007 PyBridge Project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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 General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.


"""
This module provides two-way conversion between BridgeGame objects and the
PBN 2.0 (Portable Bridge Notation) format.

The PBN 2.0 specification is available from http://www.tistis.nl/pbn/.
"""


import re
import time

from card import Card
from deck import Deck
from call import Bid, Pass, Double, Redouble
from symbols import Player as Position, Level, Strain, Rank, Suit, Vulnerable


class ParseError(Exception):
    """Raised when PBN parser encounters an unexpected input."""




def importPBN(pbn, complete=True):
    """Builds a BridgeGame object from a given PBN "import"-format string.
    
    @param pbn: a string containing PBN markup.
    @param complete: if True, expect the game described in pbn to be complete.
                     Raises a ParseError if BridgeGame cannot be completed.
    @return: a BridgeGame object equivalent to the PBN string.
    """
    from newnewgame import BridgeGame, GameError

    # Mappings from PBN symbols to their PyBridge type equivalents.
    BIDLEVEL = dict(zip('1234567', Level))
    BIDSTRAIN = dict(zip('CDHS', Strain) + [('NT', Strain.NoTrump)])
    CARDRANK = dict(zip('23456789TJQKA', Rank))
    CARDSUIT = dict(zip('CDHS', Suit))
    POSITION = dict(zip('NESW', Position))
    VULN = {'All': Vulnerable.All, 'Both': Vulnerable.All, '-': Vulnerable.None,
            'NS': Vulnerable.NorthSouth, 'EW': Vulnerable.EastWest,
            'None': Vulnerable.None, 'Love': Vulnerable.None}

    game = BridgeGame()
    players = dict([(pos, game.addPlayer(pos)) for pos in Position])

    tags, sections, notes = parsePBN(pbn)

    board = {}
    # Load values of non-essential tags.
    board['event'] = tags.get('Event')
    board['site'] = tags.get('Site')
    if tags.get('Date'):  # Convert to time tuple.
        board['date'] = time.strptime(tags['Date'], "%Y.%m.%d")
    board['boardnum'] = int(tags.get('Board', 0))
    board['players'] = dict([(p, tags.get(p.key)) for p in Position])

    # Load values of essential tags.
    for tag in ('Dealer', 'Vulnerable', 'Deal', 'Auction', 'Play'):
        if tag not in tags:
            raise ParseError, "Required tag '%s' not found" % tag
    try:
        board['dealer'] = POSITION[tags['Dealer']]
        board['vulnerable'] = VULN[tags['Vulnerable']]
        
        # Reconstruct deal.
        board['deal'] = {}
        first, hands = tags['Deal'].split(":")
        firstindex = POSITION[first.strip()].index
        order = Position[firstindex:] + Position[:firstindex]
        for player, hand in zip(order, hands.strip().split()):
            board['deal'][player] = []
            for suit, suitcards in zip(reversed(Suit), hand.split('.')):
                for rank in suitcards:
                    card = Card(CARDRANK[rank], suit)
                    board['deal'][player].append(card)
        # Validate deal.
        deck = Deck()
        if not deck.isValidDeal(board['deal']):
            raise ParseError, "Deal does not validate"

        game.start(board)  # Initialise game with board.

        # Process Auction section: build bidding.
        # TODO: PBN does not need to provide an auction.
        pos = POSITION[tags['Auction']]

        for item in sections['Auction'].split():
            if item.startswith('='):  # A note identifier.
                continue
            elif item.startswith('-'):  # Skip position.
                pos = Position[(pos.index + 1) % len(Position)]  # Next player.
                continue

            # Extract call from item.
            if item[0] in BIDLEVEL and item[1:] in BIDSTRAIN:
                call = Bid(BIDLEVEL[item[0]], BIDSTRAIN[item[1:]])
            elif item == 'Pass':
                call = Pass()
            elif item == 'X':
                call = Double()
            elif item == 'XX':
                call = Redouble()
            else:
                raise ParseError, "Unrecognised item '%s' in Auction" % item

            try:  # Make call.
                players[pos].makeCall(call)
                pos = Position[(pos.index + 1) % len(Position)]  # Next player.
            except GameError, err:
                raise ParseError, "Invalid call %s in Auction: %s" % (call, err)

        # Process Play section: build play.
        first = POSITION[tags['Play']]
        for line in sections['Play'].splitlines():
            leader, cards = game.getTurn(), {}  # Trick.
            
            # Extract cards from line.
            for item in line.split():
                print item
                if item.startswith('='):  # A note identifier.
                    continue
                if item[0] in CARDSUIT and item[1] in CARDRANK:
                    card = Card(CARDRANK[item[1]], CARDSUIT[item[0]])
                    cards[Position[(first.index + len(cards)) % len(Position)]] = card
                else:
                    raise ParseError, "Unrecognised item '%s' in Play" % item

            try:  # Play cards in trick.
                for pos in Position[leader.index:] + Position[:leader.index]:
                    players[pos].playCard(card)
            except GameError, err:
                raise ParseError, "Invalid card %s in Play: %s" % (card, err)


    except KeyError, key:
        raise ParseError, "Invalid value %s for attribute" % key





def exportPBN(game):
    """Builds a PBN "export"-format string from a given BridgeGame object.
    
    @param game: a BridgeGame object.
    @return: a PBN string equivalent to the BridgeGame object.
    """

    # Mappings from PyBridge symbol types to their PBN equivalents.
    RANKS = dict(zip(Rank, "23456789TJQKA"))
    SUITS = dict(zip(Suit, "CDHS"))
    POSITIONS = dict(zip(Player, "NESW"))





'''
    def importPBN(self, pbn):
        """Builds a BridgeGame object from a given PBN "import format" string.
        
        @param pbn: a string containing PBN markup.
        @return: a BridgeGame object equivalent to the PBN string.
        """
        # This lambda reverses the mapping between keys and values of dict d.
        # It assumes there are no duplicate values in d.
        invert = lambda d: dict([(v, k) for k, v in d.iteritems()])
        
        tagValues, sectionData = self.parse(pbn)
        
        # Get dealer.
        dealer = invert(self.SEATS)[tagValues['Dealer']]
        
        # Get deal.
        deal = {}
        # Determine first hand in Deal string.
        first = invert(self.SEATS)[tagValues['Deal'][0]]
        seatorder = Seat[first.index:] + Seat[:first.index]
        # Split deal into hands, into suits, into cards.
        handstrings = tagValues['Deal'][2:].split(' ')
        for seat, handstring in zip(seatorder, handstrings):
            deal[seat] = []
            for suit, rankstring in zip(self.SUITORDER, handstring.split('.')):
                for rankchar in rankstring:
                    card = Card(invert(self.RANKS)[rankchar], suit)
                    deal[seat].append(card)
        
        # Get vulnerability.
        for vulnTuple, vulnTexts in self.VULNERABLE.items():
            # Since PBN allows variations on the Vulnerable tag.
            if tagValues['Vulnerable'] in vulnTexts:
                vulnNS, vulnEW = vulnTuple
                break
        
        scoring = scoreDuplicate  # For now, just use duplicate scoring method.
        game = Game(dealer, deal, scoring, vulnNS, vulnEW)
        
        #
        # TODO - determine the calls made, load them in with game.makeCall
        #      - determine the cards played, load them in with game.playCard
        #
        
        # Finally, return the BridgeGame object.
        return game
    

    def exportPBN(self, game):
        """Builds a PBN "export format" string from a given BridgeGame object.
        
        @param game: a BridgeGame object.
        @return: a PBN string equivalent to the BridgeGame object.
        """
        
        def makeTag(key, value):
            """A convenience function to generate a PBN-style tag."""
            return '[%s \"%s\"]\n' % (key, value)
        
        pbn = ''
        
        #
        # TODO: fill out all 15 fields, with respect to PBN spec.
        #
        
#       (1) Event      (the name of the tournament or match)
        pbn += makeTag('Event', 'Unknown')
        
#       (2) Site       (the location of the event)
        pbn += makeTag('Site', 'Unknown')
        
#       (3) Date       (the starting date of the game)
        # TODO: use the localtime() method of the time module
        pbn += makeTag('Date', '%s.%s.%s' % (1,2,3))
        
#       (4) Board      (the board number)
        pbn += makeTag('Board', '1')
        
#       (5) West       (the west player)
#       (6) North      (the north player)
#       (7) East       (the east player)
#       (8) South      (the south player)
        # TODO: use 'Unknown' tags
        
#       (9) Dealer     (the dealer)
        pbn += makeTag('Dealer', self.SEATS[game.bidding.dealer])
        
#       (10) Vulnerable (the situation of vulnerability)
        # TODO: put game.vulnNS and game.vulnEW into a tuple, use tuple as index on self.VULNERABLE,
        # get first value (the [0]) from list.
#        pbn += makeTag('Vulnerable', self.VULNERABLE[( , )][0]
        
#       (11) Deal       (the dealt cards)
#       (12) Scoring    (the scoring method)
#       (13) Declarer   (the declarer of the contract)
#       (14) Contract   (the contract)
#       (15) Result     (the result of the game)
        
        return pbn
'''

def parsePBN(pbn):
    """Parses the given PBN string and extracts:
    
      * for each PBN tag, a dict of associated key/value pairs.
      * for each data section, a dict of key/data pairs.
        
    This method does not interpret the PBN string itself.
    
    @param pbn: a string containing PBN markup.
    @return: a tuple (tag values, section data, notes).
    """
    tagValues, sectionData, notes = {}, {}, {}
    for line in pbn.splitlines():
        line.strip()  # Remove whitespace.

        if line.startswith('%'):  # A comment.
            pass  # Skip over comments.

        elif line.startswith('['):  # A tag.
            line = line.strip('[]')  # Remove leading [ and trailing ].
            # The key is the first word, the value is everything after.
            tag, value = line.split(' ', 1)
            tag = tag.capitalize()
            value = value.strip('\'\"')
            if tag == 'Note':
                notes.setdefault(tag, [])
                notes[tag].append(value)
            else:
                tagValues[tag] = value

        else:  # Line follows tag, add line to data buffer for section.
            sectionData.setdefault(tag, '')
            sectionData[tag] += line + '\n'

    return tagValues, sectionData, notes




def testImport():
    pbnstr = file("a-pbn-file.pbn").read()  # Set path as appropriate.
    pbn = PBNHandler()  # Create our handler.
    g = pbn.importPBN(pbnstr)  # Do it!
    return g