BFOIT

Introduction
to Programming

Predicates
  (Conditional Execution)  


*Note*    In 2007, these lessons were significantly modified.    *Note*
This is a link to the new materials.
This is a link to the new predicates lesson.


Introduction

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

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

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 performed is a procedure invocation, say to some procedure that you wrote, jLogo recalls your definition and performs 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

  1. about another kind of thing called a boolean value, which can have two values: the symbol true or the symbol false
  2. about primitive (built-in) operators in Logo which output a boolean value, called predicates
  3. 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: booleanBoolean 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 it either true or false - the boolean values.  In Logo, predicates are operators that output a boolean value.  Here are the first three predicates you'll need.

Procedure Inputs Description Example
EQUAL?
EQUALP
value1  value2 Outputs "true if value1 is equal to value2, "false otherwise. EQUAL? 15 0
GREATER?
GREATERP
value1  value2 Outputs "true if value1 is greater than value2, "false otherwise. GREATER? 10 5
LESS?
LESSP
value1  value2 Outputs "true if value1 is less than value2, "false otherwise. LESS? 1 4


IF - a Command Which Optionally Executes a List of Instruction

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


Use of IF - Directing Turtle Through a Maze

Now, checkout the key numbers in Table 9.1 for the arrow keys.

 Key Number   Keyboard Key 
128 Down-Arrow
129 Left-Arrow
130 Right-Arrow
131 Up-Arrow
Table 9.1

Change your keyPressed procedure such that


Use of IF in our Graphical Programs

Figure 10.1 shows the graphical images produced by a program I've written called splat.

Figure 10.1

The program draws four sets of rays projecting out from a center point.  It starts out with a few very thick rays of random length but guaranteed to be the longest.  Each other set progressively draws more, but shorter and thinner, rays.  Here's the core part of the program.  It's missing the definitions of the randomColor, randomRange, and ray procedures.  randomColor outputs a random number in the legal range for color numbers.  randomInRange is the procedure you wrote as an exercise back in the Output Command lesson.  The ray procedure has an input that is the length of a line to draw; it just moves the turtle forward this amount and then back the amount.


  to randomRay :minLen :maxLen
    setc randomColor
    ray randomInRange :minLen :maxLen
    end

  to splat :nRay :minLen :maxLen :width
    setpensize :width
    repeat :nRay [randomRay :minLen :maxLen right quotient 360 :nRay]
    end

  to main
    hideturtle
    splat 10 110 150 40
    splat 20 80 110 20
    splat 40 50 80 7
    splat 80 1 0 50
    end

Look closely at the images.  What's ruining them is that the background color, white, is getting chosen.  In the first image, the large, thick rays are missing at 180 degrees, 252 degrees, and 324 degrees.  What we need is a random color, excluding the background color - white.

I can use an if command to check for a random output that is equal to the color number for white.  When the comparison is true, I can substitute another color I like.  Here is a procedure, an operator, which accepts two color numbers as inputs.  The first is a random color number.  The second input is a color number to substitute for white.  It outputs the input color as long as it's not white.  If the first input, the random color number matches white, it outputs the second input.


  to white
    output 7
    end

  to randomColorXWhite :color1 :color2
    if equal? :color1 white [ output :color2 ]
    output :color1
    end

Here is the TG applet, type in a version of splat that generates patterns that do not include white.

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

What if you don't really want to favor one particular color?  We could just scrap the idea of a substitution and invoke randomColor again to get a different random color number.  Here's that code:


    to randomColorXWhite :color
      if equal? :color white [ output randomColor ]
      output :color
      end
  

This will work some of the time, but there is still the possibility that randomColor will pick white again, i.e., pick it two times in a row.  Well, I'm getting a bit ahead (we don't cover recursion for a couple lessons), but what about changing the "if" command to:


    if equal? :color white [ output randomColorXWhite randomColor ]
  

Does this work?  If not, why not?  If it does work, what's going on?


