Today's lab will focus on designing programs using functions.

Functions are used to design programs and provide an elegant way to divide work among several programmers. A standard technique, called top-down design, consists of breaking a program into multiple function calls (covered in more detail in Chapter 8). Each function is written separately and then tested, before the next function is written.

In today's lab, we will write a program to draw images using turtles. Many of the functions we write today will be reused in future programs. Here's a basic outline of our program:

#Intro Programming Lab:  A program with a herd of turtles

import turtle

def main():
    welcomeMessage()            #Writes a welcome message to the shell
    numTurtles = getInput()     #Ask for number of turles
    w = setUpScreen()           #Set up a green turtle window
    turtleList = setUpTurtles(numTurtles) #Make a list of turtles, different colors
    for i in range(10):
        moveForward(turtleList) #Move each turtle in the list forward
        stamp(turtleList)       #Stamp where the turtle stopped
    

main()
We will fill in each function, one-by-one, using the comments as guidance. The first function should welcome the user to the program:
def welcomeMessage():
    print()
    print("Welcome to our herd of turtles demonstration!")
    print()
Add it to the program above and run it to make sure there are no typos or errors.

Next, let's ask the user for the number of turtles. Since the function call is on the right hand side of an equals sign, it returns a value (namely, the number of turtles) that we will use later in the program. So, our function will ask the user for the number and then use a return statement to send that value back to the calling function:

def getInput():
    n = eval(input("Please enter the number of turtles: "))
    return n
When we add these in, we now have the program:
#Intro Programming Lab:  A program with herd of turtles

import turtle


def welcomeMessage():
    print()
    print("Welcome to our herd of turtles demonstration!")
    print()

def getInput():
    n = eval(input("Please enter the number of turtles: "))
    return n

def main():
    welcomeMessage()            #Writes a welcome message to the shell
    numTurtles = getInput()     #Ask for number of turles
    w = setUpScreen()           #Set up a green turtle window
    turtleList = setUpTurtles(numTurtles) #Make a list of turtles, different colors
    for i in range(10):
        moveForward(turtleList) #Move each turtle in the list forward
        stamp(turtleList)       #Stamp where the turtle stopped
    

main()
We still need to set up the turtle window and make it green. The turtle command to change the background color is bgcolor and colors can be referred by their names or the percentage of red, green, and blue ('RGB') in the color. Let's use the name to change the window color:
def setUpScreen():
    w = turtle.Screen()
    w.bgcolor("green")
    return w
Next, we need to set up a list of turtles. From the function invocation in the main() we know it has the outline:
def setUpTurtles(n):
    #Create a list of turtles
    #Make each turtle appear turtle-shaped
    #Change the color and default direction (so they don't run over each other)
    return tList
To set up our list, we will follow our outline from the strings and lists chapter:
  1. Create an empty list
  2. Make a new item
For our turtles, this looks like:
def setUpTurtles(n):
    tList = []
    #Create turtles:
    for i in range(n):
        t = turtle.Turtle()
        t.shape("turtle")       #Make the turtle appear turtle-shaped
        tList.append(t)
        
    return tList
Lastly for this function, we need to change the color and direction. We will use the `red-blue-green' (`RGB') values to give each turtle a different color. To keep the turtle color from clashing with the green background, we will set the red and green parts of the color to 0, and just allow the blue to change from 50% to 100%. To spread the turtles out, we'll divide the circle into even angles:
def setUpTurtles(n):
    tList = []
    #Create turtles:
    for i in range(n):
        t = turtle.Turtle()
        t.shape("turtle")       #Make the turtle appear turtle-shaped
        tList.append(t)
        
    #Change their color from the blue default and default direction
    for i in range(n):
        tList[i].color(0,0,i/(2*n)+.5)
        tList[i].right(i*360/n)
     
    return tList
If you run your program, you will see the turtles arranged pointing outwards from a center point, in different shapes of blue.

The next functions of the program are straightforward. We will move each turtle forward using a for-loop. We chose 30 by experimenting with window size. If it does not fit well on your screen, change the forward distance to something that does. To make a stamp of where the turtle has been, we use the Turtle graphics function, stamp()

def moveForward(tList):
    for t in tList:
        t.forward(30)

def stamp(tList):
    for t in tList:
        t.stamp()
Putting all the pieces together, we get:
#Intro Programming Lab:  A program with herd of turtles

import turtle


def welcomeMessage():
    print()
    print("Welcome to our herd of turtles demonstration!")
    print()

def getInput():
    n = eval(input("Please enter the number of turtles: "))
    return n

          
def setUpScreen():
    w = turtle.Screen()
    w.bgcolor("green")
    return w

def setUpTurtles(n):
    tList = []
    #Create turtles:
    for i in range(n):
        t = turtle.Turtle()
        t.shape("turtle")       #Make the turtle appear turtle-shaped
        tList.append(t)
        
    #Change their color from the blue default and default direction
    for i in range(n):
        tList[i].color(0,0,i/(2*n)+.5)
        tList[i].right(i*360/n)
     
    return tList

def moveForward(tList):
    for t in tList:
        t.forward(30)

def stamp(tList):
    for t in tList:
        t.stamp()

def main():
    welcomeMessage()            #Writes a welcome message to the shell
    numTurtles = getInput()     #Ask for number of turles
    w = setUpScreen()           #Set up a green turtle window
    turtleList = setUpTurtles(numTurtles) #Make a list of turtles, different colors
    for i in range(10):
        moveForward(turtleList) #Move each turtle in the list forward
        stamp(turtleList)       #Stamp where the turtle stopped
    

