BFOIT

Introduction
to Programming

Predicates
  (Conditional Execution)  


Introduction

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

Think about how the TurtleGraphics applet (or TG application) performs your programs.  Instructions are executed from left to right on each line.  Lines are executed one after another down the page.  When the instruction to be executed is a procedure invocation, say to some procedure that you wrote, TurtleGraphics remembers where it is, performs the instructions in the procedure, then comes back and picks up where it left off.  All of the instructions in your program get executed.

What if you only want some of your instructions to be interpreted when certain things are true?

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 TurtleTalk which produce a boolean output, called predicates
  3. about the if TurtleTalk command which expects two inputs, a predicate and a list of TurtleTalk instructions.  The list is only executed if the predicate produces a "true" value


Boolean Values

In our program for this lesson, you need to do some things only when certain conditions are true. To do this we will 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 TurtleTalk 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 - our boolean values.  In TurtleTalk, predicates are operators that produce a boolean value as their output.  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 Interprets TurtleTalk

TurtleTalk has a way of interpreting a list of procedures only when a specified condition is true.  The syntax of the TurtleTalk 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:

   [       <TurtleTalk-Instructions>       ]   

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


Use of IF in our Graphical Programs

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

Figure 9.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 9.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 mouseclick 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 9.3 shows what happens when the mouse is clicked within the red box.

Figure 9.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 mouseclick 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 9.2, you can move on to writing mouseclick.

mouseclick 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 mouseclick 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 TurtleTalk source code for this.  TurtleTalk 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 produce 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 TurtleTalk 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 ( TurtleTalk Words and User Interface )
On to next Lesson ( TurtleTalk Recursion )