1.准备工作

安装python 和 pygame ,略

2. 界面与全局变量

# 初始化 Pygame
pygame.init()

# =======================游戏常量======================================
BOARD_SIZE = 13  # 棋盘是13格x13格
GRID_SIZE = 40   #每个格子的像素大小(40x40像素)
MARGIN = 50     #棋盘边缘留白

# 界面尺寸计算
WIDTH = HEIGHT = BOARD_SIZE * GRID_SIZE + 2 * MARGIN#整个棋盘的尺寸是格数x格大小+2倍留白
BUTTON_AREA = 100   # 底部按钮区域高度
SCREEN_SIZE = (WIDTH+150, HEIGHT + BUTTON_AREA+80) # 窗口总尺寸

WHITE = (255, 255, 255)#白色
BLACK = (0, 0, 0)#黑色
BACKGROUND = (238, 154, 73)#背景色
LINE_COLOR = (0, 0, 0)#线条色

screen = pygame.display.set_mode(SCREEN_SIZE) # 创建指定尺寸的窗口
pygame.display.set_caption("五子棋")  # 设置窗口标题
clock = pygame.time.Clock()     # 创建时钟对象(控制帧率)
font = pygame.font.Font(None, 36)# 创建字体对象(默认字体,36号)

board = [[0] * (BOARD_SIZE + 2) for _ in range(BOARD_SIZE + 2)]  # 棋盘数据

history = []       # 落子历史记录(用于悔棋)
current_player = 1 # 当前玩家(1: 白棋,-1: 黑棋)
game_mode = "human" # 游戏模式("human"=人人对战,"ai"=人机对战)
ai_first = False    # AI是否先手
game_active = False # 游戏是否进行中
winner = None       # 胜利者(1/-1)

