import pygame
import sys
import random
import math

# 初始化
pygame.init()
WIDTH, HEIGHT = 900, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("航海模拟器")
clock = pygame.time.Clock()
FPS = 60

# 颜色
SKY_TOP = (100, 170, 230)
SKY_BOTTOM = (190, 220, 240)
SEA_DEEP = (20, 60, 110)
SEA_MID = (30, 90, 150)
SEA_LIGHT = (60, 130, 190)
FOAM_WHITE = (230, 240, 250)
HULL_BROWN = (120, 70, 30)
HULL_DARK = (80, 45, 15)
DECK_TAN = (200, 160, 110)
SAIL_WHITE = (245, 245, 240)
SAIL_SHADOW = (210, 210, 205)
MAST_BROWN = (90, 60, 30)
FLAG_RED = (200, 40, 40)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (255, 230, 0)
RED = (255, 60, 60)
GREEN = (80, 200, 100)
ROCK_GRAY = (110, 105, 100)
ROCK_DARK = (70, 65, 60)
WHIRL_BLUE = (40, 80, 140)
WHIRL_LIGHT = (90, 140, 200)
LIGHTHOUSE_RED = (220, 50, 50)
LIGHTHOUSE_WHITE = (250, 250, 250)
LIGHT_BEAM = (255, 250, 180)

# 游戏参数
WIND_BASE_ANGLE = 45  # 风向（角度，0=东，90=北）
WIND_CHANGE_SPEED = 0.3
BOAT_MAX_SPEED = 8


class Boat:
    def __init__(self):
        self.x = WIDTH // 2
        self.y = HEIGHT - 150
        self.angle = 0            # 船头朝向（0=向上/北）
        self.speed = 3.0
        self.sail_angle = 0       # 帆的展开角度（-90~90）
        self.alive = True
        self.distance = 0

    def update(self, keys, wind_angle):
        if not self.alive:
            return

        # 转向控制
        turn = 0
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            turn = -1
        elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            turn = 1
        self.angle += turn * 2.5  # 每次转动2.5度

        # 帆角度控制
        sail_change = 0
        if keys[pygame.K_q]:
            sail_change = -2
        elif keys[pygame.K_e]:
            sail_change = 2
        self.sail_angle += sail_change
        self.sail_angle = max(-80, min(80, self.sail_angle))

        # 计算风力效率
        # 船头朝向与风向的夹角
        # 风向：wind_angle，船向：self.angle
        # 理想情况下，帆与风向垂直时效率最高
        # 帆的绝对方向 = 船向 + 帆角
        sail_world_angle = self.angle + self.sail_angle

        # 风向与帆的夹角（0~180度）
        angle_diff = abs((sail_world_angle - wind_angle) % 360)
        if angle_diff > 180:
            angle_diff = 360 - angle_diff

        # 风力效率：夹角越接近90度，效率越高
        # 0度（顺风）：效率中等；90度（侧风）：效率最高
        efficiency = math.sin(math.radians(angle_diff))
        efficiency = max(0.15, efficiency)

        # 目标速度
        target_speed = 2 + efficiency * (BOAT_MAX_SPEED - 2)

        # 平滑加速
        self.speed += (target_speed - self.speed) * 0.02

        # 移动
        rad = math.radians(self.angle)
        self.x += math.sin(rad) * self.speed
        self.y -= math.cos(rad) * self.speed

        # 累积航行距离
        self.distance += self.speed * 0.1

        # 边界（海洋无限但限制在可见范围内）
        if self.x < 40:
            self.x = 40
            self.angle = min(self.angle + 5, 180)
        if self.x > WIDTH - 40:
            self.x = WIDTH - 40
            self.angle = max(self.angle - 5, -180)
        if self.y < 80:
            self.y = 80
            self.angle = 180 if self.angle > 0 else -180
        if self.y > HEIGHT - 40:
            self.y = HEIGHT - 40
            self.angle = 0

    def get_rect(self):
        return pygame.Rect(self.x - 20, self.y - 30, 40, 50)

    def crash(self):
        self.alive = False

    def draw(self, surface):
        if not self.alive:
            # 沉船
            pygame.draw.ellipse(surface, HULL_DARK,
                                (self.x - 30, self.y, 60, 20))
            pygame.draw.line(surface, MAST_BROWN,
                             (self.x, self.y - 10), (self.x + 20, self.y - 30), 3)
            return

        # 用旋转表面绘制船体
        boat_surf = pygame.Surface((80, 80), pygame.SRCALPHA)
        cx, cy = 40, 45

        # 船体（椭圆）
        pygame.draw.ellipse(boat_surf, HULL_BROWN, (cx - 15, cy - 20, 30, 40))
        pygame.draw.ellipse(boat_surf, HULL_DARK, (cx - 15, cy - 20, 30, 40), 2)

        # 甲板
        pygame.draw.ellipse(boat_surf, DECK_TAN, (cx - 10, cy - 15, 20, 25))

        # 桅杆
        pygame.draw.line(boat_surf, MAST_BROWN, (cx, cy - 15), (cx, cy - 50), 3)

        # 帆（根据帆角度绘制）
        sail_offset = self.sail_angle * 0.4
        sail_pts = [
            (cx, cy - 45),
            (cx + sail_offset, cy - 20),
            (cx, cy - 5),
        ]
        pygame.draw.polygon(boat_surf, SAIL_WHITE, sail_pts)
        pygame.draw.polygon(boat_surf, SAIL_SHADOW, sail_pts, 2)

        # 小三角旗
        pygame.draw.polygon(boat_surf, FLAG_RED, [
            (cx, cy - 50), (cx + 12, cy - 46), (cx, cy - 42)
        ])

        # 船头指向
        pygame.draw.polygon(boat_surf, HULL_DARK, [
            (cx, cy - 24), (cx - 4, cy - 18), (cx + 4, cy - 18)
        ])

        # 旋转并绘制
        rotated = pygame.transform.rotate(boat_surf, -self.angle)
        rect = rotated.get_rect(center=(int(self.x), int(self.y)))
        surface.blit(rotated, rect)


