Week 4, Friday: Functions, indefinite loops

review

Here is part of the up/down game from last time:

level = 10
while level > 0:
  char = raw_input("char (u/d): " )
  if char == "u":
    level += 1
    result = " level UP"
  elif char == "d":
    level -= 1
    result = " level down"
  else:
    insult()
    result = " "
  print("."*level + (" (%2d)" % (level)) + result)

Notice how level is changed somewhere in the loop. If level never changed in the loop, we would have an infinite loop. If you ever write a program with a while loop, and it seems to be taking a long time to run, you have probably created an infinite loop (use Cntrl-c to stop the program).

getting input from the user

An indefinite loop is great for giving users a second (or third, fourth, etc) chance when entering data:

You are in a dimly lit computer room. A lab that is worth
50% of your grade is due in 4 hours. What do you want
to do?

  1 Start work on your lab
  2 Go play ultimate frisbee with your friends
  3 Take a nap on the CS couches


        ---> 9
please enter an integer from 1 to 3 
        ---> -3
please enter an integer from 1 to 3 
        ---> 1

If we wrote a getChoice() function, it could ask the user to enter a number and also check to make sure it is a valid number. Using a while loop, we just keep asking until we get a valid number.

In a program like the above adventure game, you could have lots of menus and choices for the user to make. Some menus might have 3 choices, others might have more or less. The getChoice() function would be more general and probably more useful if we passed in arguments for the low and high choices. Here's how it might be called from main():

printmenu()
choice = getChoice(1,3)
if choice == 1:
  stuff for choice 1 here
elif choice == 2:
  stuff for choice 2 here
...

Here's one way to write the getChoice() function:

def getChoice(low, high):
  """get valid input from user (in range low to high)"""

  while True:
    num = int(raw_input("---> "))
    if num >= low and num <= high:
      return num
    print "please enter an integer from %d to %d " % (low, high)

Note the while True. Here it is used as an infinite loop, so there must be another way out of this loop. Since this is a function, the return num statement is the way out -- the return statement ends the function, and it only ends when we know num is valid (in range from low to high). If the return num line is not run, because the input was invalid, the function just runs the print statement and then loops back to the start of the loop (the raw_input() line).

math quiz -- a real program!

As you start writing programs with multiple functions, it is very important that you write and test each function, one at a time.

Let's write a math quiz program, that runs like this:

$ python mathquiz.py 

Welcome to MathQuiz v0.1!

What factor would you like to work on? 4
-------------------------
4 x 10? 40
....Correct!
-------------------------
4 x 4? 16
....Correct!
-------------------------
4 x 5? 24
....Nope. 4 x 5 = 20
-------------------------
4 x 10? 40
....Correct!
-------------------------
4 x 7? 28
....Correct!
-------------------------
4 x 8? 32
....Correct!
-------------------------

You got 5 out of 6 correct. Good work!

I like this program because it's got almost everything we've talked about so far: functions, loops, branching, random, etc.

A few things to note about the program (which you would see, if you ran it a few times):

See if you can write this program, but start with just this for main():

def main():
  factor = 5
  result = question(factor)
  print result

Write the question() function first, and make sure it works (test it!). And start simple: have question() create a random multiplication problem, ask the question and get the answer, and then return something that says whether the user answered correctly or not (return True or False, or 1/0, or "correct"/"incorrect").