Forth Factory
Turtle Graphics, Part 2
By Gordon SmithThis is the second of two articles on implementing a Turtle Graphics system in Forth. The first one appeared in ANTIC issue #3. It discussed Turtle Graphics in general, explained why Forth is a particularly hospitable environment for a Turtle Graphics system, and gave nine screens worth of "foundation" words.
With this artcle are 17 more screens of pns-Forth source code which complete the system. I'll give an overview of the system's features; a glossary of Turtle commands, and give a few suggestions on using the system.
The Inhabitants And Language Of Turtleland
Four 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 SystemW
To start turtle-in ,, 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.
After you get acquainted with the various commands, you'll want to start extending the system by defining your own. Here is an example of a new command:
VALUE STEPS VALUE INCREMENT VALUE ANGLE
DEFINE POLYSPI AS TO ANGLE TO INCREMENT 0 TO STEPS BEGIN STEPS INCREMENT + TO STEPS STEPS FORWARD ANGLE, TURN AGAIN END
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
BEGIN 3 PICK + DUP FORWARD OVER TURN AGAIN END
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
:1- 1-; and
: TABLE
The others are highly systemspecific. Four of them-SETUP S, CLOSE S,
SPLIT-SCREEN, and GR. -were used in the word GRAPHICS in Part I. Their
definitions are quite complex, as these words are part of pns-Forth's
interface to the CIO routines in the Operating System. Their joint
effect in the word GRAPHICS, however, is quite simple. Any Forth system
sold for the ATARI will probably have words for opening the screen for
graphics. Simply use whatever your system provides to define your own
GRAPHICS, which takes one number from the stack and opens the screen in
that mode, with a text window at the bottom.
The last four words specific to pnsForth are CL#, COLOR, PLOT, and
DRAWTO. These are used by LINE (in Part I), FRAME, and POSITION. The first
two are simple to define; just use
0 VARIABLE CL#
and
: 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.
[CODE]
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 [--- turtle# ] I.eaves the number of the active turtle on the stack.
SHOW ACTIVE [ --- ] Displays a message indicating the currently active turtle.
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 [--- 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 [--- degrees 1 I.eaves the active turtle's headmg on the stack.
SHOW HEADING [ --- ] Displays a message indicating the active turtle's
heading.
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 [--- 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 [--- distallce steps ] I.eaves the current size parameters on the
steack.
SHOW SIZE [ --- ] Dispiays a message indicating the current step size.
WINDOW [--- xmin xmax ymin ymax ] I.eaves the current window parameters
on the stack.
SHOW WINDOW [ --- ] Displays a message indicating the current window.
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.
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 --- ] I owers 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 --- ] I..ike 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? [--- flaK ] I.eaves 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 I 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 [---1 Ieaves Turtleland and returns to pns-Forth.
Glossary of Turtle Commands
MODE Commands
SET 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.ACTIVE Commands
SET ACTIVE [ turtle# ---] Makes the turtle whose number
is turtle# the active turtle. Future commands will be directed to her.PEN Commands
SET PEN [ state --- ] l.owers the active turtle's pen if
state is nonzero and raises it if state is zero.INK Commands
SET 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.HEADING Commands
SET HEADING [ degrees --- ] Makes the active turtle head in the direction
specified by degrees . Directions are measured clockwise from the
vertical.X Commands
SET X [ x --- ] Changes the active turtle's X coordinate to x . I)raws
a line if her pen is down.POSITION Commands
SET POSITION [ x y --- ] Changes the active turtle's coordmates to X = x and Y = y . Draws a
line if her pen is down.SIZE Commands
SET 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 distanceWINDOW Commands
SET 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 .VIEWPORT Commands
SET 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.Y Commands
Similar to X CommandsOther Commands
CLEAR [ --- ] Clears the graphics screen without affecting the turtles.