import pygame import random # Инициализация pygame pygame.init() # Цвета BLACK = (0, 0, 0) WHITE = (255, 255, 255) GRAY = (70, 70, 70) COLORS = [ (0, 255, 255), # I - голубой (0, 0, 255), # J - синий (255, 165, 0), # L - оранжевый (255, 255, 0), # O - желтый (0, 255, 0), # S - зеленый (128, 0, 128), # T - фиолетовый (255, 0, 0) # Z - красный ] # Настройки игры BLOCK_SIZE = 30 GRID_WIDTH = 10 GRID_HEIGHT = 20 SCREEN_WIDTH = BLOCK_SIZE * (GRID_WIDTH + 6) SCREEN_HEIGHT = BLOCK_SIZE * GRID_HEIGHT GAME_AREA_LEFT = BLOCK_SIZE # Фигуры тетрамино SHAPES = [ [[1, 1, 1, 1]], # I [[1, 0, 0], [1, 1, 1]], # J [[0, 0, 1], [1, 1, 1]], # L [[1, 1], [1, 1]], # O [[0, 1, 1], [1, 1, 0]], # S [[0, 1, 0], [1, 1, 1]], # T [[1, 1, 0], [0, 1, 1]] # Z ] # Создание экрана screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("Тетрис") # Часы для управления FPS clock = pygame.time.Clock() class Tetris: def __init__(self): self.grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)] self.current_piece = self.new_piece() self.game_over = False self.score = 0 self.level = 1 self.fall_speed = 0.5 # секунды между падением на 1 клетку self.fall_time = 0 def new_piece(self): # Выбираем случайную фигуру shape = random.choice(SHAPES) color = COLORS[SHAPES.index(shape)] # Начальная позиция (по центру сверху) x = GRID_WIDTH // 2 - len(shape[0]) // 2 y = 0 return {"shape": shape, "color": color, "x": x, "y": y} def valid_move(self, piece, x_offset=0, y_offset=0): for y, row in enumerate(piece["shape"]): for x, cell in enumerate(row): if cell: new_x = piece["x"] + x + x_offset new_y = piece["y"] + y + y_offset if (new_x < 0 or new_x >= GRID_WIDTH or new_y >= GRID_HEIGHT or (new_y >= 0 and self.grid[new_y][new_x])): return False return True def rotate_piece(self): # Получаем текущую фигуру piece = self.current_piece # Транспонируем матрицу фигуры (поворот на 90 градусов) rotated = [[piece["shape"][y][x] for y in range(len(piece["shape"])-1, -1, -1)] for x in range(len(piece["shape"][0]))] old_shape = piece["shape"] piece["shape"] = rotated # Если после поворота фигура выходит за границы или пересекается с другими блоками, # отменяем поворот if not self.valid_move(piece): piece["shape"] = old_shape def lock_piece(self): piece = self.current_piece for y, row in enumerate(piece["shape"]): for x, cell in enumerate(row): if cell: # Проверяем, не выходит ли фигура за верхнюю границу (игра окончена) if piece["y"] + y < 0: self.game_over = True else: self.grid[piece["y"] + y][piece["x"] + x] = piece["color"] # Проверяем заполненные линии self.clear_lines() # Создаем новую фигуру self.current_piece = self.new_piece() # Если новая фигура сразу не может разместиться, игра окончена if not self.valid_move(self.current_piece): self.game_over = True def clear_lines(self): lines_cleared = 0 for y in range(GRID_HEIGHT): if all(self.grid[y]): lines_cleared += 1 # Удаляем линию и сдвигаем все вышележащие линии вниз for y2 in range(y, 0, -1): self.grid[y2] = self.grid[y2-1][:] self.grid[0] = [0 for _ in range(GRID_WIDTH)] # Обновляем счет if lines_cleared == 1: self.score += 100 * self.level elif lines_cleared == 2: self.score += 300 * self.level elif lines_cleared == 3: self.score += 500 * self.level elif lines_cleared == 4: self.score += 800 * self.level # Обновляем уровень (каждые 10 линий) self.level = 1 + self.score // 1000 # Увеличиваем скорость (максимум 0.05 секунды между падениями) self.fall_speed = max(0.05, 0.5 - (self.level - 1) * 0.05) def update(self, delta_time): if self.game_over: return self.fall_time += delta_time # Автоматическое падение фигуры if self.fall_time >= self.fall_speed: self.fall_time = 0 if self.valid_move(self.current_piece, 0, 1): self.current_piece["y"] += 1 else: self.lock_piece() def draw(self): # Очищаем экран screen.fill(BLACK) # Рисуем игровую область pygame.draw.rect(screen, WHITE, (GAME_AREA_LEFT, 0, BLOCK_SIZE * GRID_WIDTH, SCREEN_HEIGHT), 1) # Рисуем сетку for x in range(GRID_WIDTH): for y in range(GRID_HEIGHT): pygame.draw.rect(screen, GRAY, (GAME_AREA_LEFT + x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 1) # Рисуем статичные блоки for y in range(GRID_HEIGHT): for x in range(GRID_WIDTH): if self.grid[y][x]: pygame.draw.rect(screen, self.grid[y][x], (GAME_AREA_LEFT + x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)) pygame.draw.rect(screen, WHITE, (GAME_AREA_LEFT + x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 1) # Рисуем текущую фигуру if not self.game_over: piece = self.current_piece for y, row in enumerate(piece["shape"]): for x, cell in enumerate(row): if cell: pygame.draw.rect(screen, piece["color"], (GAME_AREA_LEFT + (piece["x"] + x) * BLOCK_SIZE, (piece["y"] + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)) pygame.draw.rect(screen, WHITE, (GAME_AREA_LEFT + (piece["x"] + x) * BLOCK_SIZE, (piece["y"] + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 1) # Рисуем информацию (счет, уровень) font = pygame.font.SysFont(None, 36) score_text = font.render(f"Счет: {self.score}", True, WHITE) level_text = font.render(f"Уровень: {self.level}", True, WHITE) screen.blit(score_text, (GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE + 10, 30)) screen.blit(level_text, (GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE + 10, 70)) # Если игра окончена, выводим сообщение if self.game_over: game_over_font = pygame.font.SysFont(None, 48) game_over_text = game_over_font.render("Игра Окончена!", True, (255, 0, 0)) screen.blit(game_over_text, (GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE // 2 - 100, SCREEN_HEIGHT // 2 - 24)) # Создаем экземпляр игры game = Tetris() # Основной игровой цикл running = True last_time = pygame.time.get_ticks() while running: # Управление FPS current_time = pygame.time.get_ticks() delta_time = (current_time - last_time) / 1000.0 # Конвертируем в секунды last_time = current_time # Обработка событий for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if not game.game_over: if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: if game.valid_move(game.current_piece, -1, 0): game.current_piece["x"] -= 1 elif event.key == pygame.K_RIGHT: if game.valid_move(game.current_piece, 1, 0): game.current_piece["x"] += 1 elif event.key == pygame.K_DOWN: if game.valid_move(game.current_piece, 0, 1): game.current_piece["y"] += 1 elif event.key == pygame.K_UP: game.rotate_piece() elif event.key == pygame.K_SPACE: # Мгновенное падение while game.valid_move(game.current_piece, 0, 1): game.current_piece["y"] += 1 game.lock_piece() # Обновление игры game.update(delta_time) # Отрисовка game.draw() pygame.display.flip() # Ограничиваем FPS clock.tick(60) pygame.quit()