class Rock:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.size = random.randint(15, 30)
        self.points = []
        for i in range(6):
            angle = i * math.pi * 2 / 6
            r = self.size * random.uniform(0.6, 1.1)
            self.points.append((math.cos(angle) * r, math.sin(angle) * r))

    def update(self, boat_speed):
        pass  # 礁石静止

    def get_rect(self):
        return pygame.Rect(self.x - self.size, self.y - self.size,
                           self.size * 2, self.size * 2)

    def draw(self, surface):
        # 岩石影子
        pygame.draw.ellipse(surface, ROCK_DARK,
                            (self.x - self.size * 0.8, self.y + self.size * 0.4,
                             self.size * 1.6, self.size * 0.6))
        # 岩石主体
        pts = [(self.x + px, self.y + py) for px, py in self.points]
        pygame.draw.polygon(surface, ROCK_GRAY, pts)
        pygame.draw.polygon(surface, ROCK_DARK, pts, 2)
        # 海浪漫过岩石
        pygame.draw.arc(surface, FOAM_WHITE,
                        (self.x - self.size, self.y - self.size * 0.2,
                         self.size * 2, self.size * 1.4),
                        0, math.pi, 2)


class Whirlpool:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.radius = 45
        self.phase = 0

    def update(self):
        self.phase += 0.08

    def get_rect(self):
        return pygame.Rect(self.x - self.radius, self.y - self.radius,
                           self.radius * 2, self.radius * 2)

    def draw(self, surface):
        # 漩涡
        for i in range(4):
            r = self.radius - i * 10
            pygame.draw.circle(surface, WHIRL_BLUE,
                               (int(self.x), int(self.y)), r, 2)
        # 旋转的线条
        for i in range(6):
            angle = self.phase + i * math.pi / 3
            x1 = self.x + math.cos(angle) * (self.radius - 5)
            y1 = self.y + math.sin(angle) * (self.radius - 5)
            x2 = self.x + math.cos(angle + 0.8) * (self.radius - 20)
            y2 = self.y + math.sin(angle + 0.8) * (self.radius - 20)
            pygame.draw.line(surface, WHIRL_LIGHT, (x1, y1), (x2, y2), 2)
        # 中心
        pygame.draw.circle(surface, (10, 30, 60),
                           (int(self.x), int(self.y)), 6)


