BFOIT - Introduction to Computer Programming

What If? (Predicates)

Introduction

So far, when the programs you've written are executed, every instruction that makes up the program is executed.

Think about how TG interprets your programs.  TO commands introduce new procedures that are remembered for execution at some later point.

Instructions not surrounded by "TO" and "end" (end lines) are executed from left to right on each line.  Lines are executed one after another down the page.  When an instruction to be interpreted is a procedure invocation, say to some procedure that you wrote, jLogo recalls your definition and interprets the instructions in it, then picks up where it left off.  All of the instructions in your program get executed.

What if you only want some instructions to be interpreted when some condition is true?  As an example, what if you want to do something when an up-arrow key is pressed and something else when the down-arrow key is pressed?

In this lesson, you will learn

  • about another kind of thing called a boolean value, which can have two values: the symbol true or the symbol false
  • about primitive (built-in) operators in Logo which output a boolean value, called predicates
  • about the if command which expects two inputs, a predicate and a list of instructions.  The list of instructions is only executed if the predicate outputs a true value.

Boolean Values

In this lesson, you will want your program to do some things only when certain conditions are true. This means you will need to use the data type: boolean.  Boolean data can have different values, but only two: true or false.  Each of these values is represented by a word, so you can express them in your programs as "true and "false.

Boolean values are used in computer programs to control what the program does.

Let's look at a few primitive (built-in) operators that Logo has and some examples of how you can use them.

Predicates -
Operators Which Output Boolean Values

      predicate n. 1 a: something that is affirmed or
      denied of the subject in a proposition of logic
      b: a term designating a property or relation
 
                - Webster's New Collegiate Dictionary 

So, in other words, a predicate is something that is either true or false - the boolean values.  In Logo, predicates are operators that output a boolean value.  Table 12.1 shows the first three predicates you'll need/use.

Name Input(s) Description
 EQUAL?
 EQUALP
 value1  value2 Outputs "true if value1 is equal to value2, "false otherwise.
 GREATER?
 GREATERP 
 number1  number2  Outputs "true if number1 is greater than number2, "false otherwise.
 LESS?
 LESSP
 number1  number2 Outputs "true if number1 is less than number2, "false otherwise.
Table 12.1

Figure 12.1 shows some example output values for these operators.

Figure 12.1

Figure 12.2 shows a few more example output values for these operators when used with symbolic values, words in this case.  Notice that equal? works correctly, but that less? causes an error.  You cannot compare symbolic values in Logo for magnitude difference. greater? and less? can only have numbers for their inputs.

Figure 12.2

IF - Maybe Execute a List of Instructions

So, how do we use these boolean operators in our programs?

Logo has a way of interpreting a list of instructions only when a specified condition is true.  The syntax of the if command is:

   if       <predicate>       <List-of-Instructions>   

  1. the command name: "if"
  2. a <predicate>, and
  3. a <List-of-Instructions>

And, the syntax of a <List-of-Instructions> is:

   [       <Instructions>       ]   

  1. an open square bracket,
  2. <Instructions>, and
  3. a close square bracket

Here are a couple of examples of the IF command in action.

Figure 12.3

Use the following TG applet to try stuff out for yourself.

alt="Your browser understands the <APPLET> tag but isn't running the applet, for some reason." Your browser is completely ignoring the <APPLET> tag! TG - TurtleGraphics Applet

Project: Moving the Turtle Around the Grid

Hope you've been keeping up with all the Grid Toolkit projects in the prior lessons.  We are going to use the Grid Toolkit to write a program: TurtleInGridLand.

