项目二:五子棋
一.创建登陆界面
1.导包
import pickle
import tkinter as tk
from tkinter import messagebox #显示提示框
import subprocess
2.创建窗口
window = tk.Tk()
window.title(“welcome”)
window.geometry(“600x400”)
3.在窗口添加图片并显示
#创建一个photoimage对象用于表示GIF格式的图片
logo = tk.PhotoImage(file=”welcome.gif”)
#创建一个控件,用来加载logo的图片,并将label控件放在window窗口中
Label = Label(window, image=logo)
Label.pack()
注:在创建登陆界面的时候,我们要注意tkinter只能显示gif图片(不会动),photoimage可以来导入图片,可以是绝对路径,也可以是相对路径。
添加图片:
4.创建用户输入框和密码以及Login按钮和Sign up按钮
#创建一个Label控件,用于显示“User name”,并将其放置在window窗口中
t1 = tk.Label(window, text=”User name”)
t1.place(x=70, y=130)
#创建一个Entry控件,用于用户输入用户名,设置边框宽度为5
Label_title1 = tk.Entry(window, bd=5)
Label_title1.pack(padx=10, pady=5)
t2 = tk.Label(window, text=”Password”)
t2.place(x = 70, y = 180)
#show='*'参数:这意味着输入的字符将被星号(*)隐藏,用于保护密码的隐私。
Label_title2 = tk.Entry(window, bd=5, show=’*’)
Label_title2.pack(padx=10, pady=5)
#创建一个Button控件,用来显示”Login”
Btn_Login = tk.Button(window,text=’Login’)
Btn_Login = tk.place(x=180,y=250)
#创建一个Button控件,用来显示”Sign up”
Btn_sign_up = tk.Button(window,text=’Sign up’)
Btn_sign_up.place(x=350,y=250)
运行图片:
二.创建注册界面
1.创建一个新的窗口
window_sign_up = tk.Toplevel(window)
window_sign_up.title(“Sign up window”)
window_sign_up.geometry(“380x230”)
2.创建标签、输入框和按钮
t1 = tk.Label(window_sign_up, text="User name:")
t1.place(x=30, y=20)
label_title1 = tk.Entry(window_sign_up, bd=2)#Entry是输入框
label_title1.place(x=180, y=20)
t2 = tk.Label(window_sign_up, text="Password:")
t2.place(x=30, y=60)
label_title2 = tk.Entry(window_sign_up, bd=2)
label_title2.place(x=180, y=60)
t3 = tk.Label(window_sign_up, text="Confirm password:")
t3.place(x=30, y=100)
label_title3 = tk.Entry(window_sign_up, bd=2, show='*')
label_title3.place(x=180, y=100)
btn_comfirm_sign_up = tk.Button(window_sign_up, text='Sign up')
btn_comfirm_sign_up.place(x=150, y=130)
window.mainloop()
运行图片:
三.将登陆界面和注册界面连接起来
1.显示弹窗窗口
def usr_login():
usr_name = label_title1.get()
usr_password = label_title2.get()
print(usr_name)
#使用抛出异常的方法抛出异常的方法来验证用户的登录信息,并在登录成功时启动另一个 Python 脚本,或者在用户尚未注册时提供注册的选项。
try:
with open('usrs_info.pickle', 'rb') as usr_file: #尝试用二进制读取方法打开文件。
print('1')
usrs_info = pickle.load(usr_file)
print(usrs_info)
except FileNotFoundError:#处理异常
with open('usrs_info.pickle', 'wb') as usr_file: #用二进制写入模式打开文件。
print('2')
usrs_info = {'admin':'admin'} #密码的字典
pickle.dump(usrs_info, usr_file) #将用户信息字典序列化写到文件中
print('OK')
print('usr_name:',usr_name)
#使用if判断语句对三种情况进行判断。
if usr_name in usrs_info:
print('3')
if usr_password == usrs_info[usr_name]:#检查输入的用户名是否在用户信息字典中。
tk.messagebox.showinfo(title='Welcome',message='How are you'+usr_name)
else:
tk.messagebox.showinfo(message='Error,your password is wrong,try again')
else:
print('4')
is_sign_up = tk.messagebox.askyesno(title='Welcome',message='You have not sign up yet.Sign up today')
if is_sign_up:
usr_sign_up() #调用usr_sign_up函数,处理用户的注册。
#定义 usr_sign_up()函数,用于处理用户的注册过程。
def usr_sign_up():
print('开始注册')
def sign_up():
#获取输入
nn = label_title1.get()
np = label_title2.get()
npf = label_title3.get()
#读取后台数据
with open('usrs_info.pickle', 'rb') as usr_file:
exist_usr_info = pickle.load(usr_file)#从文件中加载已存在的用户信息字典
#判断两次输入的密码是否一致
if np != npf:
tk.messagebox.showerror('错误','Password and confire must be the same!')
elif nn in exist_usr_info:
print('已经注册过了')
tk.messagebox.showerror('错误','The user has already signed up!')
else:
exist_usr_info[nn] = np
with open('user_info.pickle', 'wb') as usr_file:
pickle.dump(exist_usr_info, usr_file)
tk.messagebox.showinfo('Welcome','You have successfully signed up!')
window_sign_up.destroy()#销毁窗口
2.在按钮里调用函数
btn_login=tk.Button(window,text='Login',command=usr_login)
btn_login.place(x=180,y=250)
btn_sign_up=tk.Button(window,text='Sign up',command=usr_sign_up)
btn_sign_up.place(x=350,y=250)
注:在按钮里添加command用来调用函数。
运行图片:
四.创建游戏窗口
1.导包
import tkinter as tk
import random #生成随机数
from tkinter import messagebox 显示提示框
2.创建窗口
root = tk.Tk()
root.title("九宫格")
root.geometry("400x450")
3.创建九宫格
def draw_board():
#在画布上创建一条从(2, 2)到(300, 2)的线,线宽为2像素,这条线是棋盘的顶部边框。
canvas.create_line(2, 2, 300, 2, width=2) # 上
canvas.create_line(2, 2, 2, 300, width=2) # 左
canvas.create_line(2, 300, 300, 300, width=2) # 下
canvas.create_line(300, 2, 300, 300, width=2) # 右
#在画布上创建一条垂直线,将棋盘分为两半,线宽为默认值(通常是1像素)。
canvas.create_line(100, 0, 100, 300)
canvas.create_line(200, 0, 200, 300)
canvas.create_line(0, 100, 300, 100)
canvas.create_line(0, 200, 300, 200)
#初始化一个变量num,用于在棋盘格子上绘制数字1到9。
num = 1
#开始一个循环,循环3次,代表棋盘的行。
for i in range(3):
#在每个行的内部,再开始一个循环,循环3次,代表棋盘的列。
for j in range(3):
y = i * 100 + 50 #计算当前格子中心点的y坐标
x = j * 100 + 50 #计算当前格子中心点的x坐标
#在画布上创建文本,文本内容用NUM的字符串表示,位置在(X,Y)
canvas.create_text(x, y, text=str(num), font=("Arial", 24))
num += 1
#将num的值增加1,以便在下一次循环中绘制下一个数字
4.创建标签和按钮
canvas = tk.Canvas(root, bg='white', height=300, width=300) #创建一个白色的画布
canvas.pack()
t1 = tk.Label(root, text="请输入要落子的位置(1-9):") #创建标签
t1.place(x=110, y=310)
label_title1 = tk.Entry(root, bd=5) #创建输入框
label_title1.place(x=110, y=340)
botton_1 = tk.Button(root, text="按下落子")
botton_1.place(x=110, y=370)
botton_2 = tk.Button(root, text="重新开始")
botton_2.place(x=200,y=370)
root.mainloop()
运行图片:
5.定义获胜组合
def winner():
global step
global gameover
#判断所给棋子是否获胜
# 定义获胜的组合
wins = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
# 检查是否有获胜组合,循环遍历 wins 列表中的每个获胜组合
for r in wins:
# 检查 board 列表中由 r 指定的位置上的标记是否为非空,并且这三个位置上的标记是否完全相同。
if (board[r[0]] != " " and board[r[0]] == board[r[1]] == board[r[2]]):
gameover = True
messagebox.showinfo(title="提示",message='赢得是'+board[r[0]])
return
#如果 step 的值大于5(这意味着至少有一个玩家已经下了5步),这行代码会检查游戏是否平局。
if step > 5:
gameover = True
messagebox.showinfo(title="shuchu", message="平手")
return
注:定义一个名为winner()的函数是检查玩家是否获胜或者平局,如果找到一个获胜组合,或者游戏达到5步以上,它会结束游戏并显示相应的消息框。
6.定义我方落子
oot = 0
step = 0 #初始化步数为0,用于轮流切换玩。
#第一个玩家使用的标记为”X“
first_player = "X"
#初始化游戏结束标志为False,当游戏结束时,这个标志会变为True。
gameover = False
#创建一个长度为9的列表,用于表示九宫格的每个格子,初始时所有格子都为空格字符。
board = [' '] * 9
注:在初始化九宫格游戏时定义了一些全局变量,全局变量可以多个部分都可以访问。
def on_click():
global step #step为一个全局变量,它是下棋的步数。
global board #board为一个全局变量,它是一个列表,用于存储九宫格中每个位置的玩家标记。
#从名为label_title1的Tkinter组件中获取用户的输入,这个输入应该是用户想要落子的位置(1到9之间的数字)
position = label_title1.get()
if position.isdigit() and 1 <= int(position) <= 9:#检查position是否是一个数字,并且这个数字在1到9之间。
number = int(position)#将position转换成整数,因为他是以字符串的形式输入的
index = number - 1#计算在board列表中的索引位置,因为列表索引从0开始,所以要-1
if board[index] == ' ':#检查所选位置是否为空
board[index] = 'x'#在board列表中更新玩家的标记为X,表示这个位置现在被玩家占据了
x = ((int(position) - 1) % 3) * 100 + 50#这行代码计算落子的x坐标。
y = ((int(position) - 1) // 3) * 100 + 50#这行代码计算落子的y坐标。
canvas.create_line(x - 20, y - 20, x + 20, y + 20, fill='pink', width=2)
canvas.create_line(x + 20, y - 20, x - 20, y + 20, fill='pink', width=2)
#这行代码在画布上创建一条线,从点 (x - 20, y - 20) 到点 (x + 20, y + 20),颜色为粉色,宽度为2像素。这条线是玩家“X”的标记的一部分。
step += 1
#将全局变量 step 的值增加1,用于记录游戏中的步数
winner()
else:
messagebox.showerror("错误", "该位置已经落子,请选择其他位置")
注:定义了一个名为on_click的函数,它会在用户点击九宫格游戏界面时被调用。函数的主要作用是处理用户的输入,更新游戏状态,并在画布上绘制玩家的标记。int(position) - 1将用户输入的位置转换为整数并减去1(因为棋盘的索引从0开始),乘以100得到列的位置,并加上50来居中显示在棋盘的格子中。
7.定义敌方落子
def ai_move():
#全局变量,可以在函数内部访问和修改。
global board, foot
index = random.randint(0, 8) #使用random.randint函数生成随机数,范围在0-8之间(包括0,但不包括9),因为棋盘有九个格子,索引从0开始。
while board[index] != ' ':
##设置一个循环,循环条件是棋盘上的当前格子索引 index 对应的标记不是空格(’ ')。
index = random.randint(0, 8)
#设置随机数,让棋子随便下位置。
x = ((index) % 3) * 100 + 50
y = ((index) // 3) * 100 + 50
#这行代码在画布上创建一个圆形,代表AI的标记。圆的中心点是 (x, y),半径为20像素。
canvas.create_oval(x - 20, y - 20, x + 20, y + 20, fill='pink')
#将AI的标记’AI’添加到棋盘的对应位置
board[index] = 'AI'
#全局变量 foot 的值增加1,用于记录AI的步数。
foot += 1
winner()
注:定义ai_move()函数,让AI在九宫格游戏中随机选择一个空位进行落子,并在棋盘上绘制AI的标记,同时更新游戏状态并检查游戏是否结束。
8.定义异常处理
def problem():
try:
input_value = int(label_title1.get())#尝试将一个标签(label)组件的内容转换为整数。
if input_value < 1 or input_value > 9:
#检查 input_value 是否小于1或大于9。九宫格游戏的棋盘有9个格子,所以用户输入的位置应该在1到9之间。
messagebox.showerror("错误", "请输入1到9之间的数字")
else:
print("输入正确")
except ValueError:
messagebox.showerror("错误", "请输入一个有效的数字")
on_click()
注:roblem 函数的作用是验证用户输入的位置是否有效,并在输入无效时显示错误消息。如果输入有效,它会调用 on_click 函数来继续处理用户的落子操作。
9.重置游戏
def again():
global step
global gameover
gameover = False
canvas.delete("all") #使用 canvas.delete 函数清除画布上的所有元素。
draw_board()
注:again 函数的作用是重置游戏状态,包括设置 gameover 为 False 以表示游戏尚未结束,清除画布上的所有元素,并重新绘制九宫格的布局。让用户可以重新开始游戏。
canvas = tk.Canvas(root, bg='white', height=300, width=300)
canvas.pack()
draw_board()
t1 = tk.Label(root, text="请输入要落子的位置(1-9):")
t1.place(x=110, y=310)
label_title1 = tk.Entry(root, bd=5)
label_title1.place(x=110, y=340)
botton_1 = tk.Button(root, text="按下落子",command=on_click) #调用on_click函数。
botton_1.place(x=110, y=370)
botton_2 = tk.Button(root, text="重新开始",command=again) #调用again函数。
botton_2.place(x=200,y=370)
root.mainloop()
注:最后在按钮中调用这两个函数,就可以实现落子功能了。
五.将游戏界面和登录注册界面链接起来
subprocess.Popen(["python", "lx.py"])
window.destroy() #销毁窗口
注:用 subprocess.Popen 来启动一个新的Python进程,并运行lx.py来开始主功能或显示主界面。
代码位置:
运行图片:
六.全部代码
1.登陆界面和注册界面
mport pickle
import tkinter as tk
from tkinter import messagebox#显示提示框
import subprocess
window = tk.Tk()
window.title("Welcome")
window.geometry("600x400")
logo = tk.PhotoImage(file="welcome.gif")
label = tk.Label(window, image=logo)
label.pack()
t1 = tk.Label(window, text="User name")
t1.place(x=70, y=130)
label_title1 = tk.Entry(window, bd=5)
label_title1.pack(padx=10, pady=5)
t2 = tk.Label(window, text="Password")
t2.place(x=70, y=180)
label_title2 = tk.Entry(window, bd=5, show='*')
label_title2.pack(padx=10, pady=5)
def usr_login():
usr_name = label_title1.get()
usr_password = label_title2.get()
print(usr_name)
try:
with open('usrs_info.pickle', 'rb') as usr_file:
print('1')
usrs_info = pickle.load(usr_file)
print(usrs_info)
except FileNotFoundError:
with open('usrs_info.pickle', 'wb') as usr_file:
print('2')
usrs_info = {'admin':'admin'}
pickle.dump(usrs_info, usr_file)#序列化
print('OK')
print('usr_name:',usr_name)
if usr_name in usrs_info:
print('3')
if usr_password == usrs_info[usr_name]:
tk.messagebox.showinfo(title='Welcome',message='How are you'+usr_name)
#销毁窗口
window.destroy()
subprocess.Popen(["python", "lx.py"])
else:
tk.messagebox.showinfo(message='Error,your password is wrong,try again')
else:
print('4')
is_sign_up = tk.messagebox.askyesno(title='Welcome',message='You have not sign up yet.Sign up today')
if is_sign_up:
usr_sign_up()
def usr_sign_up():
print('开始注册')
def sign_up():
#获取输入
nn = label_title1.get()
np = label_title2.get()
npf = label_title3.get()
#读取后台数据
with open('usrs_info.pickle', 'rb') as usr_file:
exist_usr_info = pickle.load(usr_file)
#判断两次输入的密码是否一致
if np != npf:
tk.messagebox.showerror('错误','Password and confire must be the same!')
elif nn in exist_usr_info:
print('已经注册过了')
tk.messagebox.showerror('错误','The user has already signed up!')
else:
exist_usr_info[nn] = np
with open('user_info.pickle', 'wb') as usr_file:
pickle.dump(exist_usr_info, usr_file)
tk.messagebox.showinfo('Welcome','You have successfully signed up!')
window_sign_up.destroy()
window_sign_up = tk.Toplevel(window)
window_sign_up.title("Sign up window")
window_sign_up.geometry("380x230")
t1 = tk.Label(window_sign_up, text="User name:")
t1.place(x=30, y=20)
label_title1 = tk.Entry(window_sign_up, bd=2)
label_title1.place(x=180, y=20)
t2 = tk.Label(window_sign_up, text="Password:")
t2.place(x=30, y=60)
label_title2 = tk.Entry(window_sign_up, bd=2)
label_title2.place(x=180, y=60)
t3 = tk.Label(window_sign_up, text="Confirm password:")
t3.place(x=30, y=100)
label_title3 = tk.Entry(window_sign_up, bd=2, show='*')
label_title3.place(x=180, y=100)
btn_comfirm_sign_up = tk.Button(window_sign_up, text='Sign up', command=sign_up)
btn_comfirm_sign_up.place(x=150, y=130)
btn_sign_up=tk.Button(window,text='Sign up',command=usr_sign_up)
btn_sign_up.place(x=350,y=250)
btn_login=tk.Button(window,text='Login',command=usr_login)
btn_login.place(x=180,y=250)
window.mainloop()
2.游戏界面
import tkinter as tk
import random
from tkinter import messagebox#显示提示框
foot = 0
step = 0#初始化步数为0,用于轮流切换玩家
root = tk.Tk()
root.title("九宫格")
root.geometry("400x450")
#第一个玩家使用的标记为”X“
first_player = "X"
gameover = False#初始化游戏结束标志为False,当游戏结束时,这个标志会变为True。
board = [' '] * 9#创建一个长度为9的列表,用于表示九宫格的每个格子,初始时所有格子都为空格字符。
def draw_board():
canvas.create_line(2, 2, 300, 2, width=2) # 上#在画布上创建一条从(2, 2)到(300, 2)的线,线宽为2像素,这条线是棋盘的顶部边框。
canvas.create_line(2, 2, 2, 300, width=2) # 左
canvas.create_line(2, 300, 300, 300, width=2) # 下
canvas.create_line(300, 2, 300, 300, width=2) #
canvas.create_line(100, 0, 100, 300)#在画布上创建一条垂直线,将棋盘分为两半,线宽为默认值(通常是1像素)。
canvas.create_line(200, 0, 200, 300)
canvas.create_line(0, 100, 300, 100)
canvas.create_line(0, 200, 300, 200)
num = 1#初始化一个变量num,用于在棋盘格子上绘制数字1到9。
for i in range(3):#开始一个循环,循环3次,代表棋盘的行
for j in range(3):#在每个行的内部,再开始一个循环,循环3次,代表棋盘的列。
y = i * 100 + 50#计算当前格子中心点的y坐标
x = j * 100 + 50#计算当前格子中心点的x坐标
canvas.create_text(x, y, text=str(num), font=("Arial", 24))#在画布上创建文本,文本内容用NUM的字符串表示,位置在(X,Y)
num += 1#将num的值增加1,以便在下一次循环中绘制下一个数字
def on_click():#定义了一个名为on_click的函数,它会在用户点击九宫格游戏界面时被调用。函数的主要作用是处理用户的输入,更新游戏状态,并在画布上绘制玩家的标记。
global step
global board#board#为一个全局变量,它是一个列表,用于存储九宫格中每个位置的玩家标记
position = label_title1.get()
#从名为label_title1的Tkinter组件中获取用户的输入,这个输入应该是用户想要落子的位置(1到9之间的数字)
if position.isdigit() and 1 <= int(position) <= 9:
#检查position是否是一个数字,并且这个数字在1到9之间。
number = int(position)#将position转换成整数,因为他是以字符串的形式输入的
index = number - 1#计算在board列表中的索引位置,因为列表索引从0开始,所以要-1
if board[index] == ' ':#检查所选位置是否为空
board[index] = 'x'#在board列表中更新玩家的标记为X,表示这个位置现在被玩家占据了
x = ((int(position) - 1) % 3) * 100 + 50
y = ((int(position) - 1) // 3) * 100 + 50
canvas.create_line(x - 20, y - 20, x + 20, y + 20, fill='pink', width=2)
canvas.create_line(x + 20, y - 20, x - 20, y + 20, fill='pink', width=2)
step += 1
winner()
if not gameover:
ai_move()
else:
messagebox.showerror("错误", "该位置已经落子,请选择其他位置")
#敌方落子
def ai_move():
global board, foot
index = random.randint(0, 8)
while board[index] != ' ':
index = random.randint(0, 8)
x = ((index) % 3) * 100 + 50
y = ((index) // 3) * 100 + 50
canvas.create_oval(x - 20, y - 20, x + 20, y + 20, fill='pink')
board[index] = 'AI'
foot += 1
winner()
def problem():
try:
input_value = int(label_title1.get())#尝试将一个标签(label)组件的内容转换为整数。
if input_value < 1 or input_value > 9:
messagebox.showerror("错误", "请输入1到9之间的数字")
else:
print("输入正确")
except ValueError:
messagebox.showerror("错误", "请输入一个有效的数字")
on_click()
def winner():
global step
global gameover
#判断所给棋子是否获胜
# 定义获胜的组合
wins = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
# 检查是否有获胜组合
for r in wins:
if (board[r[0]] != " " and board[r[0]] == board[r[1]] == board[r[2]]):
gameover = True
messagebox.showinfo(title="提示",message='赢得是'+board[r[0]])
return
if step > 5:
gameover = True
messagebox.showinfo(title="shuchu", message="平手")
return
# #重新开始
def again():
global step
global gameover
gameover = False
canvas.delete("all")
draw_board()
canvas = tk.Canvas(root, bg='white', height=300, width=300)
canvas.pack()
draw_board()
t1 = tk.Label(root, text="请输入要落子的位置(1-9):")
t1.place(x=110, y=310)
label_title1 = tk.Entry(root, bd=5)
label_title1.place(x=110, y=340)
botton_1 = tk.Button(root, text="按下落子",command=on_click)
botton_1.place(x=110, y=370)
botton_2 = tk.Button(root, text="重新开始",command=again)
botton_2.place(x=200,y=370)
root.mainloop()