#!/usr/bin/env python
from math import log10, floor
from datetime import datetime
import sys
def round_sig(x, sig=2):
return round(x, sig-int(floor(log10(x)))-1)
def factorial(n):
if n >= 1:
a = 1
for i in range(2,n+1):
a *= i
return a
else:
return 1
def choose(n,r):
return factorial(n) / (factorial(r)*factorial(n-r))
def nextDistribution():
global s1,s2,s3,s,h,d,c,dc
if s1<s2:
s1+=1
elif s2<s3:
s1=0
s2+=1
else:
s1=s2=0
s3+=1
s=s1
h=s2-s1
d=s3-s2
c=13-s3
def nextHonours():
global sh,hh,dh,ch,s,h,d,c,hflag
if sh < 3 and sh < s:
sh+=1
elif hh < 3 and hh < h:
sh=0
hh+=1
elif dh < 3 and dh < d:
sh=0
hh=0
dh+=1
elif ch < 3 and ch < c:
sh=0
hh=0
dh=0
ch+=1
elif ch == 3 or ch == c:
hflag = 1
def countLosers():
a=0
if (s<=3):
a+=s-sh
else:
a+=3-sh
if (h<=3):
a+=h-hh
else:
a+=3-hh
if (d<=3):
a+=d-dh
else:
a+=3-dh
if (c<=3):
a+=c-ch
else:
a+=3-ch
return a
def countDistributions():
global dc,sh,hh,dh,ch,s,h,d,c,ltc,dctotal
dc = choose(10,s-sh)*choose(10,h-hh)*choose(10,d-dh)*choose(10,c-ch)*choose(3,sh)*choose(3,hh)*choose(3,dh)*choose(3,ch)
ltc[countLosers()]+=dc
dctotal+=dc
def printDistribution():
global s,h,d,c,dc
print "|"+"-"*s+"*"+"-"*h+"*"+"-"*d+"*"+"-"*c+"|", dc
s1 = 0 # position between spades and hearts
s2 = 0 # position between hearts and diamonds
s3 = 0 # position between diamonds and clubs
s = 0 # number of spades in hand
h = 0 # number of hearts in hand
d = 0 # number of diamonds in hand
c = 13 # number of clubs in hand
sh = 0 # number of spades honours in hand
hh = 0 # number of hearts honours in hand
dh = 0 # number of diamonds honours in hand
ch = 0 # number of clubs honours in hand
ltc = [0,0,0,0,0,0,0,0,0,0,0,0,0] # number of hands with [n] losing tricks
hflag = 0 # flag to signal when all possible honour configurations for a distribution have been processed
dc = 0 # number of hands with the current distribution
dctotal = 0 # total number of hands
startTime = datetime.now()
visual = 0
if "-v" in sys.argv:
visual = 1
for i in range(0,560): # repeat through all of the 560 possible distributions
while hflag==0: # if there are still honour configurations to process, continue the loop
countDistributions() # count losers, and add the number of hands with this distribution and honour configuration to the appopriate slot of ltc
nextHonours() # go to the next honour configuration
hflag = 0 # reset honours flag
sh = 0 # reset honours
hh = 0
dh = 0
ch = 0
if visual:
print (u'\x1b[35m|'+u'\u2588 '*int(i/28)+" "*(19-int(i/28))+u'\b|\x1b[0m '+str(int(i/5.6)) + "% " + str(datetime.now()-startTime))
for i in range(0,13):
print str(ltc[i])+" hands with "+str(i)+" losing tricks: "+str(round(100*float(ltc[i])/float(dctotal),4))+"%"
print str(dctotal)+" hands in total"
print "\r\x1b[16A"
nextDistribution() # go to the next hand distribution
completionTime = datetime.now()-startTime
if visual:
print (u'\r\x1b[35m|'+u'\u2588 '*19+u'\b|\x1b[0m '+str(100) + "% " + str(completionTime))
for i in range(0,13):
print str(ltc[i])+" hands with "+str(i)+" losing tricks: "+str(round(100*float(ltc[i])/float(dctotal),4))+"%"
print str(dctotal)+" hands in total"