How you want to work on the project is up to you.  I'll give you three choices.

    1. Copy your GridToolkit program to one named TurtleInGridland.
    2. Copy/Paste the following code into your TurtleInGridland program.
    3.   to green
          output 2
          end
      
        to leftArrow
          output 65538
          end
        to rightArrow
          output 65539
          end
        to upArrow
          output 65536
          end
      
        ;respond to a key pressed event - move/rotate the turtle  
        to keyPressed :keyNum
          if equal? :keyNum upArrow [forward gridCellSize]  
          if equal? :keyNum leftArrow [left 90]
          if equal? :keyNum rightArrow [right 90]
          end
      
        to main
          hideturtle home clean
          gridPaint
          gridGotoCellCtr random gridNumCells
          setheading 0 repeat (random 4) [right 90]
          setpencolor green showturtle penup
          end
      
        main 
    4. Change the gridNumCol procedure so that it outputs 12 instead of 8.
    5. Change the gridNumRow procedure so that it outputs 8 instead of 5.
    1. Start TG,
    2. choose the File->New menu item,
    3. Here is my version of TurtleInGridLand.jlogo. Copy/paste my code into TG's Editor,
    4. and use File->Save As... to write your new program out as the file TurtleInGridLand.jlogo
    1. Go back up to the TG applet,
    2. choose the Window->Canvas->Open menu item,
    3. choose the File->New menu item,
    4. shrink the Editor, then CommandCenter windows to minimum height,
    5. type loadcode TurtleInGridLand.jlogo into the CommandCenter.

When you run this program you should end up with something in the graphics canvas that looks like Figure 12.4.

Figure 12.4

The turtle should appear in a random cell location and facing in a random direction.

Click the left mouse button in the graphics canvas so that it has the keyboard focus.

Move the turtle around with the arrow keys.  The up-arrow key should move the turtle forward one cell.  The left-arrow and right-arrow keys should rotate the turtle left 90-degrees and right 90-degrees respectively.

Read the keyPressed procedure!  That's where the IF command you just learned about comes into play.  Everytime it is invoked it decides what to do by comparing the contents of the keyNum input to symbolic constants representing the values of the arrow keys.

There is one obvious problem with this TurtleInGridLand program.  As is shown in Figure 12.5, you can move the turtle out of the grid!

Figure 12.5

Fixing this is your new challenge.  Write a procedure moveForwardCell which will move the turtle ahead one cell if, and only if, it will still be in the bounds of the grid.

The Grid Toolkit gives you some of the information you need in the form of symbolic constants, e.g., gridLeftX, gridTopY, etc...  Two Logo primitive operators (XCOR and YCOR) described in Table 12.2 give you the remaining information you need to write the procedure.  Use the IF command to control what the Logo interpreter does, which instructions it performs. 

Name Input(s) Description
 XCOR     Outputs the turtle's X-coordinate. 
 YCOR    Outputs the turtle's Y-coordinate.
Table 12.2

Here is the skeleton of what I'm asking you to do.

  ;move turtle forward iff it remains in grid
  to moveForwardCell
    ...
    end

  to keyPressed :keyNum
    if equal? :keyNum upArrow [moveForwardCell]  
    ...
    end 

If you are stuck, remember the steps to take in programming.  Read over the Grid Toolkit source code.  Think about what you know how to do.  Experiment with your new stuff just introduced in TG's CommandCenter.  Enjoy the challenge of the puzzle.

Additional Boolean Operators

You can do quite a lot with EQUAL?, GREATER?, and LESS? operators.  But, there are times when you need to do something only when multiple comparisons are true.  There are times when you need to do something when any one of multiple comparisons is true.  Finally, there are times when you need to do something when a comparison is not true.

Table 12.3 provides the details regarding boolean operators which provide these needed capabilities.

Name Input(s) Description
 AND  trueFalse1
 trueFalse2 
Outputs true if both trueFalse1 AND trueFalse2 are true, false otherwise.
 OR  trueFalse1
 trueFalse2 
Outputs true if trueFalse1 OR trueFalse2 is true, false otherwise.
 NOT   trueFalse Outputs false if trueFalse is true, else true when trueFalse is false. NOT outputs the opposite boolean value of its input.
Table 12.3

Project: MousedQuadrants

