基于Python的Tkinter五子棋游戏开发指南

南乔
南乔
发布时间:2026-10-12 | 3人浏览过
原创

本文详解使用Python内置tkinter与numpy模块构建本地双人五子棋的完整流程。内容覆盖600×600画布初始化、15×15标准棋盘绘制、鼠标点击坐标网格化映射、黑白交替落子逻辑,以及基于四方向连续计数的胜负判定算法。附带修正边界条件的可运行源码,适合Python初学者实践图形界面与基础游戏交互逻辑。

开发准备与核心设计思路

在五子棋的程序设计中,明确规则边界是编写代码的前提。本实现采用简化通用规则:对局双方各执一色,空棋盘开局,黑先白后交替落子。棋子一旦放置即固定位置,不可移动或撤销。本文暂不实现“PASS权”与黑方禁手(如三三、四四、长连),聚焦于底层UI渲染、坐标拾取与基础胜负逻辑的实现。

整体架构分为三个核心阶段:

  • 界面渲染层:利用 tkinter.Canvas 建立坐标系,通过循环绘制15条横线与15条竖线,并计算天元及星位的偏移量。
  • 交互控制层:捕获鼠标左键点击事件,将像素坐标转换为矩阵索引 (i, j),校验该交叉点是否已被占用,并根据全局计数器动态切换黑白两色。
  • 逻辑判定层:以落子点为原点,沿水平、垂直及两条对角线四个轴向进行双向扩散扫描。当累计同色棋子数达标时触发获胜弹窗。

第1步:创建主窗口与绘制标准棋盘

程序启动需实例化根窗口,并配置一个尺寸为 600×600 像素的画布作为游戏区域。棋盘由 15 行 15 列的直线交叉构成。为保证视觉居中,起点坐标预留 20 像素边距,网格间距设定为 40 像素。通过双重循环分别调用 w1.create_line() 绘制纵向与横向网格线,随后按数学公式计算出 5 个星位黑点的矩形框坐标,使用 w1.create_oval() 填充显示。

tkinter窗口初始化与基础画布加载效果
图1:Canvas画布初始化与背景加载示意
# 引入必要的绘图模块
from tkinter import *

root = Tk()                                  # 创建主窗口
root.title("Python五子棋游戏")              # 设置窗口标题
w1 = Canvas(root, width=600, height=600, background='lightcyan')
w1.pack()                                    # 启用默认布局管理

# 绘制15x15网格线(起始偏移20,间距40)
for i in range(0, 15):
    w1.create_line(i * 40 + 20, 20, i * 40 + 20, 580)
    w1.create_line(20, i * 40 + 20, 580, i * 40 + 20)

# 绘制五个星位交点
star_points = [
    (135, 135, 145, 145), (135, 455, 145, 465),
    (465, 135, 455, 145), (455, 455, 465, 465),
    (295, 295, 305, 305)
]
for coords in star_points:
    w1.create_oval(*coords, fill='black')

第2步:绑定点击事件与网格坐标映射

玩家下棋依赖于精确的像素到逻辑坐标的转换。当鼠标点击画布时,回调函数接收 event 对象获取 event.x 和 event.y。由于棋子实际绘制在交叉点圆心,需在半径范围内容差匹配。代码通过遍历 i 和 j 计算点击点到各交叉点 (20+40*i, 20+40*j) 的欧氏距离平方,若小于等于 20^2*2(容差阈值),则锁定对应网格行列。

落子逻辑依赖两个状态矩阵:A 记录点位占用情况(0为空,1为已占),B 存储棋子颜色属性('b'黑/'w'白)。利用整型变量 num 的奇偶性控制交替出子。每次成功落子后更新矩阵状态,并通过 w1.create_oval() 绘制实色圆形棋子。

黑白棋子交替落子与网格对齐效果
图2:鼠标点击触发的坐标吸附与黑白落子动画
import numpy as np
import tkinter.messagebox as msgbox

num = 0                                       # 全局步数计数器
A = np.full((15, 15), 0)                     # 占用标记矩阵
B = np.full((15, 15), '')                    # 颜色标识矩阵

