当前位置: 代码网 > it编程>前端脚本>Python > Python通过Pygame实现一款黑白棋(翻转棋)对弈游戏

Python通过Pygame实现一款黑白棋(翻转棋)对弈游戏

2026年08月24日 Python 我要评论
项目概述本文通过 pygame 实现一款黑白棋(翻转棋)对弈游戏,支持双人对战和人机对战两种模式。游戏在 8×8 标准棋盘上进行,采用经典翻转规则:玩家点击合法交叉点落子,夹住对方棋子即可

项目概述

本文通过 pygame 实现一款黑白棋(翻转棋)对弈游戏,支持双人对战和人机对战两种模式。

游戏在 8×8 标准棋盘上进行,采用经典翻转规则:玩家点击合法交叉点落子,夹住对方棋子即可将其翻转为己方颜色,最终棋子多者获胜。ai 基于 minimax 搜索 + alpha-beta 剪枝(深度 4),结合位置权重与行动力评估,具备一定棋力。核心特性包括:

  • 双模式切换:支持双人对战与人机对战,按 a 键一键切换,重置棋局即时生效。
  • ai 对手:ai 执白(亦可配置),采用带 alpha-beta 剪枝的 minimax 搜索,评估函数融合位置权重表与行动力,深度 4 保证响应迅速且具有一定智能。
  • 合法走法提示:当前玩家可落子的位置以半透明绿色圆点标示,方便新手快速掌握可下位置。
  • 翻转动画:落子后,被翻转的棋子会播放缩放动画,视觉反馈流畅,增强操作手感。
  • 最后落子标记:每一步最后落子的位置以金色圆点高亮,便于回溯棋局进程。
  • 计分与状态栏:实时显示黑子与白子数量,标明当前轮到谁,无子可跳时给出文字提示。
  • 键盘操作:r 重置棋局、a 切换模式、esc 退出;点击任意处亦可在结束后重开。

游戏实现

初始化与基础设置

游戏启动时初始化 pygame,定义棋盘参数、窗口尺寸及布局常量。

w, h = 560, 700
cell = 64
board_x, board_y = 24, 80
size = 8
fps = 60
  • cell = 64:每格边长 64px,8×8 棋盘总宽 512px,窗口宽度 560px 留出两侧边距。
  • board_x = 24, board_y = 80:棋盘左上角坐标,上方 80px 区域留给标题、按钮与状态栏。
  • 窗口高度 700px 为棋盘下方留出计分板与操作提示区域。

颜色定义

c_bg       = (20,  30,  20)   # 深绿色背景
c_board    = (30, 110,  50)   # 棋盘格主色
c_board_d  = (25,  90,  40)   # 棋盘格间隔色
c_line     = (20,  80,  35)   # 网格线
c_black    = (20,  20,  20)   # 黑子
c_white    = (245, 245, 245)  # 白子
c_hint     = (100, 200, 100, 80) # 提示点半透明绿
c_last     = (255, 230,  60)  # 最后落子金色
c_text     = (220, 255, 220)  # 字体
c_win      = (255, 215,  50)  # 胜利/强调色

整体采用自然绿调,模拟木质或草编棋盘质感。棋盘格深浅交替形成视觉区分,棋子黑白对比鲜明,金色标记凸显关键信息。

字体加载

chinese_font_path = r"c:/windows/fonts/simsun.ttc"
try:
    font_tl = pygame.font.font(chinese_font_path, 28)
    ...
except:
    font_tl = pygame.font.sysfont("microsoftyahei", 28, bold=true)

优先使用宋体,若系统无则回退微软雅黑,保证中文字符正常显示。

棋盘与棋子数据结构

棋盘用二维列表 board[8][8] 表示,其中:

  • 0:空位
  • 1:黑子(玩家通常执黑)
  • 2:白子(ai 执白)

初始布局为经典四子交叉:

def init_board():
    b = [[0]*8 for _ in range(8)]
    b[3][3]=b[4][4]=2  # 白
    b[3][4]=b[4][3]=1  # 黑
    return b

核心游戏逻辑

翻转判定(get_flips)

黑白棋的精髓在于“夹住并翻转”。对于给定位置 (r,c) 和当前玩家 player,检查八个方向:

