一、基础设置
1.导包、窗口
我们首先导入了 tkinter 模块和 tkinter.messagebox 模块。然后,我们创建了一个名为w 的 Tk 对象,并设置了它的标题。我们这里命名为棋
import tkinter as tk
from tkinter import messagebox
yy=tk.Tk()
yy.title('井字棋')
yy.geometry('500x600')
2.添加画布
设置画布背景为白色,宽高400*400,居中
# 创建画布
c=tk.Canvas(yy,width=400,height=400,bg='white')
c.pack()
3.创建标签、输入框
y1=tk.Label(yy,text='请输入落子位置:(1-9):',font=16)
y1.place(x=150,y=450)
y2=tk.Entry(yy,width=25)
y2.place(x=150,y=480)
4.定义按钮
b1=tk.Button(yy,text='按下按钮',width=10,font=16)
b1.place(x=100,y=520)
b2=tk.Button(yy,text='重新开始',width=10,font=16)
b2.place(x=300,y=520)
yy.mainloop()
5.窗口样式
二、初始化棋盘
1.定义函数
1.1定义init函数
定义了一个名为init的函数,该函数用于初始化棋盘界面。
# 定义init函数,用于初始化棋盘
def init():
init()
1.2定义数据
1.2.1定义棋盘缩放偏移
tiling = 125 # 棋盘缩放
offset = 10 # 棋盘偏移
1.2.2定义四个变量
x0,y0,x1,y1=offset,offset, offset + tiling * 3, offset + tiling * 3
1.2.3定义空列表 用于存储棋盘上的某个点的坐标。
points = []
1.2.4定义嵌套循环,棋盘的每一行和每一列。
for row in range(3):
for col in range(3):
points.append((x0 + tiling * 0.5 + col * tiling,y0 + tiling * 0.5 + row * tiling))
第一行代码:
遍历棋盘的每一行(从0到2,共3行)
第二行代码:
遍历棋盘的每一列(从0到2,共3列)
第三行代码:
计算中心坐标,并将这个坐标添加到points列表中。
1.2.5定义空列表 用于存储棋盘上的棋子
board=[]
1.2.6初始化一个变量step,并为其赋值为0
step=0
1.2.7初始化一个变量gameover,并为其赋值为False。用于表示结束。
gameover=False
1.3放置标签
# 在棋盘的每个点上放置一个标签,显示该点的编号
for i in range(9):
tk.Label(c,text=i+1).place(x=points[i][0],y=points[i][1],anchor='center')
第一行代码:
是开始一个循环,从0到8的整数。因为棋盘是3x3的,所以总共有9个点。
第二行代码:
在循环内,创建了一个标签,显示该点的编号(从1到9),并将这个标签放置在points列表中对应坐标的位置上。anchor='center'确保标签在指定位置的中心对齐。
1.4绘制棋盘网格
# 绘制棋盘网格
for i in range(4):
c.create_line(x0 + i * tiling, y0, x0 + i * tiling, y1)
c.create_line(x0, y0 + i * tiling, x1, y0 + i * tiling)
第一行代码:
开始一个循环,从0到3的整数。因为棋盘是3x3的,所以只需要绘制4条垂直线和4条水平线。
第二行代码:
这行代码绘制一条从到(x0 + i * tiling, y0,)到(x0 + i * tiling, y1)的垂直线。这表示棋盘的列
第三行代码:
这行代码绘制一条从(x0, y0 + i * tiling)到(x1, y0 + i * tiling)的水平线。这表示棋盘的行。
1.5棋盘样式
三、设置输入数字范围
1.定义click函数
def click():
2.全局变量step
声明step是一个全局变量,这样在该函数内部可以访问和修改它在函数外部定义的值。
global step
3.函数是否返回
如果gameover变量为True(即游戏已经结束),则函数直接返回,不执行后续的代码。
if gameover:
return
4.赋值变量
将其转换为整数类型,赋值给num变量。
num = int(y2.get())
5.数字在1-9内
检查num的值是否在1到9的范围内(包含1,不包含10)。如果不在这个范围内,就显示一个警告弹窗,告诉用户输入必须在1到9的范围内,然后函数返回,不执行后续代码。
if num not in range(1, 10):
tk.messagebox.showwarning(title="警告", message="输入必须在(1-9)范围内")
return
6.索引
index = num - 1
将num的值减1,得到index。由于棋盘上的点是从0开始索引的,而用户输入的是从1开始的编号,所以需要减1来得到正确的索引。
7.检查是否为空
检查board列表在index位置的值是否不为空字符串。如果不为空,说明该位置已经有棋子,因此显示一个警告弹窗告诉用户此处不能落子,然后函数返回。
if (board[index] != ''):
tk.messagebox.showwarning(title='警告', message='此处不为空,不能落子!')
return
8.运行结果
四、设置落子
1.定义move函数
定义了一个名为move的函数,它接受一个参数index,这个参数应该是棋盘上某个点的索引。
def move(index):
2.定义变量r
r=25
3.画图
使用tk包下的create_rectangle方法在画布c上绘制一个矩形
矩形的左上角坐标是(points[index][0] - r, points[index][1] - r),
右下角坐标是(points[index][0] + r, points[index][1] + r)。
这样绘制的矩形会在中心点在points[index]上
fill棋子的颜色为蓝色。
c.create_rectangle(points[index][0]-r,points[index][1]-r,points[index][0]+r,points[index][1]+r,fill='blue')
4.设置index值
在board列表中,将index位置的值设置为'rect',表示这儿已经被一个矩形占据
board[index] = 'rect'
5.步数
步数+1
step += 1
6.运行结果
-
五、判断输赢
-
1.定义isWin函数
def isWin():
2.定义一个列表w
它包含了所有可能的获胜的线
w=[[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [0, 4, 8], [1, 4, 7], [2, 5, 8], [2, 4, 6]]
3.判断赢得条件
for i in w:
if board[i[0]] == board[i[1]] == board[i[2]] and board[i[0]] !='':
gameover=True
tk.messagebox.showinfo(title='结果',message=board[i[0]] + "赢了")
return
第一行代码:
每一条获胜的线
第二行代码:
检查获胜线上的三个格子是否都被同一个棋子占据,三个格子的值相等且不为空
第三行代码:
如果条件满足,设置gameover为True,表示结束
第四行代码:
提示一个框,告诉哪个玩家赢了
4.判断平局条件
if step>=5:
gameover=False
tk.messagebox.showinfo(title='错了', message="平局")
return
第一行代码:
如果已经走大于或者等于5步了
第二行代码:
设置gameover为False,表示游戏为平局
第三行代码:
提示一个框,告诉平局
5.运行结果
赢
平局
-
六、清除画布内容
- 清除画布上所有项目
for item in c.find_all():
c.delete(item)
七、重新开始游戏
1.定义restart函数
def restart():
init()
用init函数是重置游戏的所有状态
2.清空输入框内容
y2.delete(0, tk.END)
3.显示重新开始信息
messagebox.showinfo("提示", "游戏已重新开始。")
- 运行结果
所有代码
import tkinter as tk
from tkinter import messagebox
yy=tk.Tk()
yy.title('井字棋')
yy.geometry('500x600')
c=tk.Canvas(yy,width=400,height=400,bg='white')
c.pack()
y1=tk.Label(yy,text='请输入落子位置:(1-9):',font=16)
y1.place(x=150,y=450)
y2=tk.Entry(yy,width=25)
y2.place(x=150,y=480)
tiling = 125 # 棋盘缩放
offset = 10 # 棋盘偏移
x0,y0,x1,y1=offset,offset, offset + tiling * 3, offset + tiling * 3
points = []
for row in range(3):
for col in range(3):
points.append((x0 + tiling * 0.5 + col * tiling,y0 + tiling * 0.5 + row * tiling))
board=[]
step=0
gameover=False
def init():
# 清除画布上所有项目
for item in c.find_all():
c.delete(item)
for i in range(9):
tk.Label(c,text=i+1).place(x=points[i][0],y=points[i][1],anchor='center')
# 绘制棋盘网格
for i in range(4):
c.create_line(x0 + i * tiling, y0, x0 + i * tiling, y1)
c.create_line(x0, y0 + i * tiling, x1, y0 + i * tiling)
# 创建棋盘数据
global board
board = ['' for i in range(9)]
# 游戏进度
global gameover
gameover = False
global step
step = 0
init()
#落子操作
def move(index):
global step
r=25
c.create_rectangle(points[index][0]-r,points[index][1]-r,points[index][0]+r,points[index][1]+r,fill='blue')
board[index] = 'rect'
# 步数+1
step += 1
# 判断胜负
isWin()
if gameover:
return
def click():
global step
if gameover:
return
num = int(y2.get())
if num not in range(1, 10):
tk.messagebox.showwarning(title="警告", message="输入必须在(1-9)范围内")
return
index = num - 1
if (board[index] != ''):
tk.messagebox.showwarning(title='警告', message='此处不为空,不能落子!') # 警告弹窗
return
isWin()
move(index)
def isWin():
global gameover
w=[[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [0, 4, 8], [1, 4, 7], [2, 5, 8], [2, 4, 6]]
for i in w:
if board[i[0]] == board[i[1]] == board[i[2]] and board[i[0]] !='':
gameover=True
tk.messagebox.showinfo(title='结果',message=board[i[0]] + "赢了")
return
if step>=5:
gameover=False
tk.messagebox.showinfo(title='错了', message="平局")
return
def restart():
# 调用init函数重新初始化游戏
init()
# 清除输入框内容
y2.delete(0, tk.END)
# 显示重新开始信息
messagebox.showinfo("提示", "游戏已重新开始。")
b1=tk.Button(yy,text='按下按钮',width=10,font=16,command=click)
b1.place(x=100,y=520)
b2=tk.Button(yy,text='重新开始',width=10,font=16,command=restart)
b2.place(x=300,y=520)
yy.mainloop()