Figure 12.6 is an illustration of a standard coordinate system.

Figure 12.6

Write a program which draws the X and Y axes - don't bother with the labeled tick marks.  Then, add a mouseClicked procedure to your program.  It should print the name of the quadrant the mouse was in when it was clicked.

As an example, if the mouse is clicked above the X axis and to the right of the Y axis, the program should print "Quadrant I" in the CommandCenter.

Project: A User Interface

Now that we have the IF command in our bag of tricks, we can start to do stuff that you see computer programs doing all the time.  Let's start with a simple user interface that we can later extend into the Mastermind game.  Figure 12.7 shows the desired user interface for this project.

Figure 12.7

The user interface consists of a strip of color choices (six colored squares), a big empty box, and a rectangle with the label "Clear Box" in it.  The first thing our program needs to do is draw all of these things.  Doing stuff like this is commonly called initialization of the program.

The program then waits for mouseClicked events.  When the mouse is clicked within one of the solid colored squares, the program fills in the big box with the color that was clicked on.  Figure 12.8 shows what happens when the mouse is clicked within the red color choice.

Figure 12.8

A User Interface: Program Design

Another way of looking at this program is to think of it as a group of objects which interact with each other.  There is

  1. a big box that is initially empty (white) but displays a specified color when asked to,
  2. a strip of colored squares (color choices) which do something when they are clicked on. When the mouse is clicked on one of the colored squares, the square tells the big box to fill itself with its color, and
  3. a button that, when clicked on, tells the box to empty itself, to clear out any color it contains.

Think of the program as some kind of a machine, one with little people in it.

The big box person knows how to fill itself with a color when requested.

The colors choices person knows the boundaries of the colored squares it is composed of.  When it is told that the mouse was clicked while within its boundaries, it knows how to figure out which color was clicked on.  Since it can communicate with big box, it tells big box to fill itself with the chosen (clicked on) color. 

The clear button person's job is easy.  When it is told that the mouse was clicked within its boundaries, it simply tells big box to paint itself white.  White is just another color.

The final person's job is to pay attention to the mouse.  It handles mouse clicked events.  When it receives one, it checks to see if the mouse was clicked on its friends, color choices and clear button.  If so, it tells one of its friends to do whatever they are supposed to do when the mouse is clicked on them.

So, given this description of how the program works, take a little time to think about how you would write a program that embodies these little people.  If it helps, get some paper and a pencil and sketch out a picture of the program.

Start up TG and use File -> New... to get going with this new program; for a file name, I suggest MastermindUI.jlogo.

Moving On to Writing the Program

I always like to get something very basic working, and then build on it.  So, the obvious first thing to do is paint/draw what the program looks like when it starts up.  In this case, Figure 12.7 shows what we need.  There is nothing in this figure that we do not know how to do.  We need to paint the color choices strip , an empty box, and what is called a button in graphical user interface terminology.  Drawing a button is simply drawing a rectangle with a label in it.

But, before I start writing a bunch of instructions, telling the turtle to draw this and that, I want to define some symbolic constants.  The first symbolic constants I'll type in are the colors and turtle headings I will need.  Then I'll define where different objects are on the graphics canvas.  This gets me both flexibility and readability and extends the vocabulary my program is composed from.  Great names for things is what writing an easy-to-read program is all about. 

I'm going to name the strip of colors that the user clicks on (to select from) colorChoices.  This choice of naming comes from my little people description above.  Everything that has anything to do with the color choice strip will have "colorChoice" in its name.  So, first I quickly define a few new procedures which can be used to draw the strip.

   to colorChoiceSize
     output 50
     end
   to colorChoicesLeftX
     output -125
     end 
   to colorChoicesMiddleX
     output sum colorChoicesLeftX (quotient colorChoiceSize 2)   
     end
   to colorChoicesTopY
     output product 3 colorChoiceSize
     end
   to redChoiceBottomY
     output difference colorChoicesTopY colorChoiceSize
     end
   to orangeChoiceBottomY
     output difference redChoiceBottomY colorChoiceSize
     end
   to yellowChoiceBottomY
     output difference orangeChoiceBottomY colorChoiceSize
     end
   ... 