# 按钮位置和尺寸(pygame.Rect参数:x, y, width, height)
buttons = {
            "start": pygame.Rect(WIDTH//2-150, HEIGHT+20, 120, 60),   # 开始按钮
            "revoke": pygame.Rect(WIDTH//2+80, HEIGHT+20, 120, 60),    # 悔棋按钮
            "mode": pygame.Rect(WIDTH//2-150, HEIGHT+100, 180, 40),   # 模式切换按钮
            "first": pygame.Rect(WIDTH//2+80, HEIGHT+100, 180, 40)    # 先手选择按钮
            }

定义 一些围棋游戏需要的参数。

其中,棋盘数据board:

结构说明:

- 使用 (BOARD_SIZE+2) x (BOARD_SIZE+2) 的二维数组

- 索引从1到BOARD_SIZE有效(0和BOARD_SIZE+1是边界)

- 值说明:0=空,1=白棋,-1=黑棋

3.绘制棋盘格

定义绘制棋盘格函数draw_board

定义run函数,运行调试

def draw_board():
    screen.fill(BACKGROUND)
    for i in range(BOARD_SIZE + 1):
        start = MARGIN
        end = WIDTH - MARGIN
        # 横线
        pygame.draw.line(screen, LINE_COLOR,
                         (MARGIN, MARGIN + i * GRID_SIZE),
                         (WIDTH - MARGIN, MARGIN + i * GRID_SIZE), 2)
        # 竖线
        pygame.draw.line(screen, LINE_COLOR,
                         (MARGIN + i * GRID_SIZE, MARGIN),
                         (MARGIN + i * GRID_SIZE, HEIGHT - MARGIN), 2)

        # 绘制棋子
    for i in range(1, BOARD_SIZE + 1):
        for j in range(1, BOARD_SIZE + 1):
            if board[i][j] == 1:
                pygame.draw.circle(screen, WHITE,
                                   (MARGIN + (i - 1) * GRID_SIZE, MARGIN + (j - 1) * GRID_SIZE),
                                   GRID_SIZE // 2 - 2)
            elif board[i][j] == -1:
                pygame.draw.circle(screen, BLACK,
                                   (MARGIN + (i - 1) * GRID_SIZE, MARGIN + (j - 1) * GRID_SIZE),
                                   GRID_SIZE // 2 - 2)

def run():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()


        draw_board()

        pygame.display.flip()
        clock.tick(30)

使用pygame.draw.line在screen上绘制棋盘网格线,需要的参数有:线条颜色、起点坐标、终点坐标、线宽。

基于棋盘数据board,使用pygame.draw.circle,绘制棋子。 半径是格子大小的一半减2像素。(棋盘数据board初始全为0).

运行后:

绘制按钮

def draw_buttons():
    for name, rect in buttons.items():
        pygame.draw.rect(screen, (200, 200, 200), rect)
        pygame.draw.rect(screen, BLACK, rect, 2)

    # 绘制按钮文字
    mode_text = "PVP"  # 模式显示文本
    first_text = "people_first"  # 先手显示文本
    start_text = font.render("start", True, BLACK)
    revoke_text = font.render("revoke", True, BLACK)
    mode_text = font.render(mode_text, True, BLACK)
    first_text = font.render(first_text, True, BLACK)

    screen.blit(start_text, (buttons["start"].x + 10, buttons["start"].y + 5))
    screen.blit(revoke_text, (buttons["revoke"].x + 20, buttons["revoke"].y + 5))
    screen.blit(mode_text, (buttons["mode"].x + 10, buttons["mode"].y + 5))
    screen.blit(first_text, (buttons["first"].x + 10, buttons["first"].y + 5))

在run中,draw_board()后添加draw_buttons()

运行,

4.主要功能实现

代码如下:

import pygame
import sys
import random
import time

# 初始化 Pygame
pygame.init()

# =======================游戏常量======================================
BOARD_SIZE = 13  # 棋盘是13格x13格
GRID_SIZE = 40   #每个格子的像素大小(40x40像素)
MARGIN = 50     #棋盘边缘留白

# 界面尺寸计算
WIDTH = HEIGHT = BOARD_SIZE * GRID_SIZE + 2 * MARGIN#整个棋盘的尺寸是格数x格大小+2倍留白
BUTTON_AREA = 100   # 底部按钮区域高度
SCREEN_SIZE = (WIDTH+150, HEIGHT + BUTTON_AREA+80) # 窗口总尺寸

WHITE = (255, 255, 255)#白色
BLACK = (0, 0, 0)#黑色
BACKGROUND = (238, 154, 73)#背景色
LINE_COLOR = (0, 0, 0)#线条色

screen = pygame.display.set_mode(SCREEN_SIZE) # 创建指定尺寸的窗口
pygame.display.set_caption("五子棋")  # 设置窗口标题
clock = pygame.time.Clock()     # 创建时钟对象(控制帧率)
font = pygame.font.Font(None, 36)# 创建字体对象(默认字体,36号)

board = [[0] * (BOARD_SIZE + 2) for _ in range(BOARD_SIZE + 2)]  # 棋盘数据
history = []       # 落子历史记录(用于悔棋)
current_player = 1 # 当前玩家(1: 白棋,-1: 黑棋)
game_mode = "human" # 游戏模式("human"=人人对战,"ai"=人机对战)
ai_first = False    # AI是否先手
game_active = False # 游戏是否进行中
winner = None       # 胜利者(1/-1)

# 按钮位置和尺寸(pygame.Rect参数:x, y, width, height)
buttons = {
            "start": pygame.Rect(WIDTH//2-150, HEIGHT+20, 120, 60),   # 开始按钮
            "revoke": pygame.Rect(WIDTH//2+80, HEIGHT+20, 120, 60),    # 悔棋按钮
            "mode": pygame.Rect(WIDTH//2-150, HEIGHT+100, 180, 40),   # 模式切换按钮
            "first": pygame.Rect(WIDTH//2+80, HEIGHT+100, 180, 40)    # 先手选择按钮
            }


ai_turn = False       # AI是否该落子
ai_move_time = 0      # AI落子的时间戳
AI_DELAY = 1000      # AI思考时间(毫秒)





# ----------绘制棋盘 ------------
def draw_board():
    screen.fill(BACKGROUND)# 填充背景色
    for i in range(BOARD_SIZE + 1):
        start = MARGIN
        end = WIDTH - MARGIN
        # 横线
        pygame.draw.line(screen, LINE_COLOR,
                         (MARGIN, MARGIN + i * GRID_SIZE),
                         (WIDTH - MARGIN, MARGIN + i * GRID_SIZE), 2)
        # 竖线
        pygame.draw.line(screen, LINE_COLOR,
                         (MARGIN + i * GRID_SIZE, MARGIN),
                         (MARGIN + i * GRID_SIZE, HEIGHT - MARGIN), 2)

        # 绘制棋子
    for i in range(1, BOARD_SIZE + 1):
        for j in range(1, BOARD_SIZE + 1):
            if board[i][j] == 1:
                pygame.draw.circle(screen, WHITE,
                                   (MARGIN + (i - 1) * GRID_SIZE, MARGIN + (j - 1) * GRID_SIZE),
                                   GRID_SIZE // 2 - 2)
            elif board[i][j] == -1:
                pygame.draw.circle(screen, BLACK,
                                   (MARGIN + (i - 1) * GRID_SIZE, MARGIN + (j - 1) * GRID_SIZE),
                                   GRID_SIZE // 2 - 2)


# 绘制所有按钮
def draw_buttons():
    # 绘制所有按钮
    for name, rect in buttons.items():
        pygame.draw.rect(screen, (200, 200, 200), rect)# 填充浅灰色
        pygame.draw.rect(screen, BLACK, rect, 2)# 绘制黑色边框


    # 绘制按钮文字
    mode_text = "AI Mode" if game_mode == "ai" else "PVP Mode"
    first_text = "AI First" if ai_first else "Human First"
    start_text = font.render("start", True, BLACK)
    revoke_text = font.render("revoke", True, BLACK)
    mode_text = font.render(mode_text, True, BLACK)
    first_text = font.render(first_text, True, BLACK)

    # 定位文字(参数:文字对象,坐标)
    screen.blit(start_text, (buttons["start"].x + 10, buttons["start"].y + 5))
    screen.blit(revoke_text, (buttons["revoke"].x + 20, buttons["revoke"].y + 5))
    screen.blit(mode_text, (buttons["mode"].x + 10, buttons["mode"].y + 5))
    screen.blit(first_text, (buttons["first"].x + 10, buttons["first"].y + 5))


#将鼠标点击位置转换为棋盘坐标
def get_click_pos(pos):
    x, y = pos
    # 检查是否在棋盘区域内
    if MARGIN <= x < WIDTH - MARGIN and MARGIN <= y < HEIGHT - MARGIN:
        i = round((x - MARGIN) / GRID_SIZE) + 1# 列坐标
        j = round((y - MARGIN) / GRID_SIZE) + 1# 行坐标
        return (i, j)
    return None

    # --------------------- 胜负判断 ---------------------
def check_win(x, y):
    """检查是否五子连珠"""
    directions = [(0, 1), (1, 0), (1, 1), (1, -1)]  # 四个检查方向:右、下、右下、右上
    for dx, dy in directions:
        count = 1  # 当前位置已有一个棋子

        # 正向检查
        for step in range(1, 5):
            nx = x + dx * step
            ny = y + dy * step
            if 1 <= nx <= BOARD_SIZE and 1 <= ny <= BOARD_SIZE and board[nx][ny] == board[x][y]:
                count += 1
            else:
                break

        # 反向检查
        for step in range(1, 5):
            nx = x - dx * step
            ny = y - dy * step
            if 1 <= nx <= BOARD_SIZE and 1 <= ny <= BOARD_SIZE and board[nx][ny] == board[x][y]:
                count += 1
            else:
                break

        if count >= 5:
            return True
    return False

#人机落子
def ai_move():
    #纯随机
    empty = [(i,j) for i in range(1, BOARD_SIZE+1)
            for j in range(1, BOARD_SIZE+1) if board[i][j] == 0]
    if empty:
        return random.choice(empty)
    return None


# 执行落子
def make_move(x, y):
    global winner,game_active,current_player
    if board[x][y] == 0:
        board[x][y] = current_player
        history.append((x, y, current_player))
        if check_win(x, y):
            winner = current_player
            game_active = False
        current_player *= -1



#重置游戏
def reset_game():
    global board, history, current_player, winner, game_active
    board = [[0]*(BOARD_SIZE+2) for _ in range(BOARD_SIZE+2)]  # 清空棋盘
    history = []       # 清空历史
    current_player = 1 # 重置先手
    winner = None      # 清除胜利者
    game_active = True # 激活游戏
    # 如果是AI先手模式,AI先落子
    if game_mode == "ai" and ai_first:
        ai_pos = ai_move()
        if ai_pos:
            make_move(ai_pos[0], ai_pos[1])

#悔棋
def revoke_move():
    global history, current_player, winner
    if history:
        x, y, player = history.pop()  # 取出最后一步
        board[x][y] = 0  # 清空棋子
        current_player = player  # 恢复当前玩家
        winner = None  # 清除胜利状态




def handle_click(pos):
    global game_mode, ai_first,ai_turn,ai_move_time
    # 先检查按钮点击
    for name, rect in buttons.items():
        if rect.collidepoint(pos):  # 如果点击在按钮区域内
            if name == "start":
                reset_game()  # 重置游戏
            elif name == "revoke":
                revoke_move()  # 悔棋
            elif name == "mode":
                game_mode = "ai" if game_mode == "human" else "human"
            elif name == "first":
                ai_first = not ai_first

            return  # 处理完按钮点击后直接返回

    # 处理棋盘点击
    if not game_active:
        return

    pos = get_click_pos(pos)  # 转换为棋盘坐标
    if pos and board[pos[0]][pos[1]] == 0:  # 有效落子位置
        make_move(pos[0], pos[1])
        # 如果是人机模式且游戏未结束,AI响应
        if game_mode == "ai" and not winner:
            ai_turn = True  # 标记AI需要落子
            ai_move_time = pygame.time.get_ticks() + AI_DELAY  # 记录延迟时间



def run():
    while True:
        global ai_turn,ai_move_time

        current_time = pygame.time.get_ticks()  # 获取当前时间

        # 处理AI落子延迟
        if ai_turn and current_time >= ai_move_time:
            ai_pos = ai_move()
            if ai_pos:
                make_move(ai_pos[0], ai_pos[1])
            ai_turn = False  # 重置AI标志

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:  # 鼠标点击事件
                handle_click(event.pos)


        draw_board()
        draw_buttons()

        # 显示胜利信息
        if winner:
            text = "The white win!" if winner == 1 else "The black win!"
            status = font.render(text, True, (255, 0, 0))
            screen.blit(status, (WIDTH // 2 - 60, HEIGHT - 200))

        pygame.display.flip()
        clock.tick(30)


run()













5.人机功能优化

上述的ai_move()就是简单的随机下。

下面进行优化。

人工智障代码如下:


#======================ai======================================
def ai_move():
    """智能AI落子:增强防守意识"""
    best_score = -float('inf')
    best_move = None
    center = BOARD_SIZE // 2 + 1

    # 1. 优先检查能否立即获胜
    for x in range(1, BOARD_SIZE + 1):
        for y in range(1, BOARD_SIZE + 1):
            if board[x][y] == 0:
                board[x][y] = -1
                if check_win(x, y):
                    board[x][y] = 0
                    return (x, y)
                board[x][y] = 0

    # 2. 增强防守:检查玩家即将形成的威胁
    threat_level, threat_pos = analyze_threats()
    if threat_level >= 3:  # 当玩家形成活三或更高威胁时立即拦截
        return threat_pos

    # 3. 评估所有空位(同时考虑攻防)
    for x in range(1, BOARD_SIZE + 1):
        for y in range(1, BOARD_SIZE + 1):
            if board[x][y] == 0:
                # 计算进攻得分
                attack_score = calculate_position_score(x, y, -1)

                # 计算防守得分(玩家在此落子的威胁)
                board[x][y] = 1  # 模拟玩家落子
                defend_score = calculate_position_score(x, y, 1) * 1.2  # 防守权重稍高
                board[x][y] = 0

                # 综合得分(防守优先)
                total_score = attack_score + defend_score

                # 更新最佳落子
                if total_score > best_score:
                    best_score = total_score
                    best_move = (x, y)

    # 4. 随机选择保底
    return best_move if best_move else random.choice(
        [(i, j) for i in range(1, BOARD_SIZE + 1) for j in range(1, BOARD_SIZE + 1) if board[i][j] == 0]
    )


def find_best_defense():
    """寻找最佳防守位置(拦截玩家的活三/冲四等威胁)"""
    best_defense = None
    max_defense_score = -1

    # 遍历所有空位
    for x in range(1, BOARD_SIZE + 1):
        for y in range(1, BOARD_SIZE + 1):
            if board[x][y] == 0:
                # 计算此位置的防守价值
                defense_score = evaluate_defense(x, y)

                # 更新最佳防守位置
                if defense_score > max_defense_score:
                    max_defense_score = defense_score
                    best_defense = (x, y)

    return best_defense


def evaluate_defense(x, y):
    """评估某个位置的防守价值"""
    score = 0

    # 模拟玩家在此落子
    board[x][y] = 1
    directions = [(0, 1), (1, 0), (1, 1), (1, -1)]

    for dx, dy in directions:
        pattern = get_pattern(x, y, dx, dy, 1)

        # 根据威胁等级评分
        if pattern == "冲四":
            score += 1500  # 最高优先级拦截
        elif pattern == "活四":
            score += 1200
        elif pattern == "活三":
            score += 800
        elif pattern == "眠三":
            score += 400

    board[x][y] = 0  # 恢复

    # 考虑自身反击能力
    board[x][y] = -1
    attack_score = calculate_position_score(x, y, -1)
    board[x][y] = 0

    return score + attack_score * 0.6  # 防守优先




def analyze_threats():
    """分析玩家威胁等级"""
    max_threat = 0

    for x in range(1, BOARD_SIZE + 1):
        for y in range(1, BOARD_SIZE + 1):
            if board[x][y] == 0:
                # 模拟玩家落子
                board[x][y] = 1

                # 检查四个方向
                directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
                for dx, dy in directions:
                    pattern = get_pattern(x, y, dx, dy, 1)

                    # 立即拦截最高优先级威胁
                    if pattern in ["活四", "冲四"]:
                        board[x][y] = 0
                        return (4, (x, y))  # 最高优先级拦截

                    # 记录次级威胁
                    if pattern == "活三":
                        max_threat = max(max_threat, 3)
                    elif pattern == "眠三":
                        max_threat = max(max_threat, 2)

                board[x][y] = 0

    # 返回最高威胁位置
    if max_threat >= 3:
        return (max_threat, find_best_defense())
    return (0, None)


def get_pattern(x, y, dx, dy, player):
    """识别棋型模式"""
    count = 1
    empty_sides = 0
    blocked_sides = 0

    # 正向检查
    for step in range(1, 5):
        nx = x + dx * step
        ny = y + dy * step
        if 1 <= nx <= BOARD_SIZE and 1 <= ny <= BOARD_SIZE:
            if board[nx][ny] == player:
                count += 1
            elif board[nx][ny] == 0:
                empty_sides += 1
                break
            else:
                blocked_sides += 1
                break
        else:
            blocked_sides += 1
            break

    # 反向检查
    for step in range(1, 5):
        nx = x - dx * step
        ny = y - dy * step
        if 1 <= nx <= BOARD_SIZE and 1 <= ny <= BOARD_SIZE:
            if board[nx][ny] == player:
                count += 1
            elif board[nx][ny] == 0:
                empty_sides += 1
                break
            else:
                blocked_sides += 1
                break
        else:
            blocked_sides += 1
            break

    # 模式识别(增强防守判断)
    if count >= 5:
        return "连五"
    elif count == 4:
        # 冲四:有一端被堵且另一端开放
        if blocked_sides == 1 and empty_sides == 1:
            return "冲四"
        # 活四:两端都开放
        elif empty_sides == 2:
            return "活四"
    elif count == 3:
        # 眠三:有一端被堵
        if blocked_sides >= 1:
            return "眠三"
        return "活三"
    return "单棋"


def calculate_position_score(x, y, player):
    """计算位置综合得分"""
    score = 0
    center = BOARD_SIZE // 2 + 1

    # 基础分:距离中心越近越好
    distance = max(abs(x - center), abs(y - center))
    score += (center - distance) * 2

    # 方向评估
    directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
    for dx, dy in directions:
        pattern = get_pattern(x, y, dx, dy, player)

        # 进攻得分表
        if player == -1:  # AI棋子
            if pattern == "活四":
                score += 10000
            elif pattern == "冲四":
                score += 800
            elif pattern == "活三":
                score += 600
            elif pattern == "眠三":
                score += 300
        else:  # 玩家棋子(防守视角)
            if pattern == "活四":
                score += 15000  # 最高优先级拦截
            elif pattern == "冲四":
                score += 1200
            elif pattern == "活三":
                score += 1000
            elif pattern == "眠三":
                score += 500

    return score


#=============================================================================



6.完整代码

import pygame
import sys
import random
import time

# 初始化 Pygame
pygame.init()

# =======================游戏常量======================================
BOARD_SIZE = 13  # 棋盘是13格x13格
GRID_SIZE = 40   #每个格子的像素大小(40x40像素)
MARGIN = 50     #棋盘边缘留白

# 界面尺寸计算
WIDTH = HEIGHT = BOARD_SIZE * GRID_SIZE + 2 * MARGIN#整个棋盘的尺寸是格数x格大小+2倍留白
BUTTON_AREA = 100   # 底部按钮区域高度
SCREEN_SIZE = (WIDTH+150, HEIGHT + BUTTON_AREA+80) # 窗口总尺寸

WHITE = (255, 255, 255)#白色
BLACK = (0, 0, 0)#黑色
BACKGROUND = (238, 154, 73)#背景色
LINE_COLOR = (0, 0, 0)#线条色

screen = pygame.display.set_mode(SCREEN_SIZE) # 创建指定尺寸的窗口
pygame.display.set_caption("五子棋")  # 设置窗口标题
clock = pygame.time.Clock()     # 创建时钟对象(控制帧率)
font = pygame.font.Font(None, 36)# 创建字体对象(默认字体,36号)

board = [[0] * (BOARD_SIZE + 2) for _ in range(BOARD_SIZE + 2)]  # 棋盘数据
history = []       # 落子历史记录(用于悔棋)
current_player = 1 # 当前玩家(1: 白棋,-1: 黑棋)
game_mode = "human" # 游戏模式("human"=人人对战,"ai"=人机对战)
ai_first = False    # AI是否先手
game_active = False # 游戏是否进行中
winner = None       # 胜利者(1/-1)

# 按钮位置和尺寸(pygame.Rect参数:x, y, width, height)
buttons = {
            "start": pygame.Rect(WIDTH//2-150, HEIGHT+20, 120, 60),   # 开始按钮
            "revoke": pygame.Rect(WIDTH//2+80, HEIGHT+20, 120, 60),    # 悔棋按钮
            "mode": pygame.Rect(WIDTH//2-150, HEIGHT+100, 180, 40),   # 模式切换按钮
            "first": pygame.Rect(WIDTH//2+80, HEIGHT+100, 180, 40)    # 先手选择按钮
            }


ai_turn = False       # AI是否该落子
ai_move_time = 0      # AI落子的时间戳
AI_DELAY = 1000      # AI思考时间(毫秒)





# ----------绘制棋盘 ------------
def draw_board():
    screen.fill(BACKGROUND)# 填充背景色
    for i in range(BOARD_SIZE + 1):
        start = MARGIN
        end = WIDTH - MARGIN
        # 横线
        pygame.draw.line(screen, LINE_COLOR,
                         (MARGIN, MARGIN + i * GRID_SIZE),
                         (WIDTH - MARGIN, MARGIN + i * GRID_SIZE), 2)
        # 竖线
        pygame.draw.line(screen, LINE_COLOR,
                         (MARGIN + i * GRID_SIZE, MARGIN),
                         (MARGIN + i * GRID_SIZE, HEIGHT - MARGIN), 2)

        # 绘制棋子
    for i in range(1, BOARD_SIZE + 1):
        for j in range(1, BOARD_SIZE + 1):
            if board[i][j] == 1:
                pygame.draw.circle(screen, WHITE,
                                   (MARGIN + (i - 1) * GRID_SIZE, MARGIN + (j - 1) * GRID_SIZE),
                                   GRID_SIZE // 2 - 2)
            elif board[i][j] == -1:
                pygame.draw.circle(screen, BLACK,
                                   (MARGIN + (i - 1) * GRID_SIZE, MARGIN + (j - 1) * GRID_SIZE),
                                   GRID_SIZE // 2 - 2)


# 绘制所有按钮
def draw_buttons():
    # 绘制所有按钮
    for name, rect in buttons.items():
        pygame.draw.rect(screen, (200, 200, 200), rect)# 填充浅灰色
        pygame.draw.rect(screen, BLACK, rect, 2)# 绘制黑色边框


    # 绘制按钮文字
    mode_text = "AI Mode" if game_mode == "ai" else "PVP Mode"
    first_text = "AI First" if ai_first else "Human First"
    start_text = font.render("start", True, BLACK)
    revoke_text = font.render("revoke", True, BLACK)
    mode_text = font.render(mode_text, True, BLACK)
    first_text = font.render(first_text, True, BLACK)

    # 定位文字(参数:文字对象,坐标)
    screen.blit(start_text, (buttons["start"].x + 10, buttons["start"].y + 5))
    screen.blit(revoke_text, (buttons["revoke"].x + 20, buttons["revoke"].y + 5))
    screen.blit(mode_text, (buttons["mode"].x + 10, buttons["mode"].y + 5))
    screen.blit(first_text, (buttons["first"].x + 10, buttons["first"].y + 5))


#将鼠标点击位置转换为棋盘坐标
def get_click_pos(pos):
    x, y = pos
    # 检查是否在棋盘区域内
    if MARGIN <= x < WIDTH - MARGIN and MARGIN <= y < HEIGHT - MARGIN:
        i = round((x - MARGIN) / GRID_SIZE) + 1# 列坐标
        j = round((y - MARGIN) / GRID_SIZE) + 1# 行坐标
        return (i, j)
    return None

    # --------------------- 胜负判断 ---------------------
def check_win(x, y):
    """检查是否五子连珠"""
    directions = [(0, 1), (1, 0), (1, 1), (1, -1)]  # 四个检查方向:右、下、右下、右上
    for dx, dy in directions:
        count = 1  # 当前位置已有一个棋子

        # 正向检查
        for step in range(1, 5):
            nx = x + dx * step
            ny = y + dy * step
            if 1 <= nx <= BOARD_SIZE and 1 <= ny <= BOARD_SIZE and board[nx][ny] == board[x][y]:
                count += 1
            else:
                break

        # 反向检查
        for step in range(1, 5):
            nx = x - dx * step
            ny = y - dy * step
            if 1 <= nx <= BOARD_SIZE and 1 <= ny <= BOARD_SIZE and board[nx][ny] == board[x][y]:
                count += 1
            else:
                break

        if count >= 5:
            return True
    return False



#======================ai======================================
def ai_move():
    """智能AI落子:增强防守意识"""
    best_score = -float('inf')
    best_move = None
    center = BOARD_SIZE // 2 + 1

    # 1. 优先检查能否立即获胜
    for x in range(1, BOARD_SIZE + 1):
        for y in range(1, BOARD_SIZE + 1):
            if board[x][y] == 0:
                board[x][y] = -1
                if check_win(x, y):
                    board[x][y] = 0
                    return (x, y)
                board[x][y] = 0

    # 2. 增强防守:检查玩家即将形成的威胁
    threat_level, threat_pos = analyze_threats()
    if threat_level >= 3:  # 当玩家形成活三或更高威胁时立即拦截
        return threat_pos

    # 3. 评估所有空位(同时考虑攻防)
    for x in range(1, BOARD_SIZE + 1):
        for y in range(1, BOARD_SIZE + 1):
            if board[x][y] == 0:
                # 计算进攻得分
                attack_score = calculate_position_score(x, y, -1)

                # 计算防守得分(玩家在此落子的威胁)
                board[x][y] = 1  # 模拟玩家落子
                defend_score = calculate_position_score(x, y, 1) * 1.2  # 防守权重稍高
                board[x][y] = 0

                # 综合得分(防守优先)
                total_score = attack_score + defend_score

                # 更新最佳落子
                if total_score > best_score:
                    best_score = total_score
                    best_move = (x, y)

    # 4. 随机选择保底
    return best_move if best_move else random.choice(
        [(i, j) for i in range(1, BOARD_SIZE + 1) for j in range(1, BOARD_SIZE + 1) if board[i][j] == 0]
    )


def find_best_defense():
    """寻找最佳防守位置(拦截玩家的活三/冲四等威胁)"""
    best_defense = None
    max_defense_score = -1

    # 遍历所有空位
    for x in range(1, BOARD_SIZE + 1):
        for y in range(1, BOARD_SIZE + 1):
            if board[x][y] == 0:
                # 计算此位置的防守价值
                defense_score = evaluate_defense(x, y)

                # 更新最佳防守位置
                if defense_score > max_defense_score:
                    max_defense_score = defense_score
                    best_defense = (x, y)

    return best_defense


def evaluate_defense(x, y):
    """评估某个位置的防守价值"""
    score = 0

    # 模拟玩家在此落子
    board[x][y] = 1
    directions = [(0, 1), (1, 0), (1, 1), (1, -1)]

    for dx, dy in directions:
        pattern = get_pattern(x, y, dx, dy, 1)

        # 根据威胁等级评分
        if pattern == "冲四":
            score += 1500  # 最高优先级拦截
        elif pattern == "活四":
            score += 1200
        elif pattern == "活三":
            score += 800
        elif pattern == "眠三":
            score += 400

    board[x][y] = 0  # 恢复

    # 考虑自身反击能力
    board[x][y] = -1
    attack_score = calculate_position_score(x, y, -1)
    board[x][y] = 0

    return score + attack_score * 0.6  # 防守优先




def analyze_threats():
    """分析玩家威胁等级"""
    max_threat = 0

    for x in range(1, BOARD_SIZE + 1):
        for y in range(1, BOARD_SIZE + 1):
            if board[x][y] == 0:
                # 模拟玩家落子
                board[x][y] = 1

                # 检查四个方向
                directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
                for dx, dy in directions:
                    pattern = get_pattern(x, y, dx, dy, 1)

                    # 立即拦截最高优先级威胁
                    if pattern in ["活四", "冲四"]:
                        board[x][y] = 0
                        return (4, (x, y))  # 最高优先级拦截

                    # 记录次级威胁
                    if pattern == "活三":
                        max_threat = max(max_threat, 3)
                    elif pattern == "眠三":
                        max_threat = max(max_threat, 2)

                board[x][y] = 0

    # 返回最高威胁位置
    if max_threat >= 3:
        return (max_threat, find_best_defense())
    return (0, None)


def get_pattern(x, y, dx, dy, player):
    """识别棋型模式"""
    count = 1
    empty_sides = 0
    blocked_sides = 0

    # 正向检查
    for step in range(1, 5):
        nx = x + dx * step
        ny = y + dy * step
        if 1 <= nx <= BOARD_SIZE and 1 <= ny <= BOARD_SIZE:
            if board[nx][ny] == player:
                count += 1
            elif board[nx][ny] == 0:
                empty_sides += 1
                break
            else:
                blocked_sides += 1
                break
        else:
            blocked_sides += 1
            break

    # 反向检查
    for step in range(1, 5):
        nx = x - dx * step
        ny = y - dy * step
        if 1 <= nx <= BOARD_SIZE and 1 <= ny <= BOARD_SIZE:
            if board[nx][ny] == player:
                count += 1
            elif board[nx][ny] == 0:
                empty_sides += 1
                break
            else:
                blocked_sides += 1
                break
        else:
            blocked_sides += 1
            break

    # 模式识别(增强防守判断)
    if count >= 5:
        return "连五"
    elif count == 4:
        # 冲四:有一端被堵且另一端开放
        if blocked_sides == 1 and empty_sides == 1:
            return "冲四"
        # 活四:两端都开放
        elif empty_sides == 2:
            return "活四"
    elif count == 3:
        # 眠三:有一端被堵
        if blocked_sides >= 1:
            return "眠三"
        return "活三"
    return "单棋"


def calculate_position_score(x, y, player):
    """计算位置综合得分"""
    score = 0
    center = BOARD_SIZE // 2 + 1

    # 基础分:距离中心越近越好
    distance = max(abs(x - center), abs(y - center))
    score += (center - distance) * 2

    # 方向评估
    directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
    for dx, dy in directions:
        pattern = get_pattern(x, y, dx, dy, player)

        # 进攻得分表
        if player == -1:  # AI棋子
            if pattern == "活四":
                score += 10000
            elif pattern == "冲四":
                score += 800
            elif pattern == "活三":
                score += 600
            elif pattern == "眠三":
                score += 300
        else:  # 玩家棋子(防守视角)
            if pattern == "活四":
                score += 15000  # 最高优先级拦截
            elif pattern == "冲四":
                score += 1200
            elif pattern == "活三":
                score += 1000
            elif pattern == "眠三":
                score += 500

    return score


#=============================================================================



# 执行落子
def make_move(x, y):
    global winner,game_active,current_player
    if board[x][y] == 0:
        board[x][y] = current_player
        history.append((x, y, current_player))
        if check_win(x, y):
            winner = current_player
            game_active = False
        current_player *= -1



#重置游戏
def reset_game():
    global board, history, current_player, winner, game_active
    board = [[0]*(BOARD_SIZE+2) for _ in range(BOARD_SIZE+2)]  # 清空棋盘
    history = []       # 清空历史
    current_player = 1 # 重置先手
    winner = None      # 清除胜利者
    game_active = True # 激活游戏
    # 如果是AI先手模式,AI先落子
    if game_mode == "ai" and ai_first:
        ai_pos = ai_move()
        if ai_pos:
            make_move(ai_pos[0], ai_pos[1])

#悔棋
def revoke_move():
    global history, current_player, winner
    if history:
        x, y, player = history.pop()  # 取出最后一步
        board[x][y] = 0  # 清空棋子
        current_player = player  # 恢复当前玩家
        winner = None  # 清除胜利状态




def handle_click(pos):
    global game_mode, ai_first,ai_turn,ai_move_time
    # 先检查按钮点击
    for name, rect in buttons.items():
        if rect.collidepoint(pos):  # 如果点击在按钮区域内
            if name == "start":
                reset_game()  # 重置游戏
            elif name == "revoke":
                revoke_move()  # 悔棋
            elif name == "mode":
                game_mode = "ai" if game_mode == "human" else "human"
            elif name == "first":
                ai_first = not ai_first

            return  # 处理完按钮点击后直接返回

    # 处理棋盘点击
    if not game_active:
        return

    pos = get_click_pos(pos)  # 转换为棋盘坐标
    if pos and board[pos[0]][pos[1]] == 0:  # 有效落子位置
        make_move(pos[0], pos[1])
        # 如果是人机模式且游戏未结束,AI响应
        if game_mode == "ai" and not winner:
            ai_turn = True  # 标记AI需要落子
            ai_move_time = pygame.time.get_ticks() + AI_DELAY  # 记录延迟时间



def run():
    while True:
        global ai_turn,ai_move_time

        current_time = pygame.time.get_ticks()  # 获取当前时间

        # 处理AI落子延迟
        if ai_turn and current_time >= ai_move_time:
            ai_pos = ai_move()
            if ai_pos:
                make_move(ai_pos[0], ai_pos[1])
            ai_turn = False  # 重置AI标志

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:  # 鼠标点击事件
                handle_click(event.pos)


        draw_board()
        draw_buttons()

        # 显示胜利信息
        if winner:
            text = "The white win!" if winner == 1 else "The black win!"
            status = font.render(text, True, (255, 0, 0))
            screen.blit(status, (WIDTH // 2 - 60, HEIGHT - 200))

        pygame.display.flip()
        clock.tick(30)


run()













Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