CS21 Lab 4: Functions and While loops
Due Saturday, Oct 4, before midnight
Goals
-
Develop your understanding of the stack and how function calls and returns work
-
Write programs with multiple functions.
-
Solve problems using indefinite
while
loops. -
Learn to use the
random
library to make pseudo-random choices.
As you write programs, use good programming practices:
-
Use a comment at the top of the file to describe the purpose of the program (see example).
-
All programs should have a
main()
function (see example). -
Use variable names that describe the contents of the variables.
-
Write your programs incrementally and test them as you go. This is really crucial to success: don’t write lots of code and then test it all at once! Write a little code, make sure it works, then add some more and test it again.
-
Don’t assume that if your program passes the sample tests we provide that it is completely correct. Come up with your own test cases and verify that the program is producing the right output on them.
-
Avoid writing any lines of code that exceed 80 columns.
-
Always work in a terminal window that is 80 characters wide (resize it to be this wide)
-
In
vscode
, at the bottom right in the window, there is an indication of both the line and the column of the cursor.
-
Function Comments
All functions should include a comment explaining their purpose, parameters, return value, and describe any side effects. Please see our function example page if you are confused about writing function comments.
1. Written Assignment: Stack Diagram
The first part of this lab is a written assignment to trace through some Python code, show the program output and draw the stack. Download the following .pdf file, print it out: lab4stack.pdf
You should write your solution on the print out, and submit it at the start of the class on Monday.
1.1. Requirements
Given the pdf handbout above:
-
Draw the correct stack diagram.
-
Show the output of the program.
2. Big picture for solving this lab
In this lab, we will be writing a single program that has the user play a dice game called Pig. Consult the wikipedia entry for official rules and a history of the game.
In our version of the game, there will be two human players. Each turn, the current player rolls a single die. If the player rolls a one, they lose their turn and score nothing. Otherwise, the number on the die roll is added to their turn score, and they may either stop or roll again.
-
If a player chooses to stop, their turn score is added to their game score, and the next player takes a turn.
-
If they choose to continue, they roll again, potentially earning more points, but also risking losing all the points they’ve earned this turn if a one is rolled.
Players continue taking turns until one player earns 50 points.
Should you continue to roll, and maybe earn more points, or should you stop and lock in the points you’ve earned this turn? Pig is a game about deciding when to be greedy and when to play it safe.
Building a game like this requires planning and design. You shouldn’t just sit down in front of your computer and start writing code. In this lab, we’re going to guide you through writing each step of the process, building the program incrementally. In future labs, we’ll give you more opportunities to design and implement programs on your own.
Each section will have you write one or two functions which will be
part of the larger program. After you write each new function, we’ll
have you test that function by calling it in main
. Until you get
almost to the very end, you’ll be modifying the main
function in
order to test each function. There is no need to save your main
function from a last step as you work on each next step. At the very
end, we’ll tell you when it’s time to put all the functions together
into a working version of the game.
You’ll put all of your code for the rest of this lab in the file
pig.py
.
Before we dive in to the details, let’s take a look at what the final running program looks like.
3. Get a choice from the user
In the file named pig.py
, write a function named get_yes_no
that
asks a user if they want to stop. If the user doesn’t enter yes
or
no
, your function should print a helpful error mesage and prompt the
user to try again. The function should only return when the user
enters yes
or no
.
The get_yes_no
function does not take any input values (it has no
parameters), but it should return a string value. Its function
definition will look like:
def get_yes_no():
3.1. Test get_yes_no
in main
To test get_yes_no
, you should have your main
function call
the get_yes_no
function and print out the value returned. Your
main
should something look like this:
def main():
choice = get_yes_no()
print("get_yes_no returned %s" % (choice))
You can now test to make sure the get_yes_no
function is working
properly. Here are some examples of what your program should do at
this point:
$ python3 pig.py
Do you want to stop? yes
get_yes_no returned yes
$ python3 pig.py
Do you want to stop?: no
get_yes_no returned no
$ python3 pig.py
Do you want to stop?: apple
Oops! You can only answer yes or no. Try again.
Do you want to stop?: Yup
Oops! You can only answer yes or no. Try again.
Do you want to stop?: YES
Oops! You can only answer yes or no. Try again.
Do you want to stop?: yes
get_yes_no returned yes
$ python3 pig.py
Do you want to stop?: no
get_yes_no returned no
Remember that python strings can be compared with relational
operators like == or < just like integers and floats:
|
$ python3
>>> "rock" == "paper" # evaluates to False
>>> "rock" != "paper" # evaluates to True
4. Choose a random number
Write a function called roll_die
that generates and returns a
random integer between 1 and 6. (You should use the randrange
function,
described in the subsection below, to help you do this.)
Every integer from 1 to 6, including both 1 and 6,
are values that roll_die
could generate. Although this may be a short
function, it’s a good idea to make this a separate function because
it puts the randomness in your game into a single function. If for some
reason you wanted to change the game in some way (e.g. maybe you roll two dice
at a time), you only need to change this function and not the rest
of your program.
The roll_die
function does not take any input values (it has no
parameters), but it should return an integer value. Its function
definition will look like:
def roll_die():
4.1. Selecting a random integer from a range of integers
This subsection will remind you how the randrange function works.
To use randrange , we import it from the random library.
|
The randrange
function returns a random integer from a specific
range. The inputs work just like the range
function you’ve been
using already. For example, randrange(10)
returns a random integer
from the range 0…9
. You can also provide it with two inputs:
calling randrange(a,b)
will return a random integer x
such that a
< = x < b
. Calling randrange(2,5)
will randomly select one
integer from the integers 2,3,4.
Here’s a simple program that demonstrates how to use the randrange
with the
examples above:
from random import randrange
# When you run this program multiple times, you should get different,
# random results each time you run it.
def main():
value = randrange(100) # randomly pick an integer from 0-99
print(value)
number = randrange(2, 11) # randomly pick an integer from 2-10
print(number)
main()
In the roll_die
function described above, you will use the
randrange
function to randomly select an integer between 1 and 6.
4.2. Test roll_die
in main
Remember, we are solving this incrementally so there’s no need to
preserve your main
function as you develop the solution to this next
step.
To test roll_die
, you should have your main
function call
the roll_die
function and print out the value returned. Your
main
should something look like this:
def main():
number = roll_die()
print("roll_die returned %d" % (number))
You can now test to make sure the roll_die
function is
working properly. Here are some examples of what your program should
do at this point:
$ python3 pig.py
roll_die returned 4
$ python3 pig.py
roll_die returned 1
$ python3 pig.py
roll_die returned 2
5. Taking one turn in the game
Let’s extend our program to add a function take_turn
that allows the
user to take one full turn in the game. The function take_turn
should have two inputs: a string name
representing which player’s
turn it is, and an integer score
representing the player’s current
score. It should return the score earned in that turn—either the sum
of all the die rolls before the user chooses to stop, or zero (if a
one was rolled).
def take_turn(name, score):
take_turn
should model a complete turn by a player, and there are
several things you should code this function to do. In particular,
this function should:
-
roll a die
-
while the die roll is not one and the player hasn’t stopped:
-
print out current information about what was rolled, what the current turn score is, and what the player’s score would be if they stopped.
-
ask the user if they want to stop.
-
if they don’t want to stop, roll another die
-
-
return the score earned that turn
Note: Your take_turn
implementation should call some of the
functions you’ve already written and tested. Because you’ve tested
these functions thoroughly, you can rely on them working the way you
expect.
5.1. Test take_turn
in main
Once you write take_turn
, you can test it in main
:
def main():
turnscore = take_turn("Jane", 14)
print("Jane scored %d points this turn" % turnscore)
Here are some example runs. Your main
function
does not need to run exactly like this, and your output does not need
to look precisely like the output below.
6. Play the Pig game
For the final part, you are going to add code so that you can play the full game of Pig.
There’s no need to preserve your main
function from the last
steps, but much of what you wrote in the last step can be reused in
this step if you find that helpful.
6.1. The welcome
function
In the sample output, you will notice that there
is a welcome message displayed run the program is first run. Your message
doesn’t have to be the same, but you should write a function called welcome
that takes no parameters and returns nothing. The function should print
out a welcome message to the user. The function definition will look like:
def welcome():
6.2. The is_game_over
function
The is_game_over
function should take the following parameters as input:
-
the integer number of points that the first player has earned so far
-
the integer number of points that the second player has earned so far
This function should return True
if the game has ended-- if one
player has at least 50 points. is_game_over
should return False
neither player has scored 50 points.
6.3. The print_score
function
The print_score
function should take the following parameters as
input:
-
The string name of Player 1
-
The integer number of points Player 1 has so far
-
The string name of Player 2
-
The integer number of points Player 2 has so far
Note that this function does not return a value. It is called for the side-effect of printing some information. The function definition will look like:
def print_score(name1, score1, name2, score2):
The function should print out the current score of the two players between two lines of asterisks '*'.
For example, print_score("Jane", 14, "Tommy", 12)
, would print out
something like this:
* * * * * * * * * * *
Jane has 14 points.
Tommy has 12 points.
* * * * * * * * * * *
6.3.1. Test print_score
in main
Now that you’ve had some practice testing your other functions, write
some code in main
that will let you test the print_score
function.
When you’re satisfied that print_score
works as expected, you can
move on to the next section.
6.4. The main
function
The main function of your program should do the following:
-
Call the
welcome
function to display a welcome message. -
Ask the name of Player 1 and Player 2
-
Initialize the current score of each player to zero.
-
Initialize the current player to be Player 1.
-
While the game is not over
-
print out the current scores
-
have the current player take a turn
-
make the next player the current player
-
-
Print out information about who won the game.
7. Requirements
The code you submit for labs is expected to follow good style practices, and to meet one of the course standards, you’ll need to demonstrate good style on six or more of the lab assignments across the semester. To meet the good style expectations, you should:
|
Your program should meet the following requirements:
-
Your program should implement the
get_yes_no
function with the same number of parameters (in this case, none), the same return type (in this case,str
), and the same behavior as described above (in this case, asking the user to type in "yes" or "no", validating the input, and returning the input). -
Your program should implement the
roll_die
function with the same number of parameters, the same return type, and the same behavior described above. -
Your program should implement the
take_turn
function with the same number of parameters, the same return type, and the same behavior described above. -
Your program should implement both the
print_score
and thewelcome
function with the same number of parameters, the same return type, and the same behavior described above. -
In
main
, your program should ask the names of Player 1 and Player 2. It should keep track of each player’s score and which is the current player. -
Your program should have players take turns until the game is over. Before each turn, your program should print out the current scores.
-
Once the game is over, your program should print out the total number of points the user earned and print out who won.
Your solution should be contained within a main
function that you
call at the end of your program.
8. Sample output
Your program’s output does not need to be identical to the sample output shown earlier, but you should make sure to have all the required functionality and that your program displays the information in a readable way.
9. OPTIONAL fun things to try
If you’d like to make your game more interesting, here are some fun
things to try. These are optional, but if you’re interested in trying
them, copy your pig.py
file to a new file named pig_fun.py
and
add these fun things to your pig_fun.py
file.
-
Have the game stop at 100 points instead of 50.
-
Have players roll two six-sided dice instead of one. Players lose their turn if a seven is rolled.
-
Allow for more than two players.
-
Create a computer player. When it is the computer’s turn, have it keep rolling until it earns at least 10 points.
-
Create a computer player, but with a different strategy than the "stop at 10 points" strategy described above.
Do you have other ideas? Try them out! Make the game more fun for
you. Just be sure you put your ideas in pig_fun.py
. Your pig.py
program should be the one that we will use to determine if you have
met the requirements for the lab.
Answer the Questionnaire
After each lab, please complete the short Google Forms questionnaire. Please select the right lab number (Lab 04) from the dropdown menu on the first question.
Once you’re done with that, you should run handin21
again.
Submitting lab assignments
Remember to run handin21
to turn in your lab files! You may run handin21
as many times as you want. Each time it will turn in any new work. We
recommend running handin21
after you complete each program or after you
complete significant work on any one program.
Logging out
When you’re done working in the lab, you should log out of the computer you’re using.
First quit any applications you are running, including your vscode editor, the browser and the
terminal. Then click on the logout icon ( or
) and choose "log out".
If you plan to leave the lab for just a few minutes, you do not need to log
out. It is, however, a good idea to lock your machine while you are gone. You
can lock your screen by clicking on the lock icon.
PLEASE do not leave a session locked for a long period of time. Power may go
out, someone might reboot the machine, etc. You don’t want to lose any work!