用python的TK模塊實現猜成語游戲(附源碼)


說明:本游戲使用到的python模塊有tkinter,random,hashlib;整個游戲分為四個窗口,一個進入游戲的窗口、一個選關窗口、一個游戲進行窗口和一個游戲結束的窗口。

源碼有兩個主要的py文件,mygame.py和setting.py,mygame文件是游戲的主文件,所有的代碼邏輯在該文件;setting模塊存放游戲的一些資源,如問題、答案、提示等;

player_answers.txt文件用來記錄玩家已經回答過的關卡。

游戲規則:
  玩家點擊按鈕進入游戲窗口后,通過點擊屏幕下方的按鍵輸入問題的答案,

  答案正確則會生成進入下一關的按鈕,否則無法進入下一關。

游戲擴展:1.目前游戲暫定30關,玩家可自由地添加關數,無需修改任何代碼;
2.在setting模塊中按照三個字典的格式直接往里添加新的關數的數據即可,在if __name__ == "__main__"中
有str1和str2兩個變量用來對答案加密和對鍵盤上的字進行亂序操作。

實現的功能:1.對所有答案都使用了md5算法加密;源碼中無明文答案;
2.支持自由選關的操作;
3.支持返回上一關的操作;
4.支持答案提示操作,提示最多為一個字;
5.自動永久記錄已經回答正確的問題,其選關按鈕會由紅色變成綠色;如果想要重置,運行
mygame模塊if __name__ == "__main__"中注釋的代碼或直接修改player_answers.txt文件,
將里面所有的數據置為0.
游戲界面圖:



代碼說明:
一、選擇關卡的界面的按鈕:

 1 __author__ = {'author': 'caiwanpeng',
 2               'Email': '626004181@qq.com',
 3               'Blog': 'http://www.cnblogs.com/cwp-bg/',
 4               'Created': '2017-09-25',
 5               'Version': '1.1'}
 6 
 7 
 8 class ButtonSelect(object):
 9     """創建選擇關卡的按鈕"""
10 
11     def __init__(self, win, num, game_screen, elements, player_answer):
12         self.win = win
13         self.name = tk.StringVar(self.win)
14         self.sum_sc = len(dict_problems)
15         self.num_sc = num
16         self.start_game = game_screen
17         self.eles = elements
18         self.player_answer = player_answer
19 
20     def set_name(self, value):
21         """設置按鈕的數值"""
22         self.name.set(value)
23 
24     def set_bg(self):
25         """設置按鈕的背景色"""
26         if self.player_answer == "1":
27             return "green"
28         return "red"
29 
30     def create_button(self, place=(0, 0)):
31         """創建按鈕"""
32         button = tk.Button(self.win, textvariable=self.name,
33                            command=self._select_sc,
34                            bg=self.set_bg(), fg="black",
35                            activebackground="orange",
36                            font=("宋體", 16, "bold"))
37         button.place(width=40, height=40,
38                      relx=0.1 + place[0] * 0.8,
39                      rely=0.1 + place[1] * 0.9)
40         return button
41 
42     def _select_sc(self):
43         """選擇按鈕響應函數"""
44         #  改變窗口記錄的關數值
45         self.num_sc[0] = int(self.name.get())
46         #  清除界面所有的元素
47         try:
48             for ele in self.eles:
49                 ele.destroy()  # 刪除所有的元素
50         except Exception as re:
51             print(re)
52         self.eles.clear()  # 清空記錄
53         #  加載游戲窗口
54         self.start_game()
 
        

 

二、輸入答案的鍵盤按鈕:
 1 class ButtonNew(object):
 2     """創建鍵盤按鈕"""
 3 
 4     def __init__(self, wins, v1, v2, result, screen_num, bg='red',
 5                  fg="green", height=1, width=3,
 6                  font=("宋體", 20, "bold")):
 7         self.win = wins
 8         self.v1 = v1
 9         self.v2 = v2
