使用 Python3 实现翻牌游戏(记忆游戏)
欢迎阅读这篇博文,我们将讨论一个名为 Flip! 的趣味游戏的实现,该游戏使用 Python 开发。Flip! 是一款在 4x4 网格上翻转瓦片以显示其颜色的游戏。游戏的目标是在尽可能少的步数内翻转所有瓦片。在这篇文章中,我们将逐步介绍使用 Python 实现该游戏的过程,并解释代码的不同组成部分。
语法
以下软件包用于此代码:
itertools - 该软件包提供函数,以更简单的方式迭代集合。
tkinter - 该软件包为游戏提供图形用户界面 (GUI)。
random - 该软件包提供函数来生成随机数。
ctypes - 该软件包提供对低级 Windows 函数的访问。
由于这些软件包都是 Python 默认库的一部分,因此无需额外安装。
算法
按下按钮时,按钮的颜色会显示出来,并将其与之前按下的按钮的颜色进行比较。
如果两种颜色匹配,则按钮保持翻转状态,并更新玩家的分数。如果两种颜色不匹配,则按钮翻转回来,并且玩家的分数不会改变。
游戏持续进行,直到所有按钮都被翻转过来,程序将玩家的最高分保存在名为 maxscore.txt 的文本文件中。
在游戏结束时,将玩家的分数与其最高分进行比较,如果玩家的分数更高,则更改文件中的最高分。
按下按钮会导致按钮的白色背景发生变化,以显示下面的颜色。
当连续按下相同颜色的两个按钮时,它们会保持翻转状态。连续按下两个不同颜色的按钮,它们会翻转回来。
所有按钮都翻转后,游戏结束并显示玩家的分数。
玩家翻转按钮的次数决定了他们的分数。
import itertools import tkinter as tk import random import ctypes ctypes.windll.shcore.SetProcessDpiAwareness(1) pressed = -1 tile_flipped = 16 count_move = 0 maxscore = 0 def is_winner(): global maxscore, count_move if tile_flipped == 0: if count_move <= maxscore or maxscore == -1: maxscore = count_move with open('maxscore.txt', 'w') as f: f.write(str(maxscore)) win_lbl['text'] = f'CLICKS: {str(count_move)}, BEST: {str(maxscore)}' def print_count_move(): win_lbl['text'] = f'CLICKS: {str(count_move)}' def new_game(): global pressed, tile_flipped, btns, colours, count_move, win_lbl, maxscore pressed = -1 tile_flipped = 16 count_move = 0 btns = {} win_lbl['text'] = '' # make the file if it doesn't exist try: with open('maxscore.txt', 'r') as f: pass except FileNotFoundError: with open('maxscore.txt', 'w') as f: f.write('-1') with open('maxscore.txt', 'r') as f: maxscore = int(f.readline().strip()) random.shuffle(colours) k=0 for _, _ in itertools.product(range(4), range(4)): btn = Button(k) btns[k] = btn if k!= len(colours)-1: k+=1 k=0 for i, j in itertools.product(range(4), range(4)): btns[k].bttn.grid(row=i, column=j, sticky='nsew') if k!= len(colours)-1: k+=1 class Button: def __init__(self, k): self.index = k self.bttn = tk.Button(frm,width=6, height=2,borderwidth=6, bg='white', activebackground = colours[self.index],command=self.btn_press) def btn_press(self): global pressed, count_move self.bttn.configure(bg=colours[self.index]) count_move += 1 print_count_move() if pressed == -1: pressed = self.index else: self.compare_pressed_btns() def compare_pressed_btns(self): global pressed global tile_flipped if colours[self.index] != colours[pressed]: self.bttn.configure(bg='white') btns[pressed].bttn.configure(bg='white') elif self.index != pressed: self.bttn['state'] = tk.DISABLED btns[pressed].bttn['state']= tk.DISABLED tile_flipped -= 2 is_winner() else: self.bttn.configure(bg='white') pressed = -1 window = tk.Tk() window.title('Flip!') window.config(bg = 'black') window.rowconfigure([0,1],weight=1,pad=2) window.columnconfigure(0,weight =1, pad=2) frm = tk.Frame(window, bg='Gray') frm.grid(row = 0, column=0, sticky='nsew') frm.rowconfigure(list(range(4)), minsize=50, pad=2) frm.columnconfigure(list(range(4)), minsize=50, pad=2) btns = {} colours=['YellowGreen', 'Violet', 'Tomato', 'SlateBlue', 'DarkCyan', 'Orange','DodgerBlue', 'ForestGreen']*2 random.shuffle(colours) frm2 = tk.Frame(window, bg='Khaki') win_lbl = tk.Label(frm2,width=19, height=1,bg='PowderBlue',relief=tk.GROOVE,borderwidth=2) win_lbl.grid(row=0, column=0, padx=5, pady=5, sticky='nsew') new_game_btn = tk.Button(text='NEW GAME', master=frm2, width=10, height=1, borderwidth=3, bg='Plum', command=new_game) new_game_btn.grid(row=0, column=1, padx=5, pady=5, sticky = 'nsew') frm2.grid(row=1, column=0, sticky='nsew') new_game() window.mainloop()
输出
解释
在这个流行的记忆游戏 Flip 的简化版本中,玩家会看到一个按钮网格,每个按钮最初显示为白色,并且 4x4 网格中的每个按钮都隐藏了一个颜色。用户需要在翻转按钮时匹配两个按钮的颜色,直到没有两个按钮剩余为止,游戏结束。
首先导入必要的库,包括用于图形用户界面的 random、itertools、tkinter 和用于 Windows 特定功能的 ctypes。Random 模块用于重新排列按钮的颜色。设置不同的全局变量来跟踪游戏的进度。"pressed" 用于跟踪最近一次按钮按下事件的索引,"tile flipped" 显示匹配了多少个按钮,"count move" 显示进行了多少次移动,而 "maxscore" 显示游戏中的最高分。
is_winner 函数负责检查游戏是否获胜。它检查所有瓦片是否都已翻转,即 tile_flipped 是否等于零,如果是,则检查当前移动次数 count_move 是否小于或等于之前的最高分 maxscore。如果是,则将 maxscore 更新为新的 count_move 并将其写入名为 maxscore.txt 的文件中。最后,它更新 win_lbl 标签的文本以显示当前分数和最高分。
print_count_move 函数更新 win_lbl 标签以显示当前移动次数。
new_game 函数负责重置游戏。它将变量初始化为默认值,清除 win_lbl 标签,并从 maxscore.txt 文件中读取之前的最高分。然后,它对颜色列表进行洗牌,并使用 Button 类创建按钮网格。它还在屏幕上设置按钮的网格布局。
Button 类定义了游戏中每个瓦片的属性和行为。每个按钮都有一个索引值,对应于它在颜色洗牌列表中的位置。它创建一个 tk.Button 对象,其背景颜色为白色,活动背景颜色与其分配的颜色匹配。当按钮被点击时,其背景颜色会更改为其分配的颜色,并且 count_move 会递增。如果按钮是第一个被点击的按钮,则它会将索引值存储在 pressed 变量中。如果是第二个被点击的按钮,则通过调用 compare_pressed_btns 方法将其颜色与第一个按钮的颜色进行比较。如果颜色匹配,则禁用按钮,并且 tile_flipped 计数递减。如果颜色不匹配,则将按钮的背景颜色改回白色。
最后,代码的主体初始化 GUI 窗口,设置其标题和背景颜色,并创建 frm 和 frm2 框架,分别用于容纳游戏板和分数标签以及新游戏按钮。它还创建了 win_lbl 标签和 new_game_btn 按钮并设置其属性。然后,它调用 new_game 函数以开始游戏。最后,它使用 window.mainloop() 进入主事件循环。
应用
这个项目可以展示图形用户界面 (GUI)、按钮和函数的概念;同样,它也作为评估和提高记忆能力的绝佳方式,使用清晰的图形连接点。可以进一步修改游戏以包含各种形状、颜色和图像,使其成为初学者学习如何使用 Python 编程图形用户界面的绝佳项目。
结论
使用 Tkinter 工具包和 Python 3 开发的翻牌游戏既有趣又引人入胜,它是学习 Python GUI 开发的绝佳项目。按钮和函数的使用演示了如何使用编程语言和 GUI 框架创建交互式图形界面,因此可以根据自己的喜好调整此益智游戏,并且是初学者开始学习 Python 编程语言的图形用户界面的好起点。