import pygame
import random
import sys
import time
from enum import Enum

# ========== 初始化 ==========
pygame.init()
WINDOW_WIDTH = 900
WINDOW_HEIGHT = 700
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption("🐹 打地鼠 · 数据类型大作战")
clock = pygame.time.Clock()
FPS = 60

# ========== 中文字体 ==========
def get_font(size, bold=False):
    font_names = [
        "SimHei", "Microsoft YaHei", "STHeiti", 
        "Noto Sans CJK SC", "WenQuanYi Micro Hei"
    ]
    for name in font_names:
        try:
            font = pygame.font.SysFont(name, size, bold=bold)
            test = font.render("测试", True, (255, 255, 255))
            if test.get_width() > 0:
                return font
        except:
            continue
    
    try:
        font_paths = [
            "C:/Windows/Fonts/simsun.ttc",
            "/System/Library/Fonts/PingFang.ttc",
        ]
        for path in font_paths:
            if __import__('os').path.exists(path):
                return pygame.font.Font(path, size)
    except:
        pass
    
    return pygame.font.Font(None, size)

# ========== 颜色定义（完整版） ==========
COLORS = {
    "bg": (34, 139, 34),
    "hole": (80, 50, 30),
    "hole_dark": (50, 30, 20),
    "mole": (210, 180, 140),
    "mole_eye": (255, 255, 255),
    "mole_pupil": (0, 0, 0),
    "mole_nose": (255, 150, 150),
    "hammer": (139, 69, 19),
    "hammer_head": (169, 169, 169),
    "ui_bg": (30, 30, 30, 200),
    "white": (255, 255, 255),
    "black": (0, 0, 0),
    "gray": (128, 128, 128),        # ← 修复：添加 gray
    "light_gray": (200, 200, 200),
    "red": (255, 50, 50),
    "green": (50, 255, 50),
    "gold": (255, 215, 0),
    "blue": (50, 150, 255),
    "orange": (255, 165, 0),
    "purple": (200, 50, 255),
    "dark_gray": (80, 80, 80),
    "transparent_black": (0, 0, 0, 180),
}

# ========== 数据类型定义 ==========
class DataType(Enum):
    INT = "整数"
    FLOAT = "浮点数"
    STR = "字符串"
    BOOL = "布尔值"
    LIST = "列表"
    TUPLE = "元组"
    DICT = "字典"
    SET = "集合"
    NONE = "空值"

# 数据类型示例
DATA_EXAMPLES = {
    DataType.INT: ["42", "-5", "1000", "0", "999"],
    DataType.FLOAT: ["3.14", "-2.5", "0.0", "1.618", "99.99"],
    DataType.STR: ['"你好"', '"Python"', '"123"', '"True"', '""'],
    DataType.BOOL: ["True", "False"],
    DataType.LIST: ["[1,2,3]", '["a","b"]', "[True,False]", "[]", "[1,[2,3]]"],
    DataType.TUPLE: ["(1,2,3)", '("a","b")', "(True,False)", "()", "(1,)"],
    DataType.DICT: ['{"a":1}', '{"name":"Tom"}', "{}", "{1:2,3:4}"],
    DataType.SET: ["{1,2,3}", '{"a","b"}', "set()", "{True,False}"],
    DataType.NONE: ["None"],
}

# 数据类型颜色（用于显示）
TYPE_COLORS = {
    DataType.INT: (100, 200, 255),
    DataType.FLOAT: (100, 255, 200),
    DataType.STR: (255, 200, 100),
    DataType.BOOL: (255, 150, 255),
    DataType.LIST: (100, 255, 100),
    DataType.TUPLE: (200, 255, 100),
    DataType.DICT: (255, 100, 100),
    DataType.SET: (255, 200, 50),
    DataType.NONE: (200, 200, 200),
}

