import pygame
import sys
import random
import math

# 初始化 Pygame
pygame.init()

# 窗口设置
WIDTH, HEIGHT = 500, 650
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("2048")

# 颜色定义
BACKGROUND = (250, 248, 239)
GRID_COLOR = (187, 173, 160)
EMPTY_COLOR = (205, 193, 180)

# 数字颜色映射
COLORS = {
    0: (205, 193, 180),
    2: (238, 228, 218),
    4: (237, 224, 200),
    8: (242, 177, 121),
    16: (245, 149, 99),
    32: (246, 124, 95),
    64: (246, 94, 59),
    128: (237, 207, 114),
    256: (237, 204, 97),
    512: (237, 200, 80),
    1024: (237, 197, 63),
    2048: (237, 194, 46),
    4096: (60, 58, 50),
    8192: (60, 58, 50),
}

TEXT_COLORS = {
    0: (205, 193, 180),
    2: (119, 110, 101),
    4: (119, 110, 101),
    8: (249, 246, 242),
    16: (249, 246, 242),
    32: (249, 246, 242),
    64: (249, 246, 242),
    128: (249, 246, 242),
    256: (249, 246, 242),
    512: (249, 246, 242),
    1024: (249, 246, 242),
    2048: (249, 246, 242),
    4096: (249, 246, 242),
    8192: (249, 246, 242),
}

# 帧率控制
clock = pygame.time.Clock()
FPS = 60

# 中文字体
def get_chinese_font(size):
    font_names = ["SimHei", "Microsoft YaHei", "PingFang SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", "Arial"]
    for name in font_names:
        try:
            return pygame.font.SysFont(name, size)
        except:
            continue
    return pygame.font.Font(None, size)

font = get_chinese_font(30)
small_font = get_chinese_font(18)
big_font = get_chinese_font(50)

