24点游戏实现(合作完成)

前言

  这是我进入大学的第一个制作项目,代码极其不规范且存在很多问题,请不要直接进行复制运行,存在诸如绝对路径等问题难以解决。

  这是一个合作项目,合作人有:彭力韬,唐金,曹浩然

 

 

1.游戏实现的基本功能

(1)设计相应的游戏积分功能,以给出题目到游戏者输入结果之间的时间记分。超过一定的时间未给出答案则取消该轮,每轮10次,记总分(10次分相加)前十名。

 

(2)游戏参与者进入游戏必须先输入名称,游戏开始后,程序随机自动生成四张牌,游戏者要求尽快给出表达式,只能使用 + - × % 运算。可以使用(),不涉及小数运算。提交结果正确加十分,否则不加分并进入下一题。若无解则点击无解按钮,正确则加十分,否则不加分。如此玩10次后,计算总分并存入文件。任何一次在要求时间内不能给出表达式或无解,则进入下一题。

 

(3)可根据选择的难度不同,每一轮的时间也不同

 

(4)可判别玩家输入的算式的值是否等于24点

 

(5)可使用三次请求支援,给出这四个数字是否可以构成24点

 

2.需求分析

 

 

 

(1)提供人性化且简介明了的游戏开始界面。游戏开始界面需要包含用户名输入框,用户名登入按钮,难易度选择按钮、排行榜查询按钮以及开始游戏按钮。

 

(2)提供易于操作的游戏界面按钮。游戏界面按钮包含随机抽取的扑克牌,算式显示框、无解按钮、运算按钮、提交按钮以及只能使用3次的请求支援按钮以及结束按钮

 

(3)提供可根据难易度发生变化的计时器

 

(4)设计能够匹配包含括号的24点运算式子的算法

 

(5)设计能够读取写入并且自动排行的排行榜

 

 

 

3.概要设计

主要存储结构

 

# 创建开始游戏GUI界面
def start_game():
    # 创建开始游戏窗口
    top = Tk()
    top.title('开始游戏')
    top.geometry('480x400')
    # 添加背景
    bg_img = PhotoImage(file=r'C:\Users\SF-TS\Desktop\Python\background2.gif')
    Label(image=bg_img).pack()

    # 添加难易度选择标签
    v = IntVar()
    rad_easy = Radiobutton(top, text='简单', width=4, height=1, variable=v, value=1, font=('黑体', 16),command=lambda: difficultbutton('简单'))
    rad_normal = Radiobutton(top, text='普通', variable=v, value=2, width=4, height=1, font=('黑体', 16),command=lambda: difficultbutton('普通'))
    rad_hard = Radiobutton(top, text='困难', variable=v, value=3, width=4, height=1, font=('黑体', 16),command=lambda: difficultbutton('困难'))

    # 游戏难度标签位置
    rad_easy.place(x=330, y=150)
    rad_normal.place(x=330, y=200)
    rad_hard.place(x=330, y=250)

    # 添加控件函数
    add_widgets_1(top)

    # 锁定界面长宽比
    top.wm_resizable(width=False, height=False)

top.mainloop()

 

 

主要函数流程

(1)开始界面创建函数:用于创建游戏的开始界面,并录入游戏者的姓名以及提供积分榜前十名的查询

 

 

 

(2)控件添加函数函数:为界面添加控件提供相应的功能

 

 

 

(3)结束游戏函数:

 

 

 

4.源代码

from random import randint
from tkinter import *
from itertools import permutations
from time import sleep
import threading
import operator

# 设置全局变量
control = 0  # 点击开始游戏打开新窗口
count = 0  # 记录所做题目总数
var_time = 0  # 倒计时时间
dif = 0  # 选定困难难度
score = 0  # 记录分数
ID = None  # 用户名默认为空


