#!/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("" + self.boardno + ": North | " + self.boardno + ": East | " + self.boardno + ": South | " + self.boardno + "West |
")
for suitno in range(0,4):
ofp.write("")
for dir in range(0,4):
ofp.write("" + symb[suitno] + " " + cards[dir][suitno] + " | ");
ofp.write("
")
ofp.write("
")
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)