class Lighthouse:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self, surface):
        # 塔身（红白条纹）
        base_w = 24
        top_w = 14
        height = 90
        # 红色塔身
        pygame.draw.polygon(surface, LIGHTHOUSE_RED, [
            (self.x - base_w // 2, self.y),
            (self.x - top_w // 2, self.y - height),
            (self.x + top_w // 2, self.y - height),
            (self.x + base_w // 2, self.y),
        ])
        # 白色条纹
        for i in range(1, 4):
            t = i / 4
            y1 = self.y - height * t
            t_next = (i - 0.3) / 4
            y2 = self.y - height * t_next
            w1 = base_w // 2 - (base_w - top_w) // 2 * t
            w2 = base_w // 2 - (base_w - top_w) // 2 * t_next
            pygame.draw.polygon(surface, LIGHTHOUSE_WHITE, [
                (self.x - w1, y1), (self.x + w1, y1),
                (self.x + w2, y2), (self.x - w2, y2),
            ])

        # 灯塔顶灯
        pygame.draw.rect(surface, (60, 60, 60),
                         (self.x - top_w // 2 - 3, self.y - height - 8,
                          top_w + 6, 8))
        pygame.draw.circle(surface, LIGHT_BEAM,
                           (int(self.x), int(self.y - height - 12)), 8)
        pygame.draw.circle(surface, WHITE,
                           (int(self.x), int(self.y - height - 12)), 4)


class WindArrow:
    """显示风向和风力的指示器"""
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self, surface, wind_angle, wind_strength):
        pygame.draw.circle(surface, (255, 255, 255, 100),
                           (self.x, self.y), 35)
        pygame.draw.circle(surface, BLACK, (self.x, self.y), 35, 2)

        rad = math.radians(wind_angle)
        arrow_len = 25 + wind_strength * 5
        ex = self.x + math.sin(rad) * arrow_len
        ey = self.y - math.cos(rad) * arrow_len
        pygame.draw.line(surface, (30, 120, 200),
                         (self.x, self.y), (ex, ey), 4)
        # 箭头头部
        head_angle1 = rad + math.pi * 0.8
        head_angle2 = rad - math.pi * 0.8
        pygame.draw.polygon(surface, (30, 120, 200), [
            (ex, ey),
            (ex + math.sin(head_angle1) * 10, ey - math.cos(head_angle1) * 10),
            (ex + math.sin(head_angle2) * 10, ey - math.cos(head_angle2) * 10),
        ])

        label = pygame.font.SysFont("arial", 12).render("WIND", True, BLACK)
        surface.blit(label, (self.x - 18, self.y + 38))


def draw_sea(surface, distance):
    # 海面
    surface.fill(SEA_MID)

    # 远处的天空（地平线）
    pygame.draw.rect(surface, SKY_BOTTOM, (0, 0, WIDTH, 80))
    pygame.draw.rect(surface, SKY_TOP, (0, 0, WIDTH, 40))

    # 地平线
    pygame.draw.line(surface, (200, 220, 230), (0, 80), (WIDTH, 80), 2)

    # 海浪
    wave_offset = (distance * 3) % 80
    for i in range(20):
        y = 100 + i * 26
        phase = distance * 0.05 + i * 0.8
        for j in range(0, WIDTH + 80, 80):
            x = j - wave_offset + math.sin(phase + j * 0.02) * 10
            pygame.draw.arc(surface, SEA_LIGHT,
                            (x - 30, y - 8, 60, 16), 0.2, math.pi - 0.2, 2)
            pygame.draw.arc(surface, (80, 150, 210),
                            (x - 25, y - 5, 50, 12), 0.3, math.pi - 0.3, 1)


def draw_ui(surface, boat, font, small_font, wind_angle, wind_strength, distance):
    # 速度
    speed_text = small_font.render(f"SPD: {boat.speed:.1f} knots", True, BLACK)
    surface.blit(speed_text, (20, 20))

    # 航向
    heading_text = small_font.render(f"HEADING: {int(boat.angle)}°", True, BLACK)
    surface.blit(heading_text, (20, 50))

    # 帆角度
    sail_text = small_font.render(f"SAIL: {int(boat.sail_angle)}°", True, BLACK)
    surface.blit(sail_text, (20, 80))

    # 距离
    dist_text = font.render(f"Distance: {int(distance)} nm", True, BLACK)
    surface.blit(dist_text, (WIDTH - 300, 20))

    # 风向指示器
    WindArrow(WIDTH - 70, HEIGHT - 70).draw(surface, wind_angle, wind_strength)

    # 操作提示
    hint1 = small_font.render("A/D or ←/→ : Steer    Q/E : Adjust Sail",
                              True, (40, 40, 40))
    surface.blit(hint1, (WIDTH // 2 - 190, HEIGHT - 50))
    hint2 = small_font.render("Sail perpendicular to wind for max speed",
                              True, (60, 60, 60))
    surface.blit(hint2, (WIDTH // 2 - 180, HEIGHT - 28))

    # 游戏结束
    if not boat.alive:
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 140))
        surface.blit(overlay, (0, 0))

        go_text = font.render("SHIPWRECKED!", True, RED)
        surface.blit(go_text, (WIDTH // 2 - 140, HEIGHT // 2 - 80))

        final_dist = small_font.render(
            f"You sailed {int(distance)} nautical miles", True, WHITE)
        surface.blit(final_dist, (WIDTH // 2 - 150, HEIGHT // 2 - 20))

        restart = small_font.render("Press R to Restart", True, YELLOW)
        surface.blit(restart, (WIDTH // 2 - 110, HEIGHT // 2 + 30))


def main():
    font = pygame.font.SysFont("arial", 36, bold=True)
    small_font = pygame.font.SysFont("arial", 20)

    boat = Boat()
    wind_angle = WIND_BASE_ANGLE
    wind_strength = 5

    # 生成场景元素
    def create_scene():
        rocks = []
        whirlpools = []
        # 随机放置礁石和漩涡
        for _ in range(8):
            x = random.randint(80, WIDTH - 80)
            y = random.randint(150, HEIGHT - 100)
            if math.hypot(x - WIDTH // 2, y - (HEIGHT - 150)) < 150:
                continue
            rocks.append(Rock(x, y))
        for _ in range(3):
            x = random.randint(100, WIDTH - 100)
            y = random.randint(150, HEIGHT - 150)
            if math.hypot(x - WIDTH // 2, y - (HEIGHT - 150)) < 200:
                continue
            whirlpools.append(Whirlpool(x, y))
        return rocks, whirlpools

    rocks, whirlpools = create_scene()
    lighthouses = [Lighthouse(120, 95), Lighthouse(WIDTH - 120, 95)]
    distance = 0
    wind_timer = 0

    running = True
    while running:
        clock.tick(FPS)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r and not boat.alive:
                    boat = Boat()
                    rocks, whirlpools = create_scene()
                    wind_angle = WIND_BASE_ANGLE
                    wind_strength = 5
                    distance = 0

        keys = pygame.key.get_pressed()

        # 风向缓慢变化
        wind_timer += 1
        if wind_timer > 180:
            wind_timer = 0
            wind_angle += random.uniform(-30, 30)
            wind_strength = random.uniform(3, 8)

        if boat.alive:
            boat.update(keys, wind_angle)
            distance = boat.distance

            # 更新漩涡
            for wp in whirlpools:
                wp.update()

            # 碰撞检测：礁石
            boat_rect = boat.get_rect()
            for rock in rocks:
                if boat_rect.colliderect(rock.get_rect()):
                    boat.crash()
                    break

            # 碰撞检测：漩涡
            if boat.alive:
                for wp in whirlpools:
                    if boat_rect.colliderect(wp.get_rect()):
                        boat.crash()
                        break

        # 绘制
        draw_sea(screen, distance)

        # 灯塔
        for lh in lighthouses:
            lh.draw(screen)

        # 礁石
        for rock in rocks:
            rock.draw(screen)

        # 漩涡
        for wp in whirlpools:
            wp.draw(screen)

        # 船
        boat.draw(screen)

        # 海面泡沫（船尾）
        if boat.alive:
            for i in range(3):
                fx = boat.x - math.sin(math.radians(boat.angle)) * (25 + i * 8)
                fy = boat.y + math.cos(math.radians(boat.angle)) * (25 + i * 8)
                pygame.draw.circle(screen, FOAM_WHITE,
                                   (int(fx + random.uniform(-3, 3)),
                                    int(fy + random.uniform(-3, 3))),
                                   3 - i)

        # UI
        draw_ui(screen, boat, font, small_font, wind_angle, wind_strength, distance)

        pygame.display.flip()

    pygame.quit()
    sys.exit()


if __name__ == "__main__":
    main()