163,243-- Create a new turtle "object" with the given parameters. -- step_size: How far the turtle moves with the F command. -- angle_inc: The turn amount (in degrees) for +/- commands. function make_turtle(step_size, angle_inc) return {d=step_size, a=math.rad(angle_inc), width=2} end -- Move the given turtle to point (x,y) facing angle a (degrees). function place_turtle(turtle, x, y, a) turtle.x = x turtle.y = y turtle.facing = math.rad(a) end -- Draw a path from the turtles current position to its next position, -- taking into account its step size and current direction. function draw_forward(turtle) local new_x = turtle.x + turtle.d * math.cos(turtle.facing) local new_y = turtle.y - turtle.d * math.sin(turtle.facing) local p = path(turtle.x, turtle.y, new_x, new_y) p.strokeWidth = turtle.width turtle.x, turtle.y = new_x, new_y end -- Turn the turtle right (CCW) by its angle increment. function right(turtle) turtle.facing = turtle.facing - turtle.a end -- Turn the turtle left (CW) by its angle increment. function left(turtle) turtle.facing = turtle.facing + turtle.a end -- Push the current turtle state to the top of a stack. function push(turtle) if turtle.stack == nil then turtle.stack = {} end table.insert(turtle.stack, {x = turtle.x, y = turtle.y, facing = turtle.facing, width = turtle.width}) end -- Pop the turtle state from the tock of the stack and apply it. function pop(turtle) local val = turtle.stack[#turtle.stack] table.remove(turtle.stack) turtle.x = val.x turtle.y = val.y turtle.facing = val.facing turtle.width = val.width end -- Mapping of command character to turtle action. local actions = { ["F"] = function(turtle) draw_forward(turtle) end, ["-"] = function(turtle) left(turtle) end, ["+"] = function(turtle) right(turtle) end, ["["] = function(turtle) push(turtle) end, ["]"] = function(turtle) pop(turtle) end } -- Drive the turtle according to the given direction string. function drive_turtle(turtle, directions) for char in directions:gmatch(".") do local fnc = actions[char] if fnc ~= nil then fnc(turtle) end end if turtle.path ~= nil then turtle.path.closed = true end end -- Run the L-system productions n times on the given "initial" string (the axiom). -- Return the resulting command string. function run_productions(initial, productions, n) local acc = initial for i = 1, n do -- For each char in acc, replace it and append to new acc. -- then swap acc = newacc local newacc = "" for char in acc:gmatch(".") do local repl = productions[char] if repl ~= nil then newacc = newacc .. repl else newacc = newacc .. char end end acc = newacc end return acc end local directions = run_productions("F-", { ["F"] = "FF+F" }, 3) local t = make_turtle(30, 90) place_turtle(t, 100, 100, 90) drive_turtle(t, directions) ellipse(100, 100, 1, 1) Layer 1