main()
Try running your program. What happens? How could you modify it to make green turtles on a blue background? What would you need to modify to make the turtles make a circle each time?

Finding Errors

Finding, and fixing errors, in your programs is a very useful skill. Let's look at a program with lots of errors and work through how to identify the issues and fix them. The program, errors.py, when loaded into IDLE does not run:
# errors.py is based on dateconvert2.py from Chapter 5 of the Zelle textbook
#     Converts day month and year numbers into two date formats

def main()
    # get the day month and year
    day, month year = eval(input("Please enter day, month, and year numbers: ")

    date1 = str(month)"/"+str(day)+"/"+str(year)

    months = ["January", "February", "March", "April", 
              "May", "June", "July", "August", 
              "September", "October", "November", "December"]
    monthStr = months[month+1]
    date2 = monthStr+" " + str(day) + ",  + str(year)

    print("The date is" date1, "or", date2+".")

main()
Instead, a dialog box pops up and says "invalid syntax":


The red line indicates where the intepreter has found an error. Can you tell what it is? Syntax is another word for grammar, so, it most likely missing `punctuation' or a misspelling of some sort. We have spelled def correctly and have the right number of parenthesis, so, what else is missing?

The answer is after the parenthesis on a function definition, a colon is required. Add that in:

    def main():
and try to run the program again.

Again, we get a dialog box:



Instead of the whole line being highlighted, only the word year is. The Python intepreter was not expecting year and says there is a grammatical mistake. Since year does not include any grammatical constructs, we need to look before the message to see where the error is. Do you see it?

The answer is lists of variables need commas in between them to distinguish one from the next. Add the comma in:

    day, month, year = ...
and try to run the program again.

Once more we get a dialog box:


It has highlighted the first item, date1 on the line. That is a name and looks fine. So, as above, let's look before the highlighted error to see if there's a problem. The line above it is:

    day, month, year = eval(input("Please enter day, month, and year numbers: ")
It did not highlight this line, so, the problem must be at the end. Do you see it?

The answer is we are missing a closing parenthesis. The line has two left parenthesis but only one right parenthesis. Add the right parenthesis in:

    ... and year numbers: "))
and try to run the program again.

Again, we get a dialog box:


The intepreter does not understand the second " on the line. Why? What is this line doing? It's constructing a string and storing it in the variable date1. How do you build a string out of smaller strings?

The answer is to put smaller strings together (called concatenation) we need to use the plus sign (+). The line is missing a plus sign right before the quotes. Add the plus sign in:

    date1 = str(month) + "/" ...
and try to run the program again.

Again, we get a dialog box, but this one has a different message:


EOL means "End of the line", so, the message says that the end of the line was reached before you finished defining the string. How can you fix this?

The answer is to end the string, using quotation marks. The line is missing a quotation mark at the very end. Add the quotation mark :

    ...+ ",  + str(year)"
and try to run the program again.

Our familiar dialog box returns:


We have seen this type of error before. How do you fix it?

The answer is lists of arguments need commas in between them to distinguish one from the next. Add the comma in:

    ... date is", date1 ...
and try to run the program again.

It runs! Now let's make sure it works. Type in at the prompt:

Please enter day, month, and year numbers: 31, 12, 2014
Uh oh, instead of output, we get the following messages:
Traceback (most recent call last):
  File "/Users/stjohn/public_html/teaching/cmp/cmp230/f14/errors.py", line 18, in 
    main()
  File "/Users/stjohn/public_html/teaching/cmp/cmp230/f14/errors.py", line 13, in main
    monthStr = months[month+1]
IndexError: list index out of range

When you see messages like this, go to the very last line:

IndexError: list index out of range
It says that the index for our list is out of range. An index is the item of the list that we're accessing. For example, months[1] has index 1 and will give us February. The range of the index for a list is 0 to one less than the length of the list. In the case of months, the range is [0,1,2,...,11]. What went wrong when we entered 12 for our month?

The answer is we used month+1 = 12 + 1 = 13 as the index:

    monthStr = months[month+1]
which is out of range. What do we want instead? Instead of adding 1, we should subtract 1. Change it in the program:
    monthStr = months[month-1]
and try to run the program again.

It still runs, but does it work? Let's try the same input again:

Please enter day, month, and year numbers: 31, 12, 2014
The date is 12/31/14 or December 31,  + str(year).

Something odd is happening at the end-- str(year) does not look right. Let's look at the print statement:

date2 = monthStr+" " + str(day) + ",  + str(year)"
The intepreter is treating ", + str(year)" as a string (instead of evaluating str(year)), so, we must have put the quotation mark in the wrong place before. Let's move it:
date2 = monthStr+" " + str(day) + ","  + str(year)
and try to run the program again.

Success! But try a few other inputs, just to make sure. It is always good to try cases that are near the `boundary' of what's allowed, since those are the places we are most likely to make mistakes:

Please enter day, month, and year numbers: 1,1,2015
The date is 1/1/2015 or January 1,2015.

Please enter day, month, and year numbers: 1, 2, 2003
The date is 2/1/03 or February 1,2003.

Please enter day, month, and year numbers: 4, 7, 1976
The date is 7/4/1976 or July 4,1976.

We have removed all the errors, and the program now runs correctly!

In-class Quiz

During lab, there is a paper quiz on Programs 11-15. The quiz will be given during lab.

What's Next?

If you finish the lab early, now is a great time to get a head start on the programming problems due early next week. There's instructors to help you and you already have Python up and running. The Programming Problem List has problem descriptions, suggested reading, and due dates next to each problem.