import pygame
import sys
import math

# --- 初始化 ---
pygame.init()
BOARD_SIZE = 15
CELL = 40
MARGIN = 40
WIDTH = HEIGHT = CELL * (BOARD_SIZE - 1) + MARGIN * 2
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pygame 五子棋 - AI vs Human")
clock = pygame.time.Clock()

# 颜色
BG_COLOR = (220, 180, 120)
LINE_COLOR = (80, 60, 40)
BLACK_COLOR = (30, 30, 30)
WHITE_COLOR = (240, 240, 240)
HIGHLIGHT_COLOR = (255, 50, 50)
PREVIEW_COLOR = (100, 100, 100, 120)
TEXT_COLOR = (50, 50, 50)

FONT = pygame.font.SysFont("consolas", 24)
BIG_FONT = pygame.font.SysFont("consolas", 50)

# --- 游戏逻辑 ---

class Gomoku:
    def __init__(self):
        self.board = [[0]*BOARD_SIZE for _ in range(BOARD_SIZE)]
        self.current_player = 1  # 1=黑, 2=白
        self.history = []
        self.winner = 0
        self.win_line = []
        self.ai_enabled = True
        self.last_move = None
        self.anim_timer = 0

    def reset(self):
        self.board = [[0]*BOARD_SIZE for _ in range(BOARD_SIZE)]
        self.current_player = 1
        self.history = []
        self.winner = 0
        self.win_line = []
        self.last_move = None

    def place(self, x, y):
        if self.board[y][x] != 0 or self.winner: return False
        self.board[y][x] = self.current_player
        self.history.append((x, y, self.current_player))
        self.last_move = (x, y)
        self.anim_timer = 10

        if self.check_win(x, y):
            self.winner = self.current_player
        else:
            self.current_player = 3 - self.current_player
        return True

    def undo(self):
        if not self.history or self.winner: return
        # AI模式下悔两步
        steps = 2 if self.ai_enabled and len(self.history) >= 2 else 1
        for _ in range(steps):
            if self.history:
                x, y, p = self.history.pop()
                self.board[y][x] = 0
                self.current_player = p
        self.last_move = self.history[-1][:2] if self.history else None

    def check_win(self, x, y):
        directions = [(1,0), (0,1), (1,1), (1,-1)]
        player = self.board[y][x]
        for dx, dy in directions:
            line = [(x, y)]
            for d in [1, -1]:
                nx, ny = x + dx*d, y + dy*d
                while 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and self.board[ny][nx] == player:
                    line.append((nx, ny))
                    nx += dx*d
                    ny += dy*d
            if len(line) >= 5:
                self.win_line = line
                return True
        return False

    def ai_move(self):
        if self.winner or self.current_player != 2: return
        best_score = -1
        best_pos = (7, 7)

        for y in range(BOARD_SIZE):
            for x in range(BOARD_SIZE):
                if self.board[y][x] != 0: continue
                score = self.evaluate(x, y, 2) + self.evaluate(x, y, 1) * 0.9
                if score > best_score:
                    best_score = score
                    best_pos = (x, y)

        self.place(*best_pos)

    def evaluate(self, x, y, player):
        score = 0
        directions = [(1,0), (0,1), (1,1), (1,-1)]
        opp = 3 - player

        for dx, dy in directions:
            count = 1
            open_ends = 0
            for d in [1, -1]:
                nx, ny = x + dx*d, y + dy*d
                while 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and self.board[ny][nx] == player:
                    count += 1
                    nx += dx*d
                    ny += dy*d
                if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and self.board[ny][nx] == 0:
                    open_ends += 1

            if count >= 5: score += 100000
            elif count == 4 and open_ends == 2: score += 10000
            elif count == 4 and open_ends == 1: score += 1000
            elif count == 3 and open_ends == 2: score += 1000
            elif count == 3 and open_ends == 1: score += 100
            elif count == 2 and open_ends == 2: score += 100
            elif count == 2 and open_ends == 1: score += 10
            elif open_ends == 2: score += 1

        return score

    def draw(self, surface, mouse_pos):
        surface.fill(BG_COLOR)

        # 棋盘线
        for i in range(BOARD_SIZE):
            pos = MARGIN + i * CELL
            pygame.draw.line(surface, LINE_COLOR, (MARGIN, pos), (WIDTH - MARGIN, pos), 2)
            pygame.draw.line(surface, LINE_COLOR, (pos, MARGIN), (pos, HEIGHT - MARGIN), 2)

        # 星位
        for p in [3, 7, 11]:
            pygame.draw.circle(surface, LINE_COLOR, (MARGIN + p*CELL, MARGIN + p*CELL), 4)

        # 棋子
        for y in range(BOARD_SIZE):
            for x in range(BOARD_SIZE):
                if self.board[y][x]:
                    cx = MARGIN + x * CELL
                    cy = MARGIN + y * CELL
                    color = BLACK_COLOR if self.board[y][x] == 1 else WHITE_COLOR
                    r = CELL // 2 - 2
                    if self.last_move == (x, y) and self.anim_timer > 0:
                        r = int(r * (1 + self.anim_timer * 0.02))
                    pygame.draw.circle(surface, color, (cx, cy), r)
                    if self.board[y][x] == 2:
                        pygame.draw.circle(surface, (180, 180, 180), (cx, cy), r, 2)

        # 最后一步高亮
        if self.last_move and not self.winner:
            lx, ly = self.last_move
            pygame.draw.circle(surface, HIGHLIGHT_COLOR, (MARGIN + lx*CELL, MARGIN + ly*CELL), 6)

        # 胜利连线
        if self.win_line:
            for wx, wy in self.win_line:
                pygame.draw.circle(surface, HIGHLIGHT_COLOR, (MARGIN + wx*CELL, MARGIN + wy*CELL), CELL//2 - 2, 3)

        # 鼠标预览
        if not self.winner and mouse_pos:
            mx, my = mouse_pos
            gx = round((mx - MARGIN) / CELL)
            gy = round((my - MARGIN) / CELL)
            if 0 <= gx < BOARD_SIZE and 0 <= gy < BOARD_SIZE and self.board[gy][gx] == 0:
                s = pygame.Surface((CELL, CELL), pygame.SRCALPHA)
                color = (*BLACK_COLOR, 120) if self.current_player == 1 else (*WHITE_COLOR, 120)
                pygame.draw.circle(s, color, (CELL//2, CELL//2), CELL//2 - 2)
                surface.blit(s, (MARGIN + gx*CELL - CELL//2, MARGIN + gy*CELL - CELL//2))

        # UI
        mode = "AI" if self.ai_enabled else "PVP"
        turn = "Black" if self.current_player == 1 else "White"
        info = f"{mode} | Turn: {turn}"
        if self.winner:
            info = f"{'Black' if self.winner == 1 else 'White'} Wins!"
        txt = FONT.render(info, True, TEXT_COLOR)
        surface.blit(txt, (MARGIN, HEIGHT - 30))

        hint = FONT.render("Z:Undo | R:Reset | A:Toggle AI", True, (120, 100, 80))
        surface.blit(hint, (WIDTH - 280, HEIGHT - 30))

# --- 主程序 ---
def main():
    game = Gomoku()
    running = True

    while running:
        clock.tick(60)
        mouse_pos = pygame.mouse.get_pos()

        for event in pygame.event.get():
            if event.type == pygame.QUIT: pygame.quit(); sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN and not game.winner:
                mx, my = mouse_pos
                gx = round((mx - MARGIN) / CELL)
                gy = round((my - MARGIN) / CELL)
                if 0 <= gx < BOARD_SIZE and 0 <= gy < BOARD_SIZE:
                    if game.place(gx, gy):
                        if game.ai_enabled and not game.winner:
                            game.ai_move()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_z: game.undo()
                if event.key == pygame.K_r: game.reset()
                if event.key == pygame.K_a:
                    game.ai_enabled = not game.ai_enabled
                    game.reset()
                if event.key == pygame.K_ESCAPE: pygame.quit(); sys.exit()

        if game.anim_timer > 0: game.anim_timer -= 1

        game.draw(screen, mouse_pos)
        pygame.display.flip()

    pygame.quit()

if __name__ == "__main__":
    main()