百吉饼小游戏
参考文章: Python 小型项目大全 1~5_python 实验项目
环境:
- Python 3.10.3
- tkinter 包
- ttkbootstrap 包
界面样式:百吉饼_哔哩哔哩_bilibili
百吉饼
代码部分:
import tkinter as tk
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from PIL import Image, ImageTk
from tkinter import messagebox
import re
import random
import time
from threading import Thread
# ------------
# 常见配置
# ------------
# 猜的数字个数【暂时只能为3,且取值范围(3,9)】
NUM_DIGITS = 3
# 可以猜的次数
MAX_GUESSES = 4
# 游戏中 OR 新游戏 [不允许修改]
isNewGame = True
# 提示内容: 存储
label_list = []
# 初始化猜数字次数
numGuesses = 1
# 获取秘密数
secretNum = 0
def main():
root = ttk.Window(title="百吉饼",size=(635,470))
#防止用户调整尺寸
root.resizable ( 0, 0)
# ------------
# 放置图标(帮助、设置)
# ------------
placeImage(imgUrl='./help.png',imgSize=(30,30),ix=400,iy=25)
help_text = ttk.Label(text="帮助",font=('黑体',12));
help_text.place(x=440,y=30)
placeImage(imgUrl='./setting.png',imgSize=(30,30),ix=500,iy=23)
setting_text = ttk.Label(text="设置",font=('黑体',12));
setting_text.place(x=535,y=30)
# ------------
# 猜测总数/当前猜测次数
#-------------
# TODO
global currentGuess_text
totalGuess_text = tk.StringVar()
totalGuess_text.set("总次数:" + str(MAX_GUESSES))
totalGuess = ttk.Label(textvariable=totalGuess_text,font=('黑体',12))
totalGuess.place(x=40,y=35)
currentGuess_text = tk.StringVar()
currentGuess_text.set("当前次数:" + str(numGuesses))
currentGuess = ttk.Label(textvariable=currentGuess_text,font=('黑体',12))
currentGuess.place(x=150,y=35)
# ------------
# 放置3个文本框
#-------------
#全局,游戏主体需要
global entry1_text
global entry1
entry1_text = tk.StringVar()
entry1 = tk.Entry(width=4,font=('黑体',50),textvariable=entry1_text,validate="key",validatecommand=(root.register(limitNumber),"%P"))
entry1.grid(row=0,column=0,padx=(40,8),pady=(90,0),ipady=80)
entry1.config(fg='#616161',justify="center")
entry1.bind("<Return>",lambda event : focusEntry(event,1))
global entry2_text
global entry2
entry2_text = tk.StringVar()
entry2 = tk.Entry(width=4,font=('黑体',50),textvariable=entry2_text,validate="key",validatecommand=(root.register(limitNumber),"%P"))
entry2.grid(row=0,column=1,padx=8,pady=(90,0),ipady=80)
# 设置文本颜色和居中代码
entry2.config(fg='#616161',justify="center")
entry2.bind("<Return>",lambda event : focusEntry(event,2))
entry2.bind("<BackSpace>", lambda event : backEntry(event,2))
global entry3_text
global entry3
entry3_text = tk.StringVar()
entry3 = tk.Entry(width=4,font=('黑体',50),textvariable=entry3_text,validate="key",validatecommand=(root.register(limitNumber),"%P"))
entry3.grid(row=0,column=2,padx=(8,25),pady=(90,0),ipady=80)
entry3.config(fg='#616161',justify="center")
entry3.bind('<Return>',startGame)
entry3.bind("<BackSpace>", lambda event : backEntry(event,3))
root.mainloop()
def backEntry(event,num):
""" 回到上一个文本框 """
if num == 2:
# 判断文本框是否输入了数字
# 当为空时,才跳到上一个文本框
if entry2_text.get() == "":
entry1.focus()
elif num == 3:
if entry3_text.get() == "":
entry2.focus()
else:
# 处于第1个文本框
pass
def focusEntry(event,num):
""" 聚焦其他输入框 """
if num == 1:
# 处于第1个文本框
entry2.focus()
elif num == 2:
# 处于第2个文本框
entry3.focus()
else:
# 处于第三个文本框
# 已经进行处理
pass
def startGame(event):
""" 当全部输入数字后,在最后数字上回车,开始游戏 """
if entry1_text.get() != "" and entry2_text.get() != "" and entry3_text.get() != "":
# ------------
# 游戏开始
#-------------
gameBody(isNewGame)
def bind_adaptor(fun,**kwds):
# 没有用....
print("中介...")
print(fun)
return lambda event,fun,kwds=kwds : fun(event,**kwds)
def limitNumber(s: str) -> bool:
""" 限制输入数字 """
s = s.strip()
flag = False
# 长度为 0,无需匹配
if len(s) == 0:
return True
# 匹配规则 [匹配输入的只有1个字符,且在0-9之间]
match_result = re.match(r"[0-9]",s)
if match_result is not None:
# 调用 group() 是匹配成功的字符
# 与原字符相比
# print("验证: ",match_result.group())
# print("验证结果: ",match_result.group() == s)
flag = match_result.group() == s
return flag
def placeImage(imgUrl,imgSize,ix,iy):
# 解决 bug
# 图片不显示问题: 全局变量 垃圾不回收
# 多张图片不显示 引用
global tk_icon
# 从本地加载图片
load_image = Image.open(imgUrl)
# 设置图片大小
load_image = load_image.resize(imgSize)
ref = ttk.Label()
# 加入到 tk 中
ref.tk_icon = ImageTk.PhotoImage(load_image)
# 放到 label 标签里面显示
tk_label = ttk.Label(image=ref.tk_icon)
# 图片放入位置
tk_label.place(x=ix,y=iy)
return tk_label
def getSecretNum():
"""返回唯一随机数字组成的字符串。"""
numbers = list('0123456789')
# 打乱顺序
random.shuffle(numbers)
# 获取秘密数字
secretNum = ''
for i in range(NUM_DIGITS):
secretNum += str(numbers[i])
return secretNum
def getClues(guess, secretNum):
"""提示 red yellow green"""
# ------------
# 放置提示文本
#
# red 输入数字都不正确
# yellow 输入数字正确但位置不对
# green 输入数字正确且位置正确
#
# 两个绿色圈 ===> 有2个输入数字正确且位置正确 【其余情况同理】
#-------------
# 示例 一般动态去创建(根据用户输入数字的情况)
# placeImage(imgUrl='./green.png',imgSize=(30,30),ix=160,iy=398)
# placeImage(imgUrl='./green.png',imgSize=(30,30),ix=185,iy=398)
# clue_text = ttk.Label(text="输入数字都正确",font=('黑体',12))
# clue_text.place(x=230,y=402)
clues = []
for i in range(len(guess)):
if guess[i] == secretNum[i]:
# 正确的数字在正确的位置。
clues.append("green.png")
elif guess[i] in secretNum:
# 正确的数字在错误的位置。
clues.append("yellow.png")
if len(clues) == 0:
# 没有正确的数字。
return ["red.png"]
else:
# 排序,避免泄露信息
clues.sort()
# 用空格将其拼接起来
return clues
def gaveClue(clues):
# 线索放置位置
cluesX = [180,210,240]
tipX = 0
for item in label_list:
item.place_forget()
for i,clue in enumerate(clues):
tk_label = placeImage(imgUrl=clue,imgSize=(30,30),ix=cluesX[i],iy=380)
label_list.append(tk_label)
# load_image = Image.open(clue)
# load_image = load_image.resize((30,30))
# tk_icon = ImageTk.PhotoImage(load_image)
# tk_label = ttk.Label(image=tk_icon)
# tk_label.place(x=cluesX[i],y=380)
tipX = cluesX[i] + 35
tip_text = ""
if "red.png" in clues:
tip_text = "没有数字匹配到"
else:
tip_text = "匹配到了相关数字"
tip_label = ttk.Label(text=tip_text,font=('黑体',12))
tip_label.place(x=tipX,y=385)
label_list.append(tip_label)
def gameBody(isNew: bool):
# 全局变量
global numGuesses
global isNewGame
global secretNum
global currentGuess_text
if isNew:
# 在游戏中
isNewGame = False
# 开始游戏时,创建随机数字
secretNum = getSecretNum()
# 用户输入的数字
guess = ""
guess = entry1_text.get() + entry2_text.get() + entry3_text.get()
while numGuesses <= MAX_GUESSES:
# 判断是否胜利
if guess == secretNum:
# 处理胜利页面,如弹窗,新页面
resultFlag = True
break
# 获取提示
clues = getClues(guess,secretNum)
# 给出提示
gaveClue(clues)
# 如果失败了,将猜测数增加1
numGuesses += 1
# 更新当前次数
currentGuess_text.set("当前次数:" + str(numGuesses))
if numGuesses > MAX_GUESSES:
print("失败了,正确答案: ",secretNum)
resultFlag = False
break
# 这一回合结束,当重新输入3个数,并在最后1个数输入回车时,将会继续下一回合
return;
# 本轮游戏结束
# 清空文本框
gameOver(resultFlag)
entry1_text.set("")
entry2_text.set("")
entry3_text.set("")
# 重新初始化 isNew
isNewGame = True
numGuesses = 1
currentGuess_text.set("当前次数:" + str(numGuesses))
for item in label_list:
item.place_forget()
def gameOver(isSucc: bool):
"""
游戏结束
@param isSucc 是否成功! true : 成功
"""
fg = ""
bg = ""
imgUrl = ""
txt = tk.StringVar()
if isSucc:
# 成功处理逻辑
fg = "#67c23a"
bg = "#f0f9eb"
imgUrl = "tip_succ_msg.png"
txt.set("游戏胜利")
else:
fg = "#f56c6c"
bg = "#fef0f0"
imgUrl = "tip_fail_msg.png"
txt.set("游戏失败")
global img
load_image = Image.open(imgUrl)
load_image = load_image.resize((25,25))
img = ImageTk.PhotoImage(load_image)
pop_tip_label = tk.Label(text=txt.get(),width=160,justify="left",anchor="nw",compound="left",image=img)
pop_tip_label.config(fg=fg,bg=bg,padx=20,pady=10)
pop_tip_label.place(x=210,y=-50)
def move():
for i in range(25):
pop_tip_label.place(x=210,y=i)
time.sleep(0.011)
time.sleep(1.5)
for i in range(24,-50,-1):
pop_tip_label.place(x=210,y=i)
time.sleep(0.011)
t1 = Thread(target=move)
t1.start()
if __name__ == '__main__':
main()
运行代码:
在一个目录下,创建 python 文件,并粘贴上述代码
在 cmd 中运行 python 代码 python 文件名.py
好了,就可以玩了
分类:
Python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2022-04-12 二叉树非递归遍历与层次遍历【Java算法(九)】