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:

  1. Draw the correct stack diagram.

  2. 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:

  • Write a comment that describes the program as a whole using a comment at the top of the file.

  • All programs should have a main() function.

  • Use descriptive variable names.

  • Write code with readable line length, avoiding writing any lines of code that exceed 80 columns.

  • Add comments to explain complex code segments (as applicable).

  • Write a comment for each function (except main) that describes its purpose, parameters and return value.

Your program should meet the following requirements:

  1. 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).

  2. Your program should implement the roll_die function with the same number of parameters, the same return type, and the same behavior described above.

  3. Your program should implement the take_turn function with the same number of parameters, the same return type, and the same behavior described above.

  4. Your program should implement both the print_score and the welcome function with the same number of parameters, the same return type, and the same behavior described above.

  5. 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.

  6. Your program should have players take turns until the game is over. Before each turn, your program should print out the current scores.

  7. 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.

  1. Have the game stop at 100 points instead of 50.

  2. Have players roll two six-sided dice instead of one. Players lose their turn if a seven is rolled.

  3. Allow for more than two players.

  4. Create a computer player. When it is the computer’s turn, have it keep rolling until it earns at least 10 points.

  5. 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 (logout icon or other logout icon) 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 xlock 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!