Learning Goals
3 minBy the end of this lesson you can:
- Define the Koch curve recursively: each line becomes four shorter lines at angles +60°, -120°, +60°.
- Build a Koch curve function in turtle that recurses to a given depth.
- Compose three Koch curves into a snowflake by turning -120° between them.
- Recognise how perimeter grows infinitely while area stays bounded.
Warm-Up · The Koch Recipe
5 minA line, depth 0: ─────────
depth 1 — replace with 4 lines: /\
───/ \───
depth 2 — replace EACH of those 4 lines:
smaller bumps on every segment
depth 3 — replace each of those new lines:
even smaller bumps everywhereEach line is replaced by four lines, each ⅓ the length. After 5 levels, the curve has 4⁵ = 1024 tiny segments.
The Koch curve is self-similar like yesterday's tree — but instead of branching off the trunk, the recursion replaces each line with a more complex version of itself.
New Concept · The Koch Function
14 minThe base case · just draw a line
def koch(length, depth): if depth == 0: t.forward(length) return # ... recursive case below
The recursive case · four shorter lines
Each line at depth N gets replaced by four lines at depth N-1, each ⅓ as long. The turn pattern is +60°, -120°, +60° — between the four segments.
def koch(length, depth): if depth == 0: t.forward(length) return third = length / 3 koch(third, depth - 1) t.left(60) koch(third, depth - 1) t.right(120) koch(third, depth - 1) t.left(60) koch(third, depth - 1)
Five lines of recursive code. Four self-calls. Three angle changes. Beautiful.
The angles · why 60 and 120?
Imagine the bump is an equilateral triangle:
/\ peak is 60° rotation from the base
/ \ the two slopes are 60° on each side
___/ \___ after the peak, turn -120° to come back down
(back to the original heading at the end)Net heading change: +60 -120 +60 = 0. The end of each koch call leaves the turtle facing the same way it started — essential for stacking.
The full snowflake
A snowflake = three Koch curves forming a triangle. Between each, turn -120° (since the triangle's exterior angle is 120°).
def snowflake(length, depth): for _ in range(3): koch(length, depth) t.right(120)
Three sides. Each side is a Koch curve. Together they form a closed snowflake.
The infinite-perimeter paradox
At each level, the total perimeter grows by 4/3 (each segment becomes 4 ⅓-length segments). After infinite iterations the perimeter is infinite — but the snowflake fits inside a finite circle. An infinitely-long boundary enclosing a finite area. Maths is wild.
You won't see the infinity on your screen — at depth 5, segments are about 1 pixel long and the recursion just renders solid-looking lines.
Worked Example · The Snowflake
12 minSave as snowflake.py:
# snowflake.py — Koch snowflake at depth 4 import turtle as t screen = t.Screen() screen.setup(width=800, height=800) screen.bgcolor("midnightblue") screen.colormode(255) t.speed(0) t.hideturtle() t.color(220, 240, 255) # icy white-blue t.pensize(2) def koch(length, depth): if depth == 0: t.forward(length) return third = length / 3 koch(third, depth - 1) t.left(60) koch(third, depth - 1) t.right(120) koch(third, depth - 1) t.left(60) koch(third, depth - 1) def snowflake(length, depth): for _ in range(3): koch(length, depth) t.right(120) # Position so it's centred t.penup() t.goto(-250, 150) t.setheading(0) t.pendown() snowflake(length=500, depth=4) t.done()
What you'll see
A glowing snowflake on a dark blue background. At depth 4 you can pick out individual bumps; at depth 5 the curve looks almost smooth.
Read the diff
Two functions, one outer loop. koch is purely recursive. snowflake just runs koch three times with a 120° turn between. Total recursive calls at depth 4: 4⁴ × 3 = 768. The image emerges from 768 tiny forward() calls, all positioned automatically by the recursion.
Depth 4: 256 segments per side, fast. Depth 5: 1024, slower but smoother. Depth 6: 4096 — minutes to draw. Past 6, segments are sub-pixel and you can't tell. t.speed(0) is non-negotiable.
Basic
5 minComment out the snowflake call. Just draw koch(600, 4). Look at the bumpy line on its own.
Challenge 1
4 minChange the bumps to go inward instead of outward. Swap the left/right calls. You get an "anti-snowflake".
Hint
def koch_inward(length, depth): if depth == 0: t.forward(length) return third = length / 3 koch_inward(third, depth - 1) t.right(60) # changed from left koch_inward(third, depth - 1) t.left(120) # changed from right koch_inward(third, depth - 1) t.right(60) # changed from left koch_inward(third, depth - 1)
Bumps point inwards. The shape looks more like a star or a snowflake-with-jagged-cuts.
Challenge 2
4 minReplace each line with FIVE shorter lines in a square bump pattern (up, across, down, across, up — back to base). The angles are +90°, -90°, -90°, +90°. Apply recursively.
Hint
def koch_square(length, depth): if depth == 0: t.forward(length) return fifth = length / 5 # not 4 — see below koch_square(fifth, depth - 1) t.left(90) koch_square(fifth, depth - 1) t.right(90) koch_square(fifth, depth - 1) t.right(90) koch_square(fifth, depth - 1) t.left(90) koch_square(fifth, depth - 1)
5 segments, ⅕ length each. The angles +90-90-90+90 net to 0 — the turtle ends facing forward again.
Challenge 3 · Five-Snowflake Gallery
8 minDraw five snowflakes in a row, at depths 0, 1, 2, 3, 4. The viewer sees the recursion grow before their eyes — what depth 0 looks like (a triangle), depth 1 (a Star of David), depth 2-4 (increasingly bumpy snowflakes).
Show one possible solution
# gallery.py — five snowflakes at depths 0-4 import turtle as t screen = t.Screen() screen.setup(width=1400, height=400) screen.bgcolor("midnightblue") screen.colormode(255) t.speed(0) t.hideturtle() t.color(220, 240, 255) def koch(length, depth): if depth == 0: t.forward(length) return third = length / 3 koch(third, depth - 1) t.left(60) koch(third, depth - 1) t.right(120) koch(third, depth - 1) t.left(60) koch(third, depth - 1) def snowflake(length, depth): for _ in range(3): koch(length, depth) t.right(120) def jump_to(x, y): t.penup() t.goto(x, y) t.setheading(0) t.pendown() for i, depth in enumerate(range(5)): jump_to(-650 + i * 260, 80) snowflake(length=180, depth=depth) t.done()
Non-negotiables: one koch + one snowflake function, called five times in a row at depths 0-4. The progression is the point — viewers SEE what depth changes do.
Recap
3 minThe Koch curve is a line-replacement recursion. Each line becomes four shorter lines with angles +60°, -120°, +60°. Three Koch curves with 120° turns between form a snowflake. Each call returns the turtle to its original heading. Depth budget: 4-5 is usually right for screen-size drawings; past 6 segments are sub-pixel. Mathematically infinite perimeter, finite area — fractal weirdness.
Vocabulary Card
- Koch curve
- The line-replacement fractal. Each line becomes four shorter lines.
- Koch snowflake
- Three Koch curves arranged as the sides of a triangle.
- line replacement
- The recursion shape: substitute each segment with a smaller version of a more complex shape.
- heading preservation
- The recursive function's angle changes net to zero — turtle ends pointing the same way.
Extra Mission
4 minBuild my_fractal.py with two variations:
- Star Koch snowflake. Same code, but apply the koch transformation to each side of a 5-sided star instead of a 3-sided triangle. Turn 144° between sides (5-point star external angle).
- Random-bump Koch. The bump can go in either direction (up or down) at random. Use
random.choicefor the sign of the angle. Run with a seed; you get organic-looking coastlines.
Sample · random-bump Koch (coastline)
import random def koch_random(length, depth): if depth == 0: t.forward(length) return third = length / 3 sign = random.choice([1, -1]) # bump up or down at random koch_random(third, depth - 1) t.left(60 * sign) koch_random(third, depth - 1) t.right(120 * sign) koch_random(third, depth - 1) t.left(60 * sign) koch_random(third, depth - 1) random.seed(42) koch_random(800, 5) t.done()
Non-negotiables: a Koch variant that either changes the polygon (star) or randomises the bump direction. Different seeds → different coastlines from the same code.