
Install dependencies if not already done:
pip install pygame
You’ll need to include sound files:
line.wav (for line clear)rotate.wav (for rotation)gameover.wav (for game over)import pygame
import random
import json
import os
# --- Game Configuration ---
CELL_SIZE = 30
COLS = 10
ROWS = 20
WIDTH = CELL_SIZE * COLS
HEIGHT = CELL_SIZE * ROWS
FPS = 60
# Colors
BLACK = (0, 0, 0)
GRAY = (128, 128, 128)
WHITE = (255, 255, 255)
COLORS = [
(0, 255, 255), (255, 255, 0), (128, 0, 128),
(0, 255, 0), (255, 0, 0), (0, 0, 255), (255, 165, 0)
]
# Tetromino Shapes
SHAPES = {
'I': [[1, 1, 1, 1]],
'O': [[1, 1], [1, 1]],
'T': [[0, 1, 0], [1, 1, 1]],
'S': [[0, 1, 1], [1, 1, 0]],
'Z': [[1, 1, 0], [0, 1, 1]],
'J': [[1, 0, 0], [1, 1, 1]],
'L': [[0, 0, 1], [1, 1, 1]]
}
class Tetromino:
def __init__(self, shape):
self.shape = shape
self.color = random.choice(COLORS)
self.x = COLS // 2 - len(shape[0]) // 2
self.y = 0
def rotate(self):
self.shape = [list(row) for row in zip(*self.shape[::-1])]
class Tetris:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Tetris")
self.clock = pygame.time.Clock()
self.grid = [[None for _ in range(COLS)] for _ in range(ROWS)]
self.score = 0
self.level = 1
self.load_highscore()
self.drop_time = 1000
self.last_drop = pygame.time.get_ticks()
self.running = True
self.font = pygame.font.SysFont('Arial', 24)
self.sounds = {
'line': pygame.mixer.Sound('line.wav'),
'rotate': pygame.mixer.Sound('rotate.wav'),
'gameover': pygame.mixer.Sound('gameover.wav')
}
self.tetromino = self.new_tetromino()
def new_tetromino(self):
shape = random.choice(list(SHAPES.values()))
return Tetromino(shape)
def valid_position(self, shape, offset_x, offset_y):
for y, row in enumerate(shape):
for x, cell in enumerate(row):
if cell:
nx, ny = offset_x + x, offset_y + y
if nx < 0 or nx >= COLS or ny >= ROWS:
return False
if ny >= 0 and self.grid[ny][nx]:
return False
return True
def lock_tetromino(self):
for y, row in enumerate(self.tetromino.shape):
for x, cell in enumerate(row):
if cell:
self.grid[self.tetromino.y + y][self.tetromino.x + x] = self.tetromino.color
self.clear_lines()
self.tetromino = self.new_tetromino()
if not self.valid_position(self.tetromino.shape, self.tetromino.x, self.tetromino.y):
self.running = False
self.sounds['gameover'].play()
self.save_highscore()
def clear_lines(self):
lines = 0
new_grid = []
for row in self.grid:
if all(row):
lines += 1
new_grid.insert(0, [None] * COLS)
else:
new_grid.append(row)
self.grid = new_grid
if lines:
self.sounds['line'].play()
self.score += lines * 100
self.level = self.score // 500 + 1
self.drop_time = max(100, 1000 - (self.level - 1) * 100)
def draw_grid(self):
for y in range(ROWS):
for x in range(COLS):
rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
pygame.draw.rect(self.screen, GRAY, rect, 1)
if self.grid[y][x]:
pygame.draw.rect(self.screen, self.grid[y][x], rect)
def draw_tetromino(self):
for y, row in enumerate(self.tetromino.shape):
for x, cell in enumerate(row):
if cell:
rect = pygame.Rect((self.tetromino.x + x) * CELL_SIZE, (self.tetromino.y + y) * CELL_SIZE, CELL_SIZE, CELL_SIZE)
pygame.draw.rect(self.screen, self.tetromino.color, rect)
def draw_ui(self):
score_text = self.font.render(f"Score: {self.score}", True, WHITE)
level_text = self.font.render(f"Level: {self.level}", True, WHITE)
highscore_text = self.font.render(f"Highscore: {self.highscore}", True, WHITE)
self.screen.blit(score_text, (10, 10))
self.screen.blit(level_text, (10, 40))
self.screen.blit(highscore_text, (10, 70))
def move(self, dx):
if self.valid_position(self.tetromino.shape, self.tetromino.x + dx, self.tetromino.y):
self.tetromino.x += dx
def rotate(self):
old_shape = self.tetromino.shape
self.tetromino.rotate()
if self.valid_position(self.tetromino.shape, self.tetromino.x, self.tetromino.y):
self.sounds['rotate'].play()
else:
self.tetromino.shape = old_shape
def drop(self):
if self.valid_position(self.tetromino.shape, self.tetromino.x, self.tetromino.y + 1):
self.tetromino.y += 1
else:
self.lock_tetromino()
def load_highscore(self):
try:
with open('highscore.json', 'r') as f:
self.highscore = json.load(f).get('highscore', 0)
except:
self.highscore = 0
def save_highscore(self):
if self.score > self.highscore:
with open('highscore.json', 'w') as f:
json.dump({'highscore': self.score}, f)
def run(self):
while self.running:
self.screen.fill(BLACK)
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.move(-1)
elif event.key == pygame.K_RIGHT:
self.move(1)
elif event.key == pygame.K_DOWN:
self.drop()
elif event.key == pygame.K_UP:
self.rotate()
now = pygame.time.get_ticks()
if now - self.last_drop > self.drop_time:
self.drop()
self.last_drop = now
self.draw_grid()
self.draw_tetromino()
self.draw_ui()
pygame.display.flip()
self.clock.tick(FPS)
pygame.quit()
if __name__ == '__main__':
Tetris().run()