• 用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/
    • 本文版权归作者和博客园共有,欢迎转载、交流,但未经作者同意必须保留此段声明,且在文章明显位置给出原文链接。
    
    
  • 相关阅读:
    学习之路-前端-笔记-一、HTML笔记
    抄写例题作业1
    郭霖
    java遍历HashMap的高效方法
    Add Two Numbers II 两个数字相加之二
    基于socket的简单p2p聊天项目
    SimpleScalar Course Project
    Dijkstra Java
    PCA vs Linear Regression 可视化理解
    机器学习中的范数规则化之(一)L0、L1与L2范数
  • 原文地址:https://www.cnblogs.com/cwp-bg/p/7630166.html
Copyright © 2020-2023  润新知