CS 110 Fall 2010 

Lab 9: Dictionary Practice plus
Mindbending with Recursion

Due: Wednesday, November 10th at class time

 

Part 1 -  "Who's Your Daddy" Dictionary Practice

A menu-driven program is one that repeatedly presents the user with a list of top-level actions to take, and, at each iteration of a top level loop, gets the choice as input from the user and "processes" that request, updating data structures in the program. The process repeats until the user chooses an "Exit" option. To keep user typing to a minimum, the options are often labeled with integers, and the user simply inputs the integer corresponding to the requested action.

For instance, a menu-driven program could repeatedly offer the following action menu:

0 - Exit the program
1 - Look up the Father of a given Person
2 - Add a Person-Father relationship to the database
3 - Replace a Person-Father relationship in the database
4 - Delete a Person-Father relationship from the database

Write a Python program called Daddy.py that implements the described menu-driven program, using a dictionary as the data structure maintaining the associations between a Person and their Father. Note that multiple persons could have the same father. Make your program user-friendly and check against potential user errors. You should initialize the dictionary with some number of valid entries so that I can perform some tests without having to perform a lot of 'Add' operations.

You can earn extra credit by doing one or more of the following:

  • Implement a fancier user interface.
  • Add an option to read a set of Person-Father relationships from a file to "seed" the database.

For the remainder of this lab we'll investigate an algorithmic technique that occurs when functions call themselves.  This is called recursion. 

Part 2 - 

Consider the following two functions:

 

def weird(x):

  if x == 1:
    return 1
  else:
    return x * weird(x-1)
  

def strange(x):

  if x == 0:
    return 0
  elif x == 1:
    return 1
  else:
    y = strange(x-1) + strange(x-2)
    return y

def odd(y, z):

  if z == 0:
    return 1
  else:
    return y * odd(y, z-1)
 
Your first task is to figure out what these three functions do. Assume that you have a main() function definition that invokes weird() as follows:

def main():

  y = weird(3)
  print y

For this example, draw the function call stack starting from main(). Next, do the same for the odd() function, where the invocation in main() is given by y = odd(2,3). These call stack diagrams may be written by hand and turned in on the due date of the lab. Also, in a file named rec.rtf, describe what all three of the functions do.

A couple things to note:  First, there are parameters for which these functions do not make recursive calls.  In particular, weird(1), strange(0), strange(1), and odd(<val>, 0) all return integers without making another recursive function call.  If we didn’t have cases like this, there is no way the function calls would ever stop.  So in creating recursive functions, we need to make sure that eventually, the recursive calls stop.  These cases are often called base cases or termination conditions. 

Define recsum(n) so that it computes the sum of the first n integers.  Use the definition of weird() as a template. Similarly, create a recursive function tribonacci(n) to compute the nth Tribonacci number.  The Tribonacci numbers are a sequence T(i), where T(0) = T(1) = 0, T(2) = 1 and T(i) = T(i-1) + T(i-2) + T(i-3) for any i > 2.  Your functions should still be recursive, and can follow the definition of strange() as a template. Place both functions in a program that prompts the user to enter a single integer.  Then print the result of both function calls on that same integer.  Call this program BasicRec.py.

Part 3 - Snowflake

Now we’ll use recursion to draw some neat patterns. To do this, we need a graphics package that excels at "relative position"-based graphics. In other words, when we draw, the graphics systems knows where we last left off, and each operation is relative to some "current position". Although we could get the same effect by using the graphics module, we would have to add a lot of code to keep track of this position, and so it will be easier to use a different graphics library. The library we will use is called 'turtle', and the drawing metaphor is that we have a virtual "turtle" that we can command to move around the drawing area. The turtle has a "pen" attached to its tail that can be in the up or down position. The pen has attributes of its width and its color. The turtle starts in the center of the graphics window at coordinate (0, 0) and by default, the pen is down, the pen width is 1, the pen color is black, and the turtle is facing due east at 0 degrees. If we command the turtle to move foward some distance, it will draw a line from its current postion ((0,0)) for the given distance and in the current direction. Try this out by executing the following Python code:

from turtle import *

def main():
  winWidth = 250
  winHeight = 350

  screen = Screen()
  screen.setup(width=winWidth, height=winHeight)
  t1 = Turtle()
  t1.width(2)
  t1.color(1.0, 0, 0)
  t1.forward(100)
  t1.left(90)
  t1.forward(50)

main()

More of the turtle graphics libary functions are documented here: http://docs.python.org/py3k/library/turtle.html. You can also look up the tracer(), delay(), and update() functions for the screen and the speed() function for the turtle to control the speed of the simulaton.

Create a new program called Snowflake.py.  In the main function, set up for an 800 x 600 turtle screen.  Create a Turtle object and set the pen width to 2, and the pen position to (-380, -100).

Create a function called snow which returns nothing but is given a turtle object and two ints called iteration and length. 

This function should do one of two things. 

First, if iteration is 0, all you should do is use the forward function on the turtle that was passed in, drawing forward the distance given by length.

The more complicated case is if iteration is greater than 0.  In that case, you will have 7 instructions.  Instructions 1, 3, 5 and 7 all make calls to the function snow.  Each call will be identical, and will be passed the turtle, iteration-1, and length/3.  That is, if we aren’t down to iteration 0 yet, our function will call the snow function four times with a lower iteration value and shorter lengths. 

Between each of these recursive calls, we’ll change the direction of our pen.  To do this, you’ll use the functions <turtle>.setHeading(x) and <turtle>.heading().  You’ll need to get the current direction because we don’t want to set the pen to a fixed angle, but rather want to turn the pen relative to its current facing.  The three rotations should be 60, -120 and 60 degrees respectively.

Once you’ve got this, we can test it out.  Try calling the function snow in your main function with parameters (pic, 0, 729).  (I picked 729 just because it is a power of 3, so when we do integer division by 3 repeatedly, we’ll still have the right integer).  Display the picture.  You should see a black line drawn across most of the image.  Try this again, but this time change the iteration to 1.  This should add a kink to the middle of the line. 

Once you have this working, change your main function to make 6 calls to snow, where you start with snow(pic, 0, 729) and go up to snow(pic, 5, 729), incrementing iteration by 1 each time.  Between each call, reset the pen position to its starting position, and change the pen color so you can distinguish the lines.

Part 4 - Sierpinski’s carpet

Sierpinski’s carpet is defined as follows.  Start with an uncolored square.  Split it into 9 equal-sized squares.  Color in the middle square.  Draw Sierpinski’s carpet in the remaining 8 squares.  Here is what you should get:

 

 

Write a program called Carpet.py that creates this pattern.  Your function will probably need to take in a bunch of parameters: the Turtle object, the current iteration, the current width, and the current x and y coordinates. You can use whatever graphics library you choose to implement this program.

 

 

Part 5 - Xander’s bubbles

Xander’s bubbles are defined as follows.  Start with an uncolored square.  Draw a circle in the middle of the square with radius one quarter the length of the square.  Then split the square into 4 equal pieces, and draw Xander’s bubbles in each quadrant.  You should get something like this:

 

 

Write a program called Bubbles.py that creates this pattern.  Again, your function will probably need to take in a bunch of parameters: the Turtle object, the current iteration, the current width, and the current x and y coordinates.

 

 

Part 6 - Uploading your lab

Lab09 should contain:

Daddy.py

rec.rtf

BasicRec.py

Snowflake.py

Carpet.py

Bubbles.py

Plus the Hand-drawn Function Call Stack turned in to me.