CS21 Lab 5: More Advanced Functions
Due Saturday, Oct 9, before midnight
Programming Tips
As you write your first programs, start using good programming practices now:
-
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.
-
Atom shows the column number in the lower left and draws a vertical line down the editing window at 80 characters.
-
In
emacs
, at the bottom, center of 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
-
Work with functions and lists
-
Work with mutable and immutable function parameters
-
Work with functions that return values
-
Work with functions used only for their side effect
For this week’s lab we’re going to incrementally develop an implementation of the game Mastermind.
You can also play Mastermind online. We encourage you to play it just a few times until after you’ve finished the lab :).
For example, if the secret code is "green green blue red", then:
-
a guess of "green purple blue purple" has 2 exact matches and 0 inexact matches.
-
a guess of "red blue green purple" has 0 exact matches and 3 inexact matches.
-
a guess of "green green green green" has 2 exact and 0 inexact matches.
-
a guess of "yellow orange yellow purple" has 0 exact and 0 inexact matches.
1. Printing lists of colors, generating lists of colors
Before writing functions to handle the main game mechanics, you should write some initial simple functions that generate and print lists of colors.
The first function you write and test should be named
print_colors(color_list)
. It should take a single list color_list
of strings representing colors and nicely print the colors to the
screen. Put commas between the colors to make the printout look nice.
For example,
-
if the input to
print_colors
was["green", "green", "blue", "red"]
, thenprint_colors
should print
green, green, blue, red
-
if the input to
print_colors
was["red", "orange", "yellow", "green", "blue", "purple"]
, thenprint_colors
should print
red, orange, yellow, green, blue, purple
Before moving onto other functions, test just this function by calling
it within main()
. For now, just make up the colors you want to
print out.
Once you’ve written and tested print_colors
, write a function
get_guess(colors)
. This function should take a list of the six
possible colors, and ask the user for four legal colors. Keep on
asking for a color until the user enters a legal one. Store these
four colors in a list, and return the list once the user has entered
four legal colors.
See the example code below (user input in bold).
$ python3 mastermind.py Please enter four legal colors. Your choices are: red, orange, yellow, green, blue, purple Enter color 1: white white is not a valid color. Please choose from the following colors: red, orange, yellow, green, blue, purple Enter color 1: blue Enter color 2: blue, blue, is not a valid color. Please choose from the following colors: red, orange, yellow, green, blue, purple Enter color 2: blue Enter color 3: green Enter color 4: black black is not a valid color. Please choose from the following colors: red, orange, yellow, green, blue, purple Enter color 4: red You guessed: blue, blue, green, red
Once you’ve written and tested get_guess(colors)
, write and test a
function generate_code(colors)
. This function should take a list
of the six possible colors and return a list of four random colors.
Use the choice
function from the random library. The choice
function takes a list as input and returns a random element from the
list.
from random import choice ... L=[2,3,5,7,11] print(choice(L)) # prints out random number from L
Test your implementation of generate_code(colors)
by calling it
once or twice in main()
. Use print_colors
to print
out the colors.`
By the end of this part of the lab, you should have implemented and tested the following functions:
-
print_colors(color_list)
-
get_guess(colors)
-
generate_code(colors)
Once you’ve implemented these functions, it’s time to move onto the next part of the lab!
2. Checking the user’s guess
In this section, you will write functions that will check how many
exact and inexact matches the user got. Note: figuring out how
many matches the user gets is sublte. If not done correctly, it is
easy to overcount. For example, if the code is blue blue green
red
and the user guesses green orange green purple
, then only one
exact match should be returned, not one exact and one inexact. You’ll
need to carefully keep track of the matches to avoid overcounting.
To count the number of exact and inexact matches, write two separate functions.
-
exact_matches(secret_code, guess, status)
-
inexact_matches(secret_code, guess, status)
exact_matches
should return an integer representing the number of
exact matches in the string. Similarly, inexact_matches
also
returns an integer, representing the number of inexact matches in the
string.
status
should be a list of four strings. Initially each string is
an empty string. As a color in the secret_code
list is matched, you
should keep track of this by changing the corresponding string in
status
.
The exact_matches(secret_code, guess, status)
function takes three input
parameters. secret_code
and guess
are the target code and the user’s
guess. Each is a list of four colors. status
should initially be a
list of four empty strings ["", "", "", ""]
. As you determine where
the exact matches are in guess
, mark that element of the status list
as "exact". For example, if the secret_code is blue blue green green
and
the guess is blue green green red
, then exact_matches
should
return two, and status should change to `["exact", "", "exact", ""].
The inexact_matches(secret_code, guess, status)
function takes the
same three input paramters, and computes the number of inexact
matches between secret_code
and guess
. To compute an inexact
match, consider each color in guess
. If it was not an exact match,
scan through the colors in the secret_code
list. If there are any
colors in secret_code
that (i) equal the current guess color and
(ii) have not already been matched, you found an inexact match! Make
sure to update the status
list so the color in secret_code that you
just matched doesn’t get matched twice. For example, if the code is
[blue blue green green]
, the guess is [blue green green red]
,
and the status is ["exact", "", "exact", ""]
then
-
First, look at
blue
. The first element ofstatus
is "exact", so we’ve already matched blue. Don’t try to find an inexact match sinceblue
was already matched. -
Second, try to match
green
to a color in code.secret_code
contains two greens. The first was already matched, but fromstatus
we know that the second has not yet been matched. Increment one to your count of inexact matches, and change status to["exact", "", "exact", "inexact"]
. This status indicates that the last color insecret_code
has been matched with an inexact match (to the second color inguess
). -
Next, look at the third color in
guess
. The third element ofstatus
is "exact", so we’ve already matched this green. Don’t try to find an inexact match sincegreen
was already matched. -
Finally, try to match
red
to a color in the code. There is no match.
In the example above, inexact_matches
should return 1, and status
should change to ["exact", "", "exact", "inexact"]
.
Here is a second example:
-
Suppose the secret code is
red blue yellow purple
, the guess isorange green red red
, andstatus
is initially["","","",""]
. -
When
exact_matches
gets called on the inputs above, it should return zero (since there are no exact matches), andstatus
should remain["", "", "", ""]
. -
When
inexact_matches
gets called on the above inputs,-
orange
andgreen
are first checked, but don’t appear insecret_code
. -
Next, it checks
red
and finds an inexact match with the first color insecret_code
. The number of inexact matches is incremented to 1, andstatus
becomes["inexact", "", "", ""]
(sincered
matches the first color insecret_code
. -
Finally, it checks the second
red
. This matches the first color insecret_code
; however, since fromstatus
we know that the first color insecret_code
has already been matched, we can’t use it (otherwise we’ll overcount). The remaining colors insecret_code
are notred
, so we don’t find an additional inexact match.inexact_matches
returns 1, andstatus
changes to["inexact", "", "", ""]
.
-
To recap, to implement inexact_matches(secret_code, guess, status)
we encourage your code to follow the following outline:
-
For each guessed color
-
if that color is an exact match, skip it (it is already accounted for)
-
otherwise, check each color in
secret_code
sequentially-
if the guessed color matches this color in the
secret_code
and this color in thesecret_code
hasn’t been matched already, then you found another inexact match! Update your count of inexact matches, and updatestatus
to show that this color insecret_code
has been matched.
-
-
Be sure to test each function in your main()
program before moving
on. Do exact_matches
and inexact_matches
both return the correct
number of matches? Do they update status
correctly? If so, you are
ready to complete the full mastermind program!
2.1. The Python break
statement
While implementing inexact_matches
, you might find that you’d like
to exit a for
loop or while
loop early. Foruntately, python has
just such a command: break
. When Python encounters a break
statement inside a for loop, it immediately exits the for loop. For
example, consider the following code snippet:
print("before for loop") for i in range(10): print(i) if(i >= 3): break print("after loop")
The output of running this code is
before for loop 0 1 2 3 after loop
The break
statement can be a useful way to exit a for
loop early.
3. Mastermind game helper functions
Before moving on to the final part of the implementation, it will be helpful to write and test some simple helper functions.
-
print_introduction()
should take no parameters and print out the rules to Mastermind. -
is_game_over(num_exact_matches, turn)
takes two integer input parameters. This function should returnTrue
if the game is over; that is, if the user guessed all four exact matches, or if the user ran out of their ten turns. -
player_won(num_exact_matches)
takes one integer input parameter. This function should returnTrue
if the player won the game.
It might seem a little strange to test the is_game_over()
or
player_won()
functions before writing the main part of the game. Just
call these functions with dummy variables to see if they return what
you expect them to return. It will be helpful to know these functions
work before it comes time to complete your program.
4. Putting it all together
We’re almost all done now. The fully finished mastermind
program
might have the primary steps in main()
as shown below. Think about
how to use all the helper functions you’ve just implemented to
accomplish each step.
-
Print out instructions to the user
-
Pick a secret code for the user to guess.
-
Until the user guesses the secret code or runs out of turns:
-
Show the current turn number
-
Ask the user for a guess
-
Compute the number of exact and inexact matches
-
Print out the number of exact/inexact matches
-
-
Check to see if the player won. If so, print out how many turns it took. If not, print out a sympathetic message.
5. Sample output
As with the previous lab, your program’s output does not need to be identical to the following output, but you should have all the required functionality, and your program should display the information in a readable way.
$ python3 mastermind-jesb.py Welcome to Mastermind! Your goal is to guess a sequence of four colors Each color can be blue, green, red, orange, purple, or yellow. Then I'll tell you how many times you guessed the correct color in the correct position, and how many times you guessed the correct color, but in the wrong position. You have ten turns to guess the correct sequence. good luck! Turn 1: Please enter four legal colors. Your choices are: red, orange, yellow, green, blue, purple Enter color 1: white white is not a valid color. Please choose from the following colors: red, orange, yellow, green, blue, purple Enter color 1: blue Enter color 2: blue Enter color 3: gren gren is not a valid color. Please choose from the following colors: red, orange, yellow, green, blue, purple Enter color 3: green Enter color 4: green You guessed: blue, blue, green, green There are 1 exact matches. There are 1 inexact matches. Turn 2: Please enter four legal colors. Your choices are: red, orange, yellow, green, blue, purple Enter color 1: red Enter color 2: red Enter color 3: orange Enter color 4: orange You guessed: red, red, orange, orange There are 0 exact matches. There are 1 inexact matches. Turn 3: Please enter four legal colors. Your choices are: red, orange, yellow, green, blue, purple Enter color 1: blue Enter color 2: orange Enter color 3: blue Enter color 4: yellow You guessed: blue, orange, blue, yellow There are 2 exact matches. There are 0 inexact matches. Turn 4: Please enter four legal colors. Your choices are: red, orange, yellow, green, blue, purple Enter color 1: blue Enter color 2: purple Enter color 3: blue Enter color 4: red You guessed: blue, purple, blue, red There are 4 exact matches. There are 0 inexact matches. The answer was: blue, purple, blue, red You won! It took you 4 turns to get the correct answer.
6. 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, run handin21
again.
7. Optional Extra Challenges
This is an optional extra challenge. There are lots of fun
extensions you could add to mastermind.py
.
-
Allow the user to choose how many turns the game takes.
-
Allow the user to choose how long the code is.
-
Allow the user to change how many colors you can guess from.
-
Implement a computer player who will make guesses instead of the user.
-
Anything else you can think of? Let us know if you come up with something interesting!
Turning in your labs…
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, like 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!