代写C语言、C++、Java、Python、HTML、JavaScript、vue、MySQL相关编程作业,
长期接单,信誉有保证,标价10-20每份,如有需要请加文章末尾QQ。
本文资源:https://download.csdn.net/download/weixin_47040861/89319266
↑项目源代码免费下载↑
这期视频来介绍一个简单的五子棋案例,除去空行和注释总代码量不到一百行。
视频演示:
【Python案例】用不到100行代码实现五子棋(Tkinter)
1.基本参数
首先该项目需要使用TKinter库来生成窗口、绘制棋盘和生成提示:
import tkinter as tk
from tkinter import messagebox
然后定义几个基本常量方便后续绘制窗口:
# 定义常量
ROWS = 19 # 棋盘行数
COLS = 19 # 棋盘列数
PADDING = 30 # 棋盘边距
GRID_SIZE = 20 # 每个格子的大小
最后声明一个19*19的二维数组来表示棋盘上每一个棋子位置的状态:
board = [[0] * COLS for _ in range(ROWS)]
ROWS
和COLS
分别定义了棋盘的行数和列数,均为19。[0] * COLS
创建一个包含19个元素的列表,这些元素全部是0。这里的0表示棋盘上对应位置没有棋子。for _ in range(ROWS)
是一个列表生成式,表示要创建19行。
合在一起,这行代码使用列表生成式创建了一个19x19的二维列表(即一个包含19个子列表的列表,每个子列表包含19个0),用于表示五子棋的棋盘,其中每个元素的初始值都是0。这个棋盘可以用来记录每个位置的状态,0表示没有棋子,1表示黑子,2表示白子。
这样就完成了项目变量的基本设置。
2.绘制窗口
首先调用函数TK()创建一个新的主窗口,然后定义窗口的标题和背景颜色,在根据格子数量计算窗1口的宽高,这里高度+40是为了留出下方提示的空间:
# 创建窗口
window = tk.Tk() # 声明窗口
window.title("五子棋") # 声明窗口标题
# 根据棋盘格子计算得到窗口的适宜宽高
window.geometry(str(COLS * GRID_SIZE + PADDING * 2) + "x" + str(ROWS * GRID_SIZE + PADDING * 2 + 40))
window.configure(bg='burlywood') # 设置窗口背景颜色
(1)启动页面
接下来创建一个启动页面,首先调用Frame()函数创建一个容器,将容器背景颜色设置为棕色,然后在容器中添加一个标题和按钮,并给按钮绑定启动函数,当调用start_game()函数时隐藏启动容器,并给窗口添加棋盘容器:
# 创建启动容器
start_frame = tk.Frame(window)
start_frame.configure(bg='burlywood')
start_frame.pack()
#添加标题
start_label = tk.Label(start_frame, text="五子棋游戏", font=("黑体", 30))
start_label.configure(bg='burlywood')
start_label.pack(pady=100)
#添加按钮
start_button = tk.Button(start_frame, text="开始游戏", command=start_game, font=("宋体", 14))
start_button.pack(pady=0)
实际效果:
(2)游戏页面
然后是创建游戏页面,这里同样需要根据棋盘确定容器大小,然后还需要绘制棋盘的横竖线以及棋盘上的黑点,其中create_line()函数用于在TKinter窗口中绘制线,create_oval()函数用于绘制点,使用for循环逐行、逐列绘制:
# 创建游戏页面
game_frame = tk.Frame(window)
# 创建画布
canvas = tk.Canvas(game_frame, width=COLS * GRID_SIZE + PADDING * 2, height=ROWS * GRID_SIZE + PADDING * 2,bg="burlywood")
canvas.pack(pady=PADDING)
# 绘制棋盘线
for i in range(ROWS):
canvas.create_line(PADDING, i * GRID_SIZE + PADDING, COLS * GRID_SIZE + PADDING - GRID_SIZE,
i * GRID_SIZE + PADDING)
for i in range(COLS):
canvas.create_line(i * GRID_SIZE + PADDING, PADDING, i * GRID_SIZE + PADDING,
ROWS * GRID_SIZE + PADDING - GRID_SIZE)
# 绘制棋盘上的黑点
for i in range(3, ROWS, 6):
for j in range(3, COLS, 6):
canvas.create_oval(j * GRID_SIZE + PADDING - 3, i * GRID_SIZE + PADDING - 3,
j * GRID_SIZE + PADDING + 3, i * GRID_SIZE + PADDING + 3, fill="black")
最后,在窗口最下方绘制信息标签,用于提示当前回合信息:
# 创建游戏信息标签
label = tk.Label(window, text="黑子回合", font=("宋体", 14))
label.place(x=PADDING, y=PADDING * 2 + ROWS * GRID_SIZE + 10)
3.功能函数
(1)页面切换
该函数绑定在启动页面的“启动游戏”按钮上,每次点击该按钮时隐藏启动页面,并显示棋盘页面:
def start_game():
# 开始游戏,隐藏启动页面,显示游戏界面
start_frame.pack_forget()
game_frame.pack()
(2)落子
首先给鼠标事件绑定函数,左键或右键棋盘时调用函数:
# 绑定鼠标点击事件
canvas.bind("<Button-1>", on_click) # 左键点击
canvas.bind("<Button-3>", on_click) # 右键点击
然后调用函数时默认接收一个参数,该参数中保存着触发事件的事件源相关的信息,包括点击窗口的位置,利用点击位置相距于窗口左上角的x轴距离(event.x)和y轴距离(event.y),以及棋盘间距计算落子位置位于第几行第几列:
def on_click(event):
# 处理鼠标点击事件
row = round((event.y - PADDING) / GRID_SIZE) # 计算点击位置的行
col = round((event.x - PADDING) / GRID_SIZE) # 计算点击位置的列
然后使用if函数判断落子位置是否合理,包括是否在棋盘内,是否已存在棋子等:
if row < 0 or row >= ROWS or col < 0 or col >= COLS:
# 落子在棋盘外侧
messagebox.showinfo("提示", "不可以在棋盘外落子!")
return
if not is_valid_move(row, col):
# 提示落子位置已有棋子
messagebox.showinfo("提示", "此处已有棋子")
return
接下来根据当前的玩家编号决定落子颜色为黑色还是白色,并修改棋盘下方提示:
if current_player == 1: # 黑方玩家
color = "black"
label.config(text="白子回合")
else: # 白方玩家
color = "white"
label.config(text="黑子回合")
再将落子位置记录到二维数组中,方便后续判断游戏是否结束,并在棋盘中绘制棋子:
board[row][col] = current_player # 记录棋子
x = col * GRID_SIZE + PADDING # 计算棋子中心x坐标
y = row * GRID_SIZE + PADDING # 计算棋子中心y坐标
canvas.create_oval(x - GRID_SIZE // 2, y - GRID_SIZE // 2, x + GRID_SIZE // 2, y + GRID_SIZE // 2,
fill=color) # 绘制棋子
然后调用函数判断游戏是否结束:
if is_winner(current_player):
if current_player == 1:
messagebox.showinfo("游戏结束", "黑子获胜")
else:
messagebox.showinfo("游戏结束", "白子获胜")
window.quit()
else:
current_player = 2 if current_player == 1 else 1 # 切换玩家
(3)判断胜利
def is_winner(player):
# 检查玩家是否胜利
for row in range(ROWS):
for col in range(COLS):
if board[row][col] == player:
# 检查水平方向
if col + 4 < COLS and all(board[row][col + i] == player for i in range(5)):
return True
# 检查垂直方向
if row + 4 < ROWS and all(board[row + i][col] == player for i in range(5)):
return True
# 检查对角线方向(左上到右下)
if row + 4 < ROWS and col + 4 < COLS and all(board[row + i][col + i] == player for i in range(5)):
return True
# 检查对角线方向(右上到左下)
if row + 4 < ROWS and col - 4 >= 0 and all(board[row + i][col - i] == player for i in range(5)):
return True
return False
-
遍历整个棋盘:双重循环遍历整个棋盘,遍历每个格子。
-
检查玩家的棋子:对于每个格子,如果格子上是当前玩家的棋子(即
board[row][col] == player
),则进行以下四个方向的检查:-
水平方向:从当前位置开始向右检查4个相邻位置,如果这5个位置上的棋子都是当前玩家的,则说明玩家在水平方向获胜。
-
垂直方向:从当前位置开始向下检查4个相邻位置,如果这5个位置上的棋子都是当前玩家的,则说明玩家在垂直方向获胜。
-
对角线方向(左上到右下):从当前位置开始向右下方检查4个相邻位置,如果这5个位置上的棋子都是当前玩家的,则说明玩家在对角线方向(左上到右下)获胜。
-
对角线方向(右上到左下):从当前位置开始向左下方检查4个相邻位置,如果这5个位置上的棋子都是当前玩家的,则说明玩家在对角线方向(右上到左下)获胜。
-
-
返回结果:如果任何一个方向上检查到了五子连珠(即有五个相同棋子连在一起),则返回
True
,表示玩家获胜。如果没有在任何方向上检查到五子连珠,则返回False
,表示玩家未获胜。