10         self.v_name = tk.StringVar(self.win)  # 一個顯示按鈕文字的標簽
11         self.results = result
12         self.screen_num = screen_num  # 獲得目前的關卡數
13         # 相關屬性
14         self.bg = bg
15         self.fg = fg
16         self.height = height
17         self.width = width
18         self.font = font
19 
20     def create_button(self, place_b=(0, 0)):
21         """鍵盤按鈕"""
22         # 創建按鈕,按鈕上的標簽內容,command點擊按鈕執行函數,bg背景顏色,fg標簽顏色
23         key_answer = tk.Button(self.win, textvariable=self.v_name,
24                                command=lambda: self._button_event(self.v_name.get()),
25                                activebackground="blue",
26                                bg=self.bg, fg=self.fg,
27                                height=self.height,
28                                width=self.width, font=self.font)
29         # 設置按鈕的位置
30         key_answer.place(x=place_b[0], y=place_b[1])
31         return key_answer
32 
33     def _button_event(self, name1):
34         """創建一個點擊按鈕響應的函數"""
35         # 先清空v2標簽
36         self.v2.set("")
37         if len(self.v1.get()) < 4:  # 小於成語的長度
38             self.results.append(name1)
39         else:
40             self.results.clear()
41 
42         result = ""
43         for i in self.results:  # 拼接字符串
44             result += i
45         self.v1.set(result)
46 
47         # 判斷答案是否正確
48         if abt.the_answer is True:
49             abt.the_answer = False
50         password = dict_result[str(self.screen_num[0])]
51         if len(self.results) >= 4 and self.get_md5(result) == password:
52             abt.the_answer = True  # 將答案開關設置為正確
53             # print(abt.the_answer)
54 
55     @staticmethod
56     def get_md5(str1):
57         """對st1字符串MD5加密"""
58         return hb.md5(str1.encode("utf-8")).hexdigest()
 
        

 

三、游戲的主窗口:
  1 class GameWindow(object):
  2     """創建游戲運行窗口並加載相關的控件"""
  3 
  4     def __init__(self):
  5         """初始化窗口"""
  6         # 創建一個根窗口
  7         self.win = tk.Tk()
  8         self.win.title("史上最污猜成語")  # 標題
  9         self.win.geometry("500x500+500+100")  # 設置尺寸
 10         self.win.resizable(width=False, height=False)  # 寬高不可變
 11         self.v1 = tk.StringVar(self.win)  # 顯示答案的標簽
 12         self.v2 = tk.StringVar(self.win)  # 答案是否正確的標簽
 13         self.v_screen = tk.StringVar(self.win)  # 顯示下一關的標簽
 14         self.v_problems = tk.StringVar(self.win)  # 一個顯示問題的可變標簽
 15         self.results = []  # 創建一個記錄答案長度的變量
 16         self.eles = []  # 創建一個記錄界面元素的列表
 17         self.list_button = []  # 存放鍵盤可變文字對象
 18         self.screen_num = [1]  # 記錄當前是第幾關,使用可變類型將地址引用
 19         self.sum_screen = len(dict_problems)  # 獲取當前的總關卡數
 20         self.player_answers = self.player_answer()  # 記錄目前已回答的關數的情況
 21 
 22     def create_label(self):
 23         """創建窗口所有的標簽"""
 24         # 標簽顯示第幾關
 25         dir1 = tk.Label(self.win, bg="yellow", textvariable=self.v_screen,
 26                         fg="blue", font=("宋體", 20, "bold"))
 27         dir1.pack(side=tk.TOP, fill=tk.X)
 28         self.eles.append(dir1)
 29         # 創建一個標簽"答案"
 30         dir2 = tk.Label(self.win, bg="red", text="答案:",
 31                         font=("宋體", 20, "bold"))
 32         dir2.place(x=0, y=200)  # 位置坐標控制
 33         self.eles.append(dir2)
 34         # 創建一個換行標簽
 35         dir3 = tk.Label(self.win, bg="#00F000", textvariable=self.v_problems,
 36                         wraplength=400, justify="left",
 37                         fg="blue", font=("宋體", 20, "bold"), height=4)
 38         dir3.pack(fill=tk.X)
 39         self.eles.append(dir3)
 40         # 一個空白的標簽等待用戶輸入答案
 41         dir4 = tk.Label(self.win, bg="green", textvariable=self.v1,
 42                         font=("宋體", 20, "bold"))
 43         dir4.place(x=100, y=200)
 44         self.eles.append(dir4)
 45         # 一個空白標簽顯示答案錯誤時
 46         dir5 = tk.Label(self.win, textvariable=self.v2, fg="red",
 47                         font=("宋體", 12, "bold"))
 48         dir5.place(x=100, y=240)
 49         self.eles.append(dir5)
 50 
 51     def create_button(self):
 52         """創建游戲窗口所有的按鈕"""
 53         # 采用嵌套循環創建4*8個按鈕
 54         for j in range(4):
 55             for g in range(8):
 56                 button1 = ButtonNew(self.win, v1=self.v1,
 57                                     v2=self.v2, result=self.results,
 58                                     screen_num=self.screen_num)
 59                 # 設置按鈕的位置
 60                 key_b = button1.create_button(place_b=(30 + g * 54, 280 + j * 45))
 61                 self.list_button.append(button1.v_name)  # 將每一個標簽加入列表
 62                 self.eles.append(key_b)  # 所有的按鈕加入列表
 63         self._set_key(self.screen_num[0])  # 設置相應關數的值
 64 
 65         # 創建一個用來清除答案的按鈕
 66         cls = tk.Button(self.win, text="清除", command=self._cls_function,
 67                         bg="black", fg="white", font=("宋體", 16, "bold"))
 68         cls.place(x=250, y=200)
 69         self.eles.append(cls)
 70         # 創建一個用來提示答案的按鈕
 71         pmt = tk.Button(self.win, text="提示",
 72                         command=lambda: self._prompt_button(self.screen_num[0]),
 73                         bg="red", fg="white", font=("宋體", 16, "bold"))
 74         pmt.place(x=320, y=200)
 75         self.eles.append(pmt)
 76         # 創建一個用來確定答案的按鈕
 77         istrue = tk.Button(self.win, text="確定", command=self._ensure_button,
 78                            bg="red", fg="white", font=("宋體", 16, "bold"))
 79         istrue.place(x=390, y=200)
 80         self.eles.append(istrue)
 81         # 創建一個返回上一關的按鈕
 82         last_sc = tk.Button(self.win, text="上一關", command=self._last_sc_button,
 83                             bg="red", fg="white", font=("宋體", 16, "bold"))
 84         last_sc.place(x=250, y=155)
 85         self.eles.append(last_sc)
 86         # 創建一個返回選關窗口的按鈕
 87         return_button = tk.Button(self.win, text="返回選關", command=self._return_lock,
 88                                   bg="red", fg="white", font=("宋體", 16, "bold"))
 89         return_button.place(x=10, y=155)
 90         self.eles.append(return_button)
 91 
 92     def before_screen(self):
 93         """創建一個進入游戲的窗口所有元素"""
 94         # 空白標簽
 95         label1 = self.the_label()
 96         # 標簽顯示"史上最污猜成語"
 97         label2 = self.the_label("史上最污猜成語")
 98         # 空白標簽
 99         label3 = self.the_label()
