- Commanding a Turtle
- Adding New Commands
- Iteration & Animation
- Hierarchical Structure
- Procedure Inputs
- Operators & Expressions
- Defining Operators
- Words & Sentences
- User Interface Events
- What If? (Predicates)
- Local Variables
- Global Variables
- Word/Sentence Iteration
- Mastermind Project
- Turtles As Actors
- File Input/Output
- A Java Program
- What's a Class?
- Extending Existing Classes
- Turtle Graphics
- Control Flow
- User Interface Events
- What Is TG?
- TG Directives
- jLogo Primitives
- TG Editor
- Java Tables
- Example Programs
- Installation Notes
- December 13, 2008
- January 6, 2012
- March 15, 2013
- January 20, 2014
- February 13, 2014
- July 29, 2014
- January 18, 2016
- January 29, 2016
What If? (Predicates)
"When you come to a fork in the road take it."
- Yogi Berra
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.
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.
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.
|value1 value2||Outputs "true if value1 is equal to value2, "false otherwise.|
|number1 number2||Outputs "true if number1 is greater than number2, "false otherwise.|
|number1 number2||Outputs "true if number1 is less than number2, "false otherwise.|
Figure 12.1 shows some example output values for these operators.
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.
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:
- the command name: "if"
- a <predicate>, and
- a <List-of-Instructions>
And, the syntax of a <List-of-Instructions> is:
- an open square bracket,
- <Instructions>, and
- a close square bracket
Here are a couple of examples of the IF command in action.
Use the following TG applet to try stuff out for yourself.
TG Programming Environment 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.
- Copy your GridToolkit program to one named TurtleInGridLand.
- Copy/Paste the following code into your TurtleInGridLand program.
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
- Change the gridNumCol procedure so that it outputs 12 instead of 8.
- Change the gridNumRow procedure so that it outputs 8 instead of 5.
- Start TG,
- choose the File->New menu item,
- Here is my version of TurtleInGridLand.jlogo. Copy/paste my code into TG's Editor,
- and use File->Save As... to write your new program out as the file TurtleInGridLand.jlogo
- Go back up to the TG applet,
- choose the Window->Canvas->Open menu item,
- choose the File->New menu item,
- shrink the Editor, then CommandCenter windows to minimum height,
- 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.
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!
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.
|XCOR||Outputs the turtle's X-coordinate.|
|YCOR||Outputs the turtle's Y-coordinate.|
Here is the skeleton of what I'm asking you to do.
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.
|Outputs true if both trueFalse1 AND trueFalse2 are true, false otherwise.|
|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.|
Figure 12.6 is an illustration of a standard coordinate system.
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.
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.
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
- a big box that is initially empty (white) but displays a specified color when asked to,
- 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
- 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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
- is the point is above the rectangle,
- is the point is below the rectangle,
- is the point is to the left of the rectangle, or
- 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.
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 call graph 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.
As an example of how to read this diagram, look at the main box. main invokes paintColorChoices, paintClearButtion, and paintBigBox. paintBox 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.
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...
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 , 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.
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.
Go to the Table of Contents
On to Recursion and Advanced Iteration