CS21 Lab 4: functions and while loops
Due Saturday, Oct 5, 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 have a top-level comment! 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 Friday.
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 program that has the user play a high-low guessing game. You may find this short video helpful in understanding the premise of the game.
Normally this game is played with standard playing cards with values from 1 to 13. In our version, we will use integers from 1 to 13 to represent the cards. And instead of using a deck of cards, we will have the computer generate a random number between 1 and 13 each time we want a new card.
Before each turn, the computer will generate a random integer between 1 and 13. The user will then guess if the next number will be higher or lower. If the user guesses correctly, they continue playing. If they guess incorrectly, the user has made one mistake. The game ends when the user has made three mistakes. When the game ends, the user’s final score is displayed. The score is the number of correct guesses the user made during the entire game.
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 function 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
hilo.py
.
Before we dive in to the details, let’s take a look at what the final running program looks like. This example uses the same numbers from the video linked above.
Notice that after the first guess, the user’s next guess is based on the last number. In the example, the first number was 3. The user guessed "high" and the next number was 10, so the user was correct. When the user makes their next guess, they need to decide if the next number will be higher or lower than the last number, which was 3.
3. Get a prediction from the user
In the file named hilo.py
, write a function named get_prediction
that asks a user to enter either "H" or "L" (short for Higher or
Lower). The function returns the string value entered by the user. If
the user doesn’t enter one of these two string values, your function
should print an error message, and prompt the user to try again. The
function should only return when the user enters a valid string value.
In addition to "H" or "L", the user may also enter "h" or "l" (in lowercase). Regardless of whether the user types in uppercase or lowercase, your function should only return either "H" or "L" in uppercase.
The get_prediction
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_prediction():
3.1. Test get_prediction
in main
To test get_prediction
, you should have your main
function call
the get_prediction
function and print out the value returned. Your
main
should something look like this:
def main():
prediction = get_prediction()
print("get_prediction returned %s" % (prediction))
You can now test to make sure the get_prediction
function is working
properly. Here are some examples of what your program should do at
this point:
$ python3 hilo.py
(H)igher or (L)ower?: H
get_prediction returned H
$ python3 hilo.py
(H)igher or (L)ower?: L
get_prediction returned L
$ python3 hilo.py
(H)igher or (L)ower?: apple
Oops! You can only guess H or L. Try again.
(H)igher or (L)ower?: higher
Oops! You can only guess H or L. Try again.
(H)igher or (L)ower?: high
Oops! You can only guess H or L. Try again.
(H)igher or (L)ower?: H
get_prediction returned H
$ python3 hilo.py
(H)igher or (L)ower?: h
get_prediction returned H
$ python3 hilo.py
(H)igher or (L)ower?: l
get_prediction returned L
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 get_next_number
that generates and returns a
random integer between 1 and 13. (You should use the randrange
function,
described in the subsection below, to help you do this.)
Every integer from 1 to 13, including both 1 and 13,
are values that get_next_number
could generate. Although this may be a short
function, it’s a good idea to make this a separate function because
you will end up calling it multiple times in your program. If for some
reason you wanted to change the game in some way (e.g. maybe you guess
from 1 to 15), you only need to change this function and not the rest
of your program.
The get_next_number
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 get_next_number():
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 will randomly select one integer from all of the
values that an equivalent range
function would generate. For example,
range(100)
will generate a sequence of integers from 0 to 99. Similarly, the
randrange(100)
will randomly select one integer between 0 and 99. Calling
range(2, 10, 3)
will generate the sequence 2, 5, 8. Similarly, calling
randrange(2, 10, 3)
will randomly select one integer from the sequence 2, 5, 8.
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, 10, 3) # randomly pick an integer from 2, 5, 8
print(number)
main()
In the get_next_number
function described above, you will use the
randrange
function to randomly select an integer between 1 and 13.
4.2. Test get_next_number
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 get_next_number
, you should have your main
function call
the get_next_number
function and print out the value returned. Your
main
should something look like this:
def main():
number = get_next_number()
print("get_next_number returned %d" % (number))
You can now test to make sure the get_next_number
function is
working properly. Here are some examples of what your program should
do at this point:
$ python3 hilo.py
get_next_number returned 7
$ python3 hilo.py
get_next_number returned 13
$ python3 hilo.py
get_next_number returned 1
5. Make one guess in the high-low game
Let’s extend our program to add a function that allows the user to make one guess in the high-low game.
Add a new function called determine_success
. This function takes as
input two integers, the last number and the next number, and a
string representing the user’s prediction (either "H" or "L"). The
function should determine whether the user’s prediction was
correct. If the user’s prediction was correct, the function should
return True
. If the user’s prediction was incorrect, the function
should return False
.
For example, if the last number was 13, the next number was 2, and
the user guessed "L", the function should return True
since the user
correct guessed that the next number (2) would be lower ("L") than the last number (13).
If the last number was 8, the next number was 11, and the user guessed "L", the
function should return False
since the user incorrectly guessed that the next
number (11) would be lower ("L") than the last number (8).
Note: There will be times when the last number and the next number
are the same. In this case, the user’s prediction is considered
correct and your function should return True
.
def determine_success(last_number, next_number, prediction):
5.1. Test determine_success
in main
To test the determine_success
function, you need to simulate having
two numbers picked and asking the user to make a prediction.
In main
, call the get_next_number
function to get the last
number number. Then call the get_prediction
function to get the
user’s prediction. Then call get_next_number
again to get the next
number. Finally, call the determine_success
function to determine if
the user’s prediction was correct. Be sure to print the return value
from determine_success
to verify that the function is working
properly. You should be able to use some of the code samples from
main
above to help you with this.
The prediction is automatically successful if the last_number
and the next_number
are the same.
Here are some example runs. Your main
does not need to run exactly
like this, but it should test determine_success
in the same way as
shown below.
$ python3 hilo.py
last number: 13
(H)igher or (L)ower?: L
Next number: 2
Result: True
$ python3 hilo.py
last number: 8
(H)igher or (L)ower?: L
Next number: 11
Result: False
$ python3 hilo.py
last number: 1
(H)igher or (L)ower?: H
Next number: 8
Result: True
$ python3 hilo.py
last number: 7
(H)igher or (L)ower?: H
Next number: 1
Result: False
$ python3 hilo.py
last number: 9
(H)igher or (L)ower?: L
Next number: 9
Result: True
6. Play the high-low game
For the final part, you are going to add code so that you can play the full game of high-low.
After each guess in the game, you should print out the current scores
using a function called print_score
.
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 print_score
function
The print_score
function should take the following parameters as
input:
-
the integer number of points the user has earned so far
-
the integer number of mistakes the user has made 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(points, mistakes):
The function should print out the current score of the two players
between two dashed lines. For example, with the argument values 3
and 1
, it would print out something like this:
------------------------
Score: 3 Mistakes: 1
------------------------
6.2.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.3. The main
function
The main function of your program should do the following:
-
Call the
welcome
function to display a welcome message. -
Choose a first number to start the game.
-
Enable the user to play as many rounds of high-low as needed until the player makes 3 mistakes.
-
Be sure to make use of the
get_prediction
function to get the player’s choice each round, use theget_next_number
function to select the next random number, and use thedetermine_success
function to compute whether or not the player won. -
Display the result (e.g. report that the player was correct or incorrect) after each round. Then, use the
print_score
function to show the current scores. -
Update the player’s score and mistakes as needed.
-
When the player makes 3 mistakes, print the total number of points that the player earned and end 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_prediction
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 "H" or "L", validating the input, and returning the uppercase version of the input). -
Your program should implement the
get_next_number
function with the same number of parameters, the same return type, and the same behavior described above. -
Your program should implement the
determine_success
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 repeatedly ask the user to make a prediction based on the last number. After making a prediction, the program should choose a new number and then display whether the user’s prediction was correct or incorrect. -
Your program should keep track of the number of points and mistakes the player makes as they play the game, displaying these values after each prediction that the user makes.
-
The game should continue until the user has made 3 mistakes. At that point, the program should print out the total number of points the user earned.
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.
Here are two other example outputs that you may find helpful:
-
example game 3 (the user types bad input)
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 hilo.py
file to a new file named hilo_fun.py
and
add these fun things to your hilo_fun.py
file.
-
Display a different message if the last number and next number are the same.
-
Only give the user a point if the last number and next number are different. If they are the same, don’t count that as a mistake but also don’t give them a point.
-
Instead of playing the game until they make 3 mistakes, let the user play until they earn a specified number of points (e.g. 52 points). When they reach the target number of points, print out how many mistakes they made.
-
Let the user to quit the game at any time by typing "Q" instead of "H" or "L". If the user quits, print out how many points they earned and how many mistakes they made and end the game immediately.
-
Allows the user to play the game multiple times in a row. After the user plays one game, ask them if they want to play again. If they do, start a new game. If they don’t, end the program.
-
Allows the user to specify the range of numbers that the computer can choose from. For example, the user could specify that the computer should choose numbers between 1 and 20.
Do you have other ideas? Try them out! Make the game more fun for
you. Just be sure you put your ideas in hilo_fun.py
. Your hilo.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!