Sniff is a "Scratch-like" programming language that's designed to help Scratchers move gently from Scratch to more conventional languages. They can start writing programs, without having to learn a new language because Sniff is based on Scratch. They learn a little more about variables, compiling, syntax errors (!), and they can have fun controlling real hardware while they're doing it.

Sunday, 4 January 2015

More Turtles (and Fractals) Part 2

In the last post we set up a basic turtle system in Sniff and used it to draw some simple shapes. Now that its working lets draw some more complex things...

But before we do, lets consider first setting up a way of describing a shape, by making a rule for the turtle to follow. To keep things simple we can use a string of characters, at for now we'll just have three letters: "F" meaning move forwards and draw, "+" meaning turn left, and "-" meaning turn right. We could then set a distance and and angle to turn each time, and then tell the turtle to draw the shape.

Building that on top of what we did last time is pretty easy:

make rule string
make command string
make index number
make angleDelta number
when drawRule
.set index to 1
.repeat length of rule
..set command to letter index of rule
..change index by 1
..if command="F"
...set penDown to yes
...broadcast move and wait
..if command ="+"
...change direction by angleDelta
..if command ="-"

...change direction by -angleDelta

We have  a string called "rule" and we go through it one letter at a time, extracting that letter (command), then checking if its any of our drawing commands, and behaving appropriately. If we set angleDelta to 60, then we can draw a triangle with the code:

.set angleDelta to 60
.set rule to "F++F++F++"
.broadcast drawRule and wait

But now we've got this rule described by the "rule", what if we wrote some code to change that rule.
What if we went through and replaced each edge ("F") with the shape on the right? To do that we just need to change the string so that "F" becomes "F+F--F+". (To make sure we keep things the same size we also divide distance by three.)

make newRule string
when substitute
.set newRule to ""
. set index to 1
.repeat length of rule
..set command to letter index of rule
..change index by 1
..if command ="F"
...set newRule to join newRule "F-F++F-F"
...set newRule to join newRule command
.set rule to newRule

Much like the drawing code, we go through the string a letter at a time, and check it its "F", in which case we add the new fancy edge to the newRule, otherwise we just add the original letter. If we do this once, then we get a star, as each side of the triangle gets a little triangle added on. By why stop there - lets do the same to the new shape:

.repeat 4
..set displayColor to 000
..tell display to "clear"
..set distance to distance /3
..broadcast substitute and wait
..set displayColor to 777
..broadcast drawRule and wait
..wait 1 secs

In fact we can keep going forever (actually until we run out of memory!) replacing each new edge with a smaller edge with a triangle. What we end up with is an example of a Fractal, known as a Koch Snowflake. It has all sorts of neat properties. For example they tesselate(ish), and there are strange behaviours in term of its perimeter (which keeps getting bigger), and its area (which tends to a limit). 

We can do lots of fun things with this kind of rule rewriting. All we need to do is specify an initial rule (called an Axiom - meaning something we assume before we start), and a set of substitutions.

For example 
  • Axiom="FX"
  • X=>X+YF+
  • Y=>-FX-Y
produces a Dragon Curve.  You can just plug the Axiom and substituition rules into the Snowflake code and get a completely different shape. Set angleDelta to 90. You don't need to worry that we've got new letters in our rule - they work fine in the substitution phase and get ignored when drawing. Each time we substitute we get more detail added.

Another interesting shape is the Hilbert Curve:
  • Axiom="A"
  • A=>-BF+AFA+FB-
  • B=>+AF-BFB-FA+
  • angleDelta=90
Which produces something that looks like:

The cool thing about this one is that its "space filling". Given enough iterations it will completly fill up the square, even though its only a line. While that's a pretty cool just as a concept, its not just a neat mathematical trick: NASA have used this exact shape to design miniature radio antennae, as it clams a lot of wire into a small space!

One problem with building code like this is that the rules rapidly become very long. So long in fact that Sniff can throw away the last parts when the they get so long they won't fit in the allocated memory. If your Fractal stops drawing itself part way through, then edit the file $SNIFFDIR/lib/sniffDefs.h, and change the value for string length from 1024 to something bigger. On a PC there should be no problems setting this to 4096 or even bigger.

The idea if creating fancy patterns by rule rewriting was developed by a guy called Astrid Lindenmayer, so we call these kinds of rules Lindenmayer Systems, or L-Systems for short. The shapes we've drawn so far are among the most basic shapes that L-Systems can produce. However to see what L-Systems are really for you'll have to read the next blog post...

No comments:

Post a Comment