import pygame
import sys
import random

# ========== 初始化 ==========
pygame.init()
WIDTH, HEIGHT = 650, 500
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("🧩 House Puzzle – 9 Pieces")
clock = pygame.time.Clock()

# ========== 美观配色 ==========
BG_COLOR = (35, 32, 45)
PANEL_BG = (25, 22, 35)
REF_BORDER = (120, 180, 255)
SELECTED_BORDER = (255, 215, 0)
HOVER_BORDER = (200, 200, 220)
TEXT_COLOR = (240, 240, 250)
ACCENT_COLOR = (120, 180, 255)
BUTTON_COLOR = (60, 60, 80)
PIECE_SHADOW = (10, 10, 20)

# ========== 字体 ==========
font_title = pygame.font.Font(None, 44)
font_info = pygame.font.Font(None, 28)
font_win = pygame.font.Font(None, 40)

# ========== 游戏参数 ==========
ROWS, COLS = 3, 3
PIECE_SIZE = 100
GAP = 6
PUZZLE_X = 260
PUZZLE_Y = 80
REF_X, REF_Y = 30, 80
REF_SIZE = 150

# ========== 生成漂亮的房子图案 ==========
def create_house_image(size):
    surf = pygame.Surface((size, size), pygame.SRCALPHA)
    # 天空渐变
    for y in range(size):
        ratio = y / size
        r = int(120 + 60 * ratio)
        g = int(180 + 50 * ratio)
        b = int(230 + 20 * ratio)
        pygame.draw.line(surf, (r, g, b), (0, y), (size, y))
    # 草地
    ground_y = int(size * 0.72)
    pygame.draw.rect(surf, (120, 190, 90), (0, ground_y, size, size - ground_y))
    # 房子主体
    house_left = int(size * 0.22)
    house_right = int(size * 0.78)
    house_top = int(size * 0.38)
    house_bottom = ground_y
    house_w = house_right - house_left
    house_h = house_bottom - house_top
    pygame.draw.rect(surf, (245, 215, 160), (house_left, house_top, house_w, house_h))
    pygame.draw.rect(surf, (170, 130, 80), (house_left, house_top, house_w, house_h), 3)
    # 屋顶（三角形）
    roof_top = int(size * 0.18)
    roof_left = house_left - 14
    roof_right = house_right + 14
    pygame.draw.polygon(surf, (190, 70, 50), [
        (roof_left, house_top),
        (house_left + house_w // 2, roof_top),
        (roof_right, house_top)
    ])
    pygame.draw.polygon(surf, (140, 45, 30), [
        (roof_left, house_top),
        (house_left + house_w // 2, roof_top),
        (roof_right, house_top)
    ], 3)
    # 门
    door_w = int(house_w * 0.24)
    door_h = int(house_h * 0.38)
    door_x = house_left + house_w // 2 - door_w // 2
    door_y = house_bottom - door_h
    pygame.draw.rect(surf, (130, 80, 45), (door_x, door_y, door_w, door_h))
    pygame.draw.rect(surf, (85, 45, 20), (door_x, door_y, door_w, door_h), 2)
    pygame.draw.circle(surf, (220, 190, 60), (door_x + door_w - 8, door_y + door_h // 2), 4)
    # 窗户
    win_w = int(house_w * 0.2)
    win_h = int(house_h * 0.2)
    for wx in [house_left + int(house_w * 0.15), house_right - int(house_w * 0.15) - win_w]:
        wy = house_top + int(house_h * 0.15)
        pygame.draw.rect(surf, (210, 240, 255), (wx, wy, win_w, win_h))
        pygame.draw.rect(surf, (90, 150, 190), (wx, wy, win_w, win_h), 2)
        pygame.draw.line(surf, (90, 150, 190), (wx + win_w // 2, wy), (wx + win_w // 2, wy + win_h), 2)
        pygame.draw.line(surf, (90, 150, 190), (wx, wy + win_h // 2), (wx + win_w, wy + win_h // 2), 2)
    # 烟囱
    chimney_w = int(house_w * 0.14)
    chimney_h = int(house_h * 0.3)
    chimney_x = house_right - int(house_w * 0.22)
    chimney_y = house_top - chimney_h + 10
    pygame.draw.rect(surf, (190, 110, 65), (chimney_x, chimney_y, chimney_w, chimney_h))
    pygame.draw.rect(surf, (150, 80, 35), (chimney_x, chimney_y, chimney_w, chimney_h), 2)
    # 太阳
    pygame.draw.circle(surf, (255, 245, 120), (int(size * 0.14), int(size * 0.22)), int(size * 0.08))
    pygame.draw.circle(surf, (255, 255, 210), (int(size * 0.14), int(size * 0.22)), int(size * 0.06))
    # 云朵
    for cx, cy in [(int(size * 0.72), int(size * 0.16)), (int(size * 0.52), int(size * 0.12))]:
        pygame.draw.ellipse(surf, (255, 255, 255), (cx, cy, 30, 16))
        pygame.draw.ellipse(surf, (255, 255, 255), (cx + 10, cy - 6, 25, 16))
    return surf

# ========== 游戏类 ==========
class HousePuzzle:
    def __init__(self):
        self.full_img = create_house_image(PIECE_SIZE * COLS)
        self.ref_img = pygame.transform.smoothscale(self.full_img, (REF_SIZE, REF_SIZE))
        self.pieces = []
        self.correct_pos = []
        self.current_pos = []
        for r in range(ROWS):
            for c in range(COLS):
                x = c * PIECE_SIZE
                y = r * PIECE_SIZE
                piece = self.full_img.subsurface((x, y, PIECE_SIZE, PIECE_SIZE)).copy()
                self.pieces.append(piece)
                self.correct_pos.append((r, c))
                self.current_pos.append((r, c))
        self.shuffle_pieces()
        self.selected = None
        self.moves = 0
        self.solved = False

    def shuffle_pieces(self):
        indices = list(range(len(self.pieces)))
        random.shuffle(indices)
        for i in range(len(self.pieces)):
            self.current_pos[i] = self.correct_pos[indices[i]]
        self.moves = 0
        self.solved = False
        self.selected = None

    def get_piece_rect(self, row, col):
        x = PUZZLE_X + col * (PIECE_SIZE + GAP)
        y = PUZZLE_Y + row * (PIECE_SIZE + GAP)
        return pygame.Rect(x, y, PIECE_SIZE, PIECE_SIZE)

    def handle_click(self, pos):
        if self.solved:
            return
        clicked_idx = None
        for i, (r, c) in enumerate(self.current_pos):
            rect = self.get_piece_rect(r, c)
            if rect.collidepoint(pos):
                clicked_idx = i
                break
        if clicked_idx is not None:
            if self.selected is None:
                self.selected = clicked_idx
            else:
                if self.selected != clicked_idx:
                    self.current_pos[self.selected], self.current_pos[clicked_idx] = \
                        self.current_pos[clicked_idx], self.current_pos[self.selected]
                    self.moves += 1
                    if self.check_solved():
                        self.solved = True
                self.selected = None

    def check_solved(self):
        for i in range(len(self.pieces)):
            if self.current_pos[i] != self.correct_pos[i]:
                return False
        return True

    def draw(self):
        screen.fill(BG_COLOR)
        # 左侧参照图面板
        pygame.draw.rect(screen, PANEL_BG, (10, 10, REF_SIZE + 40, REF_SIZE + 110), border_radius=14)
        title_surf = font_title.render("Target", True, ACCENT_COLOR)
        screen.blit(title_surf, (REF_X + REF_SIZE // 2 - title_surf.get_width() // 2, 40))
        screen.blit(self.ref_img, (REF_X, REF_Y))
        pygame.draw.rect(screen, REF_BORDER, (REF_X - 3, REF_Y - 3, REF_SIZE + 6, REF_SIZE + 6), 3, border_radius=6)

        # 拼图区域背景
        for r in range(ROWS):
            for c in range(COLS):
                rect = self.get_piece_rect(r, c)
                shadow_rect = rect.move(3, 3)
                pygame.draw.rect(screen, PIECE_SHADOW, shadow_rect, border_radius=8)
                pygame.draw.rect(screen, (45, 45, 55), rect, border_radius=8)

        # 绘制碎片
        mouse_pos = pygame.mouse.get_pos()
        for i, (r, c) in enumerate(self.current_pos):
            rect = self.get_piece_rect(r, c)
            screen.blit(self.pieces[i], (rect.x, rect.y))
            # 边框处理
            border_color = HOVER_BORDER
            if self.selected == i:
                border_color = SELECTED_BORDER
            elif rect.collidepoint(mouse_pos) and self.selected != i:
                border_color = (255, 255, 200)
            pygame.draw.rect(screen, border_color, rect, 3, border_radius=6)

        # 步数显示
        moves_text = font_info.render(f"Moves: {self.moves}", True, TEXT_COLOR)
        screen.blit(moves_text, (PUZZLE_X, PUZZLE_Y + ROWS * (PIECE_SIZE + GAP) + 10))

        # 重置按钮
        reset_rect = pygame.Rect(PUZZLE_X + 200, PUZZLE_Y + ROWS * (PIECE_SIZE + GAP) + 5, 100, 40)
        pygame.draw.rect(screen, BUTTON_COLOR, reset_rect, border_radius=10)
        pygame.draw.rect(screen, TEXT_COLOR, reset_rect, 2, border_radius=10)
        reset_txt = font_info.render("Reset", True, TEXT_COLOR)
        screen.blit(reset_txt, (reset_rect.x + 18, reset_rect.y + 8))

        # 胜利画面
        if self.solved:
            overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            overlay.fill((0, 0, 0, 170))
            screen.blit(overlay, (0, 0))
            win_text = font_win.render("🎉 House Complete!", True, ACCENT_COLOR)
            screen.blit(win_text, (WIDTH // 2 - win_text.get_width() // 2, HEIGHT // 2 - 30))
            info_text = font_info.render("Press R or click Reset", True, TEXT_COLOR)
            screen.blit(info_text, (WIDTH // 2 - info_text.get_width() // 2, HEIGHT // 2 + 10))
        return reset_rect

# ========== 主循环 ==========
def main():
    game = HousePuzzle()
    running = True
    while running:
        mouse_pos = pygame.mouse.get_pos()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                # 检测重置按钮
                reset_rect = pygame.Rect(PUZZLE_X + 200, PUZZLE_Y + ROWS * (PIECE_SIZE + GAP) + 5, 100, 40)
                if reset_rect.collidepoint(mouse_pos):
                    game = HousePuzzle()
                else:
                    game.handle_click(event.pos)
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                    game = HousePuzzle()
        game.draw()
        pygame.display.flip()
        clock.tick(60)
    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()