說明:本游戲使用到的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/
- 本文版權歸作者和博客園共有,歡迎轉載、交流,但未經作者同意必須保留此段聲明,且在文章明顯位置給出原文鏈接。