# 创建开始游戏GUI界面
def start_game():
    # 创建开始游戏窗口
    top = Tk()
    top.title('开始游戏')
    top.geometry('480x400')
    # 添加背景
    bg_img = PhotoImage(file=r'C:\Users\SF-TS\Desktop\Python\background2.gif')
    Label(image=bg_img).pack()

    # 添加难易度选择标签
    v = IntVar()
    rad_easy = Radiobutton(top, text='简单', width=4, height=1, variable=v, value=1, font=('黑体', 16),
                           command=lambda: difficultbutton('简单'))
    rad_normal = Radiobutton(top, text='普通', variable=v, value=2, width=4, height=1, font=('黑体', 16),
                             command=lambda: difficultbutton('普通'))
    rad_hard = Radiobutton(top, text='困难', variable=v, value=3, width=4, height=1, font=('黑体', 16),
                           command=lambda: difficultbutton('困难'))

    # 游戏难度标签位置
    rad_easy.place(x=330, y=150)
    rad_normal.place(x=330, y=200)
    rad_hard.place(x=330, y=250)

    # 添加控件函数
    add_widgets_1(top)

    # 锁定界面长宽比
    top.wm_resizable(width=False, height=False)

    top.mainloop()


# 给开始界面添加控件
def add_widgets_1(frame):
    # 销毁开始游戏界面

    global dif

    def new_win():
        global control
        control = True
        frame.destroy()

    # 添加游戏题目标签
    lab_name = Label(frame, text='24点小游戏闯关', width=25, height=1, font=('黑体', 25), bg='#EBF5DF', fg='#35081D')

    # 添加开始游戏标签
    btn_start = Button(frame, text='开始游戏', command=new_win, width=11, height=1, font=('黑体', 16),
                       state=DISABLED)  # 开始游戏按钮

    # 添加登陆标签
    expression = Text(frame, width=20, height=1, bg='#EBF5DF', fg='#35081D', font=('楷体', 20))
    btn_login = Button(frame, text='登陆用户名', width=10, height=1, font=('黑体', 16),
                       command=lambda: input_char1('登陆用户名', expression, btn_start))

    # 添加游戏说明标签
    lab_exp = Label(frame, width=34, height=14, font=('黑体', 12), bg='#EBF5DF', fg='#35081D',
                    text='输入您的用户名点击登陆,选择难度\n'
                         '并且开始您的愉快游戏吧!\n\n'
                         '游戏开始后您将获得四张随机的扑克\n'
                         '牌,请利用四则运算法则将四张扑克\n'
                         '牌数值进行组和,使算式合理并且计\n'
                         '算的结果为24点即可获得积分,每轮\n'
                         '游戏共有十道题为您呈现,答对一题\n'
                         '获得10分,答错不给分。欢迎来到惊\n'
                         '险刺激的24点游戏!')
    # 添加排行榜按钮
    btn_score = Button(frame, text='排行榜', command=lambda: input_char1('排行榜', expression, btn_start), font=('黑体', 16))

    # 标签位置
    lab_name.place(x=20, y=10)
    expression.place(x=20, y=100)
    btn_login.place(x=330, y=97)
    lab_exp.place(x=20, y=150)
    btn_score.place(x=330, y=300)
    btn_start.place(x=330, y=350)


# 游戏难度选定功能
def difficultbutton(char):
    global dif
    if char == '简单':
        dif = 1
    elif char == '普通':
        dif = 2
    elif char == '困难':
        dif = 3


# 开始游戏按钮功能
def input_char1(char, expression, the_button):
    global dif, ID
    # 将获取到的用户名写进文件里
    if char == '登陆用户名':
        with open(r'C:\Users\SF-TS\Desktop\Python\board.txt', 'a') as f:
            try:
                if expression.get('1.0', '1.end') == r'C:\Users\SF-TS\Desktop\Python\board.txt':
                    f.write('匿名')
                    ID = '匿名'
                    the_button.config(state=NORMAL)
                else:
                    f.write(expression.get('1.0', '1.end'))
                    ID = expression.get('1.0', '1.end')
                    the_button.config(state=NORMAL)
            finally:
                f.close()
        expression.delete('1.0', END)
        expression.insert('1.end', '登入成功!')
    # 设置难度系数
    elif char == '排行榜':
        score = Tk()
        score.title('排行榜')
        score.geometry('400x200')
        score.wm_resizable(width=False, height=False)
        index()
        with open(r'C:\Users\SF-TS\Desktop\Python\board.txt', 'r') as f:
            for i in range(10):
                line = f.readline()
                name = '%s' % (line)
                Label(score, text=name,bg = '#F5F5DC').place(x=0, y=i * 20)
        Label(score, text=''+ str(i+1) +'',bg = '#F5F5DC').place(x=150, y=i * 20)            f.close()
        score.mainloop()
    else:
        pass


