# Lab 04

Functions, Pictures, and Mastermind
Due by 6pm on Tuesday, October 6

The purpose of this lab is to:

• Get practice using and creating functions
• Get more practice with nested loops

## Part 1 - Picture this

Create a program called sketchy.py that draws the picture you designed on your prelab using the picture module. Your program should use at least one function (Make a flower; make rays on the sun; make gerbil -- anything you might want to have more than one copy of in your picture); you might use x and y coordinates of the location as parameters of the function. If you are going to draw in the function you should also make the canvas one argument of the function.

Here are a few of the things you can do with the picture module:

To adjust the pen width, use the setPenWidth function. To position and draw with the pen, use the setPosition, setDirection, rotate and drawForward functions. To draw simple shapes, you can use functions like drawCircle, drawCircleFill, drawRect, drawRectFill, etc. Use setFillColor to change the fill color used when creating shapes. Use setOutlineColor to change the color of shape edges and pen lines. Don't forget to use the display function followed by an input function call so your image gets displayed, and gives you time to savor your creation before closing the window.

Some of the best sketches will be shown in class to general acclaim.

Handin:

## Part 2 -- Function Practice

For this part you need to write a program functionPractice.py that has the following as its main( ) function:

def main():
done = False
while not done:
x = eval(input( "x: "))
if x == 0:
done = True
else:
print(square(x))
checkEvenOdd(x)
print(reverse(x))

Of course, this is just our usual input loop that reads numbers typed by the user until the user exits with input 0. For each non-zero input there are three functions called; your job is to add these three functions to the program. They are

• square(x), which returns x*x
• checkEvenOrOdd(x), which prints a statement about whether x is even or odd
• reverse(x) which returns the number whose digits are those of x in the opposite order. If x is 123, reverse(x) returns 321. If x is 100, reverse(x) returns 001, which is the same thing as the number 1.

Function reverse( ) should be the only one of these that challenges you. One way to do this is to convert x to a string, reverse its digits, and then convert the result back into an integer. Here is a numerical algorithm for this function. Make variable result which starts at 0. Go into a loop until x is 0. At each step multiply result by 10 and add the rightmost digit of x, which is x%10. Divide x by 10 to eliminate its rightmost digit, and go around the loop again. If you do this on paper with a number like 325 you'll see how this algorithm works.

Notice that two of these functions return something; the middle one does something. Take a moment to look at how the code for the function and the code for the call both differ when a function returns something as opposed to doing something.

After you have tested out your functionPractice program, hand it in.

## Part 3 - Mind Mastery

Mastermind is a neat (although often frustrating) puzzle game. It works a something like this: There are two players. One player (your program) is the codemaker, the other (the user) is the codebreaker. The codemaker chooses a sequence of four colored pegs, out of a possible six colors (red, blue, green, yellow, orange, and purple). He may repeat colors and place them in any order he wishes. This sequence is hidden from the codebreaker. The codebreaker has 10 chances to guess the sequence. The codebreaker places colored pegs down to indicate each of her guesses. After each guess, the codemaker is required to reveal certain information about how close the guess was to the actual hidden sequence.

Describe the Problem:
Write a program called master.py that allows the user to play a text-based version of the fantastic game Mastermind.
input: repeatedly get guesses from the user, until they either guess the code, or run out of guesses.
goal: generate a random code, and correctly provide the user with feedback on their guesses.

Understand the Problem:
The trickiest part of this game is determining how to provide feedback on the codebreaker's guesses. In particular, next to each guess that the codebreaker makes, the codemaker places up to four clue pegs. Each clue peg is either black or white. Each black peg indicates a correct color in a correct spot. Each white peg indicates a correct color in an incorrect spot. No indication is given as to which clue corresponds to which guess.

For example, suppose that the code is RYGY (red yellow green yellow). Then the guess GRGY (green red green yellow) would cause the codemaker to put down 2 black pegs (since guesses 3 and 4 were correct) and 1 white peg (since the red guess was correct, but out of place). Note that no peg was given for guess 1 even though there was a green in the code; this is because that green had already been "counted" (a black peg had been given for that one).

As another example, again using RYGY as our code, the guess YBBB would generate 1 white peg and 0 black; yellow appears twice in the code, but the guess only contains one yellow peg. Likewise, for the guess BRRR, only 1 white peg is given; there is an R in the code, but only one. Below is a table with guesses and the correponding number of black and white pegs given for that guess (still assuming the code is RYGY).

guess black pegs white pegs
YYYY 2 0
YRYR 0 3
BBPO 0 0
PGYR 0 3
YYYG 1 2
RYGY 4 0