Before you read on, take a bit of time to try to guess why I defined each of them.  What will each of these symbolic constants be used for?

What I was doing while I was defining the colorChoice symbolic constants was thinking about how I would draw the strip of colors.  I was thinking... "first I'll use setxy to position the turtle at the middle of the top of the strip."  Continuing, "then I'll set the turtle's heading to south, its pen size to colorChoiceSize, its pen color to red and then use the forward and setpencolor commands to draw the boxes, one color at a time."

But, I kept thinking ahead...  "I'm going to need to know where one color ends and a different color starts - so that I can determine which color the mouse was clicked on."  With this in mind, I switched my plan and defined a symbolic constant for the bottom Y coordinate of each color.  These can be used with sety commands to draw the strip - AND - I will be able to use them to determine which color is clicked on, when I get to writing that code.

Just a side question for you - do you know why I defined the xxxChoiceBottomY symbolic constants (where xxx is "orange," "yellow," etc...) as expressions involving colorChoiceSize?  Think about it.

Moving on, here is a bit of my code for drawing the strip of color choices.

   to paintColorChoices
     penup setxy colorChoicesMiddleX colorChoicesTopY pendown   
     setpensize colorChoiceSize
     setpencolor red sety redChoiceBottomY
     setpencolor orange sety orangeChoiceBottomY
     ... 

Exercise: Write Code for bigBox and clearButton

Now it is your turn to write some of the program.  Think about the names for the remaining objects, our little people, the box and the button.  Define some symbolic constants for each of them, their locations and their sizes.  Then write a paint procedure for each of these objects, e.g., paintClearButton

NOTE: there is a saying: Don't reinvent the wheel.  You already have written a procedure to draw a rectangle.  You know this procedure works.  Don't rewrite it yet again.  Copy and paste it into this program.

Finally, wrapup our first step by writing your main procedure.  Test the program...

Symmetry Helps You Write Programs That Do What You Want

Once you have main written and it's drawing the three objects in our user interface, it's time to move on to writing some code that implements our remaining little person, mouseClicked.

mouseClicked needs to check to see if the location where the mouse was clicked is in the boundaries of the colorChoice object or the clearButton object.  If so, mouseClicked needs to tell one of these little people about it.  Then it will be up to them to tell bigBox it needs to fill itself with the appropriate color.

One thing that is common to both colorChoice and clearButton is that they are both represented as rectangles.  When it makes sense, I always go with standards or commonly used models as the basis for parts of my programs.  Back in the lesson that introduced procedure inputs, I wrote the Logo equivilent of Java's drawRect procedure. In the BFOIT ItP lessons, I use Java standards where they fit.  So, my version of this project has drawRect and its sister fillRect at its core.  fillRect is a Java procedure which draws a rectangle filled with the current color.  Here they are the Logo equivilents of both of these procedures.

   ;draw the outline of a rectangle
   ;the top-left corner is at x,y
   to drawRect :x :y :width :height
     penup setxy :x :y pendown
     setheading east
     repeat 2 [forward :width right 90 forward :height right 90]   
     end

   ;fill the specified rectangular area
   ;the top-left corner is at x,y
   to fillRect :x :y :width :height
     penup setxy (sum :x (quotient :width 2)) :y pendown
     setpensize :width setheading south
     forward :height
     end 

So, what does all of this have to do with the mouseClicked procedure we need to write?

Well, since we need to check to see if the mouse was clicked in a rectangular object (either the colorChoice strip or the clearButton object), I'm going to write a procedure named mouseInRect?.  It will output true if the mouse was clicked in a specified rectangular area of TurtleSpace, otherwise it will output false.

