BFOIT - Introduction to Computer Programming

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


Back to Mastermind Project

Public Domain Mark
This work (BFOIT: Introduction to Computer Programming, by Guy M. Haas),
identified by Berkeley Foundation for Opportunities in IT (BFOIT),
is free of known copyright restrictions.