## Mastermind Project

FAQs

- Where do I start?
- How about some help with the layout of things on the display?
- How does the program determine which box to fill?
- Can I use the Grid Toolkit for the Guess Boxes?
- How are the secret code and current guess data represented?
- How do I choose a secret code?
- How about some help with the inexact match count?
- Help me find the bug in my program!

# Mastermind Project - FAQs

## Determining Current Guess Box

Our player is initially presented with four empty boxes that are to be filled
in with a guess. As she plays the game, as she clicks on color squares
in the choice strip, the program fills in the leftmost empty box. As she
clicks on the **[ClearChoice]** button, the program clears the rightmost
box containing a chosen color. When she has filled all four empty guess
boxes and clicks on the **[CheckGuess]**, either she wins or she is given
four new guess boxes. The new guess boxes appear just below the previous
ones.

How does the program know which guess box is the current box?

### A Global Variable: boxNumToFill

Here's the first sentence in lesson 15 (Global Variables):

What if you need a variable that holds it's value across procedure boundaries, a lifetime that's longer than the execution of a single procedure?

This sounds like just what we need. How about a global variable that we can use to count the number of boxes that have been filled so far? When we do our initialization as the program starts, we can set our count to zero. Using this, we can compute the left edge of the box to fill. After filling this box, we can increment our variable. When we are clearing a box, we can reverse the order and fill the box with white.

Here is the definition of the global variable I used including the comments which describe how it will be used. Personally, I think it is more important to provide good documentation of global variables than any other thing in a program.

; the number of guess boxes that the player has filled with chosen ; colors. zero for no boxes yet filled so box zero will be the ; number of the next box to fill with a color choice global "boxNumToFill |

### curGuessBoxX: X Coordinate for Left Edge of a Guess Box

Now, let's use **boxNumToFill** to compute the left edge of any of the four
guess boxes in a single row. The first thing I want to do is explain why
I have chosen to number the boxes zero, one, two, and three.

Since we were very young, when we were first introduced to arithmetic, we learned to count things starting with one. Count on your fingers - one, two, three, four... Well, in programming, there is an advantage to start your counting with zero in many iterative processes. Drawing the guess boxes is just such a case. I first covered the advantage of numbering cells in a grid starting at zero back in lesson 9 (Defining Operators). But, I will go into more detail now.

First, I'll define a few symbolic constants so that I can use them in the explanation.

to guessBoxSiz output 20 end to guessBoxesGap output 5 end to guessBoxesX output -15 end |

Figure 17c.1 shows what the values depict.

Figure 17c.1 |

Given these symbolic constants and **boxNumToFill**, the left edge of a
guess box can easily be computed. The red dotted lines in Figure 17c.1
show the left edges of all four guess boxes of a single row.

The variable **boxNumToFill** will start out at *zero* when the current
box is the leftmost one. It will be incremented as the boxes get filled in
so its other values will be one, two, and three. When it contains three,
the current box is the last, the rightmost one.

This gets us to the equation for computing a box's left edge.

X = guessBoxesX + :boxNumToFill(guessBoxSiz + guessBoxesGap)

And this shows us exactly why we want **boxNumToFill** to have values ranging
from zero to three. The product of it and the sum of the widths of a box
and the gap between boxes is added to the left edge of the first guess box.
So, zero times (guessBoxSiz+guessBoxesGap) is zero, exactly what we need for the
first box.

So, let's convert our equation into an operator.

to curGuessBoxX output sum guessBoxesX product :boxNumToFill sum guessBoxSiz guessBoxesGap end |

Figure 17c.2 shows **curGuessBoxX** graphically, with a plumbing diagram.

Figure 17c.2 |

### Global Variable guessNumber and Operator curGuessesTopY

Just as the program moves from box to box, left to right, as a guess is formed,
it also needs to move from the top towards the bottom with new rows of guess
boxes. A new row of guess boxes is needed everytime a guess fails to
match the **secretCode**. What we need in our program to support this
behavior mirrors what we've done above.

First we need a global variable which will count the number of guesses that a player has made.

; the number of guesses that the player has made. this is used to ; track the progress of the player and to compute the Y coordinate ; for the current set of guess boxes to be filled by the player. ; initialized to zero, it's incremented until it reaches maxGuesses global "guessNumber |

Then we need an additional symbolic constant for the top coordinate of the first row of guess boxes drawn. I've chosen to match the top edge of the guess boxes with the top edge of the color choices strip.

to guessesTopY output colorChoicesTopY end |

Figure 17c.3 shows **guessesTopY** added to an expanded view of
the guess boxes, with three rows showing.

Figure 17c.3 |

Given this additional symbolic constant and variable (**guessNumber**),
the top edge of every guess box can easily be computed.

This gets us to the equation:

X = guessesTopY - :guessNumber(guessBoxSiz + guessBoxesGap)

I'll leave it up to you to write the operator **curGuessesTopY**...

### Putting It All Together - fillCurGuess

Ok, I've now walked you through how I defined a bunch of symbolic constants,
two global variables, and two operators that together provide the X and Y
coordinates of the top-left corner of the *current* guess box. I
emphasize *current* because this obviously depends upon the two global
variables containing proper values. If both are set to zero when the
program starts, then we know that at least they are correct then. But,
your program needs to update **boxNumToFill** and **guessNumber** at
proper points in the program. I chose to update **boxNumToFill** in
the same procedure that fills a guess box. Here is my procedure,
**fillCurGuess**, which ties everything together everything we've talked
about so far together.

;fill current guess box identified by globals boxNumToFill,guessNumber to fillCurGuess :color setpencolor :color fillRect curGuessBoxX curGuessesTopY guessBoxSiz guessBoxSiz setpencolor black setpensize 1 drawRect curGuessBoxX curGuessesTopY guessBoxSiz guessBoxSiz make "boxNumToFill sum :boxNumToFill 1 end |

So, **fillCurGuess** shows how **curGuessBoxX** and **curGuessesTopY**
are used together with the lower-level procedures **fillRect** and
**drawRect**. It also shows how I change the *current* guess box,
by incrementing **boxNumToFill**. That's it for this FAQ...