Check here for an online graphical version of the game (where their red pegs are our black pegs).

A sample run of our text-based program may look like this:

### Sample output

```    %python3 master.py

I have a 4 letter code, made from 6 colours.
The colours are R, G, B, Y, P, or O.

Not quite. You get 0 black pegs, 0 white pegs.

Not quite. You get 1 black pegs, 0 white pegs.

Not quite. You get 0 black pegs, 2 white pegs.

Not quite. You get 1 black pegs, 2 white pegs.

Not quite. You get 1 black pegs, 3 white pegs.

You win! Aren't you smart.
```

Design an Algorithm:
Once you understand how the game works, you should design a pseudocode plan of attack. The general steps are:

• Randomly choose the codemaker's code.
• Repeatedly prompt the user for their guess
• If their guess is correct, end the game with a congratulatory message.
• Otherwise, give clues (pegs) that correspond to their guess.
Some of these steps are straight-forward, but certainly it would be worth your while to write down an approach to randomly generating the code, and giving the clue. Here is our recommendation for the latter algorithm is as follows:
• First assign the black pegs. Do this by iterating through both strings one character at a time (a for-loop with i going from 0 to 4 that looks at both code[i] and guess[i]), assigning a black peg if the characters in the same position match. If they do match, change that character/peg in your guess to an 'x' and in the code strings to a 'z', say, so that you know you have used both of these pegs for a clue (and you won't use them again when assigning white pegs and accidentaly double-count). (You can find some useful string methods on pg 125 of the text, or here in order to do this.)
• Next assign the white pegs. Do this by considering the first peg in the guess string and trying to find the matching character in the code string (note that if the first character is an 'x' then there definitely won't be a match in the code string). If you find a match, again change the guess character to 'x', the matching code character to 'y' and continue with the second peg in the guess string, then the third, and so on. Because of your changes to 'x' and 'y', you won't assign both a black and white peg for one guess or clue peg.
• You know you can only return once from a function. In Python it is easy to have a function return a pair as its value. For example, if b and w are your counts for the black and white pegs, your function can say
return b, w
If the function that is evaluating guesses is called evaluateGuess( code, guess ) and it has such a return statement, you can call this function with
black, white = evaluateGuess( code, guess )

Implement a Design:
Now that you have some of the kinks worked out in theory, it is time to write your program master.py.

You may assume the user always provides a guess with the available colors, and always in uppercase.

Make and use an integer constant NUM_TURNS that represents the number of allowable turns and set this to 10..

To generate the code, write a function

`    generateCode() `

that generates the codemaker's code (and returns it as a String to the caller). That is, this function should randomly generate 4 colored pegs, selected from R, B, G, Y, O, and P, and return it as a 4-letter string. You'll want to use the random methods as discussed in lab03 in order to randomly generate a color for each peg. In particular, you'll generate an integer between 0 and 5 inclusive. You can use this as an index into the string "RBGYOP" of all of the color symbols to get your next color.

Test your generateCode function thoroughly before continuing. Once it's working, write a second function

`    evaluateGuess( code, guess )`

that returns the numbers of white and black clue pegs according to the given guess and code. Keep going around the guess loop until the number of black pegs is 4 or the user has name NUM_TURNS guesses.

Note that you can "change" the ith character in a string s to an 'x' as follows:

`    s = s[0:i] + "x" + s[i+1:]`

Also note that s[j:] is the substring of s from position j to the end. Similarly, s[:j] denotes the substring of s from the beginning up to (but not including) j.

Test the Program:
It is hard to test your program with a random code that you don't know. One trick that helps is to have your generateCode( ) function return a code that you do know. After generateCode( ) is debugged and youi are sure you are generating random codes; insert into the function a new first line:
return "RYGY"
which will make the function always return the string "RYGY". You can then tell if your evaluateGuess( ) function is giving correct answers. Remember to remove (or comment out) this line before you hand in your program.

## Handin

If you followed the Honor Code in this assignment, make a README file that says

I affirm that I have adhered to the Honor Code in this assignment.

You now just need to electronically handin all your files. As a reminder

```
% cd             # changes to your home directory
% cd cs150       # goes to your cs150 folder
% handin         # starts the handin program
# class is 150
# assignment is 4
# file/directory is lab04
% lshand         # should show that you've handed in something
```

You can also specify the options to handin from the command line

```
% cd ~/cs150     # goes to your cs150 folder
% handin -c 150 -a 4 lab04
```

#### File Checklist

You should have submitted the following files:
```	sketchy.py
functionPractice.py
mastermind.py