CS21 Lab 5: Game of Five-Six-Seven

Due Saturday, Feb. 26, by 11:59pm

Written Part (Section 1) Due: Friday Feb. 25 at the start of class

Programming Tips

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 vim, at the bottom left 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.

Are your files in the correct place?

Make sure all programs are saved to your cs21/labs/05 directory! Files outside that directory will not be graded.

$ update21
$ cd ~/cs21/labs/05
$ pwd
/home/username/cs21/labs/05
$ ls
Questions-05.txt
(should see your program files here)

Goals

The goals for this lab assignment are:

  • write programs with multiple functions

  • solve programs using indefinite while loops

  • use the Python random library

  • practice your understanding of the stack and function call and return

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: lab5stack.pdf

You should write your solution on the print out, and submit it at the start of the class on Friday.

2. Programming Assignment: The game of five-six-seven

For this week’s lab assignment, you will incrementally develop a game playing program.

The game of five-six-seven is a two player game where one player takes the role of "the challenger", while the other player takes the role of "the champion". Each player chooses a number between 0 and 5 (one way this could be played is with with players putting a hand behind their back and choosing a number of fingers). Both players reveal their choice, and if the sum of their choices is a 5, 6, or 7, the challenger wins. Otherwise the champion wins. This game can be played for multiple rounds, and the player with the most wins, is the overall winner. Although this is not necessary for the assignment, you may want to think about if this is a fair game, and if there are any game playing strategies for the two players.

For this assignment you will implement a program that plays Five-Six-Seven for some number of rounds. In your version the computer will be the champion and a human user will be the challenger. After each round your program should print out the result of all rounds of play: the winning percentage of the human player and who is the overall winner.

You will start by implementing part of the full game as the stand-alone Part1 program, and then use its solution as the starting point for completing the full game in Part2. This model is an example of incremental implementation and testing that is a good strategy for larger programs with functions: implement some functionality, and test it, then implement some more functionality and test it, and so on.

2.1. Part 1: Get a Number Between

As a first step, in getnumbetween.py you will implement a function named getNumBetween(low, high) that takes two int values represented the low and the high ends of a range of values (inclusive), and returns a value entered by the user that is between that range.

Your function should prompt the user to enter a value between low and high (inclusive) and only return the value entered by the user if it is in the range. If the user enters an invalid value, your function should print out an error message and ask the user to try again until they enter a valid value. It is okay for this lab if your function assumes the user at least enters a valid numeric value. For example, if the user enters hello it is okay if your function doesn’t handle this case and crashes.

Then add a main program, that calls your getNumBetween(low, high) function and prints out the result. Call your function twice from main, passing different values for low and high. For example (and you can use exactly these two calls to getNumBetween in your main function):

def main():

   result = getNumBetween(5, 13)
   print(" getNumBetween returned: " + str(result))
   result = getNumBetween(-4,20)
   print(" getNumBetween returned: " + str(result))

Your function does not need to check that the value of the low parameter is less than or equal to the value of the high parameter; you may assume the caller passes values high and low range values that make sense, as in the example calls from main shown above.

Here is an example run from our program (user entered values are in bold):

$ python3 getnumbetween.py
Enter a value between 5 and 13: -2
hey, -2 is not between 5 and 13 try again...
Enter a value between 5 and 13: 20
hey, 20 is not between 5 and 13 try again...
Enter a value between 5 and 13: 13
 getNumBetween returned: 13
Enter a value between -4 and 20: -2
 getNumBetween returned: -2

You should test that your function does the right thing for values in the middle of the range, the ends of the range, and outside the range. You can add more calls to it from main and/or pass different high and low argument values to getNumBetween in main to test.

Run handin21 to submit this part before starting on Part 2.

2.2. Part 2 Five-Six-Seven game

For this part, you will start with a copy of your getnumbetween.py solution and add more functionality to implement the Five-Six-Seven game in the file fivesixseven.py.

First, let’s copy your getnumbetween.py solution into the fivesixseven.py file to start. There are many ways to do this, but let’s do it in vim:

  • First, open fivesixseven.py in vim

    $ vim fivesixseven.py
  • then, inside vim copy the full contents of getnumbetween.py into the file: in ESC-mode type :r getnumbetween.py then hit the return key

This will copy the entire contents of the getnumbetween.py file into fivesixseven.py. After this, edit the top-level comment for the Five-Six-Seven game, and you are ready to add more game playing functions.

Another way to copy one file to another is to use the cp command on the Unix command line.

The general form of cp is: cp <source_file> <destination_file>. cp will overwrite the contents of <destination_file> with <source_file>. If the destination file already exits, cp asks if you are sure you want to do this before doing so. Typing y or Y tells cp "yes do it" typing n (or anything other than y or Y) tells cp not to do it.

Here is an example for this lab:

$ cp getnumbetween.py fivesixseven.py

