Example of top-down design

This is an example of applying TDD to a problem and create a set of function stubs for each function, and including some basic program control flow with calls to function stubs in roughly the correct order of a complete program.

Notice that the main function is basically complete, and part of the main control flow of the simulation loop (in simulate and simulateOne) is implemented--the parts that make calls to functions implementing the substeps. Also, note that simulate and simulateOne are mostly function stubs: the full simulation code in these two functions is not fully implemented, instead there are just parts of very general control flow of the program present with calls to functions that implement sub-steps. The rest of the functions are merely stubbed out with print messages and bogus return values. The interface of each function has been defined, i.e. how many and what types of parameters are expected as well as what will be returned, but the functions have not yet been implemented. Comments have been included inside the function definitions as reminders for how we expect to implement them, and many functions have TODO comments to remind us what we need to do to complete this program.

An example run of this program is shown at the bottom. You can see how the print statements help show what the final program's general control flow will be.

"""
 This program computes the probability of rolling N of a kind with
 N six-sided dice by running a series of simulations and computing
 the average number of rolls required. 
(Your Name, 2011)
"""

from random import *

def main():

    printIntro()
    numTrials = getPositiveInt("Enter number of simulations to run: ")
    numDice = getPositiveInt("Enter a value for N, the number of dice" \
               + " for the N-of-a-kind trial: ")
    avg = simulate(numTrials, numDice)
    print "The average of rolling", numDice, "of a kind is:", avg
    print "The probabilty is:", 1/avg

#############################################################
def printIntro():
    """
    Prints an introduction to the user.
    Inputs:  None
    Returns: None
    """
    # TODO: implement this
    print "  inside printIntro"
    return
#############################################################
def getPositiveInt(prompt):
  """
  This function gets and returns a positive int value from the user
    Input: prompt string to print
    Returns: a positive int value
  """

  # TODO: replace call to input with raw_input and error checking
  #       and re-prompt on bad input...only return positive int values
  val = input(prompt)

  return val

#############################################################
def simulate(n, num_dice):
    """
    This function simulate n trials of rolling num_dice dice and computes 
    the average number of rolls it takes to roll num_dice of a kind.
      Inputs:  An int n representing the number of simulations to run
               An int num_dice representing the number of dice to roll 
               each simulation 
      Returns: A float representing the average number of rolls required
               to get num_dice of a kind.
    """

    # TODO: need to add code to keep track of the average 
    #       across each one-time simulation  
    print "  inside simulate"

    for i in range(n):
      num_times = simulateOneTime(num_dice) 

    return 100.0

#############################################################
def simulateOneTime(num_dice):
    """
    Simulate one trial and count the number of rolls.
      Inputs:  An int, num_dice, representing the nunber of dice to roll
      Returns: An int representing the number of rolls required to
               get five of a kind.
    """
    print "    inside simulateOne"

    # TODO: add code to repeat rolling num_dice until they are all the same 
    #       add code to keep track of how many times it takes to roll
    #       num_dice until they are all the same
    roll_result = rollDice(num_dice)
    test_result = allSame(roll_result)
          

    return 100

#############################################################
def rollDice(n):
    """
    This function returns the result of n die rolls
     Inputs:  An int n representing the number of dice to roll.
     Returns: A list containing the result of n die rolls.
    """

    print "      inside rollDice, num dice =", n


    # TODO: repeat n times: 
    #          use the random library to simulate one die roll result
    #          add it to the list so far

    return [1] * n    # ([1]*n  creates a new list consisting of n 1's

#################################################################
def allSame(ls):
    """
    Checks whether the values in a list are equal.
     Inputs:  A list of values.
     Returns: True if all the values in the list are the same.
              Otherwise False.
    """

    print "      inside allSame"

    # TODO: add code to check that each value in the list is the same
    #       (check that each value is equal to the first value)
    return True

#################################################################              
if __name__ == "__main__": main()
# "if __name__ ..." is special syntax for unit testing in the python 
# interpreter.  You could also just have a call to main() here instead:
# main()

If you run this, you will see something like the following which shows the main control flow of the program (but is obviously not a correct full implementation):
  inside printIntro
Enter number of simulations to run: 3
Enter a value for N, the number of dice for the N-of-a-kind trial: 5
  inside simulate
    inside simulateOne
      inside rollDice, num dice = 5
      inside allSame
    inside simulateOne
      inside rollDice, num dice = 5
      inside allSame
    inside simulateOne
      inside rollDice, num dice = 5
      inside allSame
The average of rolling 5 of a kind is: 100.0
The probabilty is: 0.01