Python Project: Snake (Turtle)

Build the classic Snake game using Python turtle graphics.

Spec Sheet — Snake (Python Turtle Edition)

Project File: snake.py Difficulty: Beginner / Intermediate Must Have: Movement, Food, Growth, Collisions, Score

Goal

Build the classic Snake game where the player controls a snake that grows when it eats food. The game ends when the snake hits a wall or itself.

Requirements

Game Window

  • Create a window (recommended: 600x600).
  • Use a dark background for contrast.
  • Title the window: “Snake”

Snake

  • Snake is made of square segments.
  • Starts with 3 segments.
  • Moves continuously in one direction (default: right).
  • Arrow keys change direction (Up, Down, Left, Right).
  • No direct reverse: if moving right, cannot instantly go left.

Food

  • Food appears at a random location on the screen grid.
  • When snake head touches food:
    • Score increases by 1
    • Food respawns somewhere new
    • Snake grows by 1 segment

Collisions

  • Wall collision → Game Over
  • Self collision (head touches any body segment) → Game Over

Scoreboard

  • Display score at top of screen.
  • Update live as score changes.
  • Show “GAME OVER” on collision.

Controls

  • ⬆️ Up Arrow = move up
  • ⬇️ Down Arrow = move down
  • ⬅️ Left Arrow = move left
  • ➡️ Right Arrow = move right
Optional Enhancements: High score, speed increases, restart button, sound effects.

Pseudocode

START program

SET screen size, title, and background
CREATE scoreboard and display score = 0

CREATE snake as a list of 3 segments
SET snake direction to RIGHT

CREATE food at a random position

DEFINE function move_snake():
    FOR each segment from tail to head:
        move segment to the position of the segment in front of it
    move head forward by MOVE_DISTANCE

DEFINE function go_up():
    IF current direction is not DOWN:
        set direction to UP

DEFINE function go_down():
    IF current direction is not UP:
        set direction to DOWN

DEFINE function go_left():
    IF current direction is not RIGHT:
        set direction to LEFT

DEFINE function go_right():
    IF current direction is not LEFT:
        set direction to RIGHT

BIND arrow keys to direction functions

LOOP forever:
    update screen
    pause for a short time
    move_snake()

    IF head touches food:
        increase score
        update scoreboard
        respawn food randomly
        add new segment to snake tail

    IF head hits wall:
        display GAME OVER
        stop loop

    IF head hits any body segment:
        display GAME OVER
        stop loop

END program

Rubric (100 Points)

Category Excellent (Full Credit) Points
Program Runs / No Crashes Game runs without errors; clean exit/game over 15
Snake Movement Continuous movement; smooth segment following 15
Controls & No Reverse Rule Arrow keys work; cannot reverse into itself instantly 10
Food Spawn & Eating Food spawns randomly on grid; collision detection works 15
Growth Mechanic Snake grows correctly by 1 segment per food 10
Scoring Score increases correctly; displayed and updates live 10
Wall Collision Game ends when snake hits boundary 10
Self Collision Game ends when snake hits its body 10
Code Quality Meaningful names, comments, organized sections/classes 5
Style / UX Polish Clear colors, readable text, good window layout 5
Total 100

Actual Python Code — snake.py

"""
File: snake.py
Classic Snake Game (Turtle)

Controls:
- Arrow keys to move
Rules:
- Eat food to grow and score points
- Crash into wall or yourself -> Game Over
"""

import time
import random
import turtle


# ----------------------------
# CONFIG
# ----------------------------
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
MOVE_DISTANCE = 20
STARTING_SEGMENTS = 3
DELAY = 0.10  # lower = faster

UP = 90
DOWN = 270
LEFT = 180
RIGHT = 0