def get_flips(board, r, c, player):
    if board[r][c] != 0: return []
    opp = 3 - player
    all_flips = []
    for dr, dc in dirs:
        flips = []
        nr, nc = r+dr, c+dc
        while in_bounds(nr,nc) and board[nr][nc]==opp:
            flips.append((nr,nc))
            nr += dr; nc += dc
        if flips and in_bounds(nr,nc) and board[nr][nc]==player:
            all_flips.extend(flips)
    return all_flips
  • 沿某方向遍历,遇到对手棋子则暂存,直到遇到己方棋子或棋盘边界。
  • 若终止于己方棋子且中间有至少一个对手棋子,则这些对手棋子均可被翻转。
  • 返回所有可翻转位置的列表,空列表表示该位置不合法。

合法走法生成

def valid_moves(board, player):
    return [(r,c) for r in range(8) for c in range(8)
            if get_flips(board,r,c,player)]

遍历所有空格,调用 get_flips 过滤出有翻转可能的位置。

落子与翻转

def apply_move(board, r, c, player):
    flips = get_flips(board, r, c, player)
    if not flips: return board, []
    nb = copy.deepcopy(board)
    nb[r][c] = player
    for fr, fc in flips:
        nb[fr][fc] = player
    return nb, flips

深拷贝棋盘,将新子与所有被翻转的棋子改为当前玩家颜色,并返回新棋盘和翻转列表(用于动画)。

胜负判定与计分

游戏结束条件:双方均无合法走法(通常发生在棋盘填满或任何一方无子可下)。计分函数统计黑白棋子数量:

def count(board):
    b = sum(board[r][c]==1 for r in range(8) for c in range(8))
    w = sum(board[r][c]==2 for r in range(8) for c in range(8))
    return b, w

最终棋子多者获胜,平局则显示“平局!”。

ai 评估系统

位置权重表

weights = [
    [100,-20,10, 5, 5,10,-20,100],
    [-20,-50,-2,-2,-2,-2,-50,-20],
    [ 10, -2, 5, 1, 1, 5, -2, 10],
    [  5, -2, 1, 0, 0, 1, -2,  5],
    [  5, -2, 1, 0, 0, 1, -2,  5],
    [ 10, -2, 5, 1, 1, 5, -2, 10],
    [-20,-50,-2,-2,-2,-2,-50,-20],
    [100,-20,10, 5, 5,10,-20,100],
]
  • 角落(100):占据角点意味着永不被翻转,价值极高。
  • 角边(-20 ~ -50):靠近角但非角的格子(如 (0,1))易被对手占角,视为负价值。
  • 中心(0 ~ 5):控制中心有助于获得更多行动力,给予小幅正分。

该表为经典黑白棋启发式,引导 ai 争角、避弱边。

评估函数

def evaluate(board, player):
    opp = 3-player
    score = 0
    # 位置权重
    for r in range(8):
        for c in range(8):
            if board[r][c]==player: score += weights[r][c]
            elif board[r][c]==opp:  score -= weights[r][c]
    # 行动力
    score += len(valid_moves(board, player))*5
    score -= len(valid_moves(board, opp))*5
    return score
  • 位置分:己方棋子加权总和减去对方棋子加权总和。
  • 行动力:当前玩家的合法走法数减对方走法数,乘以系数 5,鼓励 ai 获得更多选择空间,同时限制对手。

minimax + alpha-beta 剪枝

def minimax(board, depth, alpha, beta, player, max_player):
    moves = valid_moves(board, player)
    if depth==0 or not moves:
        return evaluate(board, max_player), none
    best_move = none
    if player==max_player:
        best = -math.inf
        for r,c in moves:
            nb,_ = apply_move(board,r,c,player)
            val,_ = minimax(nb, depth-1, alpha, beta, 3-player, max_player)
            if val>best: best=val; best_move=(r,c)
            alpha=max(alpha,best)
            if beta<=alpha: break
        return best, best_move
    else:
        best = math.inf
        for r,c in moves:
            nb,_ = apply_move(board,r,c,player)
            val,_ = minimax(nb, depth-1, alpha, beta, 3-player, max_player)
            if val<best: best=val; best_move=(r,c)
            beta=min(beta,best)
            if beta<=alpha: break
        return best, best_move
  • 深度固定为 4(可调整),在 8×8 棋盘上搜索节点数可控(平均分支约 10~15),配合剪枝响应迅速(<0.1 秒)。
  • max_player 为 ai 自身,在 ai 回合最大化分数,对手回合最小化分数。
  • 叶节点调用 evaluate 返回静态估值。

