Skip to content

Lindenmayer Snowflake Collection

By the end of this lab you'll be able to:

  • Build a library of different L-system rule sets and draw them in a grid
  • Compare how different rules produce visually distinct snowflake and fractal shapes
  • Understand how the same interpreter produces completely different results from different rules

Six different L-system snowflakes displayed in a 2×3 grid — Koch curve, Sierpiński arrowhead, hex gossamer, crystal, quadratic Koch, and dragon. Same interpreter, six completely different rule sets.

Welcome to the Snowflake Collection!

Monty waving welcome The same L-system interpreter draws completely different patterns just by changing the rules. This is the power of data-driven design! Let's build a collection of six snowflakes!

How It Works

An lsystem(axiom, rules, depth) function expands the axiom string. A draw_lsystem(sentence, step, angle, x, y, heading) function interprets and draws it. Six different (axiom, rules, angle, depth) combinations fill a grid.

Sample Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import turtle
import math
monty = turtle.Turtle()
monty.speed(0)
monty.hideturtle()

def expand(axiom, rules, depth):
    s = axiom
    for _ in range(depth):
        s = ''.join(rules.get(c, c) for c in s)
    return s

def draw(sentence, step, angle, x, y, heading):
    stack = []
    monty.penup(); monty.goto(x, y)
    monty.setheading(heading); monty.pendown()
    for c in sentence:
        if c in 'FG':
            monty.forward(step)
        elif c == '+':
            monty.left(angle)
        elif c == '-':
            monty.right(angle)
        elif c == '[':
            stack.append((monty.pos(), monty.heading()))
        elif c == ']':
            p, h = stack.pop()
            monty.penup(); monty.goto(p)
            monty.setheading(h); monty.pendown()

systems = [
    ('F', {'F': 'F+F-F-F+F'}, 3, 90, 4),
    ('F-G-G', {'F': 'F-G+F+G-F', 'G': 'GG'}, 4, 120, 5),
    ('F++F++F', {'F': 'F-F++F-F'}, 4, 60, 5),
    ('X', {'X': 'X+YF+', 'Y': '-FX-Y'}, 10, 90, 4),
    ('F', {'F': 'F+F-F-FF+F+F-F'}, 2, 90, 3),
    ('F', {'F': 'F+F-F-F+F', 'G': 'GG'}, 3, 90, 4),
]

positions = [(-160, 0), (0, 0), (160, 0), (-160, -130), (0, -130), (160, -130)]
colors = ['royalblue', 'crimson', 'forestgreen', 'darkorange', 'purple', 'teal']
steps = [5, 4, 5, 5, 6, 5]

for i, (axiom, rules, depth, angle, _step) in enumerate(systems):
    sentence = expand(axiom, rules, depth)
    x, y = positions[i]
    monty.pencolor(colors[i])
    monty.pensize(1)
    draw(sentence, steps[i], angle, x, y, 0)

What Do You Think Will Happen?

Monty thinking Six rule sets, six different angles (60° or 90°), six different depths. Will each snowflake look unique, or will they all look similar? Make your guess — then click Run to find out!

Try It Now


  

Six completely different shapes from six rule sets — Koch curve, Sierpiński, hex, dragon, quadratic Koch, and a plant. Same interpreter, different data. Were you right?

How It Works

''.join(rules.get(c, c) for c in s) uses a generator expression to replace each character with its rule (or itself if no rule exists). This is a one-liner L-system expander. The draw() function is a universal L-system turtle interpreter.

Explanation Table

Line What it does
''.join(rules.get(c,c) for c in s) One-step rule application
if c in 'FG' Both F and G are draw-forward commands
stack.append((pos, heading)) Save state at [
systems = [...] Each tuple: axiom, rules, depth, angle, unused

Learning Check

Your Turn — Add a Seventh System

Monty thinking Add a 7th L-system to the list using the Koch snowflake rules: axiom = 'F--F--F', rules = {'F': 'F+F--F+F'}, angle = 60, depth = 4. Where will you place it? Predict what it will look like!


  

The Koch snowflake — one of the most famous fractals, produced by a single two-character rule.

Experiments

  1. Increase depth on one system. Change one system's depth from 4 to 5. You'll know it worked when that fractal is more detailed (and takes longer to draw).

  2. Color by depth. In draw(), change the pen color each time F is called (cycling through a palette). You'll know it worked when the fractal has color gradients.

  3. Change all angles to 45. Some systems will look drastically different, some similar. You'll know it worked when the shapes change to 45°-based geometry.

  4. Design your own rule. Make up a new (axiom, rules, angle) combination and see what it produces. You'll know it worked when a new pattern appears.

A Gallery of Fractals!

Monty celebrating You built a universal L-system engine that draws any rule set! This is the power of separating data (rules) from algorithm (interpreter) — one program, infinite possible outputs. Up next: Generative Art Loop — the grand finale!