# 2048游戏类
class Game2048:
    def __init__(self):
        self.size = 4
        self.grid = [[0 for _ in range(self.size)] for _ in range(self.size)]
        self.score = 0
        self.best_score = 0
        self.game_over = False
        self.win = False
        self.moved = False
        self.animating = False
        self.animation_queue = []
        
        # 动画相关
        self.tile_animations = []  # (row, col, from_row, from_col, progress)
        self.new_tile_animations = []  # (row, col, progress)
        self.merge_animations = []  # (row, col, progress)
        
        # 网格尺寸
        self.grid_size = 400
        self.grid_padding = 20
        self.cell_size = (self.grid_size - self.grid_padding * 5) // 4
        self.grid_x = (WIDTH - self.grid_size) // 2
        self.grid_y = 120
        
        # 初始化两个方块
        self.add_random_tile()
        self.add_random_tile()
        
        # 加载最佳分数
        self.load_best_score()
    
    def load_best_score(self):
        try:
            with open("2048_best.txt", "r") as f:
                self.best_score = int(f.read())
        except:
            self.best_score = 0
    
    def save_best_score(self):
        if self.score > self.best_score:
            self.best_score = self.score
            try:
                with open("2048_best.txt", "w") as f:
                    f.write(str(self.best_score))
            except:
                pass
    
    def add_random_tile(self):
        empty_cells = [(r, c) for r in range(self.size) for c in range(self.size) if self.grid[r][c] == 0]
        if empty_cells:
            r, c = random.choice(empty_cells)
            value = 2 if random.random() < 0.9 else 4
            self.grid[r][c] = value
            self.new_tile_animations.append([r, c, 0])
            return True
        return False
    
    def get_empty_cells(self):
        return [(r, c) for r in range(self.size) for c in range(self.size) if self.grid[r][c] == 0]
    
    def move(self, direction):
        if self.game_over or self.win or self.animating:
            return False
        
        moved = False
        merged = [[False for _ in range(self.size)] for _ in range(self.size)]
        score_gain = 0
        
        # 处理不同方向
        if direction == "up":
            for c in range(self.size):
                for r in range(1, self.size):
                    if self.grid[r][c] != 0:
                        new_r = r
                        while new_r > 0 and self.grid[new_r-1][c] == 0:
                            new_r -= 1
                        if new_r != r:
                            self.grid[new_r][c] = self.grid[r][c]
                            self.grid[r][c] = 0
                            moved = True
                        if new_r > 0 and self.grid[new_r-1][c] == self.grid[new_r][c] and not merged[new_r-1][c]:
                            self.grid[new_r-1][c] *= 2
                            score_gain += self.grid[new_r-1][c]
                            self.grid[new_r][c] = 0
                            merged[new_r-1][c] = True
                            moved = True
        
        elif direction == "down":
            for c in range(self.size):
                for r in range(self.size-2, -1, -1):
                    if self.grid[r][c] != 0:
                        new_r = r
                        while new_r < self.size-1 and self.grid[new_r+1][c] == 0:
                            new_r += 1
                        if new_r != r:
                            self.grid[new_r][c] = self.grid[r][c]
                            self.grid[r][c] = 0
                            moved = True
                        if new_r < self.size-1 and self.grid[new_r+1][c] == self.grid[new_r][c] and not merged[new_r+1][c]:
                            self.grid[new_r+1][c] *= 2
                            score_gain += self.grid[new_r+1][c]
                            self.grid[new_r][c] = 0
                            merged[new_r+1][c] = True
                            moved = True
        
        elif direction == "left":
            for r in range(self.size):
                for c in range(1, self.size):
                    if self.grid[r][c] != 0:
                        new_c = c
                        while new_c > 0 and self.grid[r][new_c-1] == 0:
                            new_c -= 1
                        if new_c != c:
                            self.grid[r][new_c] = self.grid[r][c]
                            self.grid[r][c] = 0
                            moved = True
                        if new_c > 0 and self.grid[r][new_c-1] == self.grid[r][new_c] and not merged[r][new_c-1]:
                            self.grid[r][new_c-1] *= 2
                            score_gain += self.grid[r][new_c-1]
                            self.grid[r][new_c] = 0
                            merged[r][new_c-1] = True
                            moved = True
        
        elif direction == "right":
            for r in range(self.size):
                for c in range(self.size-2, -1, -1):
                    if self.grid[r][c] != 0:
                        new_c = c
                        while new_c < self.size-1 and self.grid[r][new_c+1] == 0:
                            new_c += 1
                        if new_c != c:
                            self.grid[r][new_c] = self.grid[r][c]
                            self.grid[r][c] = 0
                            moved = True
                        if new_c < self.size-1 and self.grid[r][new_c+1] == self.grid[r][new_c] and not merged[r][new_c+1]:
                            self.grid[r][new_c+1] *= 2
                            score_gain += self.grid[r][new_c+1]
                            self.grid[r][new_c] = 0
                            merged[r][new_c+1] = True
                            moved = True
        
        if moved:
            self.score += score_gain
            self.save_best_score()
            self.add_random_tile()
            self.check_game_over()
            return True
        return False
    
    def check_game_over(self):
        if not self.get_empty_cells():
            # 检查是否有相邻相同的数字
            for r in range(self.size):
                for c in range(self.size):
                    if c < self.size-1 and self.grid[r][c] == self.grid[r][c+1]:
                        return
                    if r < self.size-1 and self.grid[r][c] == self.grid[r+1][c]:
                        return
            self.game_over = True
        
        # 检查胜利 (2048)
        for r in range(self.size):
            for c in range(self.size):
                if self.grid[r][c] == 2048 and not self.win:
                    self.win = True
    
    def reset(self):
        self.grid = [[0 for _ in range(self.size)] for _ in range(self.size)]
        self.score = 0
        self.game_over = False
        self.win = False
        self.add_random_tile()
        self.add_random_tile()
    
    def get_cell_position(self, row, col):
        x = self.grid_x + self.grid_padding + col * (self.cell_size + self.grid_padding)
        y = self.grid_y + self.grid_padding + row * (self.cell_size + self.grid_padding)
        return x, y
    
    def draw_tile(self, surface, value, x, y, size, alpha=255):
        # 获取颜色
        color = COLORS.get(value, COLORS[0])
        text_color = TEXT_COLORS.get(value, (255, 255, 255))
        
        # 绘制方块
        rect = pygame.Rect(x, y, size, size)
        pygame.draw.rect(surface, color, rect, border_radius=6)
        
        # 显示数字
        if value > 0:
            # 根据数字大小调整字体
            if value < 100:
                font_size = int(size * 0.5)
            elif value < 1000:
                font_size = int(size * 0.4)
            else:
                font_size = int(size * 0.3)
            
            num_font = get_chinese_font(font_size)
            text = num_font.render(str(value), True, text_color)
            text_rect = text.get_rect(center=(x + size // 2, y + size // 2))
            surface.blit(text, text_rect)
    
    def draw(self, surface):
        # 背景
        surface.fill(BACKGROUND)
        
        # 标题
        title = big_font.render("2048", True, (119, 110, 101))
        surface.blit(title, (20, 20))
        
        # 分数面板
        score_rect = pygame.Rect(WIDTH - 160, 20, 140, 60)
        pygame.draw.rect(surface, (187, 173, 160), score_rect, border_radius=6)
        score_label = small_font.render("分数", True, (249, 246, 242))
        surface.blit(score_label, (WIDTH - 140, 25))
        score_text = font.render(str(self.score), True, (249, 246, 242))
        surface.blit(score_text, (WIDTH - 130, 45))
        
        # 最佳分数
        best_rect = pygame.Rect(WIDTH - 160, 85, 140, 50)
        pygame.draw.rect(surface, (187, 173, 160), best_rect, border_radius=6)
        best_label = small_font.render("最佳", True, (249, 246, 242))
        surface.blit(best_label, (WIDTH - 140, 90))
        best_text = font.render(str(self.best_score), True, (249, 246, 242))
        surface.blit(best_text, (WIDTH - 130, 108))
        
        # 游戏网格背景
        grid_bg = pygame.Rect(self.grid_x, self.grid_y, self.grid_size, self.grid_size)
        pygame.draw.rect(surface, GRID_COLOR, grid_bg, border_radius=6)
        
        # 绘制网格线（通过绘制空方块实现）
        for r in range(self.size):
            for c in range(self.size):
                x, y = self.get_cell_position(r, c)
                pygame.draw.rect(surface, EMPTY_COLOR, 
                               (x, y, self.cell_size, self.cell_size), border_radius=6)
        
        # 绘制数字方块
        for r in range(self.size):
            for c in range(self.size):
                if self.grid[r][c] != 0:
                    x, y = self.get_cell_position(r, c)
                    self.draw_tile(surface, self.grid[r][c], x, y, self.cell_size)
        
        # 新方块动画（缩放效果）
        for anim in self.new_tile_animations[:]:
            r, c, progress = anim
            if progress < 1:
                anim[2] += 0.1
                scale = 0.5 + 0.5 * anim[2]
                x, y = self.get_cell_position(r, c)
                size = int(self.cell_size * scale)
                offset = (self.cell_size - size) // 2
                self.draw_tile(surface, self.grid[r][c], x + offset, y + offset, size)
            else:
                self.new_tile_animations.remove(anim)
        
        # 游戏结束覆盖层
        if self.game_over:
            overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            overlay.fill((0, 0, 0, 180))
            surface.blit(overlay, (0, 0))
            
            game_over_text = font.render("游戏结束!", True, (249, 246, 242))
            text_rect = game_over_text.get_rect(center=(WIDTH // 2, HEIGHT // 2 - 40))
            surface.blit(game_over_text, text_rect)
            
            restart_text = small_font.render("按 R 重新开始", True, (249, 246, 242))
            restart_rect = restart_text.get_rect(center=(WIDTH // 2, HEIGHT // 2 + 20))
            surface.blit(restart_text, restart_rect)
        
        # 胜利覆盖层
        if self.win and not self.game_over:
            overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            overlay.fill((0, 0, 0, 150))
            surface.blit(overlay, (0, 0))
            
            win_text = font.render("🎉 你赢了!", True, (255, 215, 0))
            text_rect = win_text.get_rect(center=(WIDTH // 2, HEIGHT // 2 - 40))
            surface.blit(win_text, text_rect)
            
            continue_text = small_font.render("继续游戏 或 按 R 重新开始", True, (249, 246, 242))
            continue_rect = continue_text.get_rect(center=(WIDTH // 2, HEIGHT // 2 + 20))
            surface.blit(continue_text, continue_rect)
        
        # 操作提示
        hint = small_font.render("方向键 / WASD 移动", True, (119, 110, 101))
        surface.blit(hint, (20, HEIGHT - 30))

# 主游戏函数
def main():
    game = Game2048()
    running = True
    
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                    game.reset()
                    continue
                
                if game.game_over or game.win:
                    continue
                
                # 方向控制
                if event.key in [pygame.K_UP, pygame.K_w]:
                    game.move("up")
                elif event.key in [pygame.K_DOWN, pygame.K_s]:
                    game.move("down")
                elif event.key in [pygame.K_LEFT, pygame.K_a]:
                    game.move("left")
                elif event.key in [pygame.K_RIGHT, pygame.K_d]:
                    game.move("right")
        
        # 更新动画
        game.animating = bool(game.new_tile_animations)
        
        # 绘制
        game.draw(screen)
        pygame.display.flip()
        clock.tick(FPS)
    
    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()