# ----------------------------
# SCOREBOARD
# ----------------------------
class Scoreboard(turtle.Turtle):
    def __init__(self):
        super().__init__()
        self.score = 0
        self.hideturtle()
        self.penup()
        self.color("white")
        self.goto(0, SCREEN_HEIGHT // 2 - 40)
        self.update_score()

    def update_score(self):
        self.clear()
        self.write(f"Score: {self.score}", align="center", font=("Arial", 18, "normal"))

    def add_point(self):
        self.score += 1
        self.update_score()

    def game_over(self):
        self.goto(0, 0)
        self.write("GAME OVER", align="center", font=("Arial", 28, "bold"))


# ----------------------------
# FOOD
# ----------------------------
class Food(turtle.Turtle):
    def __init__(self):
        super().__init__()
        self.shape("circle")
        self.color("red")
        self.penup()
        self.speed(0)
        self.shapesize(stretch_wid=0.7, stretch_len=0.7)
        self.respawn()

    def respawn(self):
        # Keep food inside the walls
        max_x = (SCREEN_WIDTH // 2) - 40
        max_y = (SCREEN_HEIGHT // 2) - 60

        # Snap to grid so it lines up with snake movement
        x = random.randrange(-max_x, max_x + 1, MOVE_DISTANCE)
        y = random.randrange(-max_y, max_y + 1, MOVE_DISTANCE)
        self.goto(x, y)


# ----------------------------
# SNAKE
# ----------------------------
class Snake:
    def __init__(self):
        self.segments = []
        self.direction = RIGHT
        self._create_starting_snake()

    def _create_starting_snake(self):
        start_x = 0
        for i in range(STARTING_SEGMENTS):
            self._add_segment((start_x - i * MOVE_DISTANCE, 0))

    def _add_segment(self, position):
        seg = turtle.Turtle("square")
        seg.color("lime")
        seg.penup()
        seg.goto(position)
        self.segments.append(seg)

    @property
    def head(self):
        return self.segments[0]

    def grow(self):
        # Add new segment at last segment position
        tail = self.segments[-1]
        self._add_segment(tail.position())

    def move(self):
        # Move each segment to the position of the one ahead
        for idx in range(len(self.segments) - 1, 0, -1):
            new_x = self.segments[idx - 1].xcor()
            new_y = self.segments[idx - 1].ycor()
            self.segments[idx].goto(new_x, new_y)

        # Move head forward in current direction
        self.head.setheading(self.direction)
        self.head.forward(MOVE_DISTANCE)

    # Direction controls (prevent reversing)
    def up(self):
        if self.direction != DOWN:
            self.direction = UP

    def down(self):
        if self.direction != UP:
            self.direction = DOWN

    def left(self):
        if self.direction != RIGHT:
            self.direction = LEFT

    def right(self):
        if self.direction != LEFT:
            self.direction = RIGHT


# ----------------------------
# MAIN GAME
# ----------------------------
def main():
    screen = turtle.Screen()
    screen.setup(width=SCREEN_WIDTH, height=SCREEN_HEIGHT)
    screen.bgcolor("black")
    screen.title("Snake")
    screen.tracer(0)  # manual screen refresh

    snake = Snake()
    food = Food()
    scoreboard = Scoreboard()

    # Key bindings
    screen.listen()
    screen.onkey(snake.up, "Up")
    screen.onkey(snake.down, "Down")
    screen.onkey(snake.left, "Left")
    screen.onkey(snake.right, "Right")

    game_running = True

    while game_running:
        screen.update()
        time.sleep(DELAY)

        snake.move()

        # 1) Food collision
        if snake.head.distance(food) < 15:
            food.respawn()
            snake.grow()
            scoreboard.add_point()

        # 2) Wall collision
        x = snake.head.xcor()
        y = snake.head.ycor()
        wall_limit_x = (SCREEN_WIDTH // 2) - 10
        wall_limit_y = (SCREEN_HEIGHT // 2) - 10
        if x > wall_limit_x or x < -wall_limit_x or y > wall_limit_y or y < -wall_limit_y:
            game_running = False
            scoreboard.game_over()
            break

        # 3) Self collision
        for segment in snake.segments[1:]:
            if snake.head.distance(segment) < 10:
                game_running = False
                scoreboard.game_over()
                break

    screen.update()
    screen.mainloop()


if __name__ == "__main__":
    main()
Run it: Save as snake.py and run with python snake.py. Turtle graphics opens a new window for the game.