# 创建游戏GUI界面
def game():
    win = Tk()  # 创建界面
    # 给标签添加背景
    bg_img = PhotoImage(file=r'C:\Users\SF-TS\Desktop\Python\background1.gif')
    new_game = Label(win, image=bg_img)  # 在界面上添加标签,并赋予背景
    new_game.pack(fill=BOTH, expand=1)  # 标签填充
    add_widgets_2(new_game)  # 在标签上添加控件
    win.title('24点小游戏闯关')  # 界面标题
    win.geometry('480x700')  # 界面大小
    win.wm_resizable(width=False, height=False)  # 锁定界面长宽比

    # 添加倒计时标签,时间归零自动开始下一题
    lab_time = Label(new_game, text='', width=15, height=1, font=('黑体', 16))
    lab_time.place(x=40, y=650)

    def times():
        global var_time
        for i in range(750, -1, -1):
            if var_time != 0:
                var_time -= 1
            else:
                add_widgets_2(win)
            lab_time['text'] = '剩余时间:' + str(var_time) + ''
            sleep(1)

    t = threading.Thread(target=times)
    t.start()

    # 循环界面
    win.mainloop()


# 给游戏界面添加控件
def add_widgets_2(frame):
    global ID
    poker_number = rand_number()  # 扑克牌数值
    poker_color = ['meihua', 'fangkuai', 'hongtao', 'heitao']  # 扑克牌花色
    poker_path = []  # 扑克牌路径
    for i1, i2 in zip(poker_color, poker_number):
        poker_path.append(r'C:\Users\SF-TS\Desktop\Python\poke\sucai\%s%d.gif' % (i1, i2))  # 构建扑克牌路径

    result = test24(poker_number)  # 能算出24点的算式

    # 添加扑克牌图片
    global img1, img2, img3, img4, lab_img1, lab_img2, lab_img3, lab_img4
    img1 = PhotoImage(file=poker_path[0])
    img2 = PhotoImage(file=poker_path[1])
    img3 = PhotoImage(file=poker_path[2])
    img4 = PhotoImage(file=poker_path[3])
    lab_img1 = Label(frame, image=img1)
    lab_img2 = Label(frame, image=img2)
    lab_img3 = Label(frame, image=img3)
    lab_img4 = Label(frame, image=img4)
    # 添加显示框控件
    expression = Text(frame, width=39, height=2, bg='#EBF5DF', fg='#35081D', font=('楷体', 15))
    # 添加四个数值按钮
    poker_1 = Button(frame, text=poker_number[0], width=6, height=2, font=('黑体', 16),
                     command=lambda: input_char2(poker_number[0], result, expression, btn_tijiao,
                                                 btn_no))  # lambda使得可以给函数input_char传递参数poker_number[],result和expression
    poker_2 = Button(frame, text=poker_number[1], width=6, height=2, font=('黑体', 16),
                     command=lambda: input_char2(poker_number[1], result, expression, btn_tijiao, btn_no))
    poker_3 = Button(frame, text=poker_number[2], width=6, height=2, font=('黑体', 16),
                     command=lambda: input_char2(poker_number[2], result, expression, btn_tijiao, btn_no))
    poker_4 = Button(frame, text=poker_number[3], width=6, height=2, font=('黑体', 16),
                     command=lambda: input_char2(poker_number[3], result, expression, btn_tijiao, btn_no))

    # 添加四则运算按钮
    btn_jia = Button(frame, text='+', width=6, height=2, font=('黑体', 16),
                     command=lambda: input_char2('+', result, expression, btn_tijiao, btn_no))
    btn_jian = Button(frame, text='-', width=6, height=2, font=('黑体', 16),
                      command=lambda: input_char2('-', result, expression, btn_tijiao, btn_no))
    btn_cheng = Button(frame, text='*', width=6, height=2, font=('黑体', 16),
                       command=lambda: input_char2('*', result, expression, btn_tijiao, btn_no))
    btn_chu = Button(frame, text='/', width=6, height=2, font=('黑体', 16),
                     command=lambda: input_char2('/', result, expression, btn_tijiao, btn_no))
    # 添加括号、撤销、清除、重新开始、请求支援等按钮
    btn_kuohao_1 = Button(frame, text='(', width=6, height=2, font=('黑体', 16),
                          command=lambda: input_char2('(', result, expression, btn_tijiao, btn_no))
    btn_kuohao_2 = Button(frame, text=')', width=6, height=2, font=('黑体', 16),
                          command=lambda: input_char2(')', result, expression, btn_tijiao, btn_no))
    btn_delete = Button(frame, text='撤销', width=6, height=2, font=('黑体', 16),
                        command=lambda: input_char2('撤销', result, expression, btn_tijiao, btn_no))
    btn_clear = Button(frame, text='清除', width=6, height=2, font=('黑体', 16),
                       command=lambda: input_char2('清除', result, expression, btn_tijiao, btn_no))
    btn_no = Button(frame, text='无解', width=10, height=3, font=('黑体', 16),
                    command=lambda: input_char2('无解', result, expression, btn_tijiao, btn_no))
    # 下一题按钮点击后调用addWidgets函数,重新生给界面生成新的控件,并且刷新全局变量的值
    global var_time, dif
    if dif == 3:
        var_time = 25
    elif dif == 2:
        var_time = 50
    else:
        var_time = 75
    # 设置只能点十次下一题
    global count, score
    btn_next = Button(frame, text='下一题\n\n已做' + str(count) + '', width=13, height=3, font=('黑体', 16),
                      command=lambda: add_widgets_2(frame))
    if count < 10:
        btn_next['state'] = 'normal'

    else:
        btn_next['state'] = 'disabled'
        if count == 10:
            f = open(r'C:\Users\SF-TS\Desktop\Python\board.txt', 'a')
            print(score)
            f.write('     ' + str(score) + '\n')
            f.close()
    count += 1  # 点击一次,count+1

    btn_tijiao = Button(frame, text='提交', width=6, height=8, font=('黑体', 16),
                        command=lambda: input_char2('提交', result, expression, btn_tijiao, btn_no))

    # 设置只能点击后就不能提交的查看答案按钮
    btn_help = Button(frame, text='查看答案', width=10, height=3, font=('黑体', 16),
                      command=lambda: input_char2('查看答案', result, expression, btn_tijiao, btn_no))
    # 用户名标签
    lab_name = Label(frame, text=ID, width=15, height=1, font=('黑体', 16))
    # 结束游戏的按钮
    btn_end = Button(frame, text='结束游戏', width=10, height=3, font=('黑体', 16), command=lambda: end(score))
    # 设置控件的布局
    lab_img1.place(x=10, y=20)
    lab_img2.place(x=125, y=20)
    lab_img3.place(x=240, y=20)
    lab_img4.place(x=355, y=20)

    expression.place(x=40, y=200)

    poker_1.place(x=40, y=280)
    poker_2.place(x=120, y=280)
    poker_3.place(x=200, y=280)
    poker_4.place(x=280, y=280)

    btn_jia.place(x=40, y=343)
    btn_jian.place(x=120, y=343)
    btn_cheng.place(x=200, y=343)
    btn_chu.place(x=280, y=343)

    btn_kuohao_1.place(x=40, y=406)
    btn_kuohao_2.place(x=120, y=406)
    btn_delete.place(x=200, y=406)
    btn_clear.place(x=280, y=406)

    btn_tijiao.place(x=360, y=280)

    btn_help.place(x=40, y=490)
    btn_no.place(x=162, y=490)

    btn_next.place(x=284, y=490)

    lab_name.place(x=40, y=600)
    btn_end.place(x=317, y=600)


