import tkinter as tk
from tkinter import messagebox
import random
import time

class MazeGame:
    def __init__(self, root):
        self.root = root
        self.root.title("迷宫探险")
        self.root.geometry("800x600")
        
        # 迷宫参数
        self.maze_size = 20  # 迷宫尺寸 (20x20)
        self.cell_size = 25  # 单元格大小
        
        # 游戏状态
        self.maze = None
        self.player_pos = (1, 1)
        self.exit_pos = (self.maze_size-2, self.maze_size-2)
        self.moves = 0
        self.start_time = 0
        self.game_active = False
        
        # 颜色定义
        self.colors = {
            'wall': '#2C3E50',
            'path': '#ECF0F1',
            'player': '#E74C3C',
            'exit': '#27AE60',
            'visited': '#BDC3C7',
            'solution': '#3498DB'
        }
        
        # 创建界面
        self.setup_ui()
        
        # 生成第一个迷宫
        self.generate_maze()
        
        # 绑定键盘事件
        self.root.bind('<KeyPress>', self.on_key_press)
        
    def setup_ui(self):
        """设置用户界面"""
        # 主框架
        main_frame = tk.Frame(self.root, bg='#34495E')
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 控制面板
        control_frame = tk.Frame(main_frame, bg='#2C3E50', height=80)
        control_frame.pack(fill=tk.X, padx=10, pady=10)
        control_frame.pack_propagate(False)
        
        # 标题
        title_label = tk.Label(control_frame, text="迷宫探险", 
                              font=('Arial', 24, 'bold'),
                              fg='#ECF0F1', bg='#2C3E50')
        title_label.pack(side=tk.LEFT, padx=20)
        
        # 信息显示
        info_frame = tk.Frame(control_frame, bg='#2C3E50')
        info_frame.pack(side=tk.RIGHT, padx=20)
        
        self.moves_label = tk.Label(info_frame, text="步数: 0", 
                                   font=('Arial', 14),
                                   fg='#ECF0F1', bg='#2C3E50')
        self.moves_label.pack()
        
        self.time_label = tk.Label(info_frame, text="时间: 0秒", 
                                  font=('Arial', 14),
                                  fg='#ECF0F1', bg='#2C3E50')
        self.time_label.pack()
        
        # 按钮框架
        button_frame = tk.Frame(control_frame, bg='#2C3E50')
        button_frame.pack(side=tk.RIGHT, padx=30)
        
        tk.Button(button_frame, text="新迷宫", command=self.new_maze,
                 font=('Arial', 12), bg='#3498DB', fg='white',
                 width=10, relief=tk.RAISED).pack(side=tk.LEFT, padx=5)
        
        tk.Button(button_frame, text="显示路径", command=self.show_solution,
                 font=('Arial', 12), bg='#9B59B6', fg='white',
                 width=10, relief=tk.RAISED).pack(side=tk.LEFT, padx=5)
        
        tk.Button(button_frame, text="自动求解", command=self.auto_solve,
                 font=('Arial', 12), bg='#E67E22', fg='white',
                 width=10, relief=tk.RAISED).pack(side=tk.LEFT, padx=5)
        
        # 难度选择
        diff_frame = tk.Frame(control_frame, bg='#2C3E50')
        diff_frame.pack(side=tk.RIGHT, padx=20)
        
        tk.Label(diff_frame, text="难度:", font=('Arial', 12),
                fg='#ECF0F1', bg='#2C3E50').pack(side=tk.LEFT)
        
        self.difficulty = tk.StringVar(value="medium")
        difficulties = [("简单", "easy"), ("中等", "medium"), ("困难", "hard")]
        for text, value in difficulties:
            tk.Radiobutton(diff_frame, text=text, variable=self.difficulty,
                          value=value, font=('Arial', 10),
                          fg='#ECF0F1', bg='#2C3E50',
                          selectcolor='#34495E').pack(side=tk.LEFT, padx=5)
        
        # 画布用于显示迷宫
        self.canvas = tk.Canvas(main_frame, bg='#34495E',
                               highlightthickness=0)
        self.canvas.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
        
        # 说明标签
        instructions = "使用方向键或WASD移动 | 红色方块是玩家 | 绿色方块是出口"
        tk.Label(main_frame, text=instructions, font=('Arial', 10),
                fg='#BDC3C7', bg='#34495E').pack(pady=(0, 10))
        
    def generate_maze(self):
        """使用深度优先搜索算法生成迷宫"""
        # 初始化迷宫 (1表示墙，0表示路)
        size = self.maze_size
        self.maze = [[1 for _ in range(size)] for _ in range(size)]
        
        # 设置起点和终点
        self.player_pos = (1, 1)
        self.exit_pos = (size-2, size-2)
        
        # 深度优先搜索生成迷宫
        stack = [self.player_pos]
        self.maze[self.player_pos[1]][self.player_pos[0]] = 0
        
        while stack:
            x, y = stack[-1]
            
            # 获取未访问的邻居
            neighbors = []
            for dx, dy in [(0, -2), (2, 0), (0, 2), (-2, 0)]:
                nx, ny = x + dx, y + dy
                if 0 < nx < size-1 and 0 < ny < size-1 and self.maze[ny][nx] == 1:
                    neighbors.append((nx, ny))
            
            if neighbors:
                nx, ny = random.choice(neighbors)
                # 打通墙壁
                wx, wy = (x + nx) // 2, (y + ny) // 2
                self.maze[wy][wx] = 0
                self.maze[ny][nx] = 0
                stack.append((nx, ny))
            else:
                stack.pop()
        
        # 确保出口可达
        self.maze[self.exit_pos[1]][self.exit_pos[0]] = 0
        
        # 根据难度调整迷宫复杂度
        self.adjust_difficulty()
        
        # 重置游戏状态
        self.reset_game()
        
        # 绘制迷宫
        self.draw_maze()
        
    def adjust_difficulty(self):
        """根据难度调整迷宫"""
        diff = self.difficulty.get()
        size = self.maze_size
        
        if diff == "easy":
            # 简单模式：移除一些墙壁
            for _ in range(size * 2):
                x, y = random.randint(1, size-2), random.randint(1, size-2)
                if self.maze[y][x] == 1:
                    self.maze[y][x] = 0
        elif diff == "hard":
            # 困难模式：添加一些墙壁
            for _ in range(size):
                x, y = random.randint(1, size-2), random.randint(1, size-2)
                if self.maze[y][x] == 0:
                    self.maze[y][x] = 1
        
    def draw_maze(self):
        """绘制迷宫到画布"""
        self.canvas.delete("all")
        size = self.maze_size
        cell_size = self.cell_size
        
        # 计算居中偏移
        canvas_width = self.canvas.winfo_width()
        canvas_height = self.canvas.winfo_height()
        if canvas_width < 10:  # 如果画布还没有大小，使用默认值
            canvas_width, canvas_height = 600, 500
        
        maze_width = size * cell_size
        maze_height = size * cell_size
        offset_x = (canvas_width - maze_width) // 2
        offset_y = (canvas_height - maze_height) // 2
        
        # 绘制迷宫单元格
        for y in range(size):
            for x in range(size):
                color = self.colors['wall'] if self.maze[y][x] == 1 else self.colors['path']
                x1 = offset_x + x * cell_size
                y1 = offset_y + y * cell_size
                x2 = x1 + cell_size
                y2 = y1 + cell_size
                
                self.canvas.create_rectangle(x1, y1, x2, y2, 
                                           fill=color, outline=color)
        
        # 绘制出口
        ex, ey = self.exit_pos
        x1 = offset_x + ex * cell_size + 2
        y1 = offset_y + ey * cell_size + 2
        x2 = x1 + cell_size - 4
        y2 = y1 + cell_size - 4
        self.canvas.create_rectangle(x1, y1, x2, y2,
                                   fill=self.colors['exit'], 
                                   outline=self.colors['exit'])
        
        # 绘制玩家
        self.draw_player()
        
    def draw_player(self):
        """绘制玩家"""
        cell_size = self.cell_size
        size = self.maze_size
        
        # 计算居中偏移
        canvas_width = self.canvas.winfo_width()
        canvas_height = self.canvas.winfo_height()
        if canvas_width < 10:
            canvas_width, canvas_height = 600, 500
        
        maze_width = size * cell_size
        maze_height = size * cell_size
        offset_x = (canvas_width - maze_width) // 2
        offset_y = (canvas_height - maze_height) // 2
        
        px, py = self.player_pos
        x1 = offset_x + px * cell_size + 4
        y1 = offset_y + py * cell_size + 4
        x2 = x1 + cell_size - 8
        y2 = y1 + cell_size - 8
        
        # 删除旧的玩家图形
        self.canvas.delete("player")
        
        # 创建新的玩家图形（圆形）
        self.canvas.create_oval(x1, y1, x2, y2,
                              fill=self.colors['player'],
                              outline=self.colors['player'],
                              tags="player")
        
    def on_key_press(self, event):
        """处理键盘事件"""
        if not self.game_active:
            return
            
        key = event.keysym.lower()
        
        # 移动映射
        move_map = {
            'up': (0, -1), 'w': (0, -1),
            'down': (0, 1), 's': (0, 1),
            'left': (-1, 0), 'a': (-1, 0),
            'right': (1, 0), 'd': (1, 0)
        }
        
        if key in move_map:
            dx, dy = move_map[key]
            self.move_player(dx, dy)
            
    def move_player(self, dx, dy):
        """移动玩家"""
        x, y = self.player_pos
        new_x, new_y = x + dx, y + dy
        
        # 检查是否在边界内且不是墙
        if (0 <= new_x < self.maze_size and 
            0 <= new_y < self.maze_size and 
            self.maze[new_y][new_x] == 0):
            
            self.player_pos = (new_x, new_y)
            self.moves += 1
            self.moves_label.config(text=f"步数: {self.moves}")
            
            # 重绘玩家
            self.draw_player()
            
            # 检查是否到达出口
            if self.player_pos == self.exit_pos:
                self.game_complete()
                
    def game_complete(self):
        """游戏完成"""
        elapsed_time = int(time.time() - self.start_time)
        self.game_active = False
        
        # 显示祝贺信息
        message = f"恭喜！你成功走出了迷宫！\n\n"
        message += f"用时: {elapsed_time}秒\n"
        message += f"步数: {self.moves}\n\n"
        
        # 评分
        max_moves = self.maze_size * self.maze_size
        efficiency = (max_moves - self.moves) / max_moves * 100
        message += f"效率: {efficiency:.1f}%"
        
        messagebox.showinfo("恭喜！", message)
        
    def reset_game(self):
        """重置游戏状态"""
        self.player_pos = (1, 1)
        self.moves = 0
        self.start_time = time.time()
        self.game_active = True
        self.moves_label.config(text="步数: 0")
        
    def new_maze(self):
        """生成新迷宫"""
        self.generate_maze()
        
    def show_solution(self):
        """显示迷宫的解（使用BFS算法）"""
        if not self.game_active:
            return
            
        # 使用BFS找到最短路径
        start = self.player_pos
        end = self.exit_pos
        size = self.maze_size
        
        # BFS搜索
        queue = [start]
        visited = {start: None}
        
        while queue:
            x, y = queue.pop(0)
            
            if (x, y) == end:
                break
                
            for dx, dy in [(0, -1), (1, 0), (0, 1), (-1, 0)]:
                nx, ny = x + dx, y + dy
                if (0 <= nx < size and 0 <= ny < size and 
                    self.maze[ny][nx] == 0 and (nx, ny) not in visited):
                    visited[(nx, ny)] = (x, y)
                    queue.append((nx, ny))
        
        # 重建路径
        if end in visited:
            path = []
            current = end
            while current != start:
                path.append(current)
                current = visited[current]
            path.append(start)
            path.reverse()
            
            # 绘制路径
            self.draw_path(path)
            
    def draw_path(self, path):
        """绘制解决方案路径"""
        cell_size = self.cell_size
        size = self.maze_size
        
        # 计算居中偏移
        canvas_width = self.canvas.winfo_width()
        canvas_height = self.canvas.winfo_height()
        if canvas_width < 10:
            canvas_width, canvas_height = 600, 500
        
        maze_width = size * cell_size
        maze_height = size * cell_size
        offset_x = (canvas_width - maze_width) // 2
        offset_y = (canvas_height - maze_height) // 2
        
        # 删除旧的路径
        self.canvas.delete("solution")
        
        # 绘制路径
        for x, y in path[1:-1]:  # 跳过起点和终点
            x1 = offset_x + x * cell_size + 8
            y1 = offset_y + y * cell_size + 8
            x2 = x1 + cell_size - 16
            y2 = y1 + cell_size - 16
            
            self.canvas.create_oval(x1, y1, x2, y2,
                                  fill=self.colors['solution'],
                                  outline=self.colors['solution'],
                                  tags="solution")
    
    def auto_solve(self):
        """自动求解迷宫"""
        if not self.game_active:
            return
            
        # 使用BFS找到路径
        start = self.player_pos
        end = self.exit_pos
        size = self.maze_size
        
        queue = [start]
        visited = {start: None}
        
        while queue:
            x, y = queue.pop(0)
            
            if (x, y) == end:
                break
                
            for dx, dy in [(0, -1), (1, 0), (0, 1), (-1, 0)]:
                nx, ny = x + dx, y + dy
                if (0 <= nx < size and 0 <= ny < size and 
                    self.maze[ny][nx] == 0 and (nx, ny) not in visited):
                    visited[(nx, ny)] = (x, y)
                    queue.append((nx, ny))
        
        # 重建路径并自动移动
        if end in visited:
            path = []
            current = end
            while current != start:
                path.append(current)
                current = visited[current]
            path.append(start)
            path.reverse()
            
            # 禁用用户输入
            self.game_active = False
            
            # 动画显示自动移动
            self.animate_solution(path)
    
    def animate_solution(self, path):
        """动画显示解决方案"""
        if not path:
            self.game_active = True
            return
            
        # 移动一步
        if len(path) > 1:
            self.player_pos = path[1]
            self.draw_player()
            
            # 继续下一步
            self.root.after(100, lambda: self.animate_solution(path[1:]))
        else:
            # 完成
            self.game_active = True
            self.game_complete()
    
    def update_timer(self):
        """更新计时器"""
        if self.game_active:
            elapsed_time = int(time.time() - self.start_time)
            self.time_label.config(text=f"时间: {elapsed_time}秒")
            self.root.after(1000, self.update_timer)

def main():
    root = tk.Tk()
    game = MazeGame(root)
    
    # 启动计时器
    game.root.after(1000, game.update_timer)
    
    root.mainloop()

if __name__ == "__main__":
    main()