Be careful about the source and destination order here! If you copy this way, instead of the vim way, be sure to run handin21 first so that we have a copy of your working getnumbetween.py in case you overwrite the file with cp. It is safer to do this the vim way.

Then follow these steps, to incrementally add functionality and test as you go:

Step 1: printWelcome function

First, add a function named printWelcome that is passed a string value, which is the player’s name, and prints out a welcome message and the rules of the Five-Six-Seven game (see our sample output as an example.

In the main function prompt the user to enter their name, then call your printWelcome function. You should remove the other code in main that was part of the getnumbetween.py program’s main function.

Here is an example of what a call to your complete program might look like now:

% python3 fivesixseven.py

Enter your name: Barbara Liskov

Hi Barbara Liskov and welcome to the game of 5-6-7!
Each round you pick a number between 0 and 5 inclusive
and the computer picks a number between 0 and 5 inclusive.
If the total of the two values is between 5 and 7 inclusive,
you win!  If not, the computer wins.  :(
At the end of all the rounds, I'll print out your win percentage

Good luck!

Note that the output from the call to the printWelcome function starts with the line Hi …​.

Step 2: printResults function

Next, add a function that will ultimately be called at the end of game. Write a function named printResults with three parameters:

  1. the number of games won by the human player

  2. the total number of rounds played

  3. the player's name.

This function should print out a message that includes:

  1. The number of games the human player won out of the total played

  2. The percentage of games won by the human

  3. A win or lost message to the human player (the human wins if they win the same number of rounds as the computer or more).

Add some calls to your printResults function from main to test it out. Here is some example output from a program that includes two calls to printResults (printResults(5, 10, name) and printResults(7, 15, name))

$ python3 fivesixseven.py

Enter your name: Evelyn Boyd Granville

Hi ...

Evelyn Boyd Granville, you won 5 out of 10
for a winning percentage of 0.5
You beat the computer.  Yay!

Evelyn Boyd Granville, you won 7 out of 15
for a winning percentage of 0.47
The computer beat you.  Better luck next time!

After testing and debugging your function, you can remove or comment out the test calls you made in main. This is also a good time to run handin21 to submit what you have so far.

Step 3: PlayOneRound function

Next, add a function named PlayOneRound that takes the user’s name plays one round of the game 5-6-7, and returns 1 if the user wins the round, and 0 if the computer wins. This is a function that has a few steps, namely:

  1. print out a message to the user that they get to start the round

  2. read in the user’s choice for a value for this round between 0 and 5. your function should not let the user enter an invalid choice (remember you have a function you can call to do this)

  3. randomly generate a value between 0-5 for the computer’s choice. The randrange function might be useful here (remember to add from random import * before main).

  4. determine who wins (computer or human) and print out a win or lost message to the player

  5. return the appropriate value based on the round outcome

To test your function, add a call to your PlayOneRound in main and add a debug print statement to print out the value it returns. Run your program a few times to test your function. Make sure the user and the computer choose valid choices, and make sure your function returns the correct value when one or the other wins the round. You may want to put a call to your function and printing out its return value inside a for loop in main to easily test out some repeated calls.

Here is output from a couple calls to the PlayOneRound function might look like when run (note we are only showing program output from this function):

$ python3 fivesixseven.py

...

Sarita, you get to start this round by picking a number
Enter a value between 0 and 5: 3
  you picked 3 and computer picked 2
  You win this round!

Debug: call to PlayOneRound returned 1
...

$ python3 fivesixseven.py

...

Sarita, you get to start this round by picking a number
Enter a value between 0 and 5: 1
  you picked 1 and computer picked 1
  Sorry, you lose this round!

Debug: call to PlayOneRound returned 0
...

After testing and debugging this function, remove (or comment out) these calls and debug print output from main. This is another good time to run handin21 to submit your work so far.

Step 4: putting it all together

Next, complete the full game program in main. You may have some debug code in main that you will need to remove.

Here are the main steps:

  • Get the user’s name

  • Print out the welcome message and rules by calling your printWelcome function.

  • Get the total number of rounds to play between 1 and 30 (remember that you have a function that you can use to perform this step).

  • Play the specified number of rounds of play. Each round your program should print out a message indicating which round of play it is, call your PlayOneRound function, and keep track of the number of rounds of play that the human user wins.

  • Print out the results of all the rounds of play at the end by calling your printResults function.

2.3. Sample Output

Here is sample output from a complete program: Sample Output

3. Answer the Questionnaire

Each lab will have a short questionnaire at the end. Please edit the Questions-05.txt file in your cs21/labs/05 directory and answer the questions in that file.

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.

When Remotely logged in

When you are ssh’ed into the CS labs, first quit any applications you are running, like vim, then simply type exit at the prompt in your terminal window to disconnect.

When Physically logged in

When you are in a CS lab logged into a CS machine. First quit any applications you are running, like 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!