import pygame
import random
import sys
import math

# 初始化Pygame
pygame.init()

# 游戏常量
WINDOW_WIDTH = 600
WINDOW_HEIGHT = 600
CELL_SIZE = 30
ROWS = WINDOW_HEIGHT // CELL_SIZE
COLS = WINDOW_WIDTH // CELL_SIZE

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (255, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
PINK = (255, 182, 193)
CYAN = (0, 255, 255)
ORANGE = (255, 165, 0)
GREEN = (0, 255, 0)

# 方向常量
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)

class Maze:
    """迷宫类"""
    def __init__(self):
        # 0=空地, 1=墙壁, 2=豆子, 3=能量豆
        self.layout = [
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
            [1,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1],
            [1,2,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,2,1],
            [1,3,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,3,1],
            [1,2,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,2,1],
            [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
            [1,2,1,1,2,1,2,1,1,1,1,1,1,1,2,1,2,1,2,1],
            [1,2,1,1,2,1,2,1,1,1,1,1,1,1,2,1,2,1,2,1],
            [1,2,2,2,2,1,2,2,2,2,1,2,2,2,2,1,2,2,2,1],
            [1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1],
            [1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1],
            [1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1],
            [1,2,2,2,2,1,2,2,2,2,1,2,2,2,2,1,2,2,2,1],
            [1,2,1,1,2,1,2,1,1,1,1,1,1,1,2,1,2,1,2,1],
            [1,2,1,1,2,1,2,1,1,1,1,1,1,1,2,1,2,1,2,1],
            [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
            [1,2,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,2,1],
            [1,2,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,2,1],
            [1,3,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,3,1],
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
        ]
    
    def is_wall(self, x, y):
        """检查是否是墙壁"""
        col = int(x // CELL_SIZE)
        row = int(y // CELL_SIZE)
        if 0 <= row < ROWS and 0 <= col < COLS:
            return self.layout[row][col] == 1
        return True
    
    def draw(self, screen):
        """绘制迷宫"""
        for row in range(ROWS):
            for col in range(COLS):
                x = col * CELL_SIZE
                y = row * CELL_SIZE
                if self.layout[row][col] == 1:
                    pygame.draw.rect(screen, BLUE, (x, y, CELL_SIZE, CELL_SIZE))
                elif self.layout[row][col] == 2:
                    pygame.draw.circle(screen, WHITE, (x + CELL_SIZE//2, y + CELL_SIZE//2), 4)
                elif self.layout[row][col] == 3:
                    pygame.draw.circle(screen, WHITE, (x + CELL_SIZE//2, y + CELL_SIZE//2), 10)

class PacMan:
    """吃豆人类"""
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.grid_x = x // CELL_SIZE
        self.grid_y = y // CELL_SIZE
        self.direction = RIGHT
        self.next_direction = RIGHT
        self.radius = CELL_SIZE // 2 - 2
        self.mouth_angle = 0
        self.mouth_open = True
        self.speed = 2
        self.move_counter = 0
        
    def update(self, maze):
        """更新吃豆人位置"""
        # 先尝试下一个方向
        if self.next_direction != self.direction:
            test_x = self.x + self.next_direction[0] * self.speed
            test_y = self.y + self.next_direction[1] * self.speed
            if self.can_move(test_x, test_y, maze):
                self.direction = self.next_direction
        
        # 计算新位置
        new_x = self.x + self.direction[0] * self.speed
        new_y = self.y + self.direction[1] * self.speed
        
        # 检查新位置是否可移动
        if self.can_move(new_x, new_y, maze):
            self.x = new_x
            self.y = new_y
            self.grid_x = int(self.x // CELL_SIZE)
            self.grid_y = int(self.y // CELL_SIZE)
            
            # 吃豆子
            if 0 <= self.grid_y < ROWS and 0 <= self.grid_x < COLS:
                if maze.layout[self.grid_y][self.grid_x] in [2, 3]:
                    maze.layout[self.grid_y][self.grid_x] = 0
                    return True
        else:
            # 如果无法移动，对齐到网格
            self.x = int(self.grid_x * CELL_SIZE + CELL_SIZE // 2)
            self.y = int(self.grid_y * CELL_SIZE + CELL_SIZE // 2)
        
        return False
    
    def can_move(self, x, y, maze):
        """检查是否可以移动到新位置"""
        # 检查角色中心点周围四个点
        check_points = [
            (x - self.radius + 2, y - self.radius + 2),
            (x + self.radius - 2, y - self.radius + 2),
            (x - self.radius + 2, y + self.radius - 2),
            (x + self.radius - 2, y + self.radius - 2)
        ]
        
        for px, py in check_points:
            col = int(px // CELL_SIZE)
            row = int(py // CELL_SIZE)
            if 0 <= row < ROWS and 0 <= col < COLS:
                if maze.layout[row][col] == 1:
                    return False
        return True
    
    def draw(self, screen):
        """绘制吃豆人"""
        # 计算嘴巴角度
        if self.mouth_open:
            self.mouth_angle += 5
            if self.mouth_angle > 30:
                self.mouth_open = False
        else:
            self.mouth_angle -= 5
            if self.mouth_angle < 0:
                self.mouth_open = True
        
        # 根据方向旋转
        angle_offset = 0
        if self.direction == RIGHT:
            angle_offset = 0
        elif self.direction == DOWN:
            angle_offset = 90
        elif self.direction == LEFT:
            angle_offset = 180
        elif self.direction == UP:
            angle_offset = 270
        
        # 绘制身体
        start_angle = angle_offset + self.mouth_angle
        end_angle = angle_offset - self.mouth_angle + 360
        
        # 用扇形绘制吃豆人
        pygame.draw.arc(screen, YELLOW, 
                       (self.x - self.radius, self.y - self.radius, 
                        self.radius*2, self.radius*2),
                       math.radians(start_angle),
                       math.radians(end_angle),
                       self.radius)
        
        # 填充扇形
        points = [(self.x, self.y)]
        for angle in range(int(start_angle), int(end_angle) + 1, 5):
            rad = math.radians(angle)
            points.append((self.x + self.radius * math.cos(rad), 
                          self.y + self.radius * math.sin(rad)))
        if len(points) > 2:
            pygame.draw.polygon(screen, YELLOW, points)

class Ghost:
    """幽灵类"""
    def __init__(self, x, y, color):
        self.x = x
        self.y = y
        self.grid_x = x // CELL_SIZE
        self.grid_y = y // CELL_SIZE
        self.color = color
        self.direction = random.choice([UP, DOWN, LEFT, RIGHT])
        self.speed = 1.5
        self.radius = CELL_SIZE // 2 - 2
        self.move_timer = 0
        
    def update(self, maze, pacman):
        """更新幽灵位置"""
        self.move_timer += 1
        
        # 每隔一段时间改变方向
        if self.move_timer > 20:
            self.move_timer = 0
            # 有一定概率追向吃豆人
            if random.random() < 0.4:
                dx = pacman.x - self.x
                dy = pacman.y - self.y
                if abs(dx) > abs(dy):
                    self.direction = RIGHT if dx > 0 else LEFT
                else:
                    self.direction = DOWN if dy > 0 else UP
            else:
                self.direction = random.choice([UP, DOWN, LEFT, RIGHT])
        
        # 移动
        new_x = self.x + self.direction[0] * self.speed
        new_y = self.y + self.direction[1] * self.speed
        
        if self.can_move(new_x, new_y, maze):
            self.x = new_x
            self.y = new_y
            self.grid_x = int(self.x // CELL_SIZE)
            self.grid_y = int(self.y // CELL_SIZE)
        else:
            # 如果撞墙，随机改变方向
            self.direction = random.choice([UP, DOWN, LEFT, RIGHT])
    
    def can_move(self, x, y, maze):
        """检查幽灵是否可以移动"""
        check_points = [
            (x - self.radius + 2, y - self.radius + 2),
            (x + self.radius - 2, y - self.radius + 2),
            (x - self.radius + 2, y + self.radius - 2),
            (x + self.radius - 2, y + self.radius - 2)
        ]
        
        for px, py in check_points:
            col = int(px // CELL_SIZE)
            row = int(py // CELL_SIZE)
            if 0 <= row < ROWS and 0 <= col < COLS:
                if maze.layout[row][col] == 1:
                    return False
        return True
    
    def draw(self, screen):
        """绘制幽灵"""
        # 身体
        pygame.draw.circle(screen, self.color, 
                          (int(self.x), int(self.y)), 
                          self.radius)
        # 眼睛
        for offset in [-5, 5]:
            pygame.draw.circle(screen, WHITE, 
                             (int(self.x + offset), int(self.y - 5)), 
                             4)
            pygame.draw.circle(screen, BLACK, 
                             (int(self.x + offset), int(self.y - 5)), 
                             2)

class Game:
    """游戏主类"""
    def __init__(self):
        self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
        pygame.display.set_caption("吃豆人")
        self.clock = pygame.time.Clock()
        self.font = pygame.font.Font(None, 36)
        self.small_font = pygame.font.Font(None, 24)
        
        self.reset_game()
    
    def reset_game(self):
        """重置游戏"""
        self.maze = Maze()
        self.pacman = PacMan(CELL_SIZE * 9.5, CELL_SIZE * 15.5)
        self.ghosts = [
            Ghost(CELL_SIZE * 8.5, CELL_SIZE * 8.5, RED),
            Ghost(CELL_SIZE * 10.5, CELL_SIZE * 8.5, PINK),
            Ghost(CELL_SIZE * 8.5, CELL_SIZE * 10.5, CYAN),
            Ghost(CELL_SIZE * 10.5, CELL_SIZE * 10.5, ORANGE)
        ]
        self.score = 0
        self.total_dots = sum(row.count(2) + row.count(3) for row in self.maze.layout)
        self.game_over = False
        self.win = False
        self.last_time = pygame.time.get_ticks()
    
    def handle_events(self):
        """处理事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False
            if event.type == pygame.KEYDOWN:
                if self.game_over or self.win:
                    if event.key == pygame.K_r:
                        self.reset_game()
                else:
                    if event.key == pygame.K_UP:
                        self.pacman.next_direction = UP
                    elif event.key == pygame.K_DOWN:
                        self.pacman.next_direction = DOWN
                    elif event.key == pygame.K_LEFT:
                        self.pacman.next_direction = LEFT
                    elif event.key == pygame.K_RIGHT:
                        self.pacman.next_direction = RIGHT
        return True
    
    def update(self):
        """更新游戏状态"""
        if self.game_over or self.win:
            return
        
        # 更新吃豆人
        if self.pacman.update(self.maze):
            self.score += 10
            # 检查是否吃完所有豆子
            if self.score >= self.total_dots * 10:
                self.win = True
        
        # 更新幽灵
        for ghost in self.ghosts:
            ghost.update(self.maze, self.pacman)
            
            # 检测碰撞
            distance = math.sqrt((self.pacman.x - ghost.x) ** 2 + 
                                (self.pacman.y - ghost.y) ** 2)
            if distance < self.pacman.radius + ghost.radius - 5:
                self.game_over = True
    
    def draw(self):
        """绘制游戏画面"""
        self.screen.fill(BLACK)
        
        # 绘制迷宫
        self.maze.draw(self.screen)
        
        # 绘制吃豆人
        self.pacman.draw(self.screen)
        
        # 绘制幽灵
        for ghost in self.ghosts:
            ghost.draw(self.screen)
        
        # 绘制分数
        score_text = self.font.render(f"Score: {self.score}", True, WHITE)
        self.screen.blit(score_text, (10, 10))
        
        # 显示剩余豆子
        remaining = self.total_dots - self.score // 10
        dots_text = self.small_font.render(f"Dots: {remaining}", True, WHITE)
        self.screen.blit(dots_text, (10, 50))
        
        # 游戏结束或胜利信息
        if self.game_over:
            # 半透明背景
            s = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.SRCALPHA)
            s.fill((0, 0, 0, 128))
            self.screen.blit(s, (0, 0))
            
            text = self.font.render("Game Over! Press R to restart", True, RED)
            text_rect = text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT//2 - 20))
            self.screen.blit(text, text_rect)
            
            score_text = self.small_font.render(f"Final Score: {self.score}", True, WHITE)
            score_rect = score_text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT//2 + 30))
            self.screen.blit(score_text, score_rect)
            
        elif self.win:
            # 半透明背景
            s = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.SRCALPHA)
            s.fill((0, 0, 0, 128))
            self.screen.blit(s, (0, 0))
            
            text = self.font.render("You Win! Press R to restart", True, GREEN)
            text_rect = text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT//2 - 20))
            self.screen.blit(text, text_rect)
            
            score_text = self.small_font.render(f"Final Score: {self.score}", True, WHITE)
            score_rect = score_text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT//2 + 30))
            self.screen.blit(score_text, score_rect)
        
        pygame.display.flip()
    
    def run(self):
        """游戏主循环"""
        running = True
        while running:
            running = self.handle_events()
            self.update()
            self.draw()
            self.clock.tick(60)
        
        pygame.quit()
        sys.exit()

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