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;
}