# 结束游戏
def end(score):
    global count
    if count<11:
        f = open(r'C:\Users\SF-TS\Desktop\Python\board.txt', 'a')
        f.write('     ' + str(score) + '\n')
        f.close()
    exit()


# 游戏界面按钮功能
def input_char2(char, result, expression, btn_tijiao, btn_no):
    global score
    # 清除键功能
    if char == '清除':
        expression.delete('0.0', END)  # 清除内容
    # 撤销键功能
    elif char == '撤销':
        expressionview = expression.get('1.0', '1.end')  # 光标定位到最后一位
        expression.delete('1.0', END)  # 删除最后一位
        expression.insert('1.end', expressionview[:-1])  # 光标向前移动一位
    # 请求支援功能
    elif char == "查看答案":
        if result:
            expression.delete('1.0', END)
            expression.insert('1.0', result[0][0])
        else:
            expression.delete('1.0', END)
            expression.insert('1.0', '不能构成24点哦!')
        btn_tijiao['state'] = 'disabled'
        btn_no['state'] = 'disabled'

    # 无解功能
    elif char == '无解':
        # answer为判断数,0为无解,1为有解
        answer = 0
        if result:
            answer = 1
        if answer == 0:
            expression.insert('1.0', '\n恭喜您,回答正确!按重新开始进行下一轮')
            score += 10
        else:
            expression.insert('1.0', '\n很遗憾,回答错误!按重新开始进入下一轮')
    # 排行榜功能
    elif char == '排行榜':
        score = Tk()
        score.title('排行榜')
        score.geometry('400x200')
        score.wm_resizable(width=False, height=False)

    # 其余键功能为插入对应字符
    elif char != '提交':
        expression.insert('1.end', char)
    # 等于号功能
    try:
        if char == "提交":
            result = expression.get('1.0', '1.end')  # 获取文本框最后一个字符的值
            expression.insert('1.end', '=%d' % (eval(result)))  # 在 "=" 后面插入结果,结果为eval函数计算的值
            if eval(result) == 24:  # 结果正确返回信息
                expression.insert('1.end', '\n恭喜您,运算正确!按重新开始进行下一轮。')
                score += 10
            else:
                expression.insert('1.end', '\n回答错误')
            btn_tijiao['state'] = 'disable'

    except:
        expression.insert('1.end', '\n输入错误!请检查你的算式是否合理')