Based on experience, it is much easier to get a program correct if similar procedures have similar structures and behaviors.  Since mouseInRect? will deal with rectangles, I want its structure to match the structure of my other rectangle procedures, as much as possible. 

Symmetry and consistancy are always good traits of well written programs.  I first talked about the importance of symmetry a long time ago in lesson 4 (Adding Commands) where we wrote a few procedure which drew letters.

In this case, I want the specification of the rectangle mouseInRect? works with to match the specification used in my drawRect and fillRect procedures.  This means it will have inputs x, y, width, and height which describe the rectangular area.  Here is the skeleton for what I want.

   ;output TRUE if last mouse click is within a rectangular area,
   ;otherwise output FALSE
   ;x is the left edge of the rectangular area, y is the top edge   
   ;width and height specify its size
   to mouseInRect? :x :y :width :height
     ...
     end 

I think that this procedure will be useful in many of the programs that I will be writing in the future.  So, once I get it working, it will save me time in the future.  But, if this is my intent - to write the procedure so that it can be reused in the future, I should generalize it a bit more.  How about writing a lower-level procedure that checks to see if a given x,y coordinate pair is within the boundaries of a rectangle?

Here's the skeleton I really want.

   ;output TRUE if point is within a rectangular area,
   ;otherwise output FALSE
   ;point is a sentence, an x,y coordinate pair
   ;x is the left edge of the rectangular area, y is the top edge   
   ;width and height specify its size
   to inRect? :point :x :y :width :height
     ...
     end 

This way, inRect? can be used with ANY point that I may want to check in a program, NOT just the mouse click position.  And, this makes writing mouseInRect? simple.  It becomes:

   to mouseInRect? :x :y :width :height
     output inRect? (sentence mousex mousey) :x :y :width :height   
     end 

The reason that I decided to represent the point as a sentence, instead of two separate x and y inputs, was that with a single input there is a clear distinction between the point and the specification for the rectangle.  The alternative would have resulted in two pairs of x,y coordinates, which could be confusing.  Back when I introduced sentences, I also introduced Logo's notion of representing a point in TurtleSpace, a position, as a sentence. So, here we have an example of where we can use this alternative representation to make our program more readable - the easier to read, the better...

Finishing the inRect? Operator

    Everything should be made as simple as possible, but not simpler.
                                               (Albert Einstein)
			

Now let's fill in the body of our inRect? operator.  Here is my pseudocode for what it needs to do.

  ;if the point's first member is greater than or equal to the :x input  
  ;and the point's last member is less than or equal to the :y input
  ;and the point's first member is less than the sum of :x and :width
  ;and the point's last member is greater than :y minus :height
  ;output "true 

