Python Tetris Game — Build, Drop, Repeat!

Rahul Patodi
Wiki Flood
Published in
7 min readJan 24, 2024

About Python Tetris Game

In this Python project, we are going to build the classic Tetris Game using the Pygame library. Tetris is a popular tile-matching puzzle video game where players manipulate tetrominoes i.e. geometric shapes. The goal is to complete horizontal lines without any gaps, which causes the line to clear from the board. The game ends if the tetromino stack reaches the top of the playing field.

Prerequisites For Tetris Game in Python:

  • First, we will install the required libraries and modules in our system using the pip installer.
  • You need a good knowledge of Python, as well as the pygame library and the random module, to develop this game successfully.
pip install pygame
pip install random2
Tetris Game in Python
Tetris Game in Python

Importing the pygame library and random module in the program:

import pygame
import random

Implementing the Code for initializing the pygame window and images- Here, we define the number of rows, columns, screen size, frames per second (FPS), and images used in the Tetris game.

pygame.init()
Screen = Width, Height = 300, 500
win = pygame.display.set_mode(Screen, pygame.NOFRAME)

CellSize = 20
Rows = (Height-120) // CellSize
Columns = Width // CellSize

clock = pygame.time.Clock()
FPS = 45

#Colurs
Black = (21, 24, 29)
Blue = (31, 25, 76)
Red = (251, 92, 122)
White = (255, 255, 255)

#images
img1 = pygame.image.load('1.png')
img2 = pygame.image.load('2.png')
img3 = pygame.image.load('3.png')
img4 = pygame.image.load('4.png')

Assets = {1: img1, 2: img2, 3: img3, 4: img4}

#fonts
font = pygame.font.SysFont('Arial', 50)
font2 = pygame.font.SysFont('cursive', 25)

By using ‘pygame.init()’ we have initialized the pygame, and the game window is set up with a specified width and height using ‘pygame display’.

The clock is set up to control the frames per second and ‘FPS=45’.
Constants like cell size, number of rows and columns, and colours are defined.

We have defined a dictionary variable ‘Assets’ which contains the Images of Tetris blocks (Tetraaminos).

Code for the Tetraamino class- We will create a class for displaying the tetraaminos on the screen.

class Tetraamino:
Figures = {
'I': [[1, 5, 9, 13], [4, 5, 6, 7]],
'Z': [[4, 5, 9, 10], [2, 6, 5, 9]],
'S': [[6, 7, 9, 10], [1, 5, 6, 10]],
'L': [[1, 2, 5, 9], [0, 4, 5, 6], [1, 5, 9, 8], [4, 5, 6, 10]],
'J': [[1, 2, 6, 10], [5, 6, 7, 9], [2, 6, 10, 11], [3, 5, 6, 7]],
'T': [[1, 4, 5, 6], [1, 4, 5, 9], [4, 5, 6, 9], [1, 5, 6, 9]],
'O': [[1, 2, 5, 6]]
}

Types = ['I', 'Z', 'S', 'L', 'J', 'T', 'O']


def __init__(self, x, y):
self.x = x
self.y = y
self.type = random.choice(self.Types)
self.shape = self.Figures[self.type]
self.colour = random.randint(1, 4)
self.rotation = 0

def image(self):
return self.shape[self.rotation]

def rotate(self):
self.rotation = (self.rotation + 1) % len(self.shape)

The class ‘Tetraamino’ is used to represent tetraaminos.

Each Tetraamino has a position (x, y), type, shape, colour, and rotation which are defined in a variable ‘Figures’.

The ‘image()’ method is used to return the current shape of the Tetraamino based on its rotation.

The ‘rotate()’ method is used to allow the Tetraamino to change its rotation.

Code for the Tetris class- Now, here we will create a class in which different methods are defined, which are responsible for running the game smoothly.

class Tetris:
def __init__(self, rows, colms):
self.rows = rows
self.colms = colms
self.score = 0
self.level = 1
self.board = [[0 for j in range(colms)] for i in range(rows)]
self.next = None
self.gameover = False
self.new_figure()

def draw_grid(self):
for i in range(self.rows+1):
pygame.draw.line(win, White, (0, CellSize*i), (Width, CellSize*i))
for j in range(self.colms):
pygame.draw.line(win, White, (CellSize*j, 0), (CellSize*j, Height-120))

def new_figure(self):
if not self.next:
self.next = Tetraamino(5, 0)
self.figure = self.next
self.next = Tetraamino(5, 0)

def intersects(self):
intersection = False
for i in range(4):
for j in range(4):
if i * 4 + j in self.figure.image():
if i + self.figure.y > self.rows - 1 or \
j + self.figure.x > self.colms - 1 or \
j + self.figure.x < 0 or \
self.board[i + self.figure.y][j + self.figure.x] > 0:
intersection = True
return intersection

def remove_line(self):
rerun = False
for y in range(self.rows-1, 0, 1):
is_full = True
for x in range(0, self.colms):
if self.board[y][x] == 0:
is_full = False
if is_full:
del self.board[y]
self.board.insert(0, [0 for i in range(self.colms)])
self.score += 1
if self.score % 10 == 0:
self.level += 1
rerun = True

if rerun:
self.remove_line()

def freeze(self):
for i in range(4):
for j in range(4):
if i * 4 + j in self.figure.image():
self.board[i + self.figure.y][j + self.figure.x] = self.figure.colour
self.remove_line()
self.new_figure()
if self.intersects():
self.gameover = True

def go_space(self):
while not self.intersects():
self.figure.y += 1
self.figure.y -= 1
self.freeze()

def go_down(self):
self.figure.y += 1
if self.intersects():
self.figure.y -= 1
self.freeze()

