import pygame
import sys
import random

# --- 游戏常量配置 ---
CELL_SIZE = 30
COLS = 10
ROWS = 20
SIDEBAR_WIDTH = 150
WINDOW_WIDTH = CELL_SIZE * COLS + SIDEBAR_WIDTH
WINDOW_HEIGHT = CELL_SIZE * ROWS

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRID_COLOR = (40, 40, 40)
BG_COLOR = (20, 20, 20)

# 7种经典方块的形状与颜色
SHAPES = {
    'I': [[(0,0), (1,0), (2,0), (3,0)], (0, 255, 255)],
    'O': [[(0,0), (1,0), (0,1), (1,1)], (255, 255, 0)],
    'T': [[(0,0), (1,0), (2,0), (1,1)], (128, 0, 255)],
    'S': [[(1,0), (2,0), (0,1), (1,1)], (0, 255, 0)],
    'Z': [[(0,0), (1,0), (1,1), (2,1)], (255, 0, 0)],
    'J': [[(0,0), (0,1), (1,1), (2,1)], (0, 0, 255)],
    'L': [[(2,0), (0,1), (1,1), (2,1)], (255, 165, 0)]
}

class Tetris:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
        pygame.display.set_caption("Python 俄罗斯方块")
        self.font = pygame.font.Font(None, 36)
        self.clock = pygame.time.Clock()
        
        self.reset_game()

    def reset_game(self):
        """重置游戏状态"""
        # 0代表空，其他代表颜色
        self.grid = [[0 for _ in range(COLS)] for _ in range(ROWS)]
        self.score = 0
        self.game_over = False
        
        self.current_piece = self.new_piece()
        self.next_piece = self.new_piece()
        
        self.drop_interval = 500  # 毫秒
        self.last_drop_time = pygame.time.get_ticks()

    def new_piece(self):
        """生成一个新的方块"""
        shape_key = random.choice(list(SHAPES.keys()))
        shape, color = SHAPES[shape_key]
        return {
            'shape': [list(cell) for cell in shape],
            'color': color,
            'x': COLS // 2 - 2,
            'y': 0
        }

    def get_absolute_coords(self, piece):
        """获取方块在网格中的绝对坐标"""
        return [(piece['x'] + dx, piece['y'] + dy) for dx, dy in piece['shape']]

    def is_valid_move(self, piece, dx=0, dy=0, new_shape=None):
        """检测移动或旋转后是否合法（不越界且不碰撞）"""
        shape = new_shape if new_shape else piece['shape']
        for x, y in shape:
            nx, ny = piece['x'] + x + dx, piece['y'] + y + dy
            if nx < 0 or nx >= COLS or ny >= ROWS:
                return False
            if ny >= 0 and self.grid[ny][nx] != 0:
                return False
        return True

    def rotate(self, piece):
        """旋转方块 (顺时针)"""
        # 旋转公式: (x, y) -> (-y, x)
        new_shape = [[-y, x] for x, y in piece['shape']]
        # 平移归正，使其回到第一象限
        min_x = min(x for x, y in new_shape)
        min_y = min(y for x, y in new_shape)
        new_shape = [[x - min_x, y - min_y] for x, y in new_shape]
        
        if self.is_valid_move(piece, 0, 0, new_shape):
            piece['shape'] = new_shape

    def lock_piece(self):
        """将当前方块锁定到网格中"""
        for x, y in self.get_absolute_coords(self.current_piece):
            if y < 0:
                self.game_over = True
                return
            self.grid[y][x] = self.current_piece['color']
        self.clear_lines()
        self.current_piece = self.next_piece
        self.next_piece = self.new_piece()

    def clear_lines(self):
        """消除满行并计分"""
        lines_cleared = 0
        new_grid = []
        for row in self.grid:
            if all(cell != 0 for cell in row):
                lines_cleared += 1
            else:
                new_grid.append(row)
        
        # 在顶部补充空行
        for _ in range(lines_cleared):
            new_grid.insert(0, [0 for _ in range(COLS)])
            
        self.grid = new_grid
        self.score += lines_cleared * 100

    def update(self):
        """处理自动下落逻辑"""
        if self.game_over:
            return
            
        current_time = pygame.time.get_ticks()
        if current_time - self.last_drop_time > self.drop_interval:
            if self.is_valid_move(self.current_piece, 0, 1):
                self.current_piece['y'] += 1
            else:
                self.lock_piece()
            self.last_drop_time = current_time

    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, GRID_COLOR, rect, 1)
                if self.grid[y][x] != 0:
                    pygame.draw.rect(self.screen, self.grid[y][x], rect.inflate(-2, -2))

    def draw_piece(self, piece):
        """绘制当前方块"""
        for x, y in self.get_absolute_coords(piece):
            if y >= 0:
                rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
                pygame.draw.rect(self.screen, piece['color'], rect.inflate(-2, -2))

    def draw_sidebar(self):
        """绘制侧边栏信息"""
        offset_x = CELL_SIZE * COLS + 20
        score_text = self.font.render(f"Score: {self.score}", True, WHITE)
        next_text = self.font.render("Next:", True, WHITE)
        
        self.screen.blit(score_text, (offset_x, 50))
        self.screen.blit(next_text, (offset_x, 120))
        
        # 绘制下一个方块预览
        for dx, dy in self.next_piece['shape']:
            rect = pygame.Rect(offset_x + dx * 20, 160 + dy * 20, 20, 20)
            pygame.draw.rect(self.screen, self.next_piece['color'], rect)

        if self.game_over:
            over_text = self.font.render("GAME OVER", True, (255, 0, 0))
            restart_text = self.font.render("R to Restart", True, WHITE)
            self.screen.blit(over_text, (offset_x, 300))
            self.screen.blit(restart_text, (offset_x, 350))

    def run(self):
        """游戏主循环"""
        while True:
            self.clock.tick(60)
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                
                if event.type == pygame.KEYDOWN:
                    if self.game_over:
                        if event.key == pygame.K_r:
                            self.reset_game()
                        continue

                    if event.key == pygame.K_LEFT:
                        if self.is_valid_move(self.current_piece, -1, 0):
                            self.current_piece['x'] -= 1
                    elif event.key == pygame.K_RIGHT:
                        if self.is_valid_move(self.current_piece, 1, 0):
                            self.current_piece['x'] += 1
                    elif event.key == pygame.K_DOWN:
                        if self.is_valid_move(self.current_piece, 0, 1):
                            self.current_piece['y'] += 1
                            self.score += 1  # 软降加分
                    elif event.key == pygame.K_UP:
                        self.rotate(self.current_piece)

            self.update()
            
            self.screen.fill(BG_COLOR)
            self.draw_grid()
            self.draw_piece(self.current_piece)
            self.draw_sidebar()
            pygame.display.flip()

if __name__ == "__main__":
    game = Tetris()
    game.run()