Learning Goals
3 minBy the end of this lesson you can:
- Draw any regular polygon with one
forloop using the formula angle = 360 / sides. - Build a square spiral by growing the forward distance each iteration.
- Use nested loops to stamp a polygon many times around the centre — making flowers and rosettes.
- Tune step counts and angles to design your own patterns.
Warm-Up · The Polygon Formula
5 minEvery regular polygon obeys one rule:
exterior_angle = 360 / number_of_sides
For a triangle, that's 360/3 = 120°. For a square, 360/4 = 90°. For an octagon, 360/8 = 45°. Type and verify:
import turtle as t sides = 6 # change me! for _ in range(sides): t.forward(80) t.right(360 / sides) t.done()
Try the values 3, 4, 5, 6, 8, 12, 36. At 36 sides the shape looks like a circle — and at 360 it is a circle (to your eye, at least).
A for loop turns "type the same lines N times" into "type them once with N in a variable". Every turtle pattern lives inside one of these loops.
New Concept · Three Loop Shapes
14 minShape 1 · The polygon loop
Repeat forward, turn exactly n times. Same forward, same turn — that gives you a regular polygon.
def polygon(sides, length=80): for _ in range(sides): t.forward(length) t.right(360 / sides) polygon(3, 100) # triangle polygon(8, 50) # octagon polygon(12, 30) # dodecagon
Shape 2 · The growing spiral
What if the forward distance changes each iteration? You get a spiral.
# Square spiral — same 90° turn, growing forward import turtle as t for n in range(50): t.forward(n * 5) t.right(90) t.done()
Change the turn from 90° to 91° and the spiral starts to twist into a rose. Try it.
Shape 3 · The rosette · nested loop
Stamp a polygon, then turn a bit, then stamp it again. Repeat until you've gone all the way round. That makes a flower.
import turtle as t t.speed(0) for _ in range(36): # 36 stamps around the centre for _ in range(4): # one square per stamp t.forward(80) t.right(90) t.right(360 / 36) # turn a bit before next square t.done()
The outer loop chooses how many copies of the inner shape go around the circle. 360 / count = the angle between them.
The three knobs
KNOB What it changes sides in inner loop The base shape (triangle, square, hex…) side length The size of each stamp 360 / outer count The number of stamps around the centre
Tune any one of those three numbers and you get a totally different pattern. That's what makes turtle art so meditative — endless variation from a tiny dial.
One important habit · speed(0)
For any pattern with more than ~20 turtle moves, set t.speed(0). Without it, you'll watch a turtle plod for ten minutes.
Worked Example · Spiral of Polygons
12 minThe story
One drawing that combines polygons, spirals and rosettes. Save as spiral.py:
# spiral.py — spiral of growing hexagons import turtle as t t.speed(0) t.bgcolor("black") t.color("cyan") t.pensize(2) def hexagon(length): for _ in range(6): t.forward(length) t.right(60) # 360 / 6 count = 36 for i in range(count): hexagon(20 + i * 3) # each hex bigger than the last t.right(360 / count) # turn a bit between hexes t.done()
What you'll see: a cyan rosette where each "petal" is a hexagon, and each next hexagon is bigger than the last. The whole thing fans out around the centre.
Read the diff
Two patterns nested. The hexagon function uses the polygon-loop trick. The main loop calls it 36 times, growing the side length and turning between calls. Three knobs in one file: 6 sides in the inner loop, 20 + i × 3 growth, 360/36 between stamps. Change any one of them and the whole picture changes.
Try It Yourself
13 minDraw five separate pentagons, side-by-side along the x-axis. Use a function and penup/goto/pendown between them.
Hint
import turtle as t t.speed(0) def pentagon(length=60): for _ in range(5): t.forward(length) t.right(72) # 360/5 for x in (-280, -140, 0, 140, 280): t.penup(); t.goto(x, 0); t.pendown() pentagon() t.done()
Draw a square spiral but turn 91° instead of 90°. Then try 89°. Notice how 1° of error rotates the whole spiral over time.
Hint
import turtle as t t.speed(0) t.color("magenta") for n in range(80): t.forward(n * 3) t.right(91) # change to 89 and watch t.done()
This is how chaos and beauty hide one degree apart.
Stamp 36 squares around the centre, each rotated 10° from the last. Pick a coloured background.
Hint
import turtle as t t.speed(0) t.bgcolor("midnightblue") t.color("lightyellow") t.pensize(2) def square(length=80): for _ in range(4): t.forward(length) t.right(90) for _ in range(36): square() t.right(10) t.done()
Mini-Challenge · The Pattern Picker
8 minBuild pattern_picker.py. Ask the user for two numbers — sides (3-12) and count (number of stamps around the centre, 12-48). Draw the rosette. Use safe_inputs.ask_int from PY-L2-31 if you have it, or just int(input(...)) wrapped in try/except.
After it draws, ask if the user wants to try again with different numbers. Clear the screen with t.clearscreen() for each new pattern.
Show one possible solution
# pattern_picker.py — let the user dial in their own pattern import turtle as t def polygon(sides, length=80): for _ in range(sides): t.forward(length) t.right(360 / sides) def rosette(sides, count, length=80): for _ in range(count): polygon(sides, length) t.right(360 / count) t.speed(0) t.bgcolor("black") t.color("turquoise") while True: try: sides = int(input("Sides (3-12): ")) count = int(input("Stamps (12-48): ")) except ValueError: print("Numbers only.") continue if not (3 <= sides <= 12) or not (12 <= count <= 48): print("Out of range.") continue t.clearscreen() t.speed(0); t.bgcolor("black"); t.color("turquoise") rosette(sides, count) if input("Again? (y/n) ").lower() != "y": break t.done()
Non-negotiables: two reusable functions (polygon, rosette), a clear-and-redraw loop, and user-supplied parameters. Notice t.clearscreen() resets everything including the colour — that's why we re-apply bgcolor and color inside the loop.
Recap
3 minPolygon = a for-loop with one forward and one turn. The turn is 360 / sides. Spirals come from growing the forward distance each iteration. Rosettes come from a nested loop — stamp a shape, turn a bit, repeat. Three numbers (sides, length, count) cover thousands of patterns. Always speed(0) for anything big.
Vocabulary Card
- regular polygon
- A closed shape with equal sides and equal angles. Turtle-drawable with one for-loop.
- 360 / n rule
- The exterior turn angle for a regular polygon with
nsides. - spiral
- Same turn each iteration, growing forward distance.
- rosette
- A shape stamped repeatedly around a centre. Nested loop.
Homework
4 minBuild pattern_zoo.py. Inside, define three reusable functions that each draw a different pattern when called:
polygon(sides, length)— basic polygon.spiral(turns, step, angle)— growing-forward spiral.flower(petals, petal_sides, petal_length)— rosette with a polygon at each petal.
At the bottom, call each one with different inputs (use penup/goto to position them apart on the screen).
Stretch. Add a 4th: star(points, length) — exterior angle is 180 - 180 / points for odd-point stars. (Try 5, 7, 9.)
Sample · pattern_zoo.py
# pattern_zoo.py — three (or four) reusable pattern functions import turtle as t def polygon(sides, length=60): for _ in range(sides): t.forward(length) t.right(360 / sides) def spiral(turns=50, step=4, angle=91): for n in range(turns): t.forward(n * step) t.right(angle) def flower(petals=18, petal_sides=4, petal_length=60): for _ in range(petals): polygon(petal_sides, petal_length) t.right(360 / petals) def star(points=5, length=120): angle = 180 - 180 / points for _ in range(points): t.forward(length) t.right(angle) t.speed(0); t.bgcolor("ivory"); t.color("teal") t.penup(); t.goto(-220, 0); t.pendown() polygon(8, 50) t.penup(); t.goto(-80, 0); t.pendown() spiral(40, 3, 91) t.penup(); t.goto(80, 80); t.pendown() flower() t.penup(); t.goto(200, 0); t.pendown() star() t.done()
Non-negotiables: every pattern wrapped in a parameterised function, called multiple times from the main block at different positions. This is the modular thinking from PY-L2-31 applied to graphics.