A User-Interface Project

Now that we have the IF command in our bag of tricks, we can start to do stuff that you see computer programs do all the time.  Let's start with a simple user interface that we can later extend into the Mastermind game.  Here is our user interface.

Figure 10.2

Our first pass at the interface consists of a strip of six colored boxes, a big empty frame, and a rectangle with the label "Clear Box" in it.  The first thing our program will 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 colored boxes, the program fills in the big frame with the color clicked-on.  Figure 10.3 shows what happens when the mouse is clicked within the red box.

Figure 10.3


Writing an init Procedure

So, this program is similar to the LabelPoints exercise in the previous lesson.  In particular, it doesn't need a main procedure.  I write a main procedure when my programs have a well-defined series of steps that are performed - without a graphical user interface (GUI).  When a GUI determines what the program does, the program needs a set of procedures to initialize the GUI, to draw everything.  But, once this is done, the program will wait for events generated by a user and respond to each of them in some way.  Generally, this means that the program needs a mouseClicked procedure to respond to the events created when a mouse button is clicked in TurtleSpace - the graphics area.

For these lessons, I'm always going to use the name "init" for the procedure that initializes a program - that gets it ready for servicing events.  For this exercise, init needs to draw a strip of colored boxes, a "Clear Box" button, and a big empty frame.


Program Consistency/Symmetry Helps Writing Correct Programs

Once you have init written and it's drawing the user interface, as shown in Figure 10.2, you can move on to writing mouseClicked.

mouseClicked needs to check to see if the location where the mouse was clicked is in any of the colored boxes or the "Clear Box" button.  If so, the large frame is filled in with the appropriate color.  So, what's a common operation that's needed?  How about writing an operation named "mouseInRect?" which returns true if the mouse was clicked in a specified area of TurtleSpace? 

One of the most important things in writing this program is to make sure the procedure you write to draw a box or a rectangle is similar to the procedure that checks to see if the mouse is in it.  What do I mean?

 It will be much easier to get the program right if your procedure which draws a frame is defined with the same inputs as your procedure which draws a solid colored box, which is defined with the same inputs as your mouseInRect? procedure.  Here are my suggested procedure skeletons.


  to drawFrame :x :y :width :height
    ;draw a rectangle with lower left corner at :x, :y
    end

  to drawSolidRect :x :y :width :height
    ;draw a colored-in rectangle with lower left corner at :x, :y
    end

  to mouseInRect? :x :y :width :height
    ;output true if the mouse is within the rectangle who's lower
    ;left corner is at :x, :y or false if it's outside the rectangle
    end

By doing this, when you draw a red box, you use the same inputs when you invoke drawSolidRect as you do when you invoke mouseInRect? to check to see if the mouse is in the red box.


Determining If mouseClicked Is In An Interesting Area

Let's fill in the body of mouseInRect? :x :y :width :height.  Here is my description of what it needs to do.

  ;if the mouse's X coordinate is equal to or greater-than the :x input
  ;and the mouse's Y coordinate is equal to or greater-than the :y input
  ;and the mouse's X coordinate is less-than the sum of :x and :width
  ;and the mouse's Y coordinate is less-than the sum of :y and :height
  ;output "true
