Going in spirals with Turtle - Writing good code

Posted on 14-02-18 in Computing

Using the Python Turtle library we draw spirals with ever increasing complexity. The aim is to see examples of good and bad code. In this post we'll look at the code in each case and observe the result. I would recommend running the code for yourself as you go to observe what is happening.

import turtle

step = 10
while True:
  turtle.forward(step)
  turtle.left(90)
  step += 2

This will produce

rectangular spiral drawn using code above

At each run of the loop we increase step by 2 pixels. This will cause the turtle to move further out each run.

The first improvement we will do is remove all hardcoded numbers. A hard coded number is one that isn't defined by a variable. This is generally bad practice as we may end up using the variable in multiple places. Secondly we don't really want infinite loops in our code with no way of ending. Let's change it such that it does a fixed number of loops before quitting.

import turtle

step = 1  # ever increasing distance
angle = 90 # turn by this angle each loop
loops = 5  # how many loops we wish to complete before quitting
increase_by = 2  # how many pixels to increase each run

steps_per_loop = 360 // angle  # how many steps we need to make a single loop

for loop in range(loops * steps_per_loop):
    turtle.forward(step)
    turtle.left(angle)
    step += increase_by

turtle.exitonclick()

This will work fine however we're more interested in how many sides, rather than the angle. So let's alter this slightly to become

import turtle

step = 1  # ever increasing distance
sides = 4  # how many sides per loop
loops = 50  # how many loops we wish to complete before quitting
increase_by = 10  # how many pixels to increase each loop

angle = 360 // sides  # angle to turn by each step
increase_by_per_step = increase_by // sides

for loop in range(loops * sides):
    turtle.forward(step)
    turtle.left(angle)
    step += increase_by_per_step

turtle.exitonclick()
rectangular spiral as before but now we have cleaner code producing it. Usage of variables!

Success! We can see now the code does one thing based on a set of inputs (our variables). Let's turn this into a function.

import turtle

def draw_spiral(step, sides, loops, increase_by):
    """
    Draws spirals using turtle
    step # ever increasing distance
    sides # how many sides per loop
    loops # how many loops we wish to complete before quitting
    increase_by # how many pixels to increase each loop
    """

    angle = 360 // sides
    increase_by_per_step = increase_by // sides

    for loop in range(loops * sides):
        turtle.forward(step)
        turtle.left(angle)
        step += increase_by_per_step


def move_to(x,y=0):
    """
    Moves turtle to position without drawing
    """
    turtle.penup()
    turtle.goto(x,y)
    turtle.pendown()

x = -200
while True:
    move_to(x)
    draw_spiral(1, 4, 5, 10)
    x += 50

turtle.exitonclick()
A rectangular spiral but this time we have repeated this in a horizontal pattern giving a repeated pattern to look at

Here we have used our new function to draw the spiral pattern like a stamp and move onto the next location. I've also written a short function called move_to. Note how we've used a default argument, y=0. In code where we have numbers that usually don't change, this is good practice.

User Exercises

Using the above code as a guide produce the following patterns

first exercise : Rectangular spirals are tiled across the screen with random colours per spiral Second exercise : a hexagonal spiral third exercise : a hexagonal spiral with random colours used as the line thickness is reduced each spiral.