def rand_number():  # 随机四张扑克牌函数
    result = [randint(1, 10) for j in range(4)]
    return result



#排序
def index():
    f = open(r'C:\Users\SF-TS\Desktop\Python\board.txt','r')#文件打开
    inf_content = f.readlines()#行读取
    list_temp = []#暂定列表
    list_name = []#名字列表
    for each in inf_content:#除去空格
        list_temp.append(each.split('     '))
    for i in range(len(list_temp)):
        list_temp[i][1] = int(list_temp[i][1])
    list_temp = sorted(list_temp, key=operator.itemgetter(1), reverse=True)#排序
    f.close()
    dict_temp = dict(list_temp)#字典
    f = open(r'C:\Users\SF-TS\Desktop\Python\board.txt','w')#清空源文件
    for name in dict_temp:
        f.write(str(name)+'     '+str(dict_temp[name]) + '\n')
    f.close()



# 24点算法
def test24(poker_number):
    # 4个数字和两个运算符可能组成的表达式
    exps = ('%s %s %s %s %s %s %s',
            '(%s %s %s) %s %s %s %s',
            '%s %s (%s %s %s) %s %s',
            '%s %s %s %s (%s %s %s)',
            '((%s %s %s) %s %s) %s %s',
            '(%s %s %s) %s (%s %s %s)',
            '%s %s (%s %s (%s %s %s))')
    ops = '+-*/'

    result = []

    # Python允许函数的嵌套定义
    # 这个函数对字符串表达式进行求值并验证是否等于24
    def check(exp):
        try:
            # 有可能会出现0异常,所以放到异常处理结果中
            return eval(exp) == 24
        except:
            return False

    # 全排列,枚举4个数的所有可能顺序
    for a in permutations(poker_number):
        # 查找4个数的当前排列能实现24的表达式
        t = [exp % (a[0], op1, a[1], op2, a[2], op3, a[3]) for op1 in ops for op2 in ops for op3 in ops for exp in exps
             if check(exp % (a[0], op1, a[1], op2, a[2], op3, a[3]))]
        if t:
            result.append(t)
    return result


# 主函数
if __name__ == '__main__':
    # 创建开始游戏窗口
    start_game()

    # 创建游戏窗口,同时销毁开始游戏窗口
    if control:
        game()
View Code

 

5.结果

 

 

 

 

 

posted @ 2022-01-11 21:44  sftsgly  阅读(237)  评论(0编辑  收藏  举报