def go_side(self, dx):
self.figure.x += dx
if self.intersects():
self.figure.x -= dx

def rotate(self):
rotation = self.figure.rotation
self.figure.rotate()
if self.intersects():
self.figure.rotation = rotation

The class ‘Tetris’ manages the overall game state, including the game board, score, level, and current and next Tetraaminos.

The ‘draw_grid()’ method draws the grid on the game board.

The ‘new_figure()’ method creates and assigns a new Tetraamino to the current figure while generating the next Tetraamino.

The ‘intersects()’ method is used to check if the current Tetraamino intersects with other blocks on the board.

The ‘remove_line()’ method removes completed lines from the board.

The ‘freeze()’ method locks the current Tetraamino in place when it cannot move further.

The ‘go_space()’ method instantly moves the current Tetraamino to the lowest possible position.

The ‘go_down()’ method moves the current Tetraamino down by one row.

The ‘go_side()’ method moves the current Tetraamino left or right.

The ‘rotate()’ method allows the current Tetraamino to rotate.

Code for the Main game loop- Here, we will define the main game function.

counter = 0
move_down = False
can_move = True


tetris = Tetris(Rows, Columns)


running = True
while running:
win.fill(Black)
counter += 1
if counter >= 10000:
counter = 0
if can_move:
if counter % (FPS // (tetris.level * 2)) == 0 or move_down:
if not tetris.gameover:
tetris.go_down()


for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False


if event.type == pygame.KEYDOWN:
if can_move and not tetris.gameover:
if event.key == pygame.K_LEFT:
tetris.go_side(-1)
if event.key == pygame.K_RIGHT:
tetris.go_side(1)
if event.key == pygame.K_UP:
tetris.rotate()
if event.key == pygame.K_DOWN:
move_down = True
if event.key == pygame.K_SPACE:
tetris.go_space()


if event.key == pygame.K_r:
tetris.__init__(Rows, Columns)


if event.key == pygame.K_p:
can_move = not can_move
if event.key == pygame.K_q or event.key == pygame.K_ESCAPE:
running = False


if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
move_down = False


for x in range(Rows):
for y in range(Columns):
if tetris.board[x][y] > 0:
val = tetris.board[x][y]
img = Assets[val]
win.blit(img, (y * CellSize, x * CellSize))
pygame.draw.rect(win, White, (y * CellSize, x * CellSize,
CellSize, CellSize), 1)


if tetris.figure:
for i in range(4):
for j in range(4):
if i * 4 + j in tetris.figure.image():
img = Assets[tetris.figure.colour]
x = CellSize * (tetris.figure.x + j)
y = CellSize * (tetris.figure.y + i)
win.blit(img, (x, y))
pygame.draw.rect(win, White, (x, y, CellSize, CellSize), 1)
#GAMEOVER
if tetris.gameover:
rect = pygame.Rect((50, 140, Width-100, Height-350))
pygame.draw.rect(win, Black, rect)
pygame.draw.rect(win, Red, rect, 2)

over = font2.render('Game Over', True, White)
msg1 = font2.render('Press r to restart', True, Red)
msg2 = font2.render('Press q to quite', True, Red)

win.blit(over, (rect.centerx-over.get_width() / 2, rect.y + 20))
win.blit(over, (rect.centerx-msg1.get_width() / 2, rect.y + 80))
win.blit(over, (rect.centerx-msg2.get_width() / 2, rect.y + 110))

pygame.draw.rect(win, Blue, (0, Height - 120, Width, 120))
if tetris.next:
for i in range(4):
for j in range(4):
if i * 4 + j in tetris.next.image():
img = Assets[tetris.next.colour]
x = CellSize * (tetris.next.x + j - 4)
y = Height - 100 + CellSize * (tetris.next.y + i)
win.blit(img, (x, y))

scoreimg = font.render(f'{tetris.score}', True, White)
levelimg = font2.render(f'Level : {tetris.level}', True, White)
win.blit(scoreimg, (250 - scoreimg.get_width() // 2, Height - 110))
win.blit(levelimg, (250 - levelimg.get_width() // 2, Height - 30))

pygame.draw.rect(win, Blue, (0, 0, Width, Height - 120), 2)
clock.tick(FPS)
pygame.display.update()
pygame.quit()

The ‘while’ loop controls the game’s logic and rendering.

We have used ‘if/else’ statements to handle user input for moving, rotating, and restarting the game. The Tetraaminos move down automatically, and the speed increases with the game’s level. The game continues until the player quits or triggers a game over condition.

The game board, Tetraaminos, score, and level are rendered on the screen.

The player can use arrow keys to move the Tetraamino left, right, or down and to rotate it.

The ‘space-bar’ allows the player to instantly drop the Tetraamino to the lowest possible position. The ‘r’ key restarts the game, and the ‘q’ key or escape key quits the game.

When a game-over condition is met (e.g., Tetraaminos reach the top of the board), a game-over message is displayed, and the player can choose to restart or quit.

The game keeps track of the player’s score and level using ‘font.render()’ method. The level increases every ten points.

Tetraaminos are drawn on the game board using images loaded from files. The board’s state is continually updated based on the Tetraaminos’ positions.

The ‘clock.tick(FPS)’ controls the game's frame rate, ensuring smooth animation and movement.

Python Tetris Game Output

Tetris Game in Python Output
Tetris Game in Python Output

Conclusion

We have successfully created the Python Tetris game, a fun and classic implementation of the popular Tetris puzzle game. This Python Tetris game project showcases the capabilities of the pygame library for creating 2D games in Python. Now you can enjoy playing it when bored and customize it according to your preferences.

--

--