Now, we could write source code for this.  Logo does have an AND operator (I just haven't covered it yet).  But, think about how complicated this expression would be.  The complexity could be reduced by using a hierarchy of operators you can write.  But, there's an easier way.  Let's take the opposite approach to the comparisons in out body!  What do I mean?  Here's part of the source code.

  to mouseInRect? :x :y :width :height
    if less? mousex :x [output "false]
    if less? mousey :y [output "false]
    ;if for mouse being to the right of the rectangle - outputs false
    ;if for mouse being above the rectangle - outputs false
    output "true
    end
In this case, we have four separate comparisons to see if the mouse is outside the rectangle and if it is we return false.  If all of the comparisons turn out wrong, I output "true since the mouse must be in the rectangle!


Built-in Operators For Combining/Manipulating Boolean Values

But just in case you really wanted to use the and boolean operator, I'll show you how I'd build mouseInRect? with it.  Since I've been programming for a long time, it immediately occured to me that I needed an operator that will be useful here and in other programs.  So, first I wrote an operator I named numberInRange?.

  to numberInRange? :number :min :max
    if greater? :number :min [output "false]
    if less? :number :min [output "false]
    output "true
    end
I tested it and once I was convinced it was working I made a first pass at a version of mouseInRect? that used it.

to mouseInRect? :x :y :width :height
  ;if and numberinRange? mousex :x sum :x difference :width 1
  ;       numberInRange? mousey :y sum :y difference :height 1
  ;   output true
  output "false
  end
In this case, the if invocation is just too long and complicated.   I decided to write two more operators, one for the mousex comparison and one for the mousey comparison.  Here they are.

to mousexInWidth? :x :width
  if numberInRange? mousex :x sum :x difference :width 1 [output "true]
  output "false
  end

to mouseyInHeight? :y :height
  if numberInRange? mousey :y sum :y difference :height 1 [output "true]
  output "false
  end
And with these operators, I re-entered a better version of mouseInRect?.

to mouseInRect? :x :y :width :height
  if and mousexInWidth? :x :width mouseyInHeight? :y :height [output "true]
  output "false
  end

Operator Inputs Description Example
AND trueFalse1  trueFalse2 Outputs true if trueFalse1 AND trueFalse2 are true, false otherwise.

 Input 1   Input 2   Output 
true true true
true false false
false true false
false false false

AND true true
NOT trueFalse Outputs false if trueFalse is true, else true if trueFalse is false - the opposite trueFalse value. NOT true
OR trueFalse1  trueFalse2 Outputs true if trueFalse1 OR trueFalse2 is true, false otherwise.

 Input 1   Input 2   Output 
true true true
true false true
false true true
false false false

OR false false


Exercise: MouseQuadrants

Here is an illustration of the standard coordinate system.

Write a program that draws the X and Y axes and, when the mouse is clicked on your image, displays the name of the quadrant where the mouse was when it was clicked.  As an example, if the mouse is clicked above the X axis and to the right of the Y axis, you should display "Quadrant I"


Summary

In this lesson, you learned how to do things only when certain conditions are true.  You learned how to compare two inputs for equality and magnitude with the equal?, less?, and greater? operators which output boolean values.  And, you've learned how to reverse and combine boolean values with the and, or, and not operators which also output a boolean value.


New Logo Procedures Used In This Lesson
Name Input Description Example
AND trueFalse1  trueFalse2 Outputs true if trueFalse1 AND trueFalse2 are true, false otherwise.

 Input 1   Input 2   Output 
true true true
true false false
false true false
false false false

AND true true
EQUAL?
EQUALP
value1  value2 Outputs "true if value1 is equal to value2, "false otherwise. EQUAL? 15 0
 GREATER? 
GREATERP
value1  value2 Outputs "true if value1 is greater than value2, "false otherwise. GREATER? 10 5
IF trueFalse
instructionList
If the trueFalse input is true, the instructionList input is performed. If trueFalse is false, nothing is done. IF LESS? MOUSEX 0 [ ... ]
LESS?
LESSP
value1  value2 Outputs "true if value1 is less than value2, "false otherwise. LESS? 1 4
NOT trueFalse Outputs false if trueFalse is true, else true if trueFalse is false - the opposite trueFalse value. NOT true
OR trueFalse1  trueFalse2 Outputs true if trueFalse1 OR trueFalse2 is true, false otherwise.

 Input 1   Input 2   Output 
true true true
true false true
false true true
false false false

OR false false


Back to Table of Contents
Back to previous Lesson ( Words and User Interface )
On to next Lesson ( Recursion )