Turtle, a pseudo Logo syntax

You have just seen that Forth (and as a matter of fact PF) allows you to describe a complex process by smashing it down to smaller ones which can be themselves described by even smaller definitions. So far you have seen how to play with bricks, here we're going to see how to make sense out of it.

A word is based on a definition, a definition is made out of words. Put together, words can be interpreted to make "sense". Working with a Forth based environment allows you not only to define words but let you choose how they will be interpreted by PF and how they will be interpreted by the human being who is going to use them.

As a result, you can build your own language and syntax on top of PF.

To understand this let's define some words that will allow us to interact with the drawing environment using a simplified/inspired Logo implementation. In a nutshell, in this tutorial we aim at writing a simple dictionnary for controling the moves of a turtle (we say turtle but if it makes you happy to think it's a squirel it's fine too).

As usual if you start a new PF session you need to initialize again the 2D drawing environment:

load-opengl             
512 512 display         
2d                      
drawing 

First of all we define our own cleanscreen function. This one comes with scale that is used to rescale the whole world geometry by 0.05. As a result the unit "1" doesn't define the whole height of the screen anymore but one 20th of it.

: clean  clearscreen 0.05 scale ;

Instead of using translations words we now use them within an "human interpreted" context. For example a forward move can be equivalent of doing a translation of one unit on the y axis. Even though describing your surrounding with geometrical transformations is more "correct", using more general concept can help a lot understanding a process. Think of it next time when you are asked to translate the kitchen table by -1.

: forward     1. ;
: backward   -1. ;
: left       -1. ;
: right       1. ;
: move    transy ;
: step    transx ;      

Finally we define an action to help us see where the turtle is :

: tag    0.8 square ;

In such a world system walking the turtle around to draw a square would look like this:

clean
tag
forward move tag
forward move tag
left step tag
left step tag
backward move tag
backward move tag
right step tag

The only flaw in this syntax is the confusion between step and move they share almost the same interpretation in and outside the machine. To make a proper syntax for this little turtle we should optimize the words and use move as the only translation method.

To do this we need to redefine everything using vectors. Vectors define both a magnitude and direction. To make it simple, instead of passing a number (like 1) to a translator specialized in only one axis (like transx) you pass three numbers (like 1 0 0, a 3 dimension x y z vector) to a universal translator named trans. In our case this will define our turtle's next move relatively to its current position.

In PF to create a vector you need to pass each of its components and their total number (dimensions) to the vector word. Once the vector is created you can pass it to the trans object which require as you may guess 3 dimensions (x, y, z).

Here are some examples using vector/trans and their transx/transy equivalents:

clean 1. transx tag
clean 1 0 0 3 vector trans tag
clean 1. transx 1. transy tag
clean 1 1 0 3 vector trans tag
clean 1. transx 1. transy -3. transx tag
clean -2 1 0 3 vector trans tag

Knowing that we can now redefined the words we previously created.

: forward     0.  1.  0.  ;
: backward    0. -1.  0.  ;
: left       -1.  0.  0.  ;
: right       1.  0.  0.  ;
: move  3 vector trans ;

With this updated set of words, you can make your turtle move forward, backward, left and right. The sad thing is that in this system based only on translations, your turtle always look in the same direction. One missing command is linked to rotation.

In order to limit the number of words used in this system we are going to find a way to re-use left and right and add turn to our dictionnary. As a consequence, the use of left turn means the turtle will rotate towards left using a predefined angle.

First we need to extract the direction from the left and right word and then apply this direction to a rotation.

We already know that we're only interested on the x axis so we can drop the 2 other components of the vector. Then we just need find the sign. Well easy you may think as the input data is either -1 or 1. Unfortunately if you want to redefine later the left and right vectors with greater values (say your turtle is on speed) then you will really need to find a way to isolate the sign as using the original x vector value will have influences on the rest of the process.

An easy way to isolate the sign of a number is to divide it by its absolute value. Knowing that we can define our new tool, the word sign.

: sign  dup abs / ;    # See the Forth introduction if you forgot about dup
-50 sign               # you can tryout your new toy ...
3.14 sign
-1976. sign

The left or right words used alone fill the stack with 3 integers. To create a rotation "towards left" we need to drop the 2 last entries in the stack, pass the value to sign and multiply the result to a predefined negative angle (-30°, rotations are anticlockwised based) that will be used by rotz.

: turn  drop drop sign -30. * rotz ;

Now you should be ready to play during hours with your new remotely controled turtle!

clean
backward move
backward move 
backward move 
backward move 
tag 
forward move
forward move tag 
forward move tag 
right turn forward move tag 
right turn forward move tag
left turn forward move tag 
left turn forward move tag 
left turn forward move tag 
left turn forward move tag 
left turn forward move tag 
left turn forward move tag 
left turn forward move tag

Attachments