import tkinter as tk
from tkinter import messagebox
import random
import math

class PongGame:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title("🏓 乒乓球对战 🏓")
        self.window.geometry("900x650")
        self.window.configure(bg='#1a1a2e')
        self.window.resizable(False, False)
        
        # 游戏设置
        self.width = 800
        self.height = 500
        self.paddle_width = 12
        self.paddle_height = 100
        self.ball_size = 12
        self.paddle_speed = 8
        self.ball_speed = 5
        self.ai_speed = 4
        self.max_score = 5
        
        # 游戏状态
        self.game_running = False
        self.paused = False
        self.mode = "single"  # single / double
        self.score_left = 0
        self.score_right = 0
        
        # 创建界面
        self.create_widgets()
        
        # 初始化游戏对象
        self.init_game_objects()
        
        # 绑定键盘事件
        self.window.bind('<KeyPress>', self.key_press)
        self.window.bind('<KeyRelease>', self.key_release)
        self.window.focus_set()
        
    def create_widgets(self):
        """创建界面组件"""
        # 标题
        title_frame = tk.Frame(self.window, bg='#16213e', height=60)
        title_frame.pack(fill=tk.X)
        title_frame.pack_propagate(False)
        
        tk.Label(
            title_frame,
            text="🏓 乒乓球对战 🏓",
            font=('微软雅黑', 28, 'bold'),
            bg='#16213e',
            fg='#f0c27f'
        ).pack(expand=True)
        
        # 游戏画布
        self.canvas = tk.Canvas(
            self.window,
            width=self.width,
            height=self.height,
            bg='#0f3460',
            highlightthickness=2,
            highlightbackground='#16213e'
        )
        self.canvas.pack(pady=10)
        
        # 绘制中场线
        self.draw_mid_court()
        
        # 控制面板
        control_frame = tk.Frame(self.window, bg='#1a1a2e', height=60)
        control_frame.pack(fill=tk.X, padx=20, pady=10)
        control_frame.pack_propagate(False)
        
        # 左侧分数
        self.score_left_label = tk.Label(
            control_frame,
            text="0",
            font=('Arial', 24, 'bold'),
            bg='#1a1a2e',
            fg='#4ecdc4'
        )
        self.score_left_label.pack(side=tk.LEFT, padx=30)
        
        # 中间按钮组
        button_frame = tk.Frame(control_frame, bg='#1a1a2e')
        button_frame.pack(side=tk.LEFT, expand=True)
        
        self.start_button = tk.Button(
            button_frame,
            text="▶ 开始游戏",
            font=('微软雅黑', 12, 'bold'),
            bg='#2ecc71',
            fg='white',
            relief=tk.FLAT,
            padx=20,
            pady=8,
            command=self.toggle_game
        )
        self.start_button.pack(side=tk.LEFT, padx=5)
        
        self.pause_button = tk.Button(
            button_frame,
            text="⏸ 暂停",
            font=('微软雅黑', 12, 'bold'),
            bg='#f39c12',
            fg='white',
            relief=tk.FLAT,
            padx=20,
            pady=8,
            command=self.toggle_pause,
            state=tk.DISABLED
        )
        self.pause_button.pack(side=tk.LEFT, padx=5)
        
        tk.Button(
            button_frame,
            text="🔄 重置",
            font=('微软雅黑', 12, 'bold'),
            bg='#e74c3c',
            fg='white',
            relief=tk.FLAT,
            padx=20,
            pady=8,
            command=self.reset_game
        ).pack(side=tk.LEFT, padx=5)
        
        # 模式选择
        mode_frame = tk.Frame(control_frame, bg='#1a1a2e')
        mode_frame.pack(side=tk.RIGHT, padx=10)
        
        tk.Label(
            mode_frame,
            text="模式:",
            font=('微软雅黑', 12),
            bg='#1a1a2e',
            fg='#ecf0f1'
        ).pack(side=tk.LEFT)
        
        self.mode_var = tk.StringVar(value="single")
        tk.Radiobutton(
            mode_frame,
            text="单人(AI)",
            variable=self.mode_var,
            value="single",
            bg='#1a1a2e',
            fg='#ecf0f1',
            selectcolor='#1a1a2e',
            font=('微软雅黑', 10),
            command=self.change_mode
        ).pack(side=tk.LEFT, padx=5)
        
        tk.Radiobutton(
            mode_frame,
            text="双人",
            variable=self.mode_var,
            value="double",
            bg='#1a1a2e',
            fg='#ecf0f1',
            selectcolor='#1a1a2e',
            font=('微软雅黑', 10),
            command=self.change_mode
        ).pack(side=tk.LEFT, padx=5)
        
        # 右侧分数
        self.score_right_label = tk.Label(
            control_frame,
            text="0",
            font=('Arial', 24, 'bold'),
            bg='#1a1a2e',
            fg='#ff6b6b'
        )
        self.score_right_label.pack(side=tk.RIGHT, padx=30)
        
        # 底部提示
        info_frame = tk.Frame(self.window, bg='#16213e', height=40)
        info_frame.pack(fill=tk.X, side=tk.BOTTOM)
        info_frame.pack_propagate(False)
        
        self.info_label = tk.Label(
            info_frame,
            text="🎮 W/S 控制左拍 | ↑/↓ 控制右拍 | 空格键暂停",
            font=('微软雅黑', 10),
            bg='#16213e',
            fg='#bdc3c7'
        )
        self.info_label.pack(expand=True)
        
    def draw_mid_court(self):
        """绘制中场线"""
        # 中线
        for y in range(0, self.height, 30):
            self.canvas.create_line(
                self.width // 2, y,
                self.width // 2, y + 15,
                fill='#2c3e50',
                width=3
            )
        
        # 中心圆
        self.canvas.create_oval(
            self.width // 2 - 60,
            self.height // 2 - 60,
            self.width // 2 + 60,
            self.height // 2 + 60,
            outline='#2c3e50',
            width=2
        )
        
    def init_game_objects(self):
        """初始化游戏对象"""
        # 左球拍
        self.paddle_left = self.canvas.create_rectangle(
            20,
            self.height // 2 - self.paddle_height // 2,
            20 + self.paddle_width,
            self.height // 2 + self.paddle_height // 2,
            fill='#4ecdc4',
            outline='#2c3e50',
            width=2,
            tags='paddle'
        )
        
        # 右球拍
        self.paddle_right = self.canvas.create_rectangle(
            self.width - 20 - self.paddle_width,
            self.height // 2 - self.paddle_height // 2,
            self.width - 20,
            self.height // 2 + self.paddle_height // 2,
            fill='#ff6b6b',
            outline='#2c3e50',
            width=2,
            tags='paddle'
        )
        
        # 球
        self.ball = self.canvas.create_oval(
            self.width // 2 - self.ball_size // 2,
            self.height // 2 - self.ball_size // 2,
            self.width // 2 + self.ball_size // 2,
            self.height // 2 + self.ball_size // 2,
            fill='#f1c40f',
            outline='#2c3e50',
            width=2,
            tags='ball'
        )
        
        # 速度
        self.ball_dx = 0
        self.ball_dy = 0
        
        # 按键状态
        self.keys = {
            'w': False,
            's': False,
            'up': False,
            'down': False,
            'space': False
        }
        
    def reset_ball(self, direction=None):
        """重置球的位置"""
        self.canvas.coords(
            self.ball,
            self.width // 2 - self.ball_size // 2,
            self.height // 2 - self.ball_size // 2,
            self.width // 2 + self.ball_size // 2,
            self.height // 2 + self.ball_size // 2
        )
        
        if direction is None:
            # 随机方向
            angle = random.uniform(-45, 45)
            if random.random() < 0.5:
                angle += 180
            angle = math.radians(angle)
            self.ball_dx = self.ball_speed * math.cos(angle)
            self.ball_dy = self.ball_speed * math.sin(angle)
        else:
            self.ball_dx = direction * self.ball_speed
            self.ball_dy = random.uniform(-3, 3)
        
        # 确保不会太平
        if abs(self.ball_dy) < 2:
            self.ball_dy = 2 if self.ball_dy >= 0 else -2
            
    def reset_game(self):
        """重置游戏"""
        self.game_running = False
        self.paused = False
        self.score_left = 0
        self.score_right = 0
        self.update_score()
        
        # 重置球拍位置
        self.canvas.coords(
            self.paddle_left,
            20,
            self.height // 2 - self.paddle_height // 2,
            20 + self.paddle_width,
            self.height // 2 + self.paddle_height // 2
        )
        self.canvas.coords(
            self.paddle_right,
            self.width - 20 - self.paddle_width,
            self.height // 2 - self.paddle_height // 2,
            self.width - 20,
            self.height // 2 + self.paddle_height // 2
        )
        
        self.reset_ball()
        self.ball_dx = 0
        self.ball_dy = 0
        
        self.start_button.config(text="▶ 开始游戏")
        self.pause_button.config(state=tk.DISABLED, text="⏸ 暂停")
        self.info_label.config(text="🎮 按 '开始游戏' 开始")
        
    def toggle_game(self):
        """开始/停止游戏"""
        if not self.game_running:
            self.game_running = True
            self.paused = False
            self.start_button.config(text="⏹ 停止")
            self.pause_button.config(state=tk.NORMAL, text="⏸ 暂停")
            
            if self.score_left == 0 and self.score_right == 0:
                self.reset_ball()
            self.info_label.config(text="🎮 游戏进行中...")
            self.game_loop()
        else:
            self.game_running = False
            self.paused = False
            self.start_button.config(text="▶ 开始游戏")
            self.pause_button.config(state=tk.DISABLED, text="⏸ 暂停")
            self.info_label.config(text="🎮 游戏已停止")
            
    def toggle_pause(self):
        """暂停/继续"""
        if self.game_running:
            self.paused = not self.paused
            self.pause_button.config(text="▶ 继续" if self.paused else "⏸ 暂停")
            self.info_label.config(text="⏸ 已暂停" if self.paused else "🎮 游戏进行中...")
            
    def change_mode(self):
        """切换模式"""
        if self.game_running:
            if messagebox.askyesno("切换模式", "切换模式将重置游戏，确定吗？"):
                self.reset_game()
                self.mode = self.mode_var.get()
                self.update_info_text()
        else:
            self.mode = self.mode_var.get()
            self.update_info_text()
            
    def update_info_text(self):
        """更新信息文本"""
        if self.mode == "single":
            self.info_label.config(text="🎮 W/S 控制左拍 | AI 控制右拍 | 空格键暂停")
        else:
            self.info_label.config(text="🎮 W/S 控制左拍 | ↑/↓ 控制右拍 | 空格键暂停")
            
    def update_score(self):
        """更新分数显示"""
        self.score_left_label.config(text=str(self.score_left))
        self.score_right_label.config(text=str(self.score_right))
        
    def key_press(self, event):
        """键盘按下"""
        key = event.keysym.lower()
        if key in self.keys:
            self.keys[key] = True
        if key == 'space' and self.game_running:
            self.toggle_pause()
            
    def key_release(self, event):
        """键盘释放"""
        key = event.keysym.lower()
        if key in self.keys:
            self.keys[key] = False
            
    def move_paddles(self):
        """移动球拍"""
        # 左球拍 (W/S)
        if self.keys['w']:
            coords = self.canvas.coords(self.paddle_left)
            if coords[1] > 0:
                self.canvas.move(self.paddle_left, 0, -self.paddle_speed)
        if self.keys['s']:
            coords = self.canvas.coords(self.paddle_left)
            if coords[3] < self.height:
                self.canvas.move(self.paddle_left, 0, self.paddle_speed)
                
        # 右球拍
        if self.mode == "double":
            # 双人模式：玩家2控制
            if self.keys['up']:
                coords = self.canvas.coords(self.paddle_right)
                if coords[1] > 0:
                    self.canvas.move(self.paddle_right, 0, -self.paddle_speed)
            if self.keys['down']:
                coords = self.canvas.coords(self.paddle_right)
                if coords[3] < self.height:
                    self.canvas.move(self.paddle_right, 0, self.paddle_speed)
        else:
            # 单人模式：AI控制
            self.move_ai()
            
    def move_ai(self):
        """AI移动"""
        ball_coords = self.canvas.coords(self.ball)
        paddle_coords = self.canvas.coords(self.paddle_right)
        
        ball_y = (ball_coords[1] + ball_coords[3]) / 2
        paddle_y = (paddle_coords[1] + paddle_coords[3]) / 2
        
        # AI预测球的位置
        if self.ball_dx > 0:
            # 球向右移动，预测到达右边界的位置
            time_to_reach = (self.width - ball_coords[2]) / self.ball_dx if self.ball_dx > 0 else 1000
            predicted_y = ball_y + self.ball_dy * time_to_reach
            
            # 考虑反弹
            if predicted_y < 0 or predicted_y > self.height:
                # 简单预测反弹
                cycles = abs(predicted_y) // self.height
                if cycles % 2 == 0:
                    predicted_y = abs(predicted_y) % self.height
                else:
                    predicted_y = self.height - abs(predicted_y) % self.height
                    
            # 移动AI
            target_y = max(self.paddle_height // 2, min(self.height - self.paddle_height // 2, predicted_y))
            if abs(paddle_y - target_y) > 5:
                if paddle_y < target_y:
                    self.canvas.move(self.paddle_right, 0, min(self.ai_speed, target_y - paddle_y))
                else:
                    self.canvas.move(self.paddle_right, 0, max(-self.ai_speed, target_y - paddle_y))
        else:
            # 球向左移动，回到中心位置
            target_y = self.height // 2
            if abs(paddle_y - target_y) > 5:
                if paddle_y < target_y:
                    self.canvas.move(self.paddle_right, 0, min(self.ai_speed // 2, target_y - paddle_y))
                else:
                    self.canvas.move(self.paddle_right, 0, max(-self.ai_speed // 2, target_y - paddle_y))
                    
    def check_collision(self):
        """检测碰撞"""
        ball_coords = self.canvas.coords(self.ball)
        
        # 球拍碰撞 - 左
        paddle_left_coords = self.canvas.coords(self.paddle_left)
        if (ball_coords[0] <= paddle_left_coords[2] and
            ball_coords[2] >= paddle_left_coords[0] and
            ball_coords[1] <= paddle_left_coords[3] and
            ball_coords[3] >= paddle_left_coords[1]):
            
            # 计算碰撞位置
            hit_pos = (ball_coords[1] + ball_coords[3]) / 2 - (paddle_left_coords[1] + paddle_left_coords[3]) / 2
            hit_pos = hit_pos / (self.paddle_height / 2)  # -1 到 1
            
            # 改变球的方向
            angle = hit_pos * 60  # 最大60度
            angle = math.radians(angle)
            speed = math.sqrt(self.ball_dx**2 + self.ball_dy**2)
            self.ball_dx = abs(speed * math.cos(angle))
            self.ball_dy = speed * math.sin(angle)
            
            # 增加速度
            speed_multiplier = 1.05
            self.ball_dx *= speed_multiplier
            self.ball_dy *= speed_multiplier
            
            return
        
        # 球拍碰撞 - 右
        paddle_right_coords = self.canvas.coords(self.paddle_right)
        if (ball_coords[2] >= paddle_right_coords[0] and
            ball_coords[0] <= paddle_right_coords[2] and
            ball_coords[1] <= paddle_right_coords[3] and
            ball_coords[3] >= paddle_right_coords[1]):
            
            hit_pos = (ball_coords[1] + ball_coords[3]) / 2 - (paddle_right_coords[1] + paddle_right_coords[3]) / 2
            hit_pos = hit_pos / (self.paddle_height / 2)
            
            angle = hit_pos * 60
            angle = math.radians(angle)
            speed = math.sqrt(self.ball_dx**2 + self.ball_dy**2)
            self.ball_dx = -abs(speed * math.cos(angle))
            self.ball_dy = speed * math.sin(angle)
            
            speed_multiplier = 1.05
            self.ball_dx *= speed_multiplier
            self.ball_dy *= speed_multiplier
            
    def check_score(self):
        """检查得分"""
        ball_coords = self.canvas.coords(self.ball)
        
        # 左边界得分（右方得分）
        if ball_coords[0] <= 0:
            self.score_right += 1
            self.update_score()
            self.reset_ball(direction=1)
            self.check_winner()
            return True
            
        # 右边界得分（左方得分）
        if ball_coords[2] >= self.width:
            self.score_left += 1
            self.update_score()
            self.reset_ball(direction=-1)
            self.check_winner()
            return True
            
        return False
        
    def check_winner(self):
        """检查胜利者"""
        if self.score_left >= self.max_score or self.score_right >= self.max_score:
            self.game_running = False
            winner = "左方" if self.score_left > self.score_right else "右方"
            messagebox.showinfo("🏆 游戏结束", f"{winner} 获胜！\n比分: {self.score_left} - {self.score_right}")
            self.start_button.config(text="▶ 开始游戏")
            self.pause_button.config(state=tk.DISABLED, text="⏸ 暂停")
            
    def game_loop(self):
        """游戏主循环"""
        if not self.game_running:
            return
            
        if not self.paused:
            # 移动球拍
            self.move_paddles()
            
            # 移动球
            self.canvas.move(self.ball, self.ball_dx, self.ball_dy)
            
            # 边界碰撞 - 上下
            ball_coords = self.canvas.coords(self.ball)
            if ball_coords[1] <= 0 or ball_coords[3] >= self.height:
                self.ball_dy = -self.ball_dy
                # 避免卡在边界
                if ball_coords[1] <= 0:
                    self.canvas.move(self.ball, 0, 2)
                if ball_coords[3] >= self.height:
                    self.canvas.move(self.ball, 0, -2)
            
            # 检查得分
            self.check_score()
            
            # 检查碰撞
            self.check_collision()
            
        # 继续循环
        self.window.after(16, self.game_loop)  # ~60 FPS
        
    def run(self):
        """运行游戏"""
        self.window.mainloop()


if __name__ == '__main__':
    game = PongGame()
    game.run()