def callback(event):
    global num, A
    # 查找最近的网格交点 (i, j)
    found_i, found_j = 0, 0
    for j in range(15):
        for i in range(15):
            dx = event.x - (20 + 40 * i)
            dy = event.y - (20 + 40 * j)
            if dx**2 + dy**2 <= 2 * 20**2:
                found_i, found_j = i, j
                break
        if found_i != 0 or found_j != 0: break

    # 校验空位并交替落子
    if A[found_i][found_j] == 0:
        color = 'black' if num % 2 == 0 else 'white'
        char_code = 'b' if num % 2 == 0 else 'w'
        
        w1.create_oval(40*found_i+5, 40*found_j+5,
                       40*found_i+35, 40*found_j+35, fill=color)
        A[found_i][found_j] = 1
        B[found_i][found_j] = char_code
        num += 1

第3步:四方向扫描与五连珠判定

胜负检测是核心算法。选定落子点后,定义四个基础方向向量:水平向左 [-1, 0]、左上对角线 [-1, 1]、垂直向上 [0, 1]、右上对角线 [1, 1]。针对每个方向执行两次单向扫描:

  1. 正向延伸:沿向量方向递增索引,累加同色棋子,直到越界或遇到异色/空位停止。
  2. 反向回溯:从当前点沿相反方向递减索引累加,原理相同。

注意原稿中边界判断 x + a > 0 会导致索引 0 被误判越界。此处修正为 >= 0 且 < 15 以确保全范围覆盖。单次扫描包含落子点自身,故正反向计数之和 count1 + count2 实际多算了一次落子点,判定条件设为 == 6 等效于五子连珠。满足条件则弹出 messagebox 提示获胜方。

五子连珠触发获胜提示的完整游戏界面
图3:完成五子连珠后的胜负判定与消息弹窗
    # 胜负判定逻辑嵌入callback末尾
    directions = [[-1, 0], [-1, 1], [0, 1], [1, 1]]
    
    for dx, dy in directions:
        cx, cy = found_i, found_j
        c1, c2 = 0, 0
        
        # 正向扫描
        while B[cx][cy] == B[found_i][found_j]:
            c1 += 1
            nx, ny = cx + dx, cy + dy
            if 0 <= nx < 15 and 0 <= ny < 15 and B[nx][ny] == B[found_i][found_j]:
                cx, cy = nx, ny
            else: break
            
        # 反向扫描
        while B[cx][cy] == B[found_i][found_j]:
            c2 += 1
            px, py = cx - dx, cy - dy
            if 0 <= px < 15 and 0 <= py < 15 and B[px][py] == B[found_i][found_j]:
                cx, cy = px, py
            else: break
            
        if c1 + c2 == 6:
            winner = "黑棋" if B[found_i][found_j] == 'b' else "白棋"
            msgbox.showinfo("游戏结束", f"{winner}获胜!")
            return  # 判定成功后终止本轮逻辑

w1.bind("<Button-1>", callback)

# 退出按钮与主循环
u = Button(root, text="退出", width=10, height=1, command=root.quit, font=('楷体', 15))
u.pack()
root.mainloop()

常见问题排错与建议

  • 坐标吸附不准:若发现棋子无法落在最近交叉点,检查容差公式中的半径值是否与棋盘缩放比例匹配。
  • 边界索引报错 IndexError:部分旧版代码直接使用 > 0 判断下限,在 Python 列表中会跳过第 0 行/列。务必统一使用 0 <= index < 15 规范边界拦截。
  • 资源释放:Windows/Linux 下直接关闭 Tkinter 窗口即可,若需平滑退出建议将 command=root.destroy 替代 quit 以清理系统句柄。

总结

本文通过模块化拆解,演示了如何利用 Python 基础库快速实现具有完整交互反馈的五子棋对局原型。掌握网格坐标映射算法与多向扫描判定逻辑后,开发者可进一步扩展悔棋功能、AI 对手接入或网络联机协议。以上就是基于Python实现五子棋游戏开发的详细内容,更多关于Python游戏开发与桌面应用设计的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表