100         # 顯示淡綠色背景
101         label4 = self.the_label(font=("宋體", 250, "bold"), bg="#00ee00")
102         # 顯示作者“天宇之游”
103         dirx = tk.Label(self.win, bg="#00ee00", text="----天宇之游",
104                         fg="blue", font=("宋體", 20, "bold"))
105         dirx.place(x=250, y=200)
106         list_labels = [label1, label2, label3, label4, dirx]
107         # 創建一個進入游戲的按鈕
108         go_game = tk.Button(self.win, text="開啟污旅程",
109                             command=lambda: self._start_game(go_game, *list_labels),
110                             bg="red", fg="white", activebackground="yellow",
111                             activeforeground="red", font=("宋體", 30, "bold"))
112         go_game.place(x=130, y=300)
113 
114     def lock_screen(self):
115         """創建一個展示所有的關卡及關卡解鎖的窗口"""
116         # 空白區域
117         dir_k = tk.Label(self.win, bg="#3b9dff", font=("宋體", 20, "bold"))
118         dir_k.pack(fill=tk.X)
119         self.eles.append(dir_k)
120         # 顯示相關信息
121         dir1 = tk.Message(self.win, bg="blue", text="選擇關卡",
122                           fg="red", font=("宋體", 20, "bold"),
123                           width=200)
124         dir1.pack(fill=tk.X)
125         self.eles.append(dir1)
126         # 創建一塊畫布,所有的元素都放置在畫布上
127         cans = tk.Canvas(self.win,  # 根窗口
128                          bg="#92dba0",  # 設置畫布的顏色
129                          height=500,
130                          borderwidth=0)
131         cans.pack(fill=tk.X)
132         self.eles.append(cans)  # 添加到列表便於刪除
133 
134         for i in range(self.sum_screen):  # 按照已有的關卡數生成相應的按鈕數量
135             j = i % 10 / 10.0
136             k = i // 10 / 10
137             # 傳入當前的關數和加載游戲窗口的函數
138             bn_st = ButtonSelect(cans, self.screen_num,
139                                  self._game_go, self.eles,
140                                  self.player_answers[i])
141             bn_st.create_button(place=(j, k))
142             bn_st.set_name(str(i + 1))
143 
144     def after_screen(self):
145         """一個游戲結束的畫面窗口"""
146         self.the_label()  # 空白標簽
147         text1 = "恭喜你!"
148         text2 = "成功晉升為老司機!"
149         # 標簽顯示結束語
150         self.the_label(text1)
151         self.the_label(text2)
152         self.the_label()  # 空白標簽
153         # 創建一個結束的按鈕
154         go_game = tk.Button(self.win, text="再見!",
155                             command=lambda: exit(),
156                             bg="red", fg="white",
157                             activebackground="yellow",
158                             activeforeground="red",
159                             font=("宋體", 30, "bold"))
160         go_game.place(x=170, y=300)
161 
162     def the_label(self, text=None, side=tk.TOP,
163                   font=("宋體", 40, "bold"), bg="green"):
164         """創建顯示標簽"""
165         dir1 = tk.Label(self.win, bg=bg, text=text,
166                         fg="black", font=font)
167         dir1.pack(side=side, fill=tk.X)
168         return dir1
169 
170     def _return_lock(self):
171         """返回選擇關卡的界面"""
172         # 清空標簽
173         self.list_button.clear()
174         # 清除界面的所有元素
175         self.clear_screen()
176         # 清空元素記錄列表
177         self.eles.clear()
178         # 將關數記錄還原到1
179         self.screen_num[0] = 1
180         # 調用界面創建函數
181         self.screen_control(1)
182 
183     def clear_screen(self):
184         """清除界面所有元素的函數"""
185         try:
186             for ele in self.eles:
187                 ele.destroy()  # 刪除所有的元素
188         except Exception as re:
189             print(re)
190 
191     def _set_key(self, num):
192         """設置所有的按鍵變量的值"""
193         listx = rm.sample(dict_key[str(num)], len(dict_key[str(num)]))  # 打亂順序
194         #  設置所有的鍵盤上的文字
195         for j, k in enumerate(self.list_button):
196             k.set(listx[j])  # 獲取文字設置按鍵值
197 
198     def _next_screen(self):
199         """當答案正確時生成下一關的按鈕"""
200         # 創建一個用來確定答案的按鈕
201         next_b = tk.Button(self.win, text="下一關", command=lambda: self._next_button(next_b),
202                            bg="red", fg="white",
203                            font=("宋體", 16, "bold"))
204         next_b.place(x=390, y=155)
205         return next_b
206 
207     def _next_button(self, next_b):
208         """當點擊下一關按鈕時響應函數"""
209         try:
210             # 判斷是否已經是最后一關
211             if self.screen_num[0] >= len(dict_problems):
212                 # print("這已經是最后一關")
213                 # 清除界面所有的元素
214                 self.clear_screen()
215                 # 加載游戲結束的界面
216                 self.screen_control(3)
217             else:
218                 if abt.the_answer is True:
219                     self.__update_screen()  # 更新窗口
220                 else:
221                     self.v2.set("答案錯誤!")
222 
223             # 將上一關的選關按鈕變為綠色
224             self.player_answers[self.screen_num[0] - 2] = "1"
225             # 同時將當前的數據同步到文件
226             file = open("./player_answers.txt", "w")
227             file.write("".join(self.player_answers))  # 轉化成字符串
228         except Exception as re:
229             print(re)
230         else:
231             # 刪除按鈕本身
232             next_b.destroy()
233         finally:
234             file.close()
235 
236     def _last_sc_button(self):
237         """上一關按鈕的響應函數"""
238         # 判斷目前是不是第一關
239         if self.screen_num[0] == 1:
240             self.v2.set("這是第一關!")
241         else:
242             self.screen_num[0] -= 2  # 減少一關
243             self.__update_screen()
244 
245     def __update_screen(self):
246         """更新窗口的的函數"""
247         # 顯示問題
248         self.v_problems.set(dict_problems[str(self.screen_num[0] + 1)])
249         self.screen_num[0] += 1  # 指針指向下一關
250         # 改變關數的標簽
251         self.v_screen.set("" + str(self.screen_num[0]) + "")
252         # 更新所有的按鍵值
253         self._set_key(self.screen_num[0])
254         # 清除v1和v2標簽的內容
255         self._cls_function()
256         self.v2.set("")
257         # print("成功執行!")
258 
259     def _start_game(self, *args):
260         """進入游戲的響應函數"""
261         try:
262             for ele in args:
263                 ele.destroy()  # 刪除所有的元素
264         except Exception as re:
265             print(re)
266         self.screen_control(num=1)  # 進入選關界面
267 
268     def _game_go(self):
269         str_num = str(self.screen_num[0])
270         self.v_screen.set("" + str_num + "")  # 設置第幾關標簽
271         self.v_problems.set(dict_problems[str_num])  # 設置問題
272         self.screen_control(2)  # 進入游戲界面
273 
274     def _cls_function(self):
275         """清除按鈕響應事件函數"""
276         self.results.clear()
277         self.v1.set("")  # 清空標簽
278 
279     def _ensure_button(self):
280         """確定開關的事件函數"""
281         if abt.the_answer is True:
282             self.v2.set("答案正確!")
283             self._next_screen()  # 在窗口創建一個按鈕
284         else:
285             self.v2.set("答案錯誤!")
286 
287     def _prompt_button(self, key):
288         """提示開關的事件函數"""
289         if abt.the_answer is True:  # 將可能打開的開關關閉
290             abt.the_answer = False
291         self.results.clear()  # 先清空原來的答案
292         self.results.append(list_answer[int(key)])  # 加入提示
293         self.v1.set(list_answer[int(key)])  # 設置提示答案
294 
295     def screen_control(self, num=0):
296         """創建一個窗口控件顯示的控制函數"""
297         if num == 0:
298             self.before_screen()  # 開始顯示游戲進入界面
299         elif num == 1:
300             self.lock_screen()  # 進入選關界面
301         elif num == 2:
302             self.create_label()  # 傳入所有可變的參數創建所有的標簽
303             self.create_button()  # 傳入空白標簽對象創建所有的按鈕
304         elif num == 3:
305             self.after_screen()  # 進入游戲結束界面
306 
307     def run(self):
308         self.win.mainloop()  # 窗口運行
309 
310     def player_answer(self):
311         """更新記錄的玩家回答的狀態"""
312         # 獲取目前的總關數
313         number1 = self.sum_screen
314         try:
315             # 讀取文件中的關數信息,如果數目不變則不更新文件,改變則初始化文件
316             f = open("./player_answers.txt", "r")
317             str3 = f.read()
318             # print(str3)
319         except Exception as re:
320             print(re)
321         finally:
322             f.close()
323 
324         if number1 == len(str3):
325             return list(iter(str3))
326         else:  # 初始化
327             str2 = "0" * number1
328             try:
329                 f1 = open("./player_answers.txt", "w")
330                 f1.write(str2)  # 更新信息
331             except Exception as re:
332                 print(re)
333             finally:
334                 f1.close()
335             return list(iter(str2))
336 
337 
338 win = GameWindow()
339 sc = win.screen_control
340 bs = win.before_screen
341 as_ = win.after_screen
342 ls = win.lock_screen
343 run = win.run
344 
345 
346 def main():
347     sc()
348     run()  # 游戲運行
349 
350 
351 if __name__ == "__main__":
352     main()
353     # 初始化記錄文件
354     # str2 = "0"*len(dict_key)
355     # f1 = open("./player_answers.txt", "w")
356     # f1.write(str2)  # 更新信息
357     # f1.close()
 
         
         
        

 

