This Turtle allows up to 5 rules (X, Y, Z, F, G). Per such character you can set the rule for it while processing and the meaning of it in the resulting set after processing (while drawing). By default X, Y and Z are for rule evaluation only while F and G also draw when they end up in the evaluated result.
+ and - tell the turtle to turn right and left by angle.
The brackets [ and ] store the state and retrieve that state respectively, which is effectively branching.
So valid characters in rules are: X, Y, Z, F, G, [, ], + and -. More info on variables on mouseover.
en.wikipedia.org/wiki/l-system
Default for this turtle is the Hilbert Curve, gallery image is Dekking's Church: Yet another L-System ⛪ (variation)
Show me your results in the comments!
Log in to post a comment.
/* Yet another L-System - By Jurgen Westerhof 2024 https://turtletoy.net/turtle/2db175d4c4 This Turtle allows up to 5 rules (X, Y, Z, F, G). Per such character you can set the rule for it while processing and the meaning of it in the resulting set after processing (while drawing). By default X, Y and Z are for rule evaluation only while F and G also draw when they end up in the evaluated result. + and - tell the turtle to turn right and left by angle. The brackets [ and ] store the state and retrieve that state respectively, which is effectively branching. So valid characters in rules are: X, Y, Z, F, G, [, ], + and -. More info on variables on mouseover. https://en.wikipedia.org/wiki/L-system Default for this turtle is the Hilbert Curve, gallery image is Dekking's Church: https://turtletoy.net/turtle/2db175d4c4#n=11,axiom=@R1pZWA,X=@LS1GKytZK0YtWi0tRisrWStGLVo,Y=@LS1GKytZLUYrWA,Z=@RkctRitY,F=@,G=@RkctRitYRkcrRi1a,onG=0 Show me your results in the comments! Factal Binary Tree: https://turtletoy.net/turtle/2db175d4c4#n=9,axiom=@Rg,F=@R1srRl0tRg,G=@R0c,angle=45,rotation=225 Von Koch: - Curve: https://turtletoy.net/turtle/2db175d4c4#n=9,axiom=@Rg,F=@RitG4oiS4oiSRitG,angle=60,rotation=135 - (4, 1/3) curve: https://turtletoy.net/turtle/2db175d4c4#axiom=@Rg,F=@Ri1GK0YrRi1G - Flake: https://turtletoy.net/turtle/2db175d4c4#axiom=@RisrRisrRg,F=@Ri1GKytGLUY,angle=60 Sierpiński: - Triangle: https://turtletoy.net/turtle/2db175d4c4#n=6,axiom=@Ri1HLUc,F=@Ri1HK0YrRy1G,G=@R0c,angle=120 - Triangle 2: https://turtletoy.net/turtle/2db175d4c4#n=7,axiom=@Rg,F=@Ry1GLUc,G=@RitHK0Y,angle=60 - Carpet: https://turtletoy.net/turtle/2db175d4c4#axiom=@Rg,F=@RitGLUYtRi1HK0YrRitGLUY,G=@R0dH,onG=1,rotation=45 - Median Curve: https://turtletoy.net/turtle/2db175d4c4#n=12,axiom=@WC0tRi0tWC0tRg,X=@K1ktRi1ZKw,Y=@LVgrRitYLQ,angle=45,rotation=45 - Square: https://turtletoy.net/turtle/2db175d4c4#axiom=@RitYRitGK1hG,X=@WEYtRitGLVhGK0YrWEYtRitGLVg,rotation=45 - Pentagon: https://turtletoy.net/turtle/2db175d4c4#axiom=@RitGK0YrRitG,F=@RitGWytGXS0tRitG,angle=72 Pentaflake: https://turtletoy.net/turtle/2db175d4c4#axiom=@RisrRisrRisrRisrRg,F=@RisrRisrRisrKysrRi1GKytG,angle=36 Dragon Curve: https://turtletoy.net/turtle/2db175d4c4#n=16,axiom=@Rg,F=@RitH,G=@Ri1H Fractal Plant: https://turtletoy.net/turtle/2db175d4c4#n=7,X=@RitbW1hdLVhdLUZbLUZYXStY,F=@RkY,angle=25,rotation=245 Hilbert Curve: https://turtletoy.net/turtle/2db175d4c4#n=6 Gosper: https://turtletoy.net/turtle/2db175d4c4#n=4,X=@WC1ZLS1ZK1grK1hYK1kt,Y=@K1gtWVktLVktWCsrWCtZ,angle=60,onX=2,onY=2 Lévy C Curve: https://turtletoy.net/turtle/2db175d4c4#n=15,axiom=@Rg,F=@K0YtLUYr,angle=45 Snowflake: https://turtletoy.net/turtle/2db175d4c4#n=4,axiom=@Ri1GLUYtRi1G,F=@Ri1GKytGK0YtRi1G,angle=72 Peano: - Curve 1: https://turtletoy.net/turtle/2db175d4c4#n=4,X=@WEZZRlgrRitZRlhGWeKIkkbiiJJYRllGWA,Y=@WUZYRlniiJJG4oiSWEZZRlgrRitZRlhGWQ - Curve 2: https://turtletoy.net/turtle/2db175d4c4#n=4,axiom=@Rg,F=@RitGLUYtRkYtRi1GLUZG,rotation=45 Davis-Knuth Terdragon: https://turtletoy.net/turtle/2db175d4c4#n=8,axiom=@Rg,F=@K0YtLS0tRisrKytGLQ,angle=30 - alternative: https://turtletoy.net/turtle/2db175d4c4#n=8,axiom=@Rg,F=@RuKIkkYrRg,angle=120 Dekking: - Quadratic Gosper: https://turtletoy.net/turtle/2db175d4c4#n=3,axiom=@LVlG,X=@WEZYLVlGLVlGK0ZYK0ZYLVlGLVlGRlgrWUYrRlhGWFlGLUZYK1lGK0ZYRlgrWUYtRlhZRi1ZRi1GWCtGWCtZRllGLQ,Y=@K0ZYRlgtWUYtWUYrRlgrRlhZRitGWC1ZRllGLUZYLVlGK0ZYWUZZRi1GWC1ZRkZYK0ZYK1lGLVlGLUZYK0ZYK1lGWQ - Church: https://turtletoy.net/turtle/2db175d4c4#n=11,axiom=@R1pZWA,X=@LS1GKytZK0YtWi0tRisrWStGLVo,Y=@LS1GKytZLUYrWA,Z=@RkctRitY,F=@,G=@RkctRitYRkcrRi1a,onG=0 */ const n = 5; //min=0 max=20 step=1 The number of rule application iterations const axiom = 'X'; //type=string The axiom of the L-system const X = '-YF+XFX+FY-'; //type=string Evolution rule for X, + is right, - is left, [ and ] can be used for branching const Y = '+XF-YFY-FX+'; //type=string Evolution rule for Y, + is right, - is left, [ and ] can be used for branching const Z = 'Z'; //type=string Evolution rule for Z, + is right, - is left, [ and ] can be used for branching const F = 'F'; //type=string Evolution rule for F, + is right, - is left, [ and ] can be used for branching const G = 'G'; //type=string Evolution rule for G, + is right, - is left, [ and ] can be used for branching const angle = 90; //min=0 max=360 step=1 The angle to turn left (- character) or right (+ character) const onX = 0; //min=0 max=2 step=1 (Apply rules only (no moving or drawing), Apply rules and move forward (no drawing), Apply rules and draw while moving forward) const onY = 0; //min=0 max=2 step=1 (Apply rules only (no moving or drawing), Apply rules and move forward (no drawing), Apply rules and draw while moving forward) const onZ = 0; //min=0 max=2 step=1 (Apply rules only (no moving or drawing), Apply rules and move forward (no drawing), Apply rules and draw while moving forward) const onF = 2; //min=0 max=2 step=1 (Apply rules only (no moving or drawing), Apply rules and move forward (no drawing), Apply rules and draw while moving forward) const onG = 2; //min=0 max=2 step=1 (Apply rules only (no moving or drawing), Apply rules and move forward (no drawing), Apply rules and draw while moving forward) const rotation = 0; //min=0 max=360 step=1 Rotate the result Canvas.setpenopacity(1); loadLSystem(); const rules = { X: [X, onX], Y: [Y, onY], Z: [Z, onZ], F: [F, onF], G: [G, onG], } const ls = new LSystem(axiom, rules, angle).process(n); const turtle = initializeCenteredScaledTurtleForLSystem(ls, rotation); function walk(i) { ls.drawNext(turtle); return ls.hasNext(); } function loadLSystem() { this.LSystemActions = {RulesOnly: 0, RulesMove: 1, RulesMoveDraw: 2} class LSystem { // processing #rules = {}; #wip = []; //instructions result #result = ''; //drawing #angle = 90; #distance = 1; #cmdPointer = 0; #states = []; //methods constructor(axiom, rules, angle) { this.#rules = Object.assign(this.#rules, rules); this.#wip = axiom.split(''); this.#result = axiom; this.#angle = angle; } process(iterations = 1) { for (let i = 0; i < iterations; i++) { this.#wip = this.#wip.flatMap(e => (e in this.#rules)? this.#rules[e][0].split(''): [e]); } this.#result = this.#wip.join(''); return this; } scale(scale) { this.#distance = scale; } next() { return this.#wip[this.#cmdPointer++]; } hasNext() { return this.#cmdPointer < this.#wip.length; } drawNext(turtle, dryrun = false) { const cmd = this.next(); switch (cmd) { case "+": return turtle.right(this.#angle); case "−": case "-": return turtle.left(this.#angle); case "[": return this.#states.push([turtle.pos(), turtle.h()]); case "]": return [this.#states.pop()].forEach(s => {turtle.jump(s[0]); turtle.seth(s[1]);}); case 'X': case 'Y': case 'Z': case 'F': case 'G': switch(this.#rules[cmd][1]) { case LSystemActions.RulesMove: turtle.up(); case LSystemActions.RulesMoveDraw: turtle.forward(this.#distance); if(!dryrun) turtle.down(); case LSystemActions.RulesOnly: default: } default: return; } } resetDraw() { this.#cmdPointer = 0; } } this.LSystem = LSystem; function initializeCenteredScaledTurtleForLSystem(ls, rotation) { const turtle = new MeasuringTurtle(); turtle.up(); turtle.seth(rotation); while(ls.hasNext()) { ls.drawNext(turtle, true); } ls.resetDraw(); const box = turtle.getBox(); const distance = 190 / Math.max(box.width, box.height); ls.scale(distance) const t = new Turtle(-box.center[0] * distance, -box.center[1] * distance); t.seth(rotation); t.down(); return t; } this.initializeCenteredScaledTurtleForLSystem = initializeCenteredScaledTurtleForLSystem; } function MeasuringTurtle(x, y) { class MeasuringTurtle extends Turtle { box = [[0,0], [0,0]]; constructor(x, y) { super(x, y); } goto(x, y) { super.goto(x, y); if(this.box === undefined) this.resetBox(); const p = this.pos(); this.box[0][0] = Math.min(this.box[0][0], p[0]); this.box[0][1] = Math.min(this.box[0][1], p[1]); this.box[1][0] = Math.max(this.box[1][0], p[0]); this.box[1][1] = Math.max(this.box[1][1], p[1]); } resetBox() { this.box = [this.pos(),this.pos()]; } getBox() { return { 0: [...this.box[0]], 1: [...this.box[1]], width: this.box[1][0] - this.box[0][0], height: this.box[1][1] - this.box[0][1], topLeft: [...this.box[0]], bottomRight: [...this.box[1]], center: [this.box[0][0]+(this.box[1][0] - this.box[0][0])/2, this.box[0][1]+(this.box[1][1] - this.box[0][1])/2] }; } } return new MeasuringTurtle(x, y); }