Week 4: indefinite loops, functions
Monday
import random
python has a random library that you can import
into your
programs and use to generate random numbers or choices. The actual
numbers are pseudo-random, meaning they are not really random. For our
purposes (simple games), they are random enough.
syntax
First import the random library:
from random import *
Then use one of the various functions in the library. The most commonly-used functions are:
choice(seq) -- choose one from a sequence randrange(start,stop) -- chose a random number from [start,stop-1] shuffle(list) -- shuffles a list random() -- returns a random float from [0,1)
examples
To simulate flipping a coin, you could use any of these:
flip = choice("HT") flip = choice(["heads","tails"]) flip = randrange(2) # assume 0 is heads, 1 is tails flip = random() # assume < 0.5 is heads
For example:
>>> from random import * >>> for i in range(10): ... flip = choice(["heads","tails"]) ... print(flip) ... tails heads tails heads heads heads heads tails tails tails
To simulate rolling 6-sided dice:
result = randrange(1,7)
To shuffle a list:
>>> L = list("ABCDEFG") >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G'] >>> shuffle(L) >>> print(L) ['E', 'B', 'C', 'G', 'F', 'A', 'D'] >>> shuffle(L) >>> print(L) ['G', 'B', 'D', 'A', 'F', 'E', 'C']
So how would you use random
to have the computer pick rock,
paper, or scissors?
indefinite while
loops
A while
loop should be used anytime we want our programs to loop,
but don’t know ahead of time how many iterations are needed. Examples
include:
-
games, where we don’t know how many turns will occur
-
getting input from the user, where we might have to give them more than one chance (in case they enter invalid data)
-
simulations, where they might continue running until some condition occurs
For games, like tic-tac-toe, the game might take 5 turns or more (but not more than 9). In pseudo-code, this would be:
while game is not over: # player takes a turn # update/display the new board
syntax
The syntax is exactly the same as the if
statement:
while some condition is True: # do this indented code block # could be 1 or more lines # then go back to the top and recheck the condition
However, as long as the condition is True, it will keep looping and repeating the code block.
The if
statement will do the code block once if the condition is
True
. The while
loop will recheck the condition after the code block,
and repeat it if the condition is still True
.
example
Here’s a program that rolls two 6-sided dice, and keeps rolling until the sum of the dice equals a user-entered number:
from random import *
def main():
utotal = int(input("Number 2-12: "))
dtotal = 0
while dtotal != utotal:
dice1 = randrange(1,7)
dice2 = randrange(1,7)
dtotal = dice1 + dice2
print("%d %d (%d)" % (dice1,dice2,dtotal))
main()
And here’s a run of the program, where the user enters 6:
Number 2-12: 6 5 4 (9) 6 6 (12) 4 5 (9) 6 2 (8) 3 4 (7) 6 2 (8) 6 4 (10) 2 1 (3) 6 5 (11) 5 6 (11) 3 3 (6)
Wednesday
valid user input
Another place to use a while
loop is when getting input from the
user, and making sure they entered a valid choice. Here’s a "rock,
paper, scissors" game example:
rock, paper, or scissors? zebra please enter rock, paper, or scissors!! rock, paper, or scissors? 99 please enter rock, paper, or scissors!! rock, paper, or scissors? rock
Here’s one way to write that loop, using a list of valid inputs
and the in
operator:
valids = ["rock","paper","scissors"]
userinput = input("rock, paper, scissors? ")
while userinput not in valids:
print("please enter rock, paper, or scissors!!")
userinput = input("rock, paper, or scissors? ")
Notice how the userinput
variable is set before the while
loop starts,
and the while
loop code block is only run if the initial input is not valid.
first look at functions
As our programs get larger and more complex, using functions becomes a neccessity. Designing and writing your programs using functions makes them easier to write, read, test, and debug.
The above code is probably just one part of a larger program (the rock paper scissors full program). This chunk of code would make a good function in a larger program. Here’s how to write the same code as a function:
from random import *
def main():
valids = ["rock","paper","scissors"]
userinput = getUserInput(valids)
print("You chose %s" % (userinput))
computer = choice(valids)
print("I chose %s" % (computer))
def getUserInput(valids):
userinput = input("rock, paper, scissors? ")
while userinput not in valids:
print("please enter rock, paper, or scissors!!")
userinput = input("rock, paper, or scissors? ")
return userinput
main()
If we run the above program, here are the major steps as they happen:
-
the
random
library is imported -
a function called
main()
is defined -
a function called
getUserInput()
is defined -
the
main()
function is started/called -
in
main()
, a python list (valids
) is defined -
next in
main()
, thegetUserInput()
function is called:-
the
valids
list is sent to the function -
in the function, the user is asked for input
-
once we have a valid input, that string is returned to
main()
-
-
back in
main()
, the user’s input is assigned to theuserinput
variable -
and the program keeps going with a
print()
, the computer’s choice, and anotherprint()
function syntax
Just like we’ve been doing all along with main()
, a function is just
an indented block of code with a name. Here’s a simple function:
def happybirthday(name):
"""display happy birthday song for name"""
print("Happy Birthday to you.")
print("Happy Birthday to you.")
print("Happy Birthday, dear %s." % (name))
print("Happy Birthday to you!")
return
Some things to note about the above function:
-
it has one parameter, the
name
variable -
it has four
print
statements -
the
return
at the end signals the end of the function, but is not always necessary
Here’s an example of how the above function might be called from
main()
:
def main():
name = input("Who's birthday is it? ")
happybirthday(name)
Whatever the user types in, it is stored in the variable name
.
That data is then sent to the function, for use in the print
statements. In main()
, the variable name
is used as an argument
in the call to the happybirthday()
function. When writing and calling
functions, the number of arguments must match the number of
parameters.
I also don’t have to use a variable as an argument. I could just use a string argument, like this:
happybirthday("Ravi")
which would print:
Happy Birthday to you. Happy Birthday to you. Happy Birthday, dear Ravi. Happy Birthday to you!
Friday
stack diagrams
Understanding stack diagrams helps you see how the computer works, and why python does what it does. It will also be very valuable in week 11 when we learn recursion (functions calling multiple copies of themselves).
A "stack" is just a data structure used by many programs. A stack is useful because it keeps track of where we are, and allows backtracking (e.g., hitting "undo" in your editor, or hitting the "back" button on your browser).
If you think of a stack of books or a stack of trays, you generally add items to the stack and remove items from the stack at the top end. This is different from a queue data structure (like a line at the bank or the grocery store) where items (people) are added at the back of the queue and removed (they checkout or are served) from the front of the queue.
So for your browser, say you visit espn.com, then swarthmore.edu, then cnn.com, and finally google.com. At this point, the broswer stack would look like this, with the current site on the top of the stack, and your history recorded in the rest of the stack:
google.com cnn.com swarthmore.edu espn.com
If you now hit the "back" button, the browser would "pop" the stack and remove the top item (google.com) and go to whatever is next on the stack (cnn.com).
As functions are executed in our program, they are placed on the top of the stack. When the function executing is done, it is removed from the top of the stack and the function below resumes execution. This is how the computer keeps track of the program flow.
For example, if you have a main()
function called first, and then
main()
calls another function, say func1()
, and before func1()
returns it calls another function, say func2()
, then at this point
"the stack" would look like this:
func2 func1 main
In addition to just showing what functions are on the stack, we will also include their variables and what data they refer to.
#
# drawing the stack:
#
# - when a function is called, make a stack frame (rectangle) for it on the stack
# - if one function calls another, the second stack frame goes on TOP of the stack
# - for each stack frame, when a variable is declared:
# > put the variable name in the stack frame
# > draw a small box next to the variable
# > put the data value to the right, outside the stack frame
# > draw an arrow from the small box to the data value
# For Example, if x=5 is in main(), it will look like this:
#
# STACK DATA
# -------------
# |main |
# | |
# | x []----|----------> 5
# | |
# -------------
#
# - if a variable is updated or reassigned, update the data or redraw
# the arrow to the new data
# - when a function finishes, we erase the stack frame off the top of
# the stack and the program continues in the stack frame that is
# now on TOP of the stack
#
# try drawing the stack for this program.
# stop your drawing just before the lettercount function returns
def main():
text = "mississippi"
letter = "i"
result = lettercount(letter,text)
print("Number of %s's in %s: %d" % (letter,text,result))
def lettercount(char,text):
"""count and return how many of char are in text"""
count = 0
for i in range(len(text)):
if text[i] == char:
count = count + 1
# after for loop is done, return the count
return count
main()
For the above program, here’s what the stack would look like, just
before the return count
line in lettercount(..)
:
In the above diagram, count
was initially zero, then we added 1 to it
each time the for
loop counted another "i" in "mississippi".
function terms
Here’s a summary of the function terminology we have been using,
for the above lettercount(char,text)
function:
function scope
The term scope just refers to where a variable is accessible. Variables (and the data they reference) in one function are local (ie, not global) to that function. If you need the data from one function in another function, you should pass the data from function to function using arguments and parameters, or return the data from the called function back to the calling function
For example, in the above letter count program, in the main()
function, the variables that are in scope are: text
, letter
, and
result
. If you try to print(count)
in main()
the program will
crash, because main()
doesn’t have a variable called count
.
The count
variable is only accessible/active in the lettercount(..)
function. We use the return count
statement to send the data stored in
count
back to main()
, where it is assigned to the variable result
.
Similarly, if you try to use or print the letter
variable in the
lettercount(..)
function, it will crash. The letter
variable is only
in scope in main()
.
more functions
See the FRIDAY
file for more functions to write!