1. 游戏创建
1.1导包
from tkinter import *
import numpy as np
import math
import tkinter.messagebox
1.2 窗口内容
1.2.1创建一个窗口
root = Tk() # 窗口名称
root.title("井字棋 from Sun")
1.2.2 创建一个框架,将其放置在窗口中
Frame1 = Frame(root) # 框架
Frame1.pack()
1.2.3 创建一个用来绘制九宫格的画布w1
w1 = Canvas(Frame1, width=580, height=580, bg="white") # 创建一个画布(Canvas),设置大小
w1.pack() # w1:画布
1.3 绘制九宫格
使用create_line在画布上绘制九宫格。
for i in range(0, 4):
w1.create_line(i * 180 + 20, 20, i * 180 + 20, 560) # 绘制竖线
w1.create_line(20, i * 180 + 20, 560, i * 180 + 20) # 绘制横线
运行结果:
1.4 定义一个全局变量
# 定义全局变量num
num = 0 # 记录点击的次数,用来决定点击后该画哪种图形
# 定义一个3X3的数组A
A = np.full((3, 3), 0) # 记录每个位置的图形
# 0表示空,1表示叉号,2表示圆圈。
1.5 定义一个鼠标事件
根据鼠标的点击在网格中绘制“X”和“O”
def dawn(event):
global w1
global num, A
for i in range(0, 3): # 确定被单击的网格单元格的行号。
for j in range(0, 3): # 确定被单击的网格单元格的行号。
if 20 + j * 180 < event.y and event.y <= 20 + (j+1) * 180:
break
if 20 + i * 180 <= event.x and event.x <= 20 + (i+1) * 180:
break
if num % 2 == 0 and A[i][j] == 0: # 如果当前玩家是 X并且该单元格为空,则绘制叉号。
A[i][j] = 1
1.6 创建图形“×”和“○”
1.6.1 创建“×”
# 使用create_line方法在指定位置绘制叉号。
w1.create_line(110 + 180 * i - 45 * math.sqrt(2), 110 + 180 * j - 45 * math.sqrt(2),
110 + 180 * i + 45 * math.sqrt(2), 110 + 180 * j + 45 * math.sqrt(2), width=5)
w1.create_line(110 + 180 * i + 45 * math.sqrt(2), 110 + 180 * j - 45 * math.sqrt(2),
110 + 180 * i - 45 * math.sqrt(2), 110 + 180 * j + 45 * math.sqrt(2), width=5)
num += 1 # 增加点击次数。
1.6.2 创建“○”
# 使用create_oval方法在指定位置绘制圆圈。
w1.create_oval(20 + 180 * i + 10, 20 + 180 * j + 10, 20 + 180 * (i + 1) - 10, 20 + 180 * (j + 1) - 10, width=5)
num += 1
1.7 对弈结果:①“X”获胜 ②“O获胜”③ 平局
1.7.1 “O”获胜的所有可能性
- 所有可能性: ① 横向三个相邻单元格都包含 O。
- ② 纵向三个相邻单元格都包含 O。
- ③ 从左上角到右下角的对角线上的所有单元格都包含 O。
- ④ 从右上角到左下角的对角线上的所有单元格都包含 O。
if (A[0][0] == A[0][1] == A[0][2] == 2 or A[1][0] == A[1][1] == A[1][2] == 2 or A[2][0] == A[2][1] == A[2][2] == 2 or A[0][0] == A[1][0] == A[2][0] == 2 or A[0][1] == A[1][1] == A[2][1] == 2 or A[0][2] == A[1][2] ==A[2][2] == 2 or A[0][0] == A[1][1] == A[2][2] == 2 or A[2][0] == A[1][1] == A[0][2] == 2):
tkinter.messagebox.showinfo('Warning', '恭喜O获胜啦')
1.7.2 “X”获胜的所有可能性
- 所有可能性: ① 横向三个相邻单元格都包含 X。
- ② 纵向三个相邻单元格都包含 X。
- ③ 从左上角到右下角的对角线上的所有单元格都包含 X。
- ④ 从右上角到左下角的对角线上的所有单元格都包含 X。
- ③ 从左上角到右下角的对角线上的所有单元格都包含 X。
- ② 纵向三个相邻单元格都包含 X。
elif (A[0][0] == A[0][1] == A[0][2] == 1 or A[1][0] == A[1][1] == A[1][2] == 1 or A[2][0] == A[2][1] == A[2][2] == 1 or A[0][0] == A[1][0] == A[2][0] == 1 or A[0][1] == A[1][1] == A[2][1] == 1 or A[0][2] == A[1][2] ==A[2][2] == 1 or [0][0] == A[1][1] == A[2][2] == 1 or A[2][0] == A[1][1] == A[0][2] == 1):
tkinter.messagebox.showinfo('Warning', '恭喜X获胜啦')
1.7.3 平局的所有可能性
每个棋子最多能走5步,当X走了5步时,则O只走了4步,所以XO加一起只能走9步,所以当没有棋子连在一起的时候,就该考虑是否已经走了9次,如果走了就此还没达到获胜条件时,那么这时候就是平局
elif num == 9 and not (
A[0][0] == A[0][1] == A[0][2] == 2 or A[1][0] == A[1][1] == A[1][2] == 2 or A[2][0] == A[2][1] == A[2][2] == 2 or A[0][0] == A[1][0] == A[2][0] == 2 or A[0][1] == A[1][1] == A[2][1] == 2 or A[0][2] == A[1][2] ==A[2][2] == 2 or A[0][0] == A[1][1] == A[2][2] == 2 or A[2][0] == A[1][1] == A[0][2] == 2 orA[0][0] == A[0][1] == A[0][2] == 1 or A[1][0] == A[1][1] == A[1][2] == 1 or A[2][0] == A[2][1] == A[2][2] == 1 or A[0][0] == A[1][0] == A[2][0] == 1 or A[0][1] == A[1][1] == A[2][1] == 1 or A[0][2] == A[1][2] == A[2][2] == 1 orA[0][0] == A[1][1] == A[2][2] == 1 or A[2][0] == A[1][1] == A[0][2] ==1):
tkinter.messagebox.showinfo('Warning', 'woo平局啦!')
1.8 “退出”
1.8.1 退出的函数
def quit():
root.quit()
1.8.2 退出的按钮
# 退出按钮
button1 = Button(root, text="退出", font=('微软雅黑', 15), command=quit)
button1.pack()
1.9 “重新开始”
1.9.1 重新开始的函数
def restart():
global w1, num, A
w1.delete("all") # 清除画布上所有的东西
for i in range(0, 4):
w1.create_line(i * 180 + 20, 20, i * 180 + 20, 560)
w1.create_line(20, i * 180 + 20, 560, i * 180 + 20)
num = 0
A = np.full((3, 3), 0)
w1.bind("<Button -1>", dawn)
1.9.1 从新开始的按钮
# 重新开始按钮
button2 = Button(root, text="重新开始", font=('微软雅黑', 15), command=restart)
button2.pack()
2. 完整代码
from tkinter import *
import numpy as np
import math
import tkinter.messagebox
root = Tk() # 窗口名称
root.title("井字棋 from Sun")
# root.geometry("600x600")
Frame1 = Frame(root) # 框架
Frame1.pack()
w1 = Canvas(Frame1, width=580, height=580, bg="white") # 创建一个画布(Canvas),设置大小
w1.pack() # w1:画布
for i in range(0, 4):
w1.create_line(i * 180 + 20, 20, i * 180 + 20, 560) # 绘制竖线
w1.create_line(20, i * 180 + 20, 560, i * 180 + 20) # 绘制横线
# 定义全局变量num
num = 0 # 记录点击的次数,用来决定点击后该画哪种图形
# 定义一个3X3的数组A
A = np.full((3, 3), 0) # 记录每个位置的图形
# 0表示空,1表示叉号,2表示圆圈。
def dawn(event):
global w1
global num, A
for i in range(0, 3): # 确定被单击的网格单元格的行号。
for j in range(0, 3): # 确定被单击的网格单元格的行号。
if 20 + j * 180 < event.y and event.y <= 20 + (j+1) * 180:
break
if 20 + i * 180 <= event.x and event.x <= 20 + (i+1) * 180:
break
if num % 2 == 0 and A[i][j] == 0: # 如果当前玩家是 X并且该单元格为空,则绘制叉号。
# 网格中的行 i 和列 j
A[i][j] = 1 # 二维数组:A[i][j]
# 使用create_line方法在指定位置绘制叉号。
w1.create_line(110 + 180 * i - 45 * math.sqrt(2), 110 + 180 * j - 45 * math.sqrt(2),
110 + 180 * i + 45 * math.sqrt(2), 110 + 180 * j + 45 * math.sqrt(2), width=5)
w1.create_line(110 + 180 * i + 45 * math.sqrt(2), 110 + 180 * j - 45 * math.sqrt(2),
110 + 180 * i - 45 * math.sqrt(2), 110 + 180 * j + 45 * math.sqrt(2), width=5)
num += 1 # 增加点击次数。
if num % 2 != 0 and A[i][j] == 0: # 如果当前玩家是 O 并且该单元格为空,则绘制圆圈。
A[i][j] = 2
# 使用create_oval方法在指定位置绘制圆圈。
w1.create_oval(20 + 180 * i + 10, 20 + 180 * j + 10, 20 + 180 * (i + 1) - 10, 20 + 180 * (j + 1) - 10, width=5)
num += 1
# 0表示空,1表示叉号,2表示圆圈 # \ :换行
if (A[0][0] == A[0][1] == A[0][2] == 2 or A[1][0] == A[1][1] == A[1][2] == 2 or A[2][0] == A[2][1] == A[2][
2] == 2 or A[0][0] == A[1][0] == A[2][0] == 2 or A[0][1] == A[1][1] == A[2][1] == 2 or A[0][2] == A[1][2] ==
A[2][2] == 2 or A[0][0] == A[1][1] == A[2][2] == 2 or A[2][0] == A[1][1] == A[0][2] == 2):
# 从左上角到右下角的对角线上的所有单元格都包含 O or 从右上角到左下角的对角线上的所有单元格都包含 O
tkinter.messagebox.showinfo('Warning', '恭喜O获胜啦')
elif (A[0][0] == A[0][1] == A[0][2] == 1 or A[1][0] == A[1][1] == A[1][2] == 1 or A[2][0] == A[2][1] == A[2][
2] == 1 or A[0][0] == A[1][0] == A[2][0] == 1 or A[0][1] == A[1][1] == A[2][1] == 1 or A[0][2] == A[1][2] ==
A[2][2] == 1 or
A[0][0] == A[1][1] == A[2][2] == 1 or A[2][0] == A[1][1] == A[0][2] == 1):
tkinter.messagebox.showinfo('Warning', '恭喜X获胜啦')
elif num == 9 and not (
A[0][0] == A[0][1] == A[0][2] == 2 or A[1][0] == A[1][1] == A[1][2] == 2 or A[2][0] == A[2][1] == A[2][
2] == 2 or A[0][0] == A[1][0] == A[2][0] == 2 or A[0][1] == A[1][1] == A[2][1] == 2 or A[0][2] == A[1][2] ==
A[2][2] == 2 or A[0][0] == A[1][1] == A[2][2] == 2 or A[2][0] == A[1][1] == A[0][2] == 2 or
A[0][0] == A[0][1] == A[0][2] == 1 or A[1][0] == A[1][1] == A[1][2] == 1 or A[2][0] == A[2][1] == A[2][2] == 1 or
A[0][0] == A[1][0] == A[2][0] == 1 or A[0][1] == A[1][1] == A[2][1] == 1 or A[0][2] == A[1][2] == A[2][2] == 1 or
A[0][0] == A[1][1] == A[2][2] == 1 or A[2][0] == A[1][1] == A[0][2] == 1
):
tkinter.messagebox.showinfo('Warning', 'woo平局啦!')
def restart():
global w1, num, A
w1.delete("all") # 清除画布上所有的东西
for i in range(0, 4):
w1.create_line(i * 180 + 20, 20, i * 180 + 20, 560)
w1.create_line(20, i * 180 + 20, 560, i * 180 + 20)
num = 0
A = np.full((3, 3), 0)
w1.bind("<Button -1>", dawn)
def quit():
root.quit()
# 退出按钮
button1 = Button(root, text="退出", font=('微软雅黑', 15), command=quit)
button1.pack()
# 重新开始按钮
button2 = Button(root, text="重新开始", font=('微软雅黑', 15), command=restart)
button2.pack()
root.mainloop()