ai 走法接口:

def ai_move(board, ai_player, depth=4):
    _, move = minimax(board, depth, -math.inf, math.inf, ai_player, ai_player)
    return move

若返回 none(无合法走法),则跳过该回合。

绘制与动画

棋盘绘制

def draw_board(surf, board, hints, last_move, anim_flips, anim_t):
    # 棋盘外框
    br = pygame.rect(board_x-2, board_y-2, size*cell+4, size*cell+4)
    pygame.draw.rect(surf, (15,60,25), br, border_radius=6)
    # 棋盘格(深浅交替)
    for r in range(size):
        for c in range(size):
            rect = pygame.rect(board_x+c*cell, board_y+r*cell, cell, cell)
            col = c_board if (r+c)%2==0 else c_board_d
            pygame.draw.rect(surf, col, rect)
            pygame.draw.rect(surf, c_line, rect, 1)

棋盘格交替色增加层次,网格线清晰。

合法走法提示

hint_surf = pygame.surface((cell, cell), pygame.srcalpha)
pygame.draw.circle(hint_surf, (100,230,100,70), (cell//2, cell//2), cell//4)
for r,c in hints:
    surf.blit(hint_surf, (board_x+c*cell, board_y+r*cell))

半透明绿色圆点浮在可落子格上,柔和且不干扰棋子。

棋子立体渲染

# 阴影
pygame.draw.circle(surf, (0,0,0,80), (cx+2,cy+3), piece_r)
# 主体
pygame.draw.circle(surf, color, (cx,cy), piece_r)
# 高光
hl_col = (80,80,80) if v==1 else (255,255,255)
pygame.draw.circle(surf, hl_col, (cx-piece_r//3, cy-piece_r//3), piece_r//4)

与五子棋类似,采用阴影+主体+高光三层,提升立体感。

翻转动画

翻转动画是黑白棋的视觉亮点。当 anim_flips 非空时,动画计时器 anim_t 从 0 递增至 1:

if is_flipping:
    t = anim_t  # 0~1
    scale_x = abs(math.cos(t * math.pi))
    eff_r = max(2, int(piece_r * scale_x))
    # 颜色渐变(前半段旧色,后半段新色)
    if t < 0.5:
        color = c_black if v==1 else c_white
    else:
        color = c_white if v==1 else c_black
    pygame.draw.ellipse(surf, color,
        (cx-eff_r, cy-piece_r, eff_r*2, piece_r*2))
  • 横向压缩(scale_x 从 1 → 0 → 1)模拟翻转效果。
  • 颜色在中间时刻切换,实现“翻面”视觉。
  • 非翻转棋子正常绘制。

动画速度由 anim_t += 0.08 控制,约 12 帧完成,流畅自然。

最后落子标记

if last_move and (r,c)==last_move:
    pygame.draw.circle(surf, c_last, (cx,cy), 6)

金色圆点高亮最后一步,便于追踪。

交互与状态流转

主循环状态机

while true:
    # 事件处理
    for event in pygame.event.get():
        # 鼠标点击 → 尝试落子
        if valid and not game_over:
            r,c = 计算格点
            flips = get_flips(board, r, c, current)
            if flips:
                board, flips = apply_move(...)
                last_move = (r,c)
                anim_flips = flips
                anim_t = 0.0
                # 切换玩家,跳过无子可下的一方
                nxt = 3-current
                if valid_moves(board, nxt):
                    current = nxt
                elif valid_moves(board, current):
                    message = "对方无子可下,跳过"
                else:
                    game_over = true
                if vs_ai and current == ai_player and not game_over:
                    pending_ai = true

    # ai 延迟落子(待动画结束后执行)
    if pending_ai and anim_t >= 1.0 and not game_over:
        pending_ai = false
        move = ai_move(board, ai_player)
        if move:
            ...
        else:
            # ai 无子可下,跳过或结束
  • 玩家落子:仅在非 ai 回合或双人模式下响应点击。
  • ai 落子:通过 pending_ai 标志延迟到动画完成,避免阻塞绘制。
  • 跳过逻辑:若当前玩家无合法走法,自动切换对方;若双方均无走法,游戏结束。
  • 动画同步anim_t < 1.0 时禁止新的落子,保证动画完整播放。

按钮与键盘

  • r 键或点击“重新开始”按钮 → 重置棋盘。
  • a 键或点击“模式”按钮 → 在双人/ai 间切换,重置棋局。
  • esc → 退出游戏。

绘制层次与界面布局

绘制顺序(由底至上):

  1. 深色背景填充
  2. 标题与按钮(位于顶部)
  3. 棋盘外框与格线
  4. 合法走法提示(半透明圆点)
  5. 所有棋子(含阴影、主体、高光)
  6. 翻转动画棋子(覆盖在静态棋子之上)
  7. 最后落子标记(金色圆点)
  8. 计分板(左右两侧显示黑白子数)
  9. 当前回合文字提示
  10. 跳过提示信息
  11. 游戏结束遮罩弹窗(半透明,含胜者与比分)

计分板设计

y_ui = board_y + size*cell + 12
# 黑方区域(左)
pygame.draw.rect(screen, (30,30,30), (board_x, y_ui, 200, 70), border_radius=10)
# 白方区域(右)
pygame.draw.rect(screen, (230,230,230), (board_x+size*cell-200, y_ui, 200, 70), border_radius=10)

左右对称,背景色与棋子颜色对应,字体颜色自动反色,清晰显示双方子数。

游戏结束弹窗

if game_over:
    ov = pygame.surface((w,h), pygame.srcalpha)
    ov.fill((0,0,0,130))
    screen.blit(ov, (0,0))
    # 半透明深色遮罩,中央显示胜者、比分、重开提示
    ...

弹窗展示胜负结果、最终比分,并提示点击或按 r 重开,与五子棋风格一致。

全部代码

完整代码如下(与提供的代码一致,为便于阅读整理注释):

"""
黑白棋(othello/翻转棋)
模式:双人 或 vs ai(minimax + alpha-beta剪枝,深度4)
操作:鼠标点击落子
"""

import pygame
import sys
import copy
import math

pygame.init()

w, h = 560, 700
cell = 64
board_x, board_y = 24, 80
size = 8
fps = 60

c_bg       = (20,  30,  20)
c_board    = (30, 110,  50)
c_board_d  = (25,  90,  40)
c_line     = (20,  80,  35)
c_black    = (20,  20,  20)
c_white    = (245, 245, 245)
c_hint     = (100, 200, 100, 80)
c_last     = (255, 230,  60)
c_text     = (220, 255, 220)
c_btn      = (40,  90,  50)
c_btn_hl   = (60, 130,  70)
c_win      = (255, 215,  50)

# 中文字体
chinese_font_path = r"c:/windows/fonts/simsun.ttc"
try:
    font_tl = pygame.font.font(chinese_font_path, 28)
    font_md = pygame.font.font(chinese_font_path, 20)
    font_sm = pygame.font.font(chinese_font_path, 15)
    font_sc = pygame.font.font(chinese_font_path, 42)
except:
    font_tl = pygame.font.sysfont("microsoftyahei", 28, bold=true)
    font_md = pygame.font.sysfont("microsoftyahei", 20, bold=true)
    font_sm = pygame.font.sysfont("microsoftyahei", 15)
    font_sc = pygame.font.sysfont("microsoftyahei", 42, bold=true)

dirs = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]

# 位置权重表(角落最高)
weights = [
    [100,-20,10, 5, 5,10,-20,100],
    [-20,-50,-2,-2,-2,-2,-50,-20],
    [ 10, -2, 5, 1, 1, 5, -2, 10],
    [  5, -2, 1, 0, 0, 1, -2,  5],
    [  5, -2, 1, 0, 0, 1, -2,  5],
    [ 10, -2, 5, 1, 1, 5, -2, 10],
    [-20,-50,-2,-2,-2,-2,-50,-20],
    [100,-20,10, 5, 5,10,-20,100],
]

# ── 游戏逻辑 ─────────────────────────────────────────────────────────
def init_board():
    b = [[0]*8 for _ in range(8)]
    b[3][3]=b[4][4]=2  # 白
    b[3][4]=b[4][3]=1  # 黑
    return b

def in_bounds(r,c):
    return 0<=r<8 and 0<=c<8

def get_flips(board, r, c, player):
    if board[r][c] != 0: return []
    opp = 3 - player
    all_flips = []
    for dr,dc in dirs:
        flips = []
        nr, nc = r+dr, c+dc
        while in_bounds(nr,nc) and board[nr][nc]==opp:
            flips.append((nr,nc))
            nr+=dr; nc+=dc
        if flips and in_bounds(nr,nc) and board[nr][nc]==player:
            all_flips.extend(flips)
    return all_flips

def valid_moves(board, player):
    return [(r,c) for r in range(8) for c in range(8)
            if get_flips(board,r,c,player)]

def apply_move(board, r, c, player):
    flips = get_flips(board, r, c, player)
    if not flips: return board, []
    nb = copy.deepcopy(board)
    nb[r][c] = player
    for fr,fc in flips:
        nb[fr][fc] = player
    return nb, flips

def count(board):
    b = sum(board[r][c]==1 for r in range(8) for c in range(8))
    w = sum(board[r][c]==2 for r in range(8) for c in range(8))
    return b, w

def evaluate(board, player):
    opp = 3-player
    score = 0
    # 位置权重
    for r in range(8):
        for c in range(8):
            if board[r][c]==player: score += weights[r][c]
            elif board[r][c]==opp:  score -= weights[r][c]
    # 行动力
    score += len(valid_moves(board, player))*5
    score -= len(valid_moves(board, opp))*5
    return score

def minimax(board, depth, alpha, beta, player, max_player):
    moves = valid_moves(board, player)
    if depth==0 or not moves:
        return evaluate(board, max_player), none
    best_move = none
    if player==max_player:
        best = -math.inf
        for r,c in moves:
            nb,_ = apply_move(board,r,c,player)
            val,_ = minimax(nb, depth-1, alpha, beta, 3-player, max_player)
            if val>best: best=val; best_move=(r,c)
            alpha=max(alpha,best)
            if beta<=alpha: break
        return best, best_move
    else:
        best = math.inf
        for r,c in moves:
            nb,_ = apply_move(board,r,c,player)
            val,_ = minimax(nb, depth-1, alpha, beta, 3-player, max_player)
            if val<best: best=val; best_move=(r,c)
            beta=min(beta,best)
            if beta<=alpha: break
        return best, best_move

def ai_move(board, ai_player, depth=4):
    _, move = minimax(board, depth, -math.inf, math.inf, ai_player, ai_player)
    return move

# ── 绘制 ─────────────────────────────────────────────────────────────
def draw_board(surf, board, hints, last_move, anim_flips, anim_t):
    # 棋盘背景
    br = pygame.rect(board_x-2, board_y-2, size*cell+4, size*cell+4)
    pygame.draw.rect(surf, (15,60,25), br, border_radius=6)
    for r in range(size):
        for c in range(size):
            rect = pygame.rect(board_x+c*cell, board_y+r*cell, cell, cell)
            col = c_board if (r+c)%2==0 else c_board_d
            pygame.draw.rect(surf, col, rect)
            pygame.draw.rect(surf, c_line, rect, 1)

    # 提示点
    hint_surf = pygame.surface((cell, cell), pygame.srcalpha)
    pygame.draw.circle(hint_surf, (100,230,100,70), (cell//2, cell//2), cell//4)
    for r,c in hints:
        surf.blit(hint_surf, (board_x+c*cell, board_y+r*cell))

    # 棋子
    for r in range(size):
        for c in range(size):
            v = board[r][c]
            if v==0: continue
            cx = board_x + c*cell + cell//2
            cy = board_y + r*cell + cell//2
            piece_r = cell//2 - 5

            is_flipping = (r,c) in anim_flips
            color = (c_black if v==1 else c_white)

            if is_flipping:
                t = anim_t  # 0~1
                scale_x = abs(math.cos(t * math.pi))
                eff_r = max(2, int(piece_r * scale_x))
                # 动画中颜色渐变
                if t < 0.5:
                    color = c_black if v==1 else c_white
                else:
                    color = c_white if v==1 else c_black

            # 阴影
            pygame.draw.circle(surf, (0,0,0,80), (cx+2,cy+3), piece_r)
            # 棋子
            if is_flipping:
                pygame.draw.ellipse(surf, color,
                    (cx-eff_r, cy-piece_r, eff_r*2, piece_r*2))
            else:
                pygame.draw.circle(surf, color, (cx,cy), piece_r)
                # 高光
                hl_col = (80,80,80) if v==1 else (255,255,255)
                pygame.draw.circle(surf, hl_col, (cx-piece_r//3, cy-piece_r//3), piece_r//4)

            # 最后落子标记
            if last_move and (r,c)==last_move:
                pygame.draw.circle(surf, c_last, (cx,cy), 6)

    # 角落圆点(传统棋盘标记)
    for pr,pc in [(2,2),(2,6),(6,2),(6,6)]:
        pygame.draw.circle(surf, c_line,
            (board_x+pc*cell, board_y+pr*cell), 4)

def main():
    screen = pygame.display.set_mode((w, h))
    pygame.display.set_caption("黑白棋")
    clock = pygame.time.clock()

    vs_ai = true
    ai_player = 2  # ai执白
    board = init_board()
    current = 1   # 1=黑先
    last_move = none
    game_over = false
    anim_flips = []
    anim_t = 1.0
    message = ""
    pending_ai = false

    def reset():
        nonlocal board, current, last_move, game_over, anim_flips, anim_t, message, pending_ai
        board = init_board(); current = 1; last_move = none
        game_over = false; anim_flips = []; anim_t = 1.0; message = ""; pending_ai = false

    while true:
        mx, my = pygame.mouse.get_pos()

        for event in pygame.event.get():
            if event.type == pygame.quit:
                pygame.quit(); sys.exit()
            if event.type == pygame.keydown:
                if event.key == pygame.k_escape:
                    pygame.quit(); sys.exit()
                if event.key == pygame.k_r:
                    reset()
                if event.key == pygame.k_a:
                    vs_ai = not vs_ai
                    reset()

            if event.type == pygame.mousebuttondown and event.button==1:
                # 模式切换按钮
                ai_btn = pygame.rect(w-140, 8, 130, 34)
                rst_btn = pygame.rect(w-280, 8, 130, 34)
                if ai_btn.collidepoint(mx, my):
                    vs_ai = not vs_ai; reset(); continue
                if rst_btn.collidepoint(mx, my):
                    reset(); continue

                if game_over:
                    reset(); continue

                if not vs_ai or current != ai_player:
                    if anim_t >= 1.0:
                        gx = mx - board_x; gy = my - board_y
                        if 0<=gx<size*cell and 0<=gy<size*cell:
                            r, c = gy//cell, gx//cell
                            flips = get_flips(board, r, c, current)
                            if flips:
                                board, flips = apply_move(board, r, c, current)
                                last_move = (r,c)
                                anim_flips = flips
                                anim_t = 0.0
                                nxt = 3-current
                                if valid_moves(board, nxt):
                                    current = nxt
                                elif valid_moves(board, current):
                                    message = f"{'黑' if nxt==1 else '白'}方无子可落,跳过"
                                else:
                                    game_over = true
                                if vs_ai and current == ai_player and not game_over:
                                    pending_ai = true

        # ai行动
        if pending_ai and anim_t >= 1.0 and not game_over:
            pending_ai = false
            move = ai_move(board, ai_player)
            if move:
                r,c = move
                board, flips = apply_move(board, r, c, ai_player)
                last_move = (r,c)
                anim_flips = flips
                anim_t = 0.0
                nxt = 3-ai_player
                if valid_moves(board, nxt):
                    current = nxt
                elif valid_moves(board, ai_player):
                    message = "你方无子可落,ai继续"
                    pending_ai = true
                else:
                    game_over = true

        # 翻转动画
        if anim_t < 1.0:
            anim_t = min(1.0, anim_t + 0.08)
        elif anim_flips:
            anim_flips = []

        # ── 绘制 ──────────────────────────────────────────────────────
        screen.fill(c_bg)

        # 标题
        tl = font_tl.render("黑白棋 othello", true, c_text)
        screen.blit(tl, tl.get_rect(x=14, y=14))

        # 模式/重置按钮
        rst_btn = pygame.rect(w-280, 8, 130, 34)
        ai_btn  = pygame.rect(w-140, 8, 130, 34)
        pygame.draw.rect(screen, c_btn, rst_btn, border_radius=8)
        pygame.draw.rect(screen, c_btn_hl, ai_btn, border_radius=8)
        screen.blit(font_sm.render("r / 重新开始", true, c_text), rst_btn.move(8,8))
        mode_txt = f"模式:{'ai对战' if vs_ai else '双人'}"
        screen.blit(font_sm.render(mode_txt, true, c_text), ai_btn.move(8,8))

        hints = valid_moves(board, current) if not game_over else []
        draw_board(screen, board, hints, last_move, anim_flips if anim_t<1 else [], anim_t)

        # 计分
        bc, wc = count(board)
        y_ui = board_y + size*cell + 12
        bk_r = pygame.rect(board_x, y_ui, 200, 70)
        wh_r = pygame.rect(board_x + size * cell - 200, y_ui, 200, 70)
        for rect, col, label, cnt in [(bk_r, (30,30,30), "黑●", bc), (wh_r, (230,230,230), "白○", wc)]:
        
            pygame.draw.rect(screen, col, rect, border_radius=10)
            pygame.draw.rect(screen, col, rect.inflate(-4,-4), border_radius=8)
            txt_c = c_white if col[0]<100 else c_black
            t1 = font_md.render(label, true, txt_c)
            t2 = font_sc.render(str(cnt), true, txt_c)
            screen.blit(t1, t1.get_rect(centerx=rect.centerx, y=rect.y+4))
            screen.blit(t2, t2.get_rect(centerx=rect.centerx, y=rect.y+24))

        # 当前玩家
        if not game_over:
            who = "黑方" if current==1 else ("ai(白)" if vs_ai and current==ai_player else "白方")
            turn_t = font_md.render(f"轮到:{who}", true, c_win if not (vs_ai and current==ai_player) else (150,200,255))
            screen.blit(turn_t, turn_t.get_rect(centerx=w//2, y=y_ui+16))

        if message:
            mt = font_sm.render(message, true, c_win)
            screen.blit(mt, mt.get_rect(centerx=w//2, y=y_ui+42))

        # 游戏结束
        if game_over:
            ov = pygame.surface((w, h), pygame.srcalpha)
            ov.fill((0,0,0,130))
            screen.blit(ov, (0,0))
            box = pygame.rect(w//2-160, h//2-80, 320, 180)
            pygame.draw.rect(screen, (20,30,20), box, border_radius=16)
            pygame.draw.rect(screen, c_win, box, 3, border_radius=16)
            if bc > wc:
                winner = "黑方胜!" if not (vs_ai and ai_player==1) else "你赢了!"
            elif wc > bc:
                winner = "白方胜!" if not (vs_ai and ai_player==2) else "ai获胜"
            else:
                winner = "平局!"
            c_grey = (150,180,150)
            lines = [
                (font_tl, winner, c_win, -40),
                (font_md, f"黑 {bc} : {wc} 白", c_text, 10),
                (font_sm, "点击或按 r 重新开始", c_grey, 55),
            ]
            for font, text, color, dy in lines:
                t = font.render(text, true, color)
                screen.blit(t, t.get_rect(centerx=w//2, centery=h//2+dy))

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

if __name__ == "__main__":
    main()

总结

本文从零开始,详细拆解了基于 pygame 的黑白棋游戏实现。相较于五子棋,黑白棋的核心挑战在于翻转逻辑搜索算法动画反馈

  • 翻转逻辑通过双向扫描八方向实现,简单高效。
  • ai 评估结合位置权重与行动力,配合 minimax+剪枝,在深度 4 下达到可玩性。
  • 翻转动画利用缩放与颜色渐变,提升视觉体验。
  • 界面设计延续了五子棋的清晰布局,包括模式切换、计分板、提示点等,保持统一风格。

通过本项目的学习,读者可以掌握 pygame 中棋盘游戏开发的基本范式,以及如何将经典博弈算法(minimax)应用于实际游戏。

以上就是python通过pygame实现一款黑白棋(翻转棋)对弈游戏的详细内容,更多关于python pygame黑白棋对弈游戏的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com