Small World: A Little (More) Smalltalk

Lesson 4: Turtle Geometry

Turtle geometry refers to a system for teaching basic programming and math skills using the programming language Logo. The idea was popularized by Harold Abelson and Andrea diSessa in a book of the same name published by the MIT Press in the 1980's. The idea is to allow the programmer (typically a young student) to write simple programs, such as the following:

   sam <- self newTurtle.
sam penDown.
1 to: 100 do: [:i |
sam move: i. sam turn: 30. self repaint. 300 sleep ]

which can be used to produce interesting graphics, such as the following

Our version of Turtle geometry is very simple, and is intended to illustrate one again how to create applications using the class Application. But our simple class can be used as a basis for creating much more robust systems.

Our application will be based on two classes, Turtle, and TurtleWorld. The class TurtleWorld will be the application class. It is created as a subclass of Application, with a single instance variable named "world". (Refer to the previous lesson to figure out how to create a new class with instance variables). The whole of TurtleWorld is found in three methods:

start
world <- Image size: 400@400.
self title: 'Turtle World' size: 400@400 pane: (Pane image: world)

run | sam |
sam <- self newTurtle.
sam moveTo: 200@200.
sam penDown.
1 to: 100 do: [:i |
sam move: i. sam turn: 30. self repaint. 300 sleep ]

newTurtle | t |
t <- Turtle new.
t drawOn: world.
^ t

The method start creates an Image on which the turtle will live. It is this image that is stored in the instance variable named world. The method run is the script that drives the turtle. It is this method that users will modify to make the turtle perform different actions. A small utility method named newTurtle allows users to create a turtle to run on the playing surface. It is possible to create more than one turtle.

A turtle is a simple drawing device. A turtle has a heading (expressed in degrees) and a pen. The pen can be either up or down. Expessed as a Small World class a turtle is a subclass of Object that has four instance variables: location, heading, penStatus, and drawingImage. There is one metaclass method used to initialize the turtle, as follows:

new | r |
r <- super new.
r penUp.
r moveTo: 0@0.
r heading: 0.
^ r

This method creates a turtle, sets the pen to the up position, and moves the turtle to a given initial position and heading. The numerous methods in class Turtle simple change these values:

drawOn: img
drawingImage <- img

heading
^ heading

heading: h
heading <- h

move: amount
self moveTo: location +
((amount * heading sin) asInteger @
(amount * heading cos) asInteger)

moveTo: newLoc
(penStatus and: [ drawingImage notNil] ) ifTrue:
[ drawingImage at: location drawLine: newLoc ].
location <- newLoc

penDown
penStatus <- true

penUp
penStatus <- false

turn: amount
heading <- heading + amount degreesToRadians

The method degreesToRadians is used to convert the turning amount from a degree value into a radian, as the methods sin and cos interpret their base as a radian. Drawing is performed as a side effect of the method moveto. If there is a pen and a drawing image, a line is drawn as the turtle moves to a new location.

You may have noticed the calls on repaint and sleep in the earlier script in the method run. Actually, these are unnecessary. However, without them the end result will appear all at once. By inserting the explicit calls to repaint and to sleep, the turtle is slowed down and the results appear bit by bit, making it easier for the student to see what is going on. (It perhaps might have been better to have the turtle automatically sleep after every move).

Lots of variations are possible. Our turtle doesn't have an image - you could create one. The pen isn't adjustable, it should have a variety of widths and effects. Many other ideas can be expressed using turtle. See the literature both in Logo and in Smalltalk that use turtle-like ideas.