Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Build a playable Snake game in Python with the standard-library turtle module. This version includes arrow-key controls, grid-aligned food, body growth, score and session high-score tracking, wall and self-collision detection, a game-over screen, and an R-key restart.
You do not need a separate game engine. However, Turtle depends on Tk graphical support, so it may not work in every Python installation or browser-based coding environment. See the official Turtle documentation for the module’s current API and Tk requirements.
What you will build
- A 600×600 Turtle graphics window
- Arrow-key movement in four directions
- Continuous movement on a 20-pixel grid
- Randomly placed food that never appears on the snake
- Snake growth and score tracking
- A high score retained while the program is open
- Wall and self-collision detection
- A game-over message with restart using the R key
This implementation ends the game when the snake hits a wall. It does not wrap the snake around to the opposite edge.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →What you need
- Python 3
- A text editor or Python IDE
- A desktop environment that can open a graphical window
- Basic knowledge of variables, functions, lists, and
ifstatements - A Python installation with Tk support
Turtle is documented as part of Python’s standard library, but it relies on Tk for its window. You should not install Turtle with pip as though it were an ordinary third-party graphics package.
#1 Best Overall
Check Python from a terminal:
python --version
On systems where Python 3 is invoked as python3:
python3 --version
Test Tk support with:
python -m tkinter
If that command cannot open a small Tk window, install Python or the operating system’s Tk package with Tk enabled. The official reference is docs.python.org.
How the game works
The window uses Turtle’s coordinate system. The origin (0, 0) is in the center; positive x values go right, and positive y values go up. The snake moves 20 pixels per game tick, so every head and food position is aligned to the same grid.
The snake has one Turtle object for its head and a Python list containing its body segments. Each segment is a square Turtle object. On every tick, the body moves backward through the list, the first segment moves to the head’s previous position, and the head advances one grid step.
Free tools Windows power users keep installed
One-click scans. No signup required.
Moving the body from the tail toward the head is essential. If you move the list from the front, each segment can copy the same newly changed position and the body collapses.
Rank #2
Set up the game window
The code uses tracer(0) and update() so the screen is redrawn once per game tick instead of after every Turtle movement. The playable boundary is approximately ±280 rather than the full ±300 window radius, leaving room for the visible square Turtle shape.
Controls and timing
Click the Turtle window before pressing the arrow keys. screen.listen() gives the window keyboard focus, and onkeypress() connects key presses to direction functions. The direction functions also reject an immediate 180-degree turn.
The game loop uses screen.ontimer(), which schedules the next callback without blocking the graphical event loop. The delay is measured in milliseconds: 100 means the callback is requested every 100 milliseconds, though operating-system scheduling is not a precision frame clock.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Complete code
Save the following as snake_game.py. It is designed to run as one complete file.
import random
import turtle
# Recommended game settings
WIDTH = 600
HEIGHT = 600
STEP = 20
BOUNDARY = 280
DELAY = 100 # milliseconds
# Game state
head = None
food = None
score_pen = None
message_pen = None
segments = []
direction = "stop"
score = 0
high_score = 0
game_running = True
def setup_screen():
screen = turtle.Screen()
screen.title("Snake Game")
screen.bgcolor("black")
screen.setup(width=WIDTH, height=HEIGHT)
screen.tracer(0)
return screen
def create_head():
global head
head = turtle.Turtle("square")
head.penup()
head.color("lime")
head.goto(0, 0)
def create_food():
global food
food = turtle.Turtle("circle")
food.penup()
food.color("red")
place_food()
def create_scoreboard():
global score_pen, message_pen
score_pen = turtle.Turtle()
score_pen.hideturtle()
score_pen.penup()
score_pen.color("white")
score_pen.goto(0, 260)
message_pen = turtle.Turtle()
message_pen.hideturtle()
message_pen.penup()
message_pen.color("white")
def occupied_positions():
positions = {(round(head.xcor()), round(head.ycor()))}
positions.update(
(round(segment.xcor()), round(segment.ycor()))
for segment in segments
)
return positions
def place_food():
"""Put food on an unoccupied position on the movement grid."""
available = [
(x, y)
for x in range(-BOUNDARY, BOUNDARY + STEP, STEP)
for y in range(-BOUNDARY, BOUNDARY + STEP, STEP)
if (x, y) not in occupied_positions()
]
if available:
food.goto(random.choice(available))
def update_scoreboard():
score_pen.clear()
score_pen.write(
f"Score: {score} High Score: {high_score}",
align="center",
font=("Arial", 20, "bold"),
)
def set_direction(new_direction):
global direction
opposite = {
"up": "down",
"down": "up",
"left": "right",
"right": "left",
}
if direction == "stop" or opposite.get(direction) != new_direction:
direction = new_direction
def go_up():
set_direction("up")
def go_down():
set_direction("down")
def go_left():
set_direction("left")
def go_right():
set_direction("right")
def move_body():
"""Move each body segment into the previous segment's old position."""
for index in range(len(segments) - 1, 0, -1):
segments[index].goto(segments[index - 1].position())
if segments:
segments[0].goto(head.position())
def move_head():
x = head.xcor()
y = head.ycor()
if direction == "up":
head.sety(y + STEP)
elif direction == "down":
head.sety(y - STEP)
elif direction == "left":
head.setx(x - STEP)
elif direction == "right":
head.setx(x + STEP)
def grow_snake():
segment = turtle.Turtle("square")
segment.penup()
segment.color("green")
if segments:
segment.goto(segments[-1].position())
else:
segment.goto(head.position())
segments.append(segment)
def end_game():
global game_running
game_running = False
message_pen.clear()
message_pen.goto(0, 0)
message_pen.write(
"GAME OVER",
align="center",
font=("Arial", 28, "bold"),
)
message_pen.goto(0, -40)
message_pen.write(
"Press R to restart",
align="center",
font=("Arial", 16, "normal"),
)
def check_collisions():
global score, high_score
head_position = (round(head.xcor()), round(head.ycor()))
# Wall collision
if abs(head_position[0]) > BOUNDARY or abs(head_position[1]) > BOUNDARY:
end_game()
return
# Self-collision
body_positions = {
(round(segment.xcor()), round(segment.ycor()))
for segment in segments
}
if head_position in body_positions:
end_game()
return
# Food collision
food_position = (round(food.xcor()), round(food.ycor()))
if head_position == food_position:
grow_snake()
score += 1
high_score = max(high_score, score)
update_scoreboard()
place_food()
def reset_game():
global direction, score, game_running
for segment in segments:
segment.hideturtle()
segments.clear()
head.goto(0, 0)
direction = "stop"
score = 0
game_running = True
message_pen.clear()
place_food()
update_scoreboard()
screen.ontimer(game_loop, DELAY)
def game_loop():
if not game_running:
return
move_body()
move_head()
check_collisions()
screen.update()
if game_running:
screen.ontimer(game_loop, DELAY)
screen = setup_screen()
create_head()
create_food()
create_scoreboard()
update_scoreboard()
screen.listen()
screen.onkeypress(go_up, "Up")
screen.onkeypress(go_down, "Down")
screen.onkeypress(go_left, "Left")
screen.onkeypress(go_right, "Right")
screen.onkeypress(reset_game, "r")
screen.onkeypress(reset_game, "R")
game_loop()
screen.mainloop()
Run the game
Open a terminal in the directory containing snake_game.py and run:
python snake_game.py
Or, on systems that use the python3 command:
python3 snake_game.py
A black 600×600 window should open. The snake initially stays still until you press an arrow key. Eating food increases the score and adds a green body segment. Hitting a wall or the snake’s body displays the game-over message. Press R to reset the board and score.
Important implementation details
Why food is grid-aligned
The snake moves in 20-pixel increments, so food should use the same coordinate grid. Generating arbitrary random coordinates can place food between reachable movement cells. The place_food() function builds a list of valid grid positions and chooses one that is not occupied by the snake.
Why food placement checks the body
Food is not merely placed inside the window. It is compared with the head and every body segment first, preventing food from appearing underneath the snake.
Why the body moves backward
Suppose the head is at (40, 0) and the first body segment is at (20, 0). The first segment must move to the head’s old position, while the tail must move into the position previously occupied by the segment before it. Updating from the last list item toward the first preserves all of those old positions.
Why immediate reversals are blocked
When a snake has a body, turning directly from left to right or up to down would make the head enter the segment immediately behind it. The direction map rejects those changes.
What the high score means
This code keeps high_score in memory only. It survives a game reset during the current program session, but it is lost when the program closes. Saving it permanently would require writing the value to a file.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Troubleshooting
Arrow keys do nothing
- Click the Turtle window so it has focus.
- Confirm that
screen.listen()is present. - Use the exact key names
"Up","Down","Left", and"Right". - Pass the function itself, not the result of calling it.
# Correct
screen.onkeypress(go_up, "Up")
# Incorrect
screen.onkeypress(go_up(), "Up")
Turtle’s keyboard documentation notes that the TurtleScreen must have focus to receive key events. See the official reference.
Best Value
No module named '_tkinter'
Your Python installation lacks Tk support or the operating system’s Tk package is missing. Install a Python distribution with Tk enabled, or install the appropriate Tk package for your operating system. Then retry:
python -m tkinter
Installing an unrelated package named turtle is not the correct fix for a missing _tkinter module.
The window closes immediately
Run the program from a terminal rather than double-clicking it so that any traceback remains visible. Also make sure the file reaches screen.mainloop() and that the code was copied as one complete block.
The game is too fast or too slow
Change:
DELAY = 100
A smaller value requests faster movement; a larger value requests slower movement. With ontimer(), the value is in milliseconds. It is not the same as a time.sleep() value in seconds.
The scoreboard duplicates or flickers
The scoreboard is cleared before each rewrite:
score_pen.clear()
The code also uses controlled rendering through tracer(0) and screen.update().
The window crashes when closed
A permanently blocking loop can continue trying to update a destroyed Tk window. This version uses Turtle’s event timer and a game_running flag, which provides a cleaner shutdown path. If you adapt it, avoid adding an unconditional while True loop around the window.
Possible extensions
Once the basic version works, you can add:
- Pause and resume controls
- A start screen and a dedicated game-over screen
- Persistent high-score storage in
high_score.txt - Increasing speed as the score rises
- Wraparound walls instead of wall collisions
- Obstacles and multiple food types
- Sound effects
- A Pygame version if you want a larger, more scalable game architecture
Turtle is well suited to learning movement, coordinates, lists, callbacks, and collision rules. A larger game may eventually benefit from a framework with more control over rendering, input, audio, and asset management.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

