#!/usr/bin/python
import sys
import random
debug = False
def fact(n):
if n == 0: return 1
return n * fact(n - 1)
success_odds_by_dice = {}
sides = 6
def get_odds(num_dice, indent = 0):
global sides, debug, success_odds_by_dice
def iprint(val, *args):
if debug:
print (indent * " ") + str(val).format(*args)
if num_dice == 0: return 1
iprint("-- get_odds({}) --", num_dice)
if num_dice in success_odds_by_dice:
iprint("-- odds: {} --", success_odds_by_dice[num_dice])
return success_odds_by_dice[num_dice]
total_odds_success = 0
num_rolls = pow(sides, num_dice)
iprint("num rolls with {} dice: {:,}", num_dice, num_rolls)
for i in xrange(1, num_dice + 1):
remaining_dice = num_dice - i
num_rolls_with_i_sixes = pow(sides - 1, remaining_dice) * fact(num_dice) / (fact(remaining_dice) * fact(i))
for j in xrange(i + 1, num_dice + 1):
num_rolls_with_i_sixes
iprint(" num rolls of {} dice with {} {}'s: {:,}", num_dice, i, sides, num_rolls_with_i_sixes)
odds_i_sixes = num_rolls_with_i_sixes / float(num_rolls)
iprint(" odds of that happening: {}", odds_i_sixes)
total_odds_success += get_odds(num_dice - i, indent + 3) * odds_i_sixes
success_odds_by_dice[num_dice] = total_odds_success
iprint("-- odds: {} --", total_odds_success)
return total_odds_success
def get_monte_carlo_odds(iterations, num_dice):
global debug
successes = 0
for i in xrange(0, iterations):
dice_left = num_dice
while dice_left > 0:
num_sixes = 0
for j in xrange(0, dice_left):
if random.randint(1, sides) == sides:
num_sixes += 1
if num_sixes == 0:
dice_left = 0
else:
dice_left -= num_sixes
if dice_left == 0:
successes += 1
if debug:
print "-- monte carlo: {:,} / {:,} --".format(successes, iterations)
return successes / float(iterations)
def find_flag(flag):
if flag in sys.argv:
sys.argv.remove(flag)
return True
return False
debug = find_flag("debug")
simple_output = find_flag("simple")
do_monte_carlo = not simple_output and not find_flag("no_mc")
dice = int(sys.argv[1])
if len(sys.argv) > 2:
sides = int(sys.argv[2])
monte_carlo_iters = 100000
if len(sys.argv) > 3:
monte_carlo_iters = int(sys.argv[3])
if do_monte_carlo:
monte_carlo_odds = get_monte_carlo_odds(monte_carlo_iters, dice)
odds = get_odds(dice)
if debug:
# extra line to separate debug output
print
if simple_output:
print odds
else:
odds_str = "odds of getting donuts with {} {}-sided dice: {:.2}%".format(dice, sides, odds * 100)
if do_monte_carlo:
odds_str += ", monte carlo with {:,} iterations gives: {:.2}%".format(monte_carlo_iters, monte_carlo_odds * 100)
print odds_str