This chapter first appeared in ANTIC as two articles implementing a turtle graphics system in Forth.
Let me make two quick points about FORTH:
- Doing this project in any other computer language would have been so involved that I would never have done it, and so lengthy that this magazine would never have published it.
- Doing it in FORTH was so easy it took me considerably longer to write the English for this article than the FORTH!
Turtle Graphics Versus Coordinate Graphics"Turtle Graphics" is a simple but powerful approach to creating graphic designs with a computer. It was originally developed in the 1960's at MIT-primarily by computer scientist, child psychologist, and educator Seymour Papert -as part of the LOGO system.
Let me give you a very simple example of how it works. Suppose we want to draw a square on the screen, 10 units on a side. The sequence of commands
10 DRAW 90 TURN 10 DRAW 90 TURN 10 DRAW 90 TURN 10 DRAW 90 TURNor, in a shorter form,
4 ( 10 DRAW 90 TURN )requests an imaginary turtle on the screen to crawl 10 units forward, draw a line as it goes, turn 90 degrees clockwise, repeat four times. The turtle will leave behind a square.
DEFINE SQUARE AS A ( 10 MOVE 90 TURN ) ENDwe can add the new command SQUARE to our turtle's graphics repertoire. Then typing the single command SQUARE will have the same effect as our previous sequence of commands. For example, to draw a square tilted by thirty degrees, we need only to type
30 TURNThe conventional approach to graphics, in which one must specify fixed screen coordinates and the endpoints of each line is much more complicated.
The principle advantage of Turtle Graphics is that it describes shapes in an intrinsic way, without referring to where they are or how they're oriented. The numbers used in Turtle Graphics represent easily visualizable things, like lengths of lines, or angles.
A further important aspect of a Turtle Graphics system is the nature of the programming it encourages: structured, modular, and hierarchichal. The DEFINE . . . AS . . . END construct shown above is the key to this. Basic subdesigns can be made into new turtle commands which are then as much a part of the turtle's language as the predefined system commands. These higher-level commands can then be used to define still higher ones, and so on.
For example, a simple picture of a house like that in Figure 1 could be drawn with a long sequence of DRAWs and TURNs (along with another command for the turtle to move without drawing). But the structure of the design cries out for the programmer to instead first enrich the turtle's vocabulary by defining commands such as, perhaps, RECTANGLE, WINDOW, DOOR, FRONT, AND ROOF, before using these higher-level command to define one called HOUSE.
The FORTH AdvantageFORTH is so ideally suited to Turtle Graphics that, in a sense, implementing it is a trivial exercise.
The most complicated aspect of Turtle Graphics is the problem of providing a programming environment in which turtle commands can be executed. Such a capability is already intrinsic to FORTH, while it is quite foreign to conventional languages like BASIC.
The point here is that the turtle's language can be just an extension of the FORTH language-turtle commands are simply FORTH words. There is no need to write an extensible command language processor. That's what a FORTH system already is!
What the Screens ContainThe ten screens of FORTH listed in this article lay the necessary foundations for us to build a Turtle Graphics system in Part 2 (next issue). The words here are not specifically turtle-oriented. Rather, they extend FORTH's capabilities in directions particularly useful to the application.
Screens 1, 2, and 3 add some trigonometric capability to FORTH. If the turtle is to move 10 units forward at 30 degrees from the vertical, we need to compute how far up and how far over she goes. For this we use a lookup-table approach. Scaling the values by 10000 enables us to store them as single-precision integers. The words SIN* and COS* are the result of this. For example,
10 30 SIN
leaves 5, or 10 times the sine of 30 degrees, on the stack; and this is how far over the turtle would move.
Screen 4a makes available a defining word, VALUE, for a new data type. An alternative to CONSTANT and VARIABLE, VALUE words tend to make FORTH code more readable. They are best explained by the following example:
VALUE A VALUE B VALUE C ok 2 TO A 3 TO B ok A . B . 2 3 ok AB + TO C C . 5 okVALUE words return their value when executed, except when they are preceded by TO; in which case they store the top of the stack into themselves. (This idea has been discussed in the FORTH DIMENSIONS newsletter of the Forth Interest Group.)
In screen 4a the words TO and VALUE are defined in assembly language, rather than FORTH, so that they will execute as fast as CONSTANTs and VARIABLEs. If you don't have an assembler, use the alternate FORTH code on screen 4b.
Screens 5 through 8, culminating in the word CLIP, implement a line-dipping algorithm. We want the turtle to be able to cross the edge of the screen, so that if we execute SQUARE when she is near the top we'll get a clipped box. But the opearing system will refuse to draw a line whose endpoints aren't both within the screen boundaries. Therefore, we must be able to calculate the endpoints of the portion of the line which lies on the screen. If we give CLIP the coordinates of two points, it first determines whether any part of the line between them lies within a "dipping rectangle" whose extent we can specify by setting the values of LEFT, RIGHT, TOP, and BOTTOM. (Note that these words are in the vocabulary CLIPPING). If so, it returns the coordinates of the endpoints of the portion within the dipping rectangle, and a true flag. If not, it returns only a false flag.
For example, suppose we set the dipping rectangle to be the size of the mode-7 graphics screen with
CLIPPING 0 TO LEFT 159 TO RIGHT 0 TO TOP 79 TO BOTTOMThen
30 30 50 50 CLIP
leaves 30 30 50 50 1 on the stack because the line between (30,30) and (50,50) is completely within the dipping rectangle. But
80 100 200 40 CLIP
leaves 122 79 159 61 1 because only the portion between (122,79) and (159,61) of the specified line lies inside the dipping rectangle. And
200 200 300 300 CLIP
leaves 0 because no part of the line lies inside. The Cohen-Sutherland algorithm that CLIP uses is described in detail in Chapter 5, "Clipping and Windowing", of Newman and Sproull's Principles of Interactive Computer Graphics.
The last screen, number 9, defines the word GRAPHICS for opening the screen in the graphics mode specified by the top the stack, and LINE, which takes the coordinates of two endpoints and draws the clipped part of it on the screen.
If you want to see the dipping in action, before the rest of the code is given in Part 2, try the following: Define the words BORDER, RANDOM_LINE, and RANDOM_ LINES as
: BORDER CLIPPING 1 COLOR LEFT BOTTOM PLOT LEFT TOP DRAWTO RIGHT TOP DRAWTO RIGHT BOTTOM DRAWTO LEFT BOTTOM DRAWTO ; : RANDOM LINE 4 0 DO CRANDOM LOOP LINE ; : RANDOM_LINES 0 DO RANDOM_LINE LOOP ;and then type
CLIPPING 20 TO LEFT 140 TO RIGHT 20 TO TOP 60 TO BOTTOM 7 GRAPHICS BORDER 100 RANDOM_LINES
The Inhabitants And Language Of TurtlelandFour independent turtles live in Turtleland. Multiple turtles open up interesting possibilities, like having turtles chase each other. With four turtles, each can draw in a different color (there are only four colors possible at one time). If you want a different number, you can change the value of the constant #TURTLES on screen 2 before loading. One turtle at a time can be designated the "active turtle" with the SET ACTIVE command. She is the one who will respond when we type a command like "10 DRAW."
Each turtle carries a pen. The active turtle's pen can be lowered with the PENDOWN command, leaving a trail when she moves, or raised with the PENUP command. The more general SET PEN command can be used to do either.
The SET INK command fills the active turtle's pen wtih various colors of ink, depending on the Graphics Mode used. (Modes 3 through 8 can be selected with the SET MODE command.) In all modes, ink of type 0 is erasing ink. It is black, the same color as the background, except in Mode 8 when it is light blue. The command, ERASING, is the same as 0 SET INK. Both choose erasing ink. In Modes 3, 5, and 7, there is also ink of type 1 (gold), type 2 (light green), and type 3 (dark blue). In Modes 4, 6, and 8, types 2 and 3 are not available. The number of ink types is determined by the color video capabilities of the CTIA or GTIA chip. The colors are established by the Operating System when it opens the screen. You can use pns-Forth SETCOLOR word to- change them.
Each turtle has a position and a heading. The heading is the number of degrees clockwise from the vertical that she is facing. The active turtle's heading can be changed directly to any value with SET HEADING, also known as TURNTO, or it can be changed incrementally by the commands RIGHT (or TURN) and LEFT.
The system keeps track of each turtle's position with X and Y coordinates. These are not the same as the screen column and row numbers. The SET MODE command arranges these coordinates so that the turtle's home al X=0 and Y=0 is the center of the screen, and so that there are one hundred X or Y units per pixel. This means that if a turtle is at X = 1000 and Y = 500 she will appear ten pixels to thl right and five pixels up from the center. You can arrange the coordinates differently if you wish.
The active turtle's coordinates can be individually or jointly set with the commands SET X, SET Y, or SET POSITION (also known as GOTO). They cause the turtle to leave a track only if her pen is down. MOVETO can be used to temporarily raise the pen, or DRAWTO to lower it, before changing position. The pen is restored to its original state after the change.
The most interesting way to move the active turtle is with FORWARD, BACKWARD, DRAW, and MOVE commands. These move her a specified number of steps in whatever direction she is currently heading. FORWARD and BACKWARD draw a line only it the pen is down; DRAW always draws; MOVE never does. Each step normally moves the turtle one pixel, a distance of 100 units in XY coordinates, unless you use the SET SIZE command to alter the step size. By changing the step size you can use the same word -to draw the same shape in different sizes.
A turtle's heading and her XY coordinates are always integers. The maximum range for X and Y is from -32768 to 32767. If you drive a turtle beyond this range you may see unwanted tracks as she "jumps" to the other edge of Turtleland.
Usually you can't see all of Turtleland on the screen. For example: in Mode 7 the screen displays only the part of Turtleland from X =15900 to X = 15800 and from Y = -7900 to Y = 7800. You can select your own "window" into Turtleland with SET WINDOW command. Any tracks beyond the edges of the window won't be visible. Changing the window will affect the number of X or Y units per pixel. An alternate way to set the window (and the step size) is with the PERPIXEL command.
The reason that the system defaults to 100 units per pixel is to let the turtle sit "between" pixels. If we used a coordinate system as coarse as the screen pixels, then every time we moved a turtle at some angle, her new position would get "rounded" to the nearest pixel. We wouldn't be able to do a series of moves without errors accumulating. Using one hundred XY units per pixel gives us increased precision.
The SET MODE command establishes the whole screen as the "viewport" This means that the view of Turtleland visible through the window will be projected onto all of the screen. You can select any rectangular piece of the screen to be the viewport with the SET VIEWPORT command. When you experiment with this, use the FRAME or NEW commands to draw a frame around the new viewport so you can see where it is.
So far, four commands-MODE, SIZE, WINDOW, and VIEWPORT- relate to Turtleland as a whole, and seven of them-ACTIVE, PEN, INK, HEADING, X, Y, and POSITION- relate to the turtles. It is also possible for you to determine the current value of any of these parameters, by leaving out the word SET or by changing it to SHOW. For example, the command X by itself (i.e., not preceded by SET) leaves the active turtle's current X coordinate on the stack, where it can be used by any word for any purpose. So, the command SHOW X will display some message like "Turtle #1 is at X=300".
The system also has miscellaneous commands like CLEAR for clearing the screen, FRAME for drawing a frame around your picture, and HOME, START, and NEW for starting over. The command BYE leaves Turtleland and returns to pns-Forth.
Of course, all the usual Forth words are still available while you're in Turtleland, in case you need to do arithmetic, comparisons, branching, looping, or whatever. You can use the more compact loop syntax ( . . . ) and ( . . . + ) in place of the structures 0 DO . . . LOOP and 0 DO... + LOOP.
The important command DEFINE . . . AS . . . END allows you to add new words to the turtle's vocabulary. This makes it very easy to change any of my command names that you don't like.
As an interesting example, you might want to
DEFINE HILDA AS 1 SET ACTIVE END DEFINE GILDA AS 2 SET ACTIVE END DEFINE MATILDA AS 3 SET ACTIVE END
so that you can talk to a turtle simply by invoking her name.
Using the SystemTo start turtle-ing, just use the SET MODE command. If you want to have Turtleland displayed in Graphics Mode 7, for example, type 7 SET MODE. After this you can immediately move the turtles around with 10 DRAW, 45 TURN, etc. SET MODE initializes the system as follows:
- All four turtles are home at X=0 and Y = 0, with heading 0 degrees.
- They all have their pens down.
- Their pens are filled with various ink types as described under the
START command in the glossary. -Turtle #1 is active.
- The window is such that X = 0, Y =0 is in the center of the screen and
there are 100 X or Y units per pixel.
- The viewport is the whole screen.
DEFINE POLYSPI AS
0 TO STEPS
STEPS INCREMENT + TO STEPS
POLYSPI can make all sorts of interesting polygonal spirals. It expects to find two numbers on the stack. It stores the top one in ANGLE; this will be how many degrees the turtle will turn between each move. The one below gets stored in INCREMENT; this will be how many more steps the turtle will take each time compared to the previous time. Next STEPS is initialized to 0 and we enter a Forth BEGIN . . . AGAIN loop. The words between BEGIN and AGAIN will be executed indefinitely. (You must press a yellow console button to stop POLYSPI.) Each time through the loop, STEPS is incremented by INCREMENT, and the turtle takes the number of steps in STEPS and turns the number of degrees in ANGLE. Thus POLYSPI is just an automated sequence of FORWARDs and TURNs. For example, 2 90 POLYSPI is really the same as
2 FORWARD 90 TURN
4 FORWARD 90 TURN
6 FORWARD 90 TURN
and so on.The three VALUE words POLYSPI uies make it easy to see what's going on. However, another definition of POLYSPI is possible which uses no variables at all:
DEFINE POLYSPI AS
3 PICK +
This version keeps everything on the stack, using the Forth words PICK, DUP, and OVER for stack manipulation. You can make a variety of patterns with this one command by changing its two parameters.
Pressing a yellow console button will break out of an indefinite loop of turtle moves. In fact, every time a turtle changes position, the system checks the console buttons and returns to command level if one is depressed. This makes it easy to regain control.
As mentioned in Part I, ten of the words used in my screens are pnsForth words which won't be available (at least not with the same meanings) in other Forth systems. Two of these, 1and TABLE, are common Forth extensions whose high-level definitions are
+ + @;
The last four words specific to pnsForth are CL#, COLOR, PLOT, and DRAWTO. These are used by LINE , FRAME, and POSITION. The first two are simple to define; just use
0 VARIABLE CL#
: COLOR DUP CL# ! PAD C! ;
CL# is a variable which is used to keep track of the color data used to plot a pixel. COLOR takes a number from the stack and stores it both in CL# and at PAD, for later use by PLOT and DRAWTO. The definitions of PLOT and DRAWTO are complicated because these words result in calls to CIO. Again, however, their functions are simple and your system probably provides similar words. Define a PLOT which takes a column and a row number from the stack, moves the screen cursor to that position, and plots a pixel there using whatever byte is at PAD as the color data. Similarly, define a DRAWTO which takes a column and a row number from the stack, and draws a line from the current position of the screen cursor to this specified position, using the byte at PAD as color data.
I believe that all the other words I've used in this system are either standard fig-Forth words or new words that I've defined.
Glossary of Turtle Commands
MODE CommandsSET MODE [ mode --- ] Opens the screen in the Graphics Mode specified by mode, which should be 3-8. Sets up a default viewport, window, and step size by executing WHOILE SCREEN SET VIEWPORT and 100 PER-PIXEL. Draws a frame around the viewport with ink of type 1. Initializes the turtles by executing START.
MODE [--- mode 1 I.eaves the number of the current Graphics Mode on the stack.
SHOW MODE [ --- ] Displays a message indicating the current Graphics Mode.
ACTIVE CommandsSET ACTIVE [ turtle# ---] Makes the turtle whose number is turtle# the active turtle. Future commands will be directed to her.
ACTIVE [--- turtle# ] I.eaves the number of the active turtle on the stack.
SHOW ACTIVE [ --- ] Displays a message indicating the currently active turtle.
PEN CommandsSET PEN [ state --- ] l.owers the active turtle's pen if state is nonzero and raises it if state is zero.
PEN [--- state 1 I.eaves I on the stack if the active turtle's pen is down and 0 if it is up.
SHOW PEN [ --- ] Displays a message indicating whether the active turtle's pen is up or down.
INK CommandsSET INK [ ink# ] Fills the active turtle's pen with ink of type ink# . Type () ink is erasing ink. Types 1, 2, and 3 are colored Typcs 2 alld 3 are not available in rnodes 4, 6, or S.
INK [--- illk# 1 I.eaves on thc stack the type of ink in the active turtle's pen .
SHOW INK [ --- ] Displays a message indicating the type of ink in the active turtle's pen.
HEADING CommandsSET HEADING [ degrees --- ] Makes the active turtle head in the direction specified by degrees . Directions are measured clockwise from the vertical.
HEADING [--- degrees 1 I.eaves the active turtle's headmg on the stack.
SHOW HEADING [ --- ] Displays a message indicating the active turtle's heading.
X CommandsSET X [ x --- ] Changes the active turtle's X coordinate to x . I)raws a line if her pen is down.
X [ x ] leaves the active turtle's X coordinate on the stack.
SHOW X [ --- ] Displays a message indicating the active turtle's X coordinate.
POSITION CommandsSET POSITION [ x y --- ] Changes the active turtle's coordmates to X = x and Y = y . Draws a line if her pen is down.
POSITION [--- x y ] I eaves the activc turtle's X and Y coordimltes on the stack.
SHOW POSITION [ --- ] Displays a message indicating the active turtle's X and Y coordinates.
SIZE CommandsSET SIZE [ distance steps --- ] Sets the step size so that the number of steps given by steps will cover a distance in XY coordinates given by distance
SIZE [--- distallce steps ] I.eaves the current size parameters on the steack.
SHOW SIZE [ --- ] Dispiays a message indicating the current step size.
WINDOW CommandsSET WINDOW [ xmin xmax ymin ymax ---] Sets the window to be the region from X = xmin to X = xmax and from Y = ymin to Y = ymax .
WINDOW [--- xmin xmax ymin ymax ] I.eaves the current window parameters on the stack.
SHOW WINDOW [ --- ] Displays a message indicating the current window.
VIEWPORT CommandsSET VIEWPORT [ left right top bottom --- ] Sets the viewport to extend from screen column left to screen column right and from screen row top to screen row bottom.
WHOLE-SCREEN SET VIEWPORT [ --- ] Sets the viewport to extend from column I to the next to the hlst column and from row :I to the next to the last row.
VIEWPORT [--- left right top bottom ] I.eaves the current viewport parameters on the stack.
SHOW VIEWPORT [ --- ] Displays a message indicating the current viewport.
Y CommandsSimilar to X Commands
Other CommandsCLEAR [ --- ] Clears the graphics screen without affecting the turtles.
FRAME [ ink# --- ] Draw a frame ilround the viewport, using ink of type ink#
HOME [ --- ] Moves the active turtle to X = () and Y = () with heading (), without drawing a line, and then lowers her pen .
START [--- ] HOMEs all the turtles first. Then fills their pens with ink. (In mode 3, 5, or 7, the Nth turtle's pen is filled with ink of type N. In mode 2, 4, or 6, turtle's 0's pen is filled with type 0 ink while the pens of turtles I, 2, and 3 are filled with type ] ink, the only colored ink available in these modes.) Finally, makes turtle 1 the active turtle .
NEW [ --- ] Clears the screen, draws a frame with type 1 ink, and initializes the turtles by executing START.
PER-PIXEL [ distance --- ] Sets the window so that the point X = (), Y = 0 is the center of the viewport, and so that the distance in XY coordinates given by distance will be the size of one pixel. Also, sets the step size so that each step is distance units long.
FORWARD [ steps --- ] Moves the active turtle forward the number of steps specified by steps . The movement is in the direction she is currently heading if steps is positive and in the opposite direction if steps is negative. The turtle's heading is unaffected. A line is drawn if her pen is down.
BACKWARD [ steps --- ] Like FORWARD except in the opposite direction.
DRAW [ steps --- ] Lowers the active turtle's pen so that a line will definitely be drawn as she moves forward the number of steps given by steps . Then her pen is returned to its prevlous state.
MOVE [ steps --- ] Raises the active turtle's pen so that a line will definitely not be drawn as she moves forward the number of steps given by steps . Then her pen is returned to its previous state.
RIGHT [ degrees --- ] Turns the active turtle the specifiefd number of degrees, to the right if degrees is positive and to the left if negatlve.
LEFT [ degrees --- ] Like RIGHT except in the opposite direction.
TURN [ degrees --- ] The same as RIGHT.
GOTO [ x y --- ] The same as SET POSITION.
DRAWTO [ x y --- ] I.owers the active turtle's pen so that a line will definitely be drawn as she moves toX= x andY= y . Then her pen is returned to its previous state.
MOVETO [ x y --- ] Raises the active turtle's pen so that a line will definitely not be drawn as she moves to X= x and Y= y . Then her pen is returned to its previous state.
TURNTO [ degrees --- ] The same as SET HEADING.
PENDOWN [ --- ] I.owers the active turtle's pen. This is the same as 1 SET PENSTATE.
PENUP [ --- ] Raises the active turtle's pen This is the same as 0 SET PENSTATE .
PENDOWN? [--- flag ] Leaves a 1 on the stack if the active turtle's pen is down and a 0 if it is up. This is the same as PEN.
PENUP? [--- flag ] Leaves a 1 on the stack if the active turtle's pen is up and a 0 if it is down. This is the opposite of PEN.
ERASING [ --- ] Fills the active turtle's pen with type 0 ink (the erasing type.) This is the same as 0 SET INK.
(...) [ #loops --- ] Executes the words between the left parenthesis and the right parenthesis the number of times given by #loops .
DEFINE...AS...END Defines the word between DEFINE and AS to be a new turtle command which will execute the words between AS and END.
BYE [---] Leaves Turtleland and returns to pns-Forth.
by Gordon Smith