项目概述
本文通过 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→ 退出游戏。
绘制层次与界面布局
绘制顺序(由底至上):
- 深色背景填充
- 标题与按钮(位于顶部)
- 棋盘外框与格线
- 合法走法提示(半透明圆点)
- 所有棋子(含阴影、主体、高光)
- 翻转动画棋子(覆盖在静态棋子之上)
- 最后落子标记(金色圆点)
- 计分板(左右两侧显示黑白子数)
- 当前回合文字提示
- 跳过提示信息
- 游戏结束遮罩弹窗(半透明,含胜者与比分)
计分板设计
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黑白棋对弈游戏的资料请关注代码网其它相关文章!
发表评论