#!/usr/bin/python from operator import attrgetter import sys import random import tkFileDialog import Tkinter def getCardNumber(c): if c == 'A': return 1 if c == 'K': return 2 if c == 'Q': return 3 if c == 'J': return 4 if c == 'T': return 5 # 9 to 2 return 6 + (9 - int(c)) class Card: inSorted = 0 inTarget = 0 intermPile = 0 inInterm = 0 # input should be of this form # Q965.Q8764.A9.Q7 T43.AK2.T432.A52 8.JT9.KJ7.KT8643 AKJ72.53.Q865.J9 class Deal: def __init__(self, boardno_, deal_): self.boardno = "Bd#{0}".format(boardno_ + 1) self.cards = [] self.deal = deal_ hands = deal_.split() if len(hands) != 4: print "Corrupt deal: " + deal sys.exit(-1) # make an array of 13 0s, 1s, 2s and 3s and shuffle it shuffled = range(0,52) for i in shuffled: shuffled[i] = (shuffled[i] % 4) random.shuffle(shuffled) # create the 52 cards for hand in hands: # 'Q965.Q8764.A9.Q7', 'T43.AK2.T432.A52', etc. suits = hand.split('.') # 'Q965', 'Q8764', etc. if len(suits) != 4: print "Corrupt deal: " + deal sys.exit(-1) for suitno in xrange(0,4): for c in suits[suitno]: # 'Q','9', etc. cardno = len(self.cards) + 1 card = Card() # stage 0 (sorted deck) 9!S is 6th card in sorted deck card.inSorted = suitno*13 + getCardNumber(c) # stage 1 9!S is randomly placed in one of the 4 piles card.intermPile = shuffled[cardno-1] # stage 2 9!S needs to be 2nd card in target deck card.inTarget = cardno self.cards.append(card) if len(self.cards) != 52: print "Corrupt deal: " + self.deal sys.exit(-1) # figure out the card number in the intermediate pile cardsInPile = [0,0,0,0] self.cards = sorted(self.cards, key=attrgetter('inSorted')) for card in self.cards: pileno = card.intermPile cardsInPile[pileno] = cardsInPile[pileno] + 1 # if there is 1 card in the pile, this will be the 13th card! card.inInterm = (14 - cardsInPile[pileno]) + 13*pileno def print_debug(self): print self.boardno, for card in self.cards: print "{0},{1},{2} ".format(card.inSorted, card.inTarget, card.inInterm), print "" def print_plaintext(self, ofp): hands = self.deal.split() symb = ['', '', '', ''] cards = [] for handno in range(0,4): suits = hands[handno].split('.') cards.append( suits ) # card[x][y] is xth direction, yth suit ofp.write("") ofp.write("") for suitno in range(0,4): ofp.write("") for dir in range(0,4): ofp.write(""); ofp.write("") ofp.write("
" + self.boardno + ": North" + self.boardno + ": East" + self.boardno + ": South" + self.boardno + "West
" + symb[suitno] + " " + cards[dir][suitno] + "
") ofp.write("\n") def print_stage1(self, ofp): ofp.write(self.boardno) ofp.write("Stage1: ") # the deck should be sorted first self.cards = sorted(self.cards, key=attrgetter('inSorted')) # now go through and print the interm hand number cardno = 0 for card in self.cards: ofp.write("{0}".format(1 + ((card.inInterm-1) / 13))) cardno = cardno + 1 if cardno%4 == 0: ofp.write(" ") ofp.write("\n") def print_stage2(self, ofp): ofp.write(self.boardno) ofp.write("Stage2: ") # the deck should be in intermediate order self.cards = sorted(self.cards, key=attrgetter('inInterm')) # now go through and print the target hand number cardno = 0 for card in self.cards: ofp.write("{0}".format(1 + ((card.inTarget-1) / 13))) cardno = cardno + 1 if cardno%4 == 0: ofp.write(" ") ofp.write("\n") #Example input line: #[Deal "N:Q965.Q8764.A9.Q7 T43.AK2.T432.A52 8.JT9.KJ7.KT8643 AKJ72.53.Q865.J9"] def getDealsFromPBN(filename): print "Reading " + filename ifp = open(filename, "r") if ifp is None: print "Unable to open " + filename + " for reading.\n" sys.exit(-1) deals = [] for line in ifp: if line[0:6] == '[Deal ': start = line.find('N:',0) + 2 end = line.find('"', start) line = line[start:end] deals.append(line) return deals def predeal(infile, outfile): deals = getDealsFromPBN(infile) slips = [] for dealno in xrange(0,len(deals)): slip = Deal(dealno, deals[dealno]) #slip.print_debug() slips.append(slip) # Now print each of the slips in HTML form ofp = open(outfile, "w") if ofp is None: print "Unable to write to " + outfile sys.exit(-1) ofp.write("\nPredeal to duplication instructions\n"); ofp.write("Program by V Lakshmanan based on idea by Matthew Johnson
"); ofp.write("V Lakshmanan: http://bridgemishaps.blogspot.com/
"); ofp.write("Matthew Johnson: http://www.matthew.ath.cx/projects/pescetti
"); ofp.write("