# ========== 地鼠类 ==========
class Mole:
    def __init__(self, x, y, hole_size=80):
        self.x = x
        self.y = y
        self.hole_size = hole_size
        self.is_up = False
        self.data_type = None
        self.example = None
        self.up_time = 0
        self.duration = random.randint(60, 120)
        self.appear_count = 0
    
    def pop_up(self):
        if not self.is_up:
            self.is_up = True
            self.data_type = random.choice(list(DataType))
            self.example = random.choice(DATA_EXAMPLES[self.data_type])
            self.up_time = 0
            self.duration = random.randint(80, 150)
            self.appear_count += 1
            return True
        return False
    
    def update(self):
        if self.is_up:
            self.up_time += 1
            if self.up_time > self.duration:
                self.hide()
    
    def hide(self):
        self.is_up = False
        self.data_type = None
        self.example = None
    
    def draw(self, screen, font):
        if not self.is_up:
            pygame.draw.ellipse(screen, COLORS["hole"], 
                              (self.x, self.y, self.hole_size, self.hole_size // 2))
            pygame.draw.ellipse(screen, COLORS["hole_dark"], 
                              (self.x + 5, self.y + 5, self.hole_size - 10, self.hole_size // 2 - 5))
            return
        
        # 地鼠身体
        body_rect = (self.x + 10, self.y - 30, self.hole_size - 20, 50)
        pygame.draw.ellipse(screen, COLORS["mole"], body_rect)
        
        # 地鼠眼睛
        eye_y = self.y - 15
        pygame.draw.circle(screen, COLORS["mole_eye"], (self.x + 20, eye_y), 10)
        pygame.draw.circle(screen, COLORS["mole_eye"], (self.x + 60, eye_y), 10)
        pygame.draw.circle(screen, COLORS["mole_pupil"], (self.x + 23, eye_y + 2), 5)
        pygame.draw.circle(screen, COLORS["mole_pupil"], (self.x + 63, eye_y + 2), 5)
        
        # 鼻子
        pygame.draw.circle(screen, COLORS["mole_nose"], (self.x + 40, self.y + 5), 8)
        
        # 显示数据类型标签
        type_name = self.data_type.value
        type_color = TYPE_COLORS.get(self.data_type, COLORS["white"])
        
        label_text = f"📊 {type_name}"
        text_surf = font.render(label_text, True, COLORS["white"])
        text_rect = text_surf.get_rect(center=(self.x + self.hole_size//2, self.y - 45))
        
        bg_rect = text_rect.inflate(20, 10)
        pygame.draw.rect(screen, (0, 0, 0, 180), bg_rect)
        pygame.draw.rect(screen, type_color, bg_rect, 2)
        screen.blit(text_surf, text_rect)
        
        # 显示示例值
        example_text = f"例子: {self.example}"
        ex_surf = font.render(example_text, True, type_color)
        ex_rect = ex_surf.get_rect(center=(self.x + self.hole_size//2, self.y - 20))
        screen.blit(ex_surf, ex_rect)

# ========== 锤子 ==========
class Hammer:
    def __init__(self):
        self.x = 0
        self.y = 0
        self.is_hitting = False
        self.hit_timer = 0
        self.angle = 0
    
    def update(self):
        self.x, self.y = pygame.mouse.get_pos()
        if self.is_hitting:
            self.hit_timer += 1
            if self.hit_timer > 10:
                self.is_hitting = False
                self.hit_timer = 0
                self.angle = 0
    
    def swing(self):
        if not self.is_hitting:
            self.is_hitting = True
            self.hit_timer = 0
            self.angle = -30
    
    def draw(self, screen):
        if self.is_hitting:
            handle_rect = (self.x + 20, self.y - 10, 30, 8)
            pygame.draw.rect(screen, COLORS["hammer"], handle_rect)
            pygame.draw.circle(screen, COLORS["hammer_head"], (self.x + 35, self.y - 10), 15)
            pygame.draw.circle(screen, (255, 255, 200, 100), (self.x + 35, self.y - 10), 20)
        else:
            handle_rect = (self.x - 20, self.y - 10, 30, 8)
            pygame.draw.rect(screen, COLORS["hammer"], handle_rect)
            pygame.draw.circle(screen, COLORS["hammer_head"], (self.x - 25, self.y - 10), 15)

# ========== 游戏主类 ==========
class WhackAMoleGame:
    def __init__(self):
        self.font_small = get_font(18)
        self.font_medium = get_font(26)
        self.font_large = get_font(36)
        self.font_huge = get_font(48, bold=True)
        
        self.hole_size = 80
        self.margin = 30
        self.grid_start_x = (WINDOW_WIDTH - 3 * (self.hole_size + self.margin)) // 2
        self.grid_start_y = 150
        
        self.moles = []
        for row in range(3):
            for col in range(3):
                x = self.grid_start_x + col * (self.hole_size + self.margin)
                y = self.grid_start_y + row * (self.hole_size + self.margin)
                self.moles.append(Mole(x, y, self.hole_size))
        
        self.hammer = Hammer()
        
        self.score = 0
        self.combo = 0
        self.max_combo = 0
        self.total_hits = 0
        self.missed = 0
        self.game_time = 60
        self.start_time = time.time()
        self.is_running = True
        self.is_game_over = False
        
        self.combo_timer = 0
        self.type_stats = {dt: {"correct": 0, "wrong": 0} for dt in DataType}
        
        self.last_message = ""
        self.message_timer = 0
        self.message_color = COLORS["white"]
        
        self.spawn_timer = 0
        self.waiting_for_answer = False
        self.current_mole = None
        self.question_buttons = []  # 存储按钮信息
        self.difficulty = 1
    
    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.is_running = False
            
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    if self.is_game_over:
                        return
                    if self.waiting_for_answer:
                        self.handle_question_click(event.pos)
                    else:
                        self.hit_mole()
            
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    self.is_running = False
                elif event.key == pygame.K_r and self.is_game_over:
                    self.restart_game()
    
    def hit_mole(self):
        self.hammer.swing()
        
        if self.is_game_over:
            return
        
        mouse_x, mouse_y = pygame.mouse.get_pos()
        
        for mole in self.moles:
            if mole.is_up:
                mole_center_x = mole.x + mole.hole_size // 2
                mole_center_y = mole.y + mole.hole_size // 4
                dist = ((mouse_x - mole_center_x) ** 2 + (mouse_y - mole_center_y) ** 2) ** 0.5
                
                if dist < 50:
                    self.current_mole = mole
                    self.waiting_for_answer = True
                    return
        
        self.missed += 1
        self.combo = 0
        self.show_message("❌ 没打中！", COLORS["red"])
    
    def check_answer(self, user_answer):
        if not self.waiting_for_answer or not self.current_mole:
            return
        
        mole = self.current_mole
        correct = user_answer == mole.data_type
        
        if correct:
            self.score += 10 + self.combo * 2
            self.combo += 1
            self.total_hits += 1
            if self.combo > self.max_combo:
                self.max_combo = self.combo
            self.type_stats[mole.data_type]["correct"] += 1
            self.show_message(f"✅ 正确！+{10 + (self.combo-1) * 2}分", COLORS["green"])
            mole.hide()
        else:
            self.combo = 0
            self.type_stats[mole.data_type]["wrong"] += 1
            correct_type_name = mole.data_type.value
            self.show_message(f"❌ 错误！应该是「{correct_type_name}」", COLORS["red"])
        
        self.waiting_for_answer = False
        self.current_mole = None
        self.question_buttons = []
        self.difficulty = 1 + self.score // 100
    
    def show_message(self, msg, color):
        self.last_message = msg
        self.message_color = color
        self.message_timer = 60
    
    def spawn_moles(self):
        if self.is_game_over:
            return
        
        spawn_chance = min(0.3 + self.difficulty * 0.02, 0.7)
        up_count = sum(1 for m in self.moles if m.is_up)
        max_up = min(2 + self.difficulty // 2, 6)
        
        if up_count < max_up and random.random() < spawn_chance:
            hidden_moles = [m for m in self.moles if not m.is_up]
            if hidden_moles:
                mole = random.choice(hidden_moles)
                mole.pop_up()
    
    def update(self):
        if self.is_game_over:
            return
        
        elapsed = time.time() - self.start_time
        remaining = max(0, self.game_time - elapsed)
        
        if remaining <= 0:
            self.is_game_over = True
            return
        
        for mole in self.moles:
            mole.update()
        
        self.spawn_timer += 1
        if self.spawn_timer > max(10, 30 - self.difficulty * 2):
            self.spawn_timer = 0
            self.spawn_moles()
        
        self.hammer.update()
        
        if self.message_timer > 0:
            self.message_timer -= 1
    
    def restart_game(self):
        self.score = 0
        self.combo = 0
        self.max_combo = 0
        self.total_hits = 0
        self.missed = 0
        self.game_time = 60
        self.start_time = time.time()
        self.is_game_over = False
        self.waiting_for_answer = False
        self.current_mole = None
        self.difficulty = 1
        self.question_buttons = []
        self.type_stats = {dt: {"correct": 0, "wrong": 0} for dt in DataType}
        
        for mole in self.moles:
            mole.hide()
    
    def render(self):
        screen.fill(COLORS["bg"])
        
        # 草地纹理
        for x in range(0, WINDOW_WIDTH, 40):
            pygame.draw.line(screen, (50, 180, 50), (x, 0), (x, WINDOW_HEIGHT), 1)
        for y in range(0, WINDOW_HEIGHT, 40):
            pygame.draw.line(screen, (50, 180, 50), (0, y), (WINDOW_WIDTH, y), 1)
        
        # 标题
        title = "🐹 打地鼠 · 数据类型大作战"
        title_surf = self.font_huge.render(title, True, COLORS["gold"])
        title_rect = title_surf.get_rect(center=(WINDOW_WIDTH//2, 50))
        screen.blit(title_surf, title_rect)
        
        # 绘制地鼠
        for mole in self.moles:
            mole.draw(screen, self.font_small)
        
        # 绘制锤子
        self.hammer.draw(screen)
        
        # ===== UI =====
        ui_bg = pygame.Surface((WINDOW_WIDTH, 50))
        ui_bg.set_alpha(180)
        ui_bg.fill((0, 0, 0))
        screen.blit(ui_bg, (0, 0))
        screen.blit(ui_bg, (0, WINDOW_HEIGHT - 60))
        
        # 分数
        score_text = self.font_large.render(f"⭐ 分数: {self.score}", True, COLORS["gold"])
        screen.blit(score_text, (20, 5))
        
        # 连击
        if self.combo >= 3:
            combo_color = COLORS["orange"] if self.combo < 10 else COLORS["red"]
            combo_text = self.font_medium.render(f"🔥 {self.combo}连击!", True, combo_color)
            screen.blit(combo_text, (350, 10))
        
        # 时间
        elapsed = time.time() - self.start_time
        remaining = max(0, self.game_time - elapsed)
        time_color = COLORS["green"] if remaining > 20 else COLORS["orange"] if remaining > 10 else COLORS["red"]
        time_text = self.font_large.render(f"⏱️ {int(remaining)}s", True, time_color)
        screen.blit(time_text, (WINDOW_WIDTH - 150, 5))
        
        # 底部信息
        total_hits_text = self.font_small.render(f"🎯 命中: {self.total_hits}", True, COLORS["white"])
        screen.blit(total_hits_text, (20, WINDOW_HEIGHT - 50))
        
        missed_text = self.font_small.render(f"❌ 未命中: {self.missed}", True, COLORS["red"])
        screen.blit(missed_text, (180, WINDOW_HEIGHT - 50))
        
        max_combo_text = self.font_small.render(f"🏆 最高连击: {self.max_combo}", True, COLORS["gold"])
        screen.blit(max_combo_text, (350, WINDOW_HEIGHT - 50))
        
        # 消息
        if self.message_timer > 0:
            msg_surf = self.font_medium.render(self.last_message, True, self.message_color)
            msg_rect = msg_surf.get_rect(center=(WINDOW_WIDTH//2, 110))
            bg_rect = msg_rect.inflate(30, 15)
            pygame.draw.rect(screen, (0, 0, 0, 200), bg_rect)
            pygame.draw.rect(screen, self.message_color, bg_rect, 2)
            screen.blit(msg_surf, msg_rect)
        
        # 答题界面
        if self.waiting_for_answer and self.current_mole:
            self.render_question_ui()
        
        # 游戏结束
        if self.is_game_over:
            self.render_game_over()
        
        pygame.display.flip()
    
    def render_question_ui(self):
        if not self.current_mole:
            return
        
        mole = self.current_mole
        
        # 半透明背景
        overlay = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT))
        overlay.set_alpha(150)
        overlay.fill((0, 0, 0))
        screen.blit(overlay, (0, 0))
        
        # 问题框
        box_width = 600
        box_height = 350
        box_x = (WINDOW_WIDTH - box_width) // 2
        box_y = (WINDOW_HEIGHT - box_height) // 2 - 50
        
        pygame.draw.rect(screen, (40, 40, 60), (box_x, box_y, box_width, box_height))
        pygame.draw.rect(screen, COLORS["gold"], (box_x, box_y, box_width, box_height), 3)
        
        # 问题文字
        q_text = "这个数据是什么类型？"
        q_surf = self.font_large.render(q_text, True, COLORS["white"])
        q_rect = q_surf.get_rect(center=(WINDOW_WIDTH//2, box_y + 50))
        screen.blit(q_surf, q_rect)
        
        # 显示示例
        example_text = f"📝 {mole.example}"
        ex_surf = self.font_huge.render(example_text, True, TYPE_COLORS.get(mole.data_type, COLORS["white"]))
        ex_rect = ex_surf.get_rect(center=(WINDOW_WIDTH//2, box_y + 120))
        screen.blit(ex_surf, ex_rect)
        
        # 选项按钮
        data_types = list(DataType)
        btn_width = 160
        btn_height = 50
        btn_margin = 15
        cols = 3
        rows = 3
        
        self.question_buttons = []
        
        for i, dt in enumerate(data_types):
            row = i // cols
            col = i % cols
            btn_x = box_x + 40 + col * (btn_width + btn_margin)
            btn_y = box_y + 170 + row * (btn_height + btn_margin)
            
            color = TYPE_COLORS.get(dt, COLORS["white"])
            pygame.draw.rect(screen, (60, 60, 80), (btn_x, btn_y, btn_width, btn_height))
            pygame.draw.rect(screen, color, (btn_x, btn_y, btn_width, btn_height), 2)
            
            btn_text = dt.value
            btn_surf = self.font_medium.render(btn_text, True, color)
            btn_rect = btn_surf.get_rect(center=(btn_x + btn_width//2, btn_y + btn_height//2))
            screen.blit(btn_surf, btn_rect)
            
            self.question_buttons.append({
                "rect": pygame.Rect(btn_x, btn_y, btn_width, btn_height),
                "type": dt
            })
        
        # 提示文字
        hint = "点击上方选项回答问题"
        hint_surf = self.font_small.render(hint, True, COLORS["gray"])  # ← 修复：gray 已定义
        hint_rect = hint_surf.get_rect(center=(WINDOW_WIDTH//2, box_y + box_height - 20))
        screen.blit(hint_surf, hint_rect)
    
    def render_game_over(self):
        overlay = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT))
        overlay.set_alpha(180)
        overlay.fill((0, 0, 0))
        screen.blit(overlay, (0, 0))
        
        end_title = "🎉 游戏结束！"
        title_surf = self.font_huge.render(end_title, True, COLORS["gold"])
        title_rect = title_surf.get_rect(center=(WINDOW_WIDTH//2, 100))
        screen.blit(title_surf, title_rect)
        
        stats_y = 180
        hit_rate = 0
        if (self.total_hits + self.missed) > 0:
            hit_rate = self.total_hits / (self.total_hits + self.missed) * 100
        
        stats = [
            f"⭐ 最终得分: {self.score}",
            f"🎯 命中次数: {self.total_hits}",
            f"❌ 未命中次数: {self.missed}",
            f"🔥 最高连击: {self.max_combo}",
            f"📊 命中率: {hit_rate:.1f}%",
        ]
        
        for i, stat in enumerate(stats):
            stat_surf = self.font_medium.render(stat, True, COLORS["white"])
            stat_rect = stat_surf.get_rect(center=(WINDOW_WIDTH//2, stats_y + i * 40))
            screen.blit(stat_surf, stat_rect)
        
        # 数据类型统计
        stats_y += 220
        type_title = "📊 数据类型掌握情况"
        type_surf = self.font_medium.render(type_title, True, COLORS["gold"])
        type_rect = type_surf.get_rect(center=(WINDOW_WIDTH//2, stats_y))
        screen.blit(type_surf, type_rect)
        
        stats_y += 40
        type_parts = []
        for dt in DataType:
            stats = self.type_stats[dt]
            total = stats["correct"] + stats["wrong"]
            if total > 0:
                rate = stats["correct"] / total * 100
                type_parts.append(f"{dt.value} {rate:.0f}%")
        
        if type_parts:
            type_text = "  ".join(type_parts)
            type_surf = self.font_small.render(type_text, True, COLORS["white"])
            type_rect = type_surf.get_rect(center=(WINDOW_WIDTH//2, stats_y))
            screen.blit(type_surf, type_rect)
        
        restart_text = "按 R 键重新开始"
        restart_surf = self.font_medium.render(restart_text, True, COLORS["green"])
        restart_rect = restart_surf.get_rect(center=(WINDOW_WIDTH//2, 620))
        screen.blit(restart_surf, restart_rect)
    
    def handle_question_click(self, mouse_pos):
        if not self.waiting_for_answer:
            return
        
        for btn in self.question_buttons:
            if btn["rect"].collidepoint(mouse_pos):
                self.check_answer(btn["type"])
                break

# ========== 主循环 ==========
def main():
    game = WhackAMoleGame()
    
    while game.is_running:
        game.handle_events()
        game.update()
        game.render()
        clock.tick(FPS)
    
    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()