By the end of this tutorial you will have a program similar to :

Rules to follow:
- The length of snake increases by one unit if it eats the fruit.
- Fruit appears at random position at the screen every time it is eaten.
- Game is over if snake bites its own tail.
Index:
- Installing pygame.
- Creating a screen.
- Creating Snake Head.
- Defining snake movements.
- Adding the food.
- Eating food and redrawing food at new coordinates .
- Increasing snakes length.
- Setting score.
- Game over when snake bites its tail.
- Adding quit or play again option.
Installing pygame.
Firstly, you should have python Installed on your system, and pip (Python installation manager) added to path.
How to add pip to path?
Now, if open command prompt for windows and type:
/pip install pygame
Now you can import pygame module and start with your game development.
Creating a screen.
To create a screen use display.set_mode( ) method, also the init( ) and quit( ) method to initialize and uninitialize the code at starting and end.
import pygame
pygame.init()
screen = pygame.display.set_mode((450,450))
pygame.display.update()
pygame.quit()
But if you run this code the screen will appear and disappear quickly.
To solve this we will create a while loop. Anything we want to display and stay on our screen will be inside this while loop.
Also set screen color to White using screen.fill( )
import pygame
pygame.init()
screen = pygame.display.set_mode((450,450))
running = True
while running:
screen.fill((255,255,255)) #RGB value for white
pygame.display.update()
pygame.quit()
But in the above code there is no condition for the while loop to end, hence it will create a infinite loop and program will keep running and eventually hang.
So lets add a condition where running = False so the loop will end.
import pygame
pygame.init()
screen = pygame.display.set_mode((450,450))
running = True
while running:
screen.fill((255,255,255)) #RGB value for white
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.update()
pygame.quit()
Now when we press Cross the program will terminate.