四、游戲的setting模塊。
數據資源見源碼包。
 1 class AllButton(object):
 2     """創建一個開關類管理所有的開關便於以后的擴展"""
 3 
 4     def __init__(self):
 5         self.the_answer = False  # 設置答案是否正確的開關
 6         self.cls_answer = False  # 設置清空答案的開關
 7         self.start_game = False  # 進入游戲的開關
 8 
 9 
10 abt = AllButton()
11 
12 if __name__ == "__main__":
13     print(len(dict_key))
14     str1 = ""  # 用來生成加密的答案
15     md5_answer = hb.md5(str1.encode("utf-8")).hexdigest()
16     print(md5_answer)  # 得到加密的答案
17     str2 = ""
18     results = rm.sample(str2, len(str2))
19     results = "".join(results)
20     print(results)  # 得到亂序后的字列

游戲源碼下載:https://files.cnblogs.com/files/cwp-bg/game_one.zip

碼雲
地址:https://gitee.com/TianYuZhiYou/guess_the_chengyu
  • 作者:天宇之游
  • 出處:http://www.cnblogs.com/cwp-bg/
  • 本文版權歸作者和博客園共有,歡迎轉載、交流,但未經作者同意必須保留此段聲明,且在文章明顯位置給出原文鏈接。
 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM