#!/usr/bin/env python
#
# I wrote this to calculate the minimum number of dice rolls required in order to have greater than a 50% chance
# of hitting at least one roll per dice value.
import gmpy
import sys
from multiprocessing import Process, Lock, Value

coefficients = list()

def main_loop(trial, found, lock, sides):
	# Keep going until we've found the break-even point
	while not found.value:
		# Fetch the next value
		lock.acquire()
		trial.value = trial.value + 1
		rnd = trial.value
		lock.release()

		terms = list()
		# Calculate the value of each term in the polynomial
		for x in xrange(len(coefficients)):
			terms.append( pow(sides - x, rnd) * coefficients[x] * pow(-1, x) )
		#print terms
		# Sum each term of the polynomial
		val = sum(terms)
		# Determine the denominator
		den = pow(sides, rnd)
		# Calculate the quotient between
		probability = val / gmpy.mpf(den)
		# Report
		if rnd % 100 == 0:
			print "Probability after %d rolls is %s" % (rnd, gmpy.fdigits(probability, 10, 10))
		if probability > 0.5:
			print "Probability after %d rolls is %s" % (rnd, gmpy.fdigits(probability, 10, 10))
			found.value = True
			
def main():
	if len(sys.argv) != 2:
		print "Please provide exactly one number"
		sys.exit(-1)
	# The number of sides on the die in question
	sides = int(sys.argv[1])
	
	# First we generate the coefficients of the equation
	n = gmpy.mpz(0)
	while n < sides:
		coefficients.append( gmpy.bincoef(sides, n) )
		n += 1
	
	# Next we start at the number of sides and increment, making a calculation at each row.
	trial = Value('i', sides)
	found = Value('b', False)
	lock  = Lock()
	
	for num in range(4):
		Process(target=main_loop, args=(trial, found, lock, sides)).start()

if __name__ == '__main__':
	main()