I could write source code for this.  Logo does have AND and OR operators (I just haven't introduced them yet).  But, think about how complicated this expression would be.  Complexity is bad.  Simplicity is good.

One way to reduce the complexity is to use a hierarchy of operators.  I'm going to write a new operator which checks to see if a number in within some range of numbers.

   ;output TRUE if number is
   ;greater than or equal to floor and
   ;less than ceiling,
   ;otherwise output FALSE
   to inRange? :number :floor :ceiling
     if less? :number :floor [output "false]
     if less? :number :ceiling [output "true]   
     output "false
     end 

inRange? can be used to reduce the body of inRect? to one AND, a combination of x within the range of the rectangle's width and y within the range of the rectangle's height.

  and (inRange? (first :point) :x (sum :x :width))
      (inRange? (last :point) (difference :y :height) :y)  

But, there is a simpler implementation of the inRect? operator.  All we need to do is make four comparisons to see if the point is outside the rectangle.

  1. is the point is above the rectangle,
  2. is the point is below the rectangle,
  3. is the point is to the left of the rectangle, or
  4. is the point is to the right of the rectangle

If any of these comparisons return true then inRect? outputs false.  If all of these comparisons fail (output false), then inRect? outputs true.  Here's my inRect? operator.

 ;output TRUE if point is within a rectangular area, otherwise FALSE
 ;point is a sentence, an x,y coordinate pair
 ;x is the left edge of the rectangular area, y is the top edge
 ;width and height specify its size
 to inRect? :point :x :y :width :height
   if less? (first :point) :x [output "false]
   if greater? (last :point) :y [output "false]
   if greater? (first :point) sum :x (difference :width 1) [output "false]
   if less? (last :point) difference :y (difference :height 1) [output "false] 
   output "true
   end 

What's Left?
Putting It All Together

Reviewing what we have done, the first thing we did was to identify all of the objects our program consisted of.  I then described how I went about writing my procedure to paint the strip of color choices (paintColorChoices).  I left it up to you to write procedures to paint the bigBox and clearButton.

Next I talked about the importance of consistancy and symmetry in writing good programs and reviewed the drawRect procedure we previously wrote.  Then I showed a similar procedure, fillRect.  I did this hoping to show you how best to design another rectangular-oriented, a procedure that checks for a mouse click in a specified rectangular area.

Lastly, I ended this section by spending a bit of time showing a couple of ways that the procedure inRect? can be written.  What I hope you got out of this part of the project is a feeling for how good solutions can come from unexpected approaches.  Our task was to determine if a point was in a rectanglar area.  But, the simplest, most readable solution involved tests determining it the point was outside of the rectangle!  If it's outside, it can't be inside...

Figure 12.9 is a diagram that shows the structure of my program.  It contains all of the major procedures in my program; I've left out all of the symbolic constants.  The arrows represent invocations of a procedure.

Figure 12.9

As an example of how to read this diagram, look at the main box.  main invokes paintColorChoices, paintClearButtion, and paintBigBoxpaintBox invokes drawRect and fillRect.

mouseClicked has a slightly more complex arrangement.  Just in case you need a bit more help with the project, here is most of the body of my mouseClicked.

   to mouseClicked
     if mouseInRect? colorChoicesLeftX colorChoicesTopY... [colorChoice]   
     if mouseInRect? clearButtonLeftX clearButtonTopY... [clearButton]
     end 

What's missing (where the "..." is) are a couple of inputs that my mouseInRect? is expecting.  I gave you mouseInRect? so you should be able to figure out what I left out.  But, this is my code - you might have taken a slightly different approach, maybe the names of your symbolic constants are different.  As you must know by now, there are many ways to solve a given problem...

All right, now you are on your own.  Complete the project...

Looking Back

There are many ways to write this program and it is not obvious which approach is the best.  In this year's rewrite of these notes [2007], I changed the structure of the solution I described.  Looking back, I've written this program a few times over the past five or six years.  Each time, I think the new program is a bit more flexible, or a bit easier to read.

As an example regarding flexibility, let's look at how easy it is to make a change to to the program.  What if I was asked to change the size of the color choice boxes?  I just checked.  I changed the value of my colorChoiceSize symbolic constant - I changed 40 to 75.  The program worked!  The color choice strip was much bigger, almost twice as big; but everything worked just like the initial version of the program.  This is good...

So, why is this important?

Programs evolve.  We will extend this program in a future lesson when we write a game called Mastermind.  And, parts of programs you write can be copied into future programs you write.  I can copy the drawRect, fillRect, and inRect? into future programs.

Summary

In this lesson, you learned

  • about a new type of value, a boolean value.  Boolean values are represented by the symbols (words) true or false
  • about a new type of operator, a precicate, which outputs a boolean value.  The predicates we used in this lesson compared two inputs for equality (the equal? operator) and compared the relative magnitudes of two inputs (the less? and greater? operators)
  • about a new command if.  With it you learned how to do things only when some condition is true. 
  • how to get the location of the turtle.  The xcor and ycor operators output the X and Y coordinates (respectively) for the center pixel of where the current turtle is at in TurtleSpace.


Back to User Interface Events
Go to the Table of Contents
On to Recursion and Advanced Iteration

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.