# Hilbert curve

Generic implementation of the Lindenmayer system:

``````require('Image::Magick')

class Turtle(
x      = 500,
y      = 500,
angle  = 0,
scale  = 1,
mirror = 1,
xoff   = 0,
yoff   = 0,
color  = 'black',
) {

has im = %O<Image::Magick>.new(size => "#{x}x#{y}")

method init {
}

method forward(r) {
var (newx, newy) = (x + r*sin(angle), y + r*-cos(angle))

im.Draw(
primitive => 'line',
points    => join(' ',
round(x    * scale + xoff),
round(y    * scale + yoff),
round(newx * scale + xoff),
round(newy * scale + yoff),
),
stroke      => color,
strokewidth => 1,
)

(x, y) = (newx, newy)
}

method save_as(filename) {
im.Write(filename)
}

method turn(theta) {
angle += theta*mirror
}

method state {
[x, y, angle, mirror]
}

method setstate(state) {
(x, y, angle, mirror) = state...
}

method mirror {
mirror.neg!
}
}

class LSystem(
angle  = 90,
scale  = 1,
xoff   = 0,
yoff   = 0,
len    = 5,
color  = 'black',
width  = 500,
height = 500,
turn   = 0,
) {
method execute(string, repetitions, filename, rules) {

var turtle = Turtle(
x:     width,
y:     height,
angle: turn,
scale: scale,
color: color,
xoff:  xoff,
yoff:  yoff,
)

var stack = []
var table = Hash(
'+' => { turtle.turn(theta) },
'-' => { turtle.turn(-theta) },
':' => { turtle.mirror },
'[' => { stack.push(turtle.state) },
']' => { turtle.setstate(stack.pop) },
)

repetitions.times {
string.gsub!(/(.)/, {|c| rules{c} \\ c })
}

string.each_char { |c|
if (table.contains(c)) {
table{c}.run
}
elsif (c.is_uppercase) {
turtle.forward(len)
}
}

turtle.save_as(filename)
}
}
``````

Generating the Hilbert curve:

``````var rules = Hash(
a => '-bF+aFa+Fb-',
b => '+aF-bFb-Fa+',
)

var lsys = LSystem(
width:  600,
height: 600,

xoff: -50,
yoff: -50,

len:   8,
angle: 90,
color: 'dark green',
)

lsys.execute('a', 6, "hilbert_curve.png", rules)
``````

Output image: Hilbert curve