Deals in Plaintext / Curtain cards

\n"); ofp.write("Use this if you are making boards that you will not play. This works well if you have a Mitchell or if you have a Howell with a sitout pair. See http://bridgemishaps.blogspot.com/2013/11/using-predealt-hands-in-small-games.html for which pair needs to make which boards.

\n"); ofp.write("You could also use this to have the director or other non-player verify to see that the cards were dealt properly. Verification should be faster than dealing by hand. The format of these makes them suitable for use as curtain cards (cut the hands of each player and insert them so that players in the first round can check to make sure they have the right card. The problem with curtain cards is that errors are hard to fix at the table since the players have seen the wrong card.).

\n"); for slip in slips: slip.print_plaintext(ofp) ofp.write("

") ofp.write("

Stage 1 of Duplication Algorithm

\n"); ofp.write("Start from a sorted deck. The deck should be sorted in suits (Spades, Hearts, Diamonds, then Clubs) and within each suit, the cards should be sorted AKQJT98765432. In your sorted deck, Ace of spades should be the first card and the deuce of clubs the last one.

Deal the cards one-by-one to one of the 4 piles indicated. Then stack them up so that the last card of pile 1 is followed by the first card of pile 2, etc. This new stack should be given to the person carrying out Stage 2 (could even be the same person).

Errors tend to be reduced if one person reads the slip aloud while the other person handles the cards.

\n"); for slip in slips: slip.print_stage1(ofp) ofp.write("

") ofp.write("

Stage 2 of Duplication Algorithm

\n"); ofp.write("Start from the deck that comes from stage 1. Deal each card to one of the 4 piles indicated. Pile 1 goes to North, pile 2 to East, pile 3 to South and pile 4 to West. The hands are now ready to play. Good luck!

\n"); for slip in slips: slip.print_stage2(ofp) ofp.write("

") ofp.write("") ofp.close() print "{0} written out. Please view and print from a web browser.".format(outfile) if __name__ == '__main__': print "predeal.py will take a PBN file and generate slips for dealing by hand." print "Program by V Lakshmanan based on idea by Matthew Johnson" print "V Lakshmanan: http://bridgemishaps.blogspot.com/" print "Matthew Johnson: http://www.matthew.ath.cx/projects/pescetti" # commandline usage # Usage: predeal.py pbn-file-name output-html-name" # Example: predeal.py 131111HandRecord.pbn 131111HandRecord.htm" if len(sys.argv) == 3: predeal( sys.argv[1], sys.argv[2] ) sys.exit(0) #predeal( '131111HandRecord.pbn', '131111HandRecord.htm' ) #sys.exit(0) # GUI to get input and output Tkinter.Tk().withdraw() # no root window inopts = {} inopts['defaultextension'] = '.pbn' inopts['filetypes'] = [('PBN','.pbn'),('all files', '.*')] inopts['title'] = 'Please choose the input PBN file' inpbn = tkFileDialog.askopenfilename(**inopts) outopts = {} outopts['defaultextension'] = '.htm' outopts['filetypes'] = [('HTML','.htm'),('HTML', '.html')] outopts['title'] = 'Please name the output HTML file' outhtm = tkFileDialog.askopenfilename(**outopts) predeal(inpbn, outhtm)