Friday May 1, 2026

  • This Free Friday I am working on a project on YouTube a Tetris game.
import pygame 
import random
import sys

pygame.init()

WIDTH, HEIGHT = 300, 500
FPS = 35
CELL = 20
ROWS = (HEIGHT - 120) // CELL
COLS = WIDTH // CELL

SCREEN = pygame.display.set_mode((WIDTH, HEIGHT), pygame.NOFRAME)
clock = pygame.time.Clock()
pygame.display.set_caption("Tetris")

BLACK = (0,0,0)
WHITE = (255,255, 255)
BG_COLOR = (31, 25, 76)
GRID = (31, 25, 132)
WIN = (50, 230, 50)
LOSE = (252, 91, 122)

ASSETS ={
    1: pygame.image.load("Assets/1.png"),
    2: pygame.image.load("Assets/2.png"),
    3: pygame.image.load("Assets/3.png"),
    4: pygame.image.load("Assets/4.png")
}

font = pygame.font.SysFont("verdana", 50)
font2 = pygame.font.SysFont("verdana", 15)
  • Initializes Pygame and creates a 300×500 window with no frame.
  • Defines constants:
    • Grid cell size
    • Number of rows/columns
    • Colors
    • Block images (1.png, 2.png, etc.)
  • Creates fonts for text.
  • This section prepares everything the game needs before running.
class Shape:
    VERSION = {
        '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,6, 10], [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]]
    }

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

    def __init__(self,x,y):
        self.x = x
        self.y = y
        self.type = random.choice(self.SHAPES)
        self.shape = self.VERSION[self.type]
        self.color = random.randint(1,4)
        self.orientation = 0

    def image(self):
        return self.shape[self.orientation]
    
    def rotate(self):
        self.orientation = (self.orientation + 1) % len(self.shape)
  • This class represents a single falling Tetris piece.
  • Each shape type (I, Z, S, L, J, T, O) has predefined rotation patterns.
  • A shape has:
    • x, y position on the grid
    • A random type
    • A random color (1–4)
    • A rotation index (orientation)
  • image() returns the current rotation pattern.
  • rotate() cycles through the available rotations.
  • This class handles the behavior of individual tetrominoes.
class Tetris:

    def __init__(self, rows, cols):
        self.rows = rows
        self.cols = cols
        self.score = 0
        self.level = 1
        self.grid = [[0 for j in range(cols)] for i in range(rows)]
        self.next = None
        self.end = False
        self.new_shape()

    def make_grid(self):
        for i in range(self.rows + 1):
            pygame.draw.line(SCREEN, GRID, (0,CELL*i), (WIDTH,CELL*i))
        for j in range(self.rows + 1):
            pygame.draw.line(SCREEN, GRID, (CELL*j, 0), (CELL*j, HEIGHT-120))

    def new_shape(self):
        if not self.next:
            self.next = Shape(5,0)
        self.figure = self.next
        self.next = Shape(5,0)

    def collision(self) -> bool:
        for i in range(4):
            for j in range(4):
                if (i*4 *j) in self.figure.image():
                    block_row = i + self.figure.y
                    block_col = j + self.figure.x
                    if(block_row >= self.rows or block_col >= self.cols or block_col < 0 or self.grid(block_row) (block_col) > 0):
                        return True
                    
            return False
        

    def freeze(self):
        for i in range(4):
            for j in range(4):
                if (i*4+j) in self.figure.image():
                    self.grid[i+self.figure.y][j+self.figure.x] = self.figure.color

        self.new_shape()
        if self.collision():
            self.end = True


    def move_down(self):
        self.figure.y += 1
        if self.collision():
            self.figure.y -= 1
            self.freeze()

    def left(self):
        self.figure.x -= 1
        if self.collision():
            self.figure.x += 1

    def right(self):
        self.figure.y += 1
        if self.collision():
            self.figure.y -= 1

    def freefall(self):
        while not self.collision():
            self.figure.y += 1
        self.figure.y -= 1
        self.freeze()

    def rotate(self):
        orientation = self.figure.orientation
        self.figure.rotate()
        if self.collision():
            self.figure.orientation = orientation
  • This class manages the entire game board.
  • It stores:
  • The grid (2D list of rows × columns)
  • The current falling shape
  • The next shape
  • Score, level, and game-over state
  • It handles:
  • Drawing the grid
  • Spawning new shapes
  • Collision detection
  • Freezing pieces into the grid
  • Movement (left, right, down)
  • Rotation
  • Instant drop (space bar)
  • This is the core engine of the game.
def main():
    tetris = Tetris(ROWS, COLS)
    counter = 0
    move = True
    run = True
    space_pressed = False
    while run:
        SCREEN.fill(BG_COLOR)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                sys.exit()

        keys = pygame.key.get_pressed()
        if not tetris.end:
            if keys[pygame.K_LEFT]:
                tetris.left()
            elif keys[pygame.K_RIGHT]:
                tetris.right()
            elif keys[pygame.K_DOWN]:
                tetris.move_down()
            elif keys[pygame.K_UP]:
                tetris.rotate()
            elif keys[pygame.K_SPACE]:
                space_pressed = True
        if keys[pygame.K_ESCAPE] or keys[pygame.K_q]:
            run = False

        counter += 1
        if counter >= 15000:
            counter = 0 

        if move:
            if counter % (FPS //(tetris.level*2)) == 0:
                if not tetris.end:
                    if space_pressed:
                        tetris.freefall()
                        space_pressed = False
                    else:
                        tetris.move_down()

        tetris.make_grid()

        for x in range(ROWS):
            for y in range(COLS):
                if tetris.grid[x][y] > 0:
                    value = tetris.grid[x][y]
                    image = ASSETS[value]
                    SCREEN.blit(image, (x*CELL, y*CELL))
                    pygame.draw.rect(SCREEN, WHITE, (y*CELL, x*CELL, CELL, CELL),1)

        if tetris.figure:
            for i in range(4):
                for j in range(4):
                    if (i *4 + j) in tetris.figure.image():
                        shape = ASSETS[tetris.figure.color]
                        x = CELL * (tetris.figure.x + j)
                        y = CELL * (tetris.figure.y + i)
                        SCREEN.blit(shape, (x,y))
                        pygame.draw.rect(SCREEN, WHITE, (x,y,CELL,CELL),1)


        pygame.display.update()
        clock.tick(FPS)


if __name__ == "__main__":
    main()
     
  • Runs continuously until the player quits.
  • It handles:
  • Keyboard input:
    • Arrow keys to move/rotate
    • Space for instant drop
    • Escape/Q to quit
  • Automatic falling based on a timer
  • Drawing:
    • Background
    • Grid lines
    • Frozen blocks
    • Current falling piece
  • Updating the display each frame
  • This loop is the heartbeat of the game.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top