Log in to post a comment.
var turtle = new Turtle(); turtle.radians(); var PI = Math.PI; var width = 1024; var height = 1024; var ANGLE; var START; var RULES = {}; var ITERATIONS; var turtle_length; var turtle_scale; var turtle_scale_factor = 1.5; if(Math.random() < 0.5){ // Half of the time, render snowflake ANGLE = 36/360*PI*2; START = 'F++F++F++F++F'; RULES = { 'F': 'F++F++F|F-F++F', }; ITERATIONS = 5; turtle_length = 0.2; turtle_scale = 2.3; turtle.up(); turtle.goto(-30,30); turtle.down(); } else { ANGLE = 40/360*PI*2; START = 'FX'; RULES = { 'X': '>[-FX]+FX', }; ITERATIONS = 8; turtle_length = 40; turtle_scale = 0.9; turtle.left(PI/2); turtle.up(); turtle.goto(0,40); turtle.down(); } var stack = []; var alphabet = { '+': function(){ // turn left turtle.left(ANGLE); }, '-': function(){ // turn right turtle.right(ANGLE); }, 'F': function(){ // go forward turtle.forward(turtle_scale * turtle_length); }, '0': function(){ }, '1': function(){ // go forward turtle.forward(turtle_scale * turtle_length); }, 'X': function(){ // do nothing }, 'Y': function(){ // do nothing }, '[': function(){ stack.push({ x: turtle.x(), y: turtle.y(), heading: turtle.heading(), turtle_scale: turtle_scale, }); }, ']': function(){ state = stack.pop(); turtle.up(); turtle.goto(state.x, state.y); turtle.setheading(state.heading); turtle.down(); turtle_scale = state.turtle_scale; }, 'A': function() {}, 'B': function() {}, 'M': function() {turtle.forward(turtle_scale * turtle_length);}, 'N': function() {turtle.forward(turtle_scale * turtle_length);}, 'O': function() {turtle.forward(turtle_scale * turtle_length);}, 'P': function() {turtle.forward(turtle_scale * turtle_length);}, '<': function() {turtle_scale *= turtle_scale_factor;}, '>': function() {turtle_scale /= turtle_scale_factor;}, '|': function() {turtle.right(PI)}, }; // Thanks to wikipedia for teaching me about l-systems: // https://en.wikipedia.org/wiki/L-system // Note: I learned from the L-system Wikipedia article that: // F means go forward // + means turn left by angle (which is 90 for Dragon curve) // - means turn left by same angle // X and Y mean \"do nothing\" // Their purpose is only to control the creation of the string // Produce the string // This means \"read the string\" and: // Replace X by something // Replace Y by something else // [...] // We start with an initial string. (Example: FX) function produce(initial){ let string = initial; for(let j = 0; j < string.length; j++){ let before = string.substr(0,j); let after = string.substr(j+1,string.length); for(let key in RULES){ if(string[j] == key){ string = before + RULES[key] + after; j += RULES[key].length-1; } } } return string; } function setup() { // For the dragon curve, we start with: string = START; execute_step = 0; // Generate the string only one time for(let i = 0; i < ITERATIONS; i++){ string = produce(string); } } // These are the actions we will take when executing the string // Used to keep track of current position in string var execute_step = 0; // Run some characters of the string function execute(string, steps_per_frame){ for(let i = 0; i < steps_per_frame && execute_step < string.length; i++){ // Reset turtle angle, background, etc at frame 0 try { // Execute the function at given letter alphabet[string[execute_step]](); } catch (e) { throw new Error("Error executing rule for: " + string[execute_step] + "\n" + e); } execute_step++; } } Canvas.setpenopacity(1); setup(); // The walk function will be called until it returns false. function walk(i) { let steps_per_frame = 1; execute(string, steps_per_frame); return i < 400000; }