In this short guide we will show you how to make a snake game for playing in your terminal using Python. The main prerequisites for this is Python installation in the system. At the end of the tutorial, the application should run without any additional steps.
To begin, verify that Python is installed and functioning correctly:
$ python3 --version
Python 3.13.1
Now let’s create a directory for our snake game
mkdir -p ~/snake_game && cd ~/snake_game
Now we’ll create a snake game implementation using Python’s curses library. The game will include:
- Snake movement using arrow keys
- Food generation
- Score tracking
- Game over conditions
- Simple UI
The game will be terminal-based and include features like arrow key movement, score display, random food generation, collision detection, and game restart capabilities.
To start, add a snake_game.py
file to the snake_game folder created earlier.
vim snake_game.py
Paste the following contents into the file.
#!/usr/bin/env python3
import curses
import random
import time
def main(stdscr):
# Setup initial game state
curses.curs_set(0) # Hide cursor
stdscr.timeout(100) # Set input timeout (controls game speed)
# Get terminal dimensions
height, width = stdscr.getmaxyx()
# Check if terminal is large enough
if height < 10 or width < 30:
stdscr.clear()
stdscr.addstr(0, 0, "Terminal too small. Please resize.")
stdscr.refresh()
stdscr.getch()
return
# Create color pairs
curses.start_color()
curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK) # Snake
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK) # Food
curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK) # Score
# Game boundaries (leave space for borders and score)
game_height = height - 2
game_width = width - 2
# Display welcome message and instructions
show_instructions(stdscr)
while True:
# Game variables
snake = [[game_height // 2, game_width // 4]] # Start with a single segment
direction = curses.KEY_RIGHT
food = generate_food(snake, game_height, game_width)
score = 0
# Draw initial game state
draw_game(stdscr, snake, food, score, game_height, game_width)
game_over = False
while not game_over:
# Get user input
key = stdscr.getch()
# Process key press
if key == ord('q'):
return # Quit game
elif key in [curses.KEY_UP, curses.KEY_DOWN, curses.KEY_LEFT, curses.KEY_RIGHT]:
# Prevent 180-degree turns
if (key == curses.KEY_UP and direction != curses.KEY_DOWN) or \
(key == curses.KEY_DOWN and direction != curses.KEY_UP) or \
(key == curses.KEY_LEFT and direction != curses.KEY_RIGHT) or \
(key == curses.KEY_RIGHT and direction != curses.KEY_LEFT):
direction = key
# Calculate new head position
head = snake[0].copy()
if direction == curses.KEY_UP:
head[0] -= 1
elif direction == curses.KEY_DOWN:
head[0] += 1
elif direction == curses.KEY_LEFT:
head[1] -= 1
elif direction == curses.KEY_RIGHT:
head[1] += 1
# Add new head
snake.insert(0, head)
# Check if snake eats food
if snake[0] == food:
food = generate_food(snake, game_height, game_width)
score += 10
# Speed up game slightly after eating (decrease timeout value)
new_timeout = max(50, 100 - (score // 20))
stdscr.timeout(new_timeout)
else:
# Remove tail if no food eaten
snake.pop()
# Check for collisions with boundaries
if (snake[0][0] <= 0 or snake[0][0] >= game_height or
snake[0][1] <= 0 or snake[0][1] >= game_width):
game_over = True
# Check for collisions with self
if snake[0] in snake[1:]:
game_over = True
# Draw game state
draw_game(stdscr, snake, food, score, game_height, game_width)
# Game over screen
if show_game_over(stdscr, score) == ord('r'):
continue # Restart game
else:
break # Exit game
def draw_game(stdscr, snake, food, score, height, width):
"""Draw the game state on the screen"""
stdscr.clear()
# Draw borders
for i in range(width + 1):
stdscr.addch(0, i, '#')
stdscr.addch(height, i, '#')
for i in range(height + 1):
stdscr.addch(i, 0, '#')
stdscr.addch(i, width, '#')
# Draw snake
for i, segment in enumerate(snake):
char = '@' if i == 0 else 'O' # Different char for head
stdscr.attron(curses.color_pair(1))
stdscr.addch(segment[0], segment[1], char)
stdscr.attroff(curses.color_pair(1))
# Draw food
stdscr.attron(curses.color_pair(2))
stdscr.addch(food[0], food[1], '*')
stdscr.attroff(curses.color_pair(2))
# Draw score
score_text = f"Score: {score}"
stdscr.attron(curses.color_pair(3))
stdscr.addstr(0, width - len(score_text) - 1, score_text)
stdscr.attroff(curses.color_pair(3))
stdscr.refresh()
def generate_food(snake, height, width):
"""Generate food at a random position not occupied by the snake"""
while True:
food = [random.randint(1, height - 1), random.randint(1, width - 1)]
if food not in snake:
return food
def show_instructions(stdscr):
"""Display game instructions to the player"""
stdscr.clear()
height, width = stdscr.getmaxyx()
title = "SNAKE GAME"
stdscr.attron(curses.A_BOLD)
stdscr.addstr(height // 4, (width - len(title)) // 2, title)
stdscr.attroff(curses.A_BOLD)
instructions = [
"Use arrow keys to move the snake",
"Eat food (*) to grow and increase your score",
"Avoid hitting the walls or yourself",
"Press 'q' to quit at any time",
"Press 'r' to restart after game over",
"",
"Press any key to start..."
]
for i, line in enumerate(instructions):
stdscr.addstr(height // 3 + i + 1, (width - len(line)) // 2, line)
stdscr.refresh()
stdscr.getch()
def show_game_over(stdscr, score):
"""Display game over screen and return key pressed"""
stdscr.clear()
height, width = stdscr.getmaxyx()
game_over_text = "GAME OVER"
stdscr.attron(curses.A_BOLD)
stdscr.addstr(height // 3, (width - len(game_over_text)) // 2, game_over_text)
stdscr.attroff(curses.A_BOLD)
score_text = f"Your score: {score}"
stdscr.addstr(height // 3 + 2, (width - len(score_text)) // 2, score_text)
restart_text = "Press 'r' to restart or 'q' to quit"
stdscr.addstr(height // 3 + 4, (width - len(restart_text)) // 2, restart_text)
stdscr.refresh()
# Wait for 'r' or 'q' key
while True:
key = stdscr.getch()
if key in [ord('r'), ord('q')]:
return key
if __name__ == "__main__":
# Initialize curses and start game
try:
curses.wrapper(main)
except KeyboardInterrupt:
# Handle Ctrl+C gracefully
pass
finally:
# Ensure terminal is reset properly
curses.endwin()
print("Thanks for playing Snake Game!")
Make the file executable:
chmod +x ~/snake_game/snake_game.py
The game is ready! It includes the following features:
- Arrow key controls
- Score tracking
- Food collection
- Collision detection
- Color display
- Game over screen with restart option
- Clear instructions
Here’s how you can play it:
~/snake_game/snake_game.py
- Use arrow keys (↑,↓,←,→) to control the snake
- Collect the red ‘*‘ symbols to grow and increase your score
- Avoid hitting the walls or your own tail
- Press ‘q‘ to quit at any time
- If you lose, press ‘r‘ to restart or ‘q‘ to quit

On quitting you will get the message:
Thanks for playing Snake Game!