🎓 A1Learner
🔍
0 of 18 lessons completed

Python Snake The Following Body

The following body is the set of segments that trail behind the head. On every pass of the loop, each segment moves into the place of the square ahead of it, and then the head steps forward.

Walking the body backwards

The for loop counts down from the last segment to the second one. Each segment reads the place of the one ahead and goes there.

    for index in range(len(segments) - 1, 0, -1):
        x = segments[index - 1].xcor()
        y = segments[index - 1].ycor()
        segments[index].goto(x, y)

The first segment takes the head's place

segments[0] has no segment ahead of it, so it takes the head's current place. The if keeps the line safe while the body is still empty.

    if len(segments) > 0:
        segments[0].goto(head.xcor(), head.ycor())

A new segment joins the tail

A segment born in the eat check starts in the centre of the board. On the next pass the follow block moves it into the tail's old place, and it follows from there.

        segments.append(new_segment)

Example

import turtle
import time
import random

# The game window
screen = turtle.Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake")
screen.tracer(0)

# The snake head
head = turtle.Turtle()
head.speed(0)
head.shape("square")
head.color("white")
head.penup()
head.goto(0, 0)
head.direction = "right"

# The food: one red circle on the board
food = turtle.Turtle()
food.speed(0)
food.shape("circle")
food.color("red")
food.penup()

# The body starts empty; the score starts at zero
segments = []
score = 0


def move():
    if head.direction == "up":
        head.sety(head.ycor() + 20)
    if head.direction == "down":
        head.sety(head.ycor() - 20)
    if head.direction == "left":
        head.setx(head.xcor() - 20)
    if head.direction == "right":
        head.setx(head.xcor() + 20)


def go_up():
    if head.direction != "down":
        head.direction = "up"


def go_down():
    if head.direction != "up":
        head.direction = "down"


def go_left():
    if head.direction != "right":
        head.direction = "left"


def go_right():
    if head.direction != "left":
        head.direction = "right"


def new_food_spot():
    x = random.randint(-14, 14) * 20
    y = random.randint(-14, 14) * 20
    food.goto(x, y)


new_food_spot()

# The keyboard steers the snake
screen.listen()
screen.onkey(go_up, "Up")
screen.onkey(go_down, "Down")
screen.onkey(go_left, "Left")
screen.onkey(go_right, "Right")

# The game loop: redraw, follow, move, check for a bite, wait, repeat
while True:
    screen.update()

    # The body follows: each segment takes the place of the one ahead
    for index in range(len(segments) - 1, 0, -1):
        x = segments[index - 1].xcor()
        y = segments[index - 1].ycor()
        segments[index].goto(x, y)
    if len(segments) > 0:
        segments[0].goto(head.xcor(), head.ycor())

    move()

    # Eat: the head reached the food
    if head.distance(food) < 20:
        new_food_spot()
        new_segment = turtle.Turtle()
        new_segment.speed(0)
        new_segment.shape("square")
        new_segment.color("grey")
        new_segment.penup()
        segments.append(new_segment)
        score = score + 10

    time.sleep(0.1)

Key points

  • The follow block runs before move() on every pass of the loop
  • Walking last-to-first means no place is overwritten before the segment behind it reads it
  • The head steps forward only after the whole body has shifted
  • With an empty segments list the follow block does nothing, and the head moves alone
  • The body trails the head because every square follows the one in front

In this example, one new block joins the loop between screen.update() and move(). The block first walks the segments from the last one back to the second, and each segment goes to the place of the one ahead of it. Walking backwards keeps each place safe until the segment behind it has taken it. segments[0] then goes to the head's current place, while the head has not moved yet. Only then does move() step the head into its next square, so the body ends one square behind it. A segment added by the eat check later in the pass waits in the centre, and the follow block picks it up as the new tail on the next pass.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Why does the follow block walk the segments from last to first?