NOTE : This code will be common to all your pygame codes, so learn and understand it.
Creating Snake Head
The snake head will be a rectangle of dimensions 10×10.
To create a rectangle in pygame use:
rectangle = pygame.Rect(x , y , width, length )
pygame.draw.rect(screen , (color) , rectangle)
# where x, y are the top left coordinates of the rectangle
Now, we created snake_head at snakeX,snakeY.
Also we created a game( ) function and moved our main loop inside it.
import pygame
pygame.init()
red = (255,0,0)
snake_width = 10
screen = pygame.display.set_mode((450,450))
def game():
snakeX = 200
snakeY = 200
running = True
while running:
screen.fill((255,255,255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
pygame.display.update()
pygame.quit()
game()

Defining snake movements
We create two variables snakeX_speed and snakeY_speed which will represent the change in snakeX and snakeY with time.
Also, a direction variable to keep track of the direction in which the snake is moving because it can not reverse its direction immediately. For instance, is the snake is moving towards right it can not start to move towards left in one keystroke.
import pygame
pygame.init()
red = (255, 0, 0)
snake_width = 10
screen = pygame.display.set_mode((450,450))
def game():
snakeX = 200
snakeY = 200
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
running = True
while running:
screen.fill((255,255,255))
snakeX += snakeX_speed
snakeY += snakeY_speed
snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and direction != "down":
snakeY_speed = -0.1
snakeX_speed = 0
direction = "up"
if event.key == pygame.K_DOWN and direction != "up":
snakeY_speed = 0.1
snakeX_speed = 0
direction = "down"
if event.key == pygame.K_LEFT and direction != "right":
snakeX_speed = -0.1
snakeY_speed = 0
direction = "left"
if event.key == pygame.K_RIGHT and direction != "left":
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
pygame.display.update()
pygame.quit()
game()
Also if the snake goes out of the screen we will have it reappear from other side of the screen.
import pygame
pygame.init()
red = (255, 0, 0)
snake_width = 10
screen = pygame.display.set_mode((450,450))
def game():
snakeX = 200
snakeY = 200
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
running = True
while running:
screen.fill((255,255,255))
snakeX += snakeX_speed
snakeY += snakeY_speed
snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and direction != "down":
snakeY_speed = -0.1
snakeX_speed = 0
direction = "up"
if event.key == pygame.K_DOWN and direction != "up":
snakeY_speed = 0.1
snakeX_speed = 0
direction = "down"
if event.key == pygame.K_LEFT and direction != "right":
snakeX_speed = -0.1
snakeY_speed = 0
direction = "left"
if event.key == pygame.K_RIGHT and direction != "left":
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
# snake does not go outside the screen
if snakeX < 0:
snakeX = 450
if snakeX > 450:
snakeX = 0
if snakeY < 0:
snakeY = 450
if snakeY > 450:
snakeY = 0
pygame.display.update()
pygame.quit()
game()
Adding the food
Lets create a function to draw food on screen.
Also import random module to randomize the position of food.
import pygame
import random
pygame.init()
red = (255, 0, 0)
snake_width = 10
screen = pygame.display.set_mode((450,450))
def draw_food(x, y):
food = pygame.Rect(x, y, snake_width, snake_width)
pygame.draw.rect(screen, (0, 255, 255), food)
def game():
snakeX = 200
snakeY = 200
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
foodX = random.randint(20, 420)
foodY = random.randint(20, 420)
running = True
while running:
screen.fill((255,255,255))
snakeX += snakeX_speed
snakeY += snakeY_speed
snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and direction != "down":
snakeY_speed = -0.1
snakeX_speed = 0
direction = "up"
if event.key == pygame.K_DOWN and direction != "up":
snakeY_speed = 0.1
snakeX_speed = 0
direction = "down"
if event.key == pygame.K_LEFT and direction != "right":
snakeX_speed = -0.1
snakeY_speed = 0
direction = "left"
if event.key == pygame.K_RIGHT and direction != "left":
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
# snake does not go outside the screen
if snakeX < 0:
snakeX = 450
if snakeX > 450:
snakeX = 0
if snakeY < 0:
snakeY = 450
if snakeY > 450:
snakeY = 0
draw_food(foodX, foodY)
pygame.display.update()
pygame.quit()
game()
Eating food and redrawing food at new coordinates
To solve this problem we will use the collision method.
We will calculate the distance between the snake_head and food and when this distance is relatively less we will assume that collision has occurred and draw food to a new location.

Import math module and create a lenth_of_snake variable for future reference.
import pygame
import random
import math
pygame.init()
red = (255, 0, 0)
snake_width = 10
screen = pygame.display.set_mode((450,450))
def draw_food(x, y):
food = pygame.Rect(x, y, snake_width, snake_width)
pygame.draw.rect(screen, (0, 255, 255), food)
def collision(snakeX, snakeY, foodX, foodY):
d = math.sqrt((snakeX - foodX) ** 2 + (snakeY - foodY) ** 2)
if d < 15:
return True
else:
return False
def game():
snakeX = 200
snakeY = 200
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
foodX = random.randint(20, 420)
foodY = random.randint(20, 420)
lenth_of_snake = 1
running = True
while running:
screen.fill((255,255,255))
snakeX += snakeX_speed
snakeY += snakeY_speed
snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and direction != "down":
snakeY_speed = -0.1
snakeX_speed = 0
direction = "up"
if event.key == pygame.K_DOWN and direction != "up":
snakeY_speed = 0.1
snakeX_speed = 0
direction = "down"
if event.key == pygame.K_LEFT and direction != "right":
snakeX_speed = -0.1
snakeY_speed = 0
direction = "left"
if event.key == pygame.K_RIGHT and direction != "left":
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
# snake does not go outside the screen
if snakeX < 0:
snakeX = 450
if snakeX > 450:
snakeX = 0
if snakeY < 0:
snakeY = 450
if snakeY > 450:
snakeY = 0
# eating food
if collision(snakeX, snakeY, foodX, foodY):
lenth_of_snake += 1
foodX = random.randint(5, 420)
foodY = random.randint(5, 420)
draw_food(foodX, foodY)
pygame.display.update()
pygame.quit()
game()
Increasing snakes length
This is the most challenging part of this program.
We will create a pos[ ] list which will contain the position of snake head at all point in the loop but when the length of position list becomes greater than lenth_of_snake we delete the pos[0] element to maintain the length of snake.
And for every element in pos list we draw a rectangle which will represent the snake body.
import pygame
import random
import math
pygame.init()
red = (255, 0, 0)
snake_width = 10
pos = []
screen = pygame.display.set_mode((450,450))
def inc_length():
for x in pos:
snake_head = pygame.Rect(x[0], x[1], snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
def draw_food(x, y):
food = pygame.Rect(x, y, snake_width, snake_width)
pygame.draw.rect(screen, (0, 255, 255), food)
def collision(snakeX, snakeY, foodX, foodY):
d = math.sqrt((snakeX - foodX) ** 2 + (snakeY - foodY) ** 2)
if d < 15:
return True
else:
return False
def game():
snakeX = 200
snakeY = 200
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
foodX = random.randint(20, 420)
foodY = random.randint(20, 420)
lenth_of_snake = 1
running = True
while running:
screen.fill((255,255,255))
snakeX += snakeX_speed
snakeY += snakeY_speed
snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and direction != "down":
snakeY_speed = -0.1
snakeX_speed = 0
direction = "up"
if event.key == pygame.K_DOWN and direction != "up":
snakeY_speed = 0.1
snakeX_speed = 0
direction = "down"
if event.key == pygame.K_LEFT and direction != "right":
snakeX_speed = -0.1
snakeY_speed = 0
direction = "left"
if event.key == pygame.K_RIGHT and direction != "left":
snakeX_speed = 0.1
snakeY_speed = 0
direction = "right"
# snake does not go outside the screen
if snakeX < 0:
snakeX = 450
if snakeX > 450:
snakeX = 0
if snakeY < 0:
snakeY = 450
if snakeY > 450:
snakeY = 0
# eating food
if collision(snakeX, snakeY, foodX, foodY):
lenth_of_snake += 1
foodX = random.randint(5, 420)
foodY = random.randint(5, 420)
# increasing snakes length
snake_head = []
snake_head.append(snakeX)
snake_head.append(snakeY)
pos.append(snake_head)
if len(pos) > lenth_of_snake:
del pos[0]
draw_food(foodX, foodY)
pygame.display.update()
pygame.quit()
game()
But if you run the above code you will not be able to spot any progress from our last code.
It is due to the speed at which the process is taking place, the body is drawn at the same position as the head hence it is not visible thus to delay the loop we will use the pygame.time.clock( ) method.
Also as we slow the loop we will have to increase the speed of snake to compensate.
import pygame
import random
import math
pygame.init()
red = (255, 0, 0)
snake_width = 10
pos = []
snake_speed = 15
clock = pygame.time.Clock()
screen = pygame.display.set_mode((450,450))
def inc_length():
for x in pos:
snake_head = pygame.Rect(x[0], x[1], snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
def draw_food(x, y):
food = pygame.Rect(x, y, snake_width, snake_width)
pygame.draw.rect(screen, (0, 255, 255), food)
def collision(snakeX, snakeY, foodX, foodY):
d = math.sqrt((snakeX - foodX) ** 2 + (snakeY - foodY) ** 2)
if d < 15:
return True
else:
return False
def game():
snakeX = 200
snakeY = 200
snakeX_speed = snake_width
snakeY_speed = 0
direction = "right"
foodX = random.randint(20, 420)
foodY = random.randint(20, 420)
lenth_of_snake = 1
running = True
while running:
screen.fill((255,255,255))
snakeX += snakeX_speed
snakeY += snakeY_speed
snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and direction != "down":
snakeY_speed = -snake_width
snakeX_speed = 0
direction = "up"
if event.key == pygame.K_DOWN and direction != "up":
snakeY_speed = snake_width
snakeX_speed = 0
direction = "down"
if event.key == pygame.K_LEFT and direction != "right":
snakeX_speed = -snake_width
snakeY_speed = 0
direction = "left"
if event.key == pygame.K_RIGHT and direction != "left":
snakeX_speed = snake_width
snakeY_speed = 0
direction = "right"
# snake does not go outside the screen
if snakeX < 0:
snakeX = 450
if snakeX > 450:
snakeX = 0
if snakeY < 0:
snakeY = 450
if snakeY > 450:
snakeY = 0
# eating food
if collision(snakeX, snakeY, foodX, foodY):
lenth_of_snake += 1
foodX = random.randint(5, 420)
foodY = random.randint(5, 420)
# increasing snakes length
snake_head = []
snake_head.append(snakeX)
snake_head.append(snakeY)
pos.append(snake_head)
if len(pos) > lenth_of_snake:
del pos[0]
clock.tick(snake_speed)
draw_food(foodX, foodY)
inc_length()
pygame.display.update()
pygame.quit()
game()
Setting score
Score will be equal to lenth_of_snake – 1.
Lets create a function to print text on our screen. Also import sys module.
def print_message(msg, x, y, size):
font = pygame.font.SysFont("comicsansms", size)
text = font.render(msg, True, (0, 0, 0))
screen.blit(text, (x, y))
Now call this function inside of main loop
print_message("Score : " + str(lenth_of_snake - 1), 10, 10, 15)
Game over when snake bites its tail
Write this inside the main loop.
# game over
for x in pos[:-1]:
if x == snake_head:
game_over = True
time.sleep(1)
pos.clear()
If at anytime the position of snake_head and snake body are equal the game_over = True
Adding quit or play again option
Now we will create a while loop that will run until game_over is true

THE FINAL CODE IS:
import pygame
import random
import math, sys, time
pygame.init()
screen = pygame.display.set_mode((450, 450))
snake_width = 10
red = (255, 0, 0)
snake_speed = 15
pos = []
clock = pygame.time.Clock()
def inc_length():
for x in pos:
snake_head = pygame.Rect(x[0], x[1], snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
def draw_food(x, y):
food = pygame.Rect(x, y, snake_width, snake_width)
pygame.draw.rect(screen, (0, 255, 255), food)
def collision(snakeX, snakeY, foodX, foodY):
d = math.sqrt((snakeX - foodX) ** 2 + (snakeY - foodY) ** 2)
if d < 15:
return True
else:
return False
def print_message(msg, x, y, size):
font = pygame.font.SysFont("comicsansms", size)
text = font.render(msg, True, (0, 0, 0))
screen.blit(text, (x, y))
def game():
snakeX = 100
snakeY = 100
snakeX_speed = 10
snakeY_speed = 0
foodX = random.randint(20, 420)
foodY = random.randint(20, 420)
lenth_of_snake = 1
direction = "right"
game_over = False
# main loop
running = True
while running:
screen.fill((255, 255, 255))
snakeX += snakeX_speed
snakeY += snakeY_speed
snake_head = pygame.Rect(snakeX, snakeY, snake_width, snake_width)
pygame.draw.rect(screen, red, snake_head)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and direction != "down":
snakeY_speed = -snake_width
snakeX_speed = 0
direction = "up"
if event.key == pygame.K_DOWN and direction != "up":
snakeY_speed = snake_width
snakeX_speed = 0
direction = "down"
if event.key == pygame.K_LEFT and direction != "right":
snakeX_speed = -snake_width
snakeY_speed = 0
direction = "left"
if event.key == pygame.K_RIGHT and direction != "left":
snakeX_speed = snake_width
snakeY_speed = 0
direction = "right"
# snake does not go outside the screen
if snakeX < 0:
snakeX = 450
if snakeX > 450:
snakeX = 0
if snakeY < 0:
snakeY = 450
if snakeY > 450:
snakeY = 0
# eating food
if collision(snakeX, snakeY, foodX, foodY):
lenth_of_snake += 1
foodX = random.randint(5, 420)
foodY = random.randint(5, 420)
# increasing snakes length
snake_head = []
snake_head.append(snakeX)
snake_head.append(snakeY)
pos.append(snake_head)
if len(pos) > lenth_of_snake:
del pos[0]
# game over
for x in pos[:-1]:
if x == snake_head:
game_over = True
time.sleep(1)
pos.clear()
while game_over == True:
screen.fill((255, 150, 0))
print_message("GAME OVER, Press P to play again or q to quit.", 30, 200, 16)
pygame.display.update()
# quit or play again option
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
game_over = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
quit()
if event.key == pygame.K_p:
game_over = False
game()
clock.tick(snake_speed)
draw_food(foodX, foodY)
inc_length()
print_message("Score : " + str(lenth_of_snake - 1), 10, 10, 15)
pygame.display.update()
game()