Summary

Resources

Notes\ Code

In the final challenge of our Day 1 snake game project, we receive several helpful hints, shown here:

image.png

Our instructions tell us to place screen.listen() after creating the snake. We need to set up arrow key controls using onkey(), with corresponding up, down, left, and right methods in the snake class. The directions are specified by degrees: up is 90°, right is 0°, down is 270°, and left is 180°. We'll use turtle's setheading() method with these values. Here's my code to implement this:

from turtle import Turtle

STARTING_POSITIONS = [(0, 0), (-20, 0), (-40, 0)]
MOVE_DISTANCE = 20

class Snake:
    def __init__(self):
        self.segments = []
        self.create_snake()

    def create_snake(self):
        for position in STARTING_POSITIONS:
            new_segment = Turtle("square")
            new_segment.color("white")
            new_segment.penup()
            new_segment.goto(position)
            self.segments.append(new_segment)

    def move(self):
        for seg_num in range(len(self.segments) - 1, 0, -1):
            new_x = self.segments[seg_num - 1].xcor()
            new_y = self.segments[seg_num - 1].ycor()
            self.segments[seg_num].goto(new_x, new_y)
        self.segments[0].forward(MOVE_DISTANCE)

    def up(self):
        self.segments[0].setheading(90)

    def down(self):
        self.segments[0].setheading(270)

    def right(self):
        self.segments[0].setheading(0)

    def left(self):
        self.segments[0].setheading(180)

This wasn’t too bad. We know from our previous lesson today segments need self applied and we saw previously to move forward that we had to call the segment of the snake in index 0. Dr. Yu then points out something I should have remembered from playing Snake: the snake's head cannot pass back over its body. This means if we're moving right, we can't suddenly turn left, and if we're moving up, we can't suddenly go down (and vice versa). How could we code this restriction? Before tackling that problem, she suggests using constants to make our code clearer. Let's add constants for up, down, left, and right.

STARTING_POSITIONS = [(0, 0), (-20, 0), (-40, 0)]
MOVE_DISTANCE = 20
UP = 90
DOWN = 270
LEFT = 180
RIGHT = 0

Easy enough, now lets see if we can accomplish this with if statements and saying things like “if heading not equal to down then set heading to up.” Let’s give it a shot.

    def up(self):
        if self.segments[0].heading() != DOWN:
            self.segments[0].setheading(UP)

    def down(self):
        if self.segments[0].heading() != UP:
            self.segments[0].setheading(DOWN)

    def right(self):
        if self.segments[0].heading() != LEFT:
            self.segments[0].setheading(RIGHT)

    def left(self):
        if self.segments[0].heading() != RIGHT:
            self.segments[0].setheading(LEFT)

These work great. But we missed one trick that we should have noticed. We’re declaring self.segment[0] a ton. Lets add a head attribute in our __init__ to represent this.

class Snake:
    def __init__(self):
        self.segments = []
        self.create_snake()
        self.head = self.segments[0]

And lastly lets update our up, down, right, and left methods.

    def up(self):
        if self.head.heading() != DOWN:
            self.head.setheading(UP)

    def down(self):
        if self.head.heading() != UP:
            self.head.setheading(DOWN)

    def right(self):
        if self.head.heading() != LEFT:
            self.head.setheading(RIGHT)

    def left(self):
        if self.head.heading() != RIGHT:
            self.head.setheading(LEFT)

That's all for this section of snake game lessons, we'll wrap it up in the next section.