宋晓丽 20190919-6 四则运算试题生成,结对

我怕爱的太早我们不能终老 提交于 2019-11-30 12:27:09

此作业的要求参见[https://edu.cnblogs.com/campus/nenu/2019fall/homework/7631]

代码的git地址[https://e.coding.net/sxl357/f4.git]

git地址下的功能1.py和功能1.exe用来完成功能1,f4.py和f4.exe用来完成功能2和功能3.

功能1. 四则运算

支持出题4个数的四则运算题目,所有题目要求作者有能力正确回答

> f4
1+2*3+4=
?11
答对啦,你真是个天才!
1+2*3+5=
?11
再想想吧,答案似乎是12喔!
1+2/4-5=
?-3.5
答对啦,你真是个天才!
...(一共20道题)

你一共答对4道题,共20道题。重难点:1.给定一个运算式,如何让计算机算出结果?给定的运算式属于中缀表达式,将其改为后缀表达式,再计算结果。(1)中缀转后缀
#将中缀表达式转为后缀表达式
def make_Expression(s):
    operations=[]
    result=''
    front={'+':1,'-':1,'*':2,'/':2}
    for i in s:
        if i in ['+','-','*','/']:#判断是否是操作符
            if len(operations)==0:#栈空,直接入栈
                 operations.append(i)
            elif front[operations[-1]]>=front[i]:#判断栈顶元素和操作符的优先级别
                while len(operations)>0 and front[operations[-1]]>=front[i]:#持续将栈顶元素弹出并输出,直至遇到低于或等于此操作符的优先级别
                    p=operations.pop()
                    result+=p
                operations.append(i)
            else:
                operations.append(i)
        else:
            result+=i#若是数,直接输出
    while len(operations)>0:#将栈中的所有元素依次弹出
        p=operations.pop()
        result+=p
    return result#返回后缀表达式

(2)计算后缀表达式

#计算后缀表达式
def make_Value(s):
    lists=[]
    for i in s:
        if i in ['+','-','*','/']:
            b=float(lists.pop())#先弹出的是b,下个弹出的是a
            a=float(lists.pop())
            c=0
            if i=='+':#判断做哪则运算
                c=a+b
            elif i=='-':
                c=a-b
            elif i=='*':
                c=a*b
            else:
                c=a/b
            lists.append(c)#得到的结果压入栈中
        else:
            lists.append(i)
    return lists[0]

2.如何随机生成运算式(3个运算符,4个操作数)?

这对于我们来说是个大问题,查资料,询问 师哥师姐,了解到random.randint(a,b)用于生成一个指定范围内的整数n

 

#随机生成运算式
from random import randint #random.randint(a,b)用于生成一个指定范围内的整数n,其中a<=n<=b
# 定义类
class Expression:
    # 生成运算式
    def expre(self):#在类里定义函数必须传入self,指的是类实例对象本身
        exp = []
        for j in range(0,7):  #range(a)=[0,1,2,3,...,a-1]
            if j % 2 != 0:#通过模2,生成带3个运算符4个10以内数字的表达式
                operators = ['+', '-', '*', '/']
                exp.append(operators[randint(0, len(operators) - 1)])  #随机生成运算符
            else:
                exp.append(str(randint(1, 9)))  #随机生成操作数
        expression = ''.join(exp)
        return expression

 

generate=Expression() #定义对象
expression = generate.expre()#调用generate()函数,生成运算式

3.如何循环出题,并验算结果,给出反馈?

先生成运算式,然后调用转后缀,计算后缀的函数 ,得到正确结果,与用户输入的对比,给出反馈,循环20次,并利用全局变量累积答对的题的数目。

#出20道考题,判断用户结果是否等于正确答案,实现功能一
def question():
    num = 0
    global correctNumber  # 定义全局变量,统计答对的次数
    while num <20:
        generate=Expression() #定义对象
        expression = generate.expre()#调用generate()函数,生成运算式
        print(expression + "=")
        expression1 = make_Expression(expression)  # 将中缀表达式转换为后缀表达式
        result = make_Value(expression1)  # 计算后缀表达式的值
        userAnswer = input()  # 输入你的答案
        if '?' in userAnswer:
            userAnswer = userAnswer.replace('?', '')#str.replace(old,new,max)方法,把字符中的old替换成new,且替换不超过max次
        if (float(userAnswer) == float(result)):  # 判断用户结果是否和正确答案相等
            correctNumber += 1
            print("答对了,你真是个天才!")
        else:
            result = str(result)
            print('再想想吧,答案似乎是' + result + '喔!')
        num += 1
    correctNumber = str(correctNumber)
    print("你一共答对" + correctNumber + "道题,共20道题。")

4.如何定义此时的主函数?

#定义主函数
def main(argv):
        question()#实现功能一


#主函数
if __name__ == "__main__":
    main(sys.argv[1:])

运行测试截图

 

功能2 支持括号

> f4
1+2*(3+4)=
?15
答对啦,你真是个天才!
(1+2)*3+5=
?11
再想想吧,答案似乎是14喔!
((1/2)-4)*5=
?-17.5
答对啦,你真是个天才!
...(一共20道题)

你一共答对4道题,共20道题。

重难点

1.中缀转后缀时,有括号怎么办?

左括号可以直接入栈,但遇到右括号时,遇到右括号,持续将栈顶元素弹出并输出,直至遇到左括号

 

 for i in s:
        if i in ['+','-','*','/','(',')']:#判断是否是操作符
            if i=='(':#遇到左括号,将其直接放入栈中
                operations.append(i)
            elif i==')':#遇到右括号,持续将栈顶元素弹出并输出,直至遇到左括号
                while (len(operations)>0 and operations[-1]!='(' ):#-1表示列表的最后一个元素,即栈顶
                    p=operations.pop()
                    result+=p
                operations.pop()#左括号只弹出不输出
            elif len(operations)==0:#栈空,直接入栈
                 operations.append(i)
            elif front[operations[-1]]>=front[i]:#判断栈顶元素和操作符的优先级别
                while len(operations)>0 and front[operations[-1]]>=front[i]:#持续将栈顶元素弹出并输出,直至遇到低于或等于此操作符的优先级别
                    p=operations.pop()
                    result+=p
                operations.append(i)
            else:
                operations.append(i)
        else:
            result+=i#若是数,直接输出

2.何时何地生成括号?

在生成运算式的类中,生成了不带括号的运算式后,随机生成0或1,0就表示不插入括号,1表示插入括号,此时调用生成括号的函数,在该函数中,用枚举法确定括号的位置,然后根据随机数选择其中一种,将括号插入,最后返回带括号的表达式。

  is_need_brackets = randint(0, 1) # 判断是否要括号
        if is_need_brackets:#添加括号
            expression = ''.join(self.make_brackets(exp))#.join()将序列中的元素以指定的字符连接生成一个新的字符串
                                                                #加括号时,调用生成括号表达式的函数,得到一个带括号的运算式
        else:#不添加括号
            expression = ''.join(exp)
# 生成括号表达式
    def make_brackets(self,exp):#传入由运算符和数字组成的列表
        expression = []
        # 可能有一对括号,也可能有两对括号,所以最多有11个位置可以添加括号
        #经过枚举,共有10种可能的添加方式
        # 0表示直接将运算符或数字传入生成式,1表示在生成式加入左括号,2表示在生成式加入右括号,-1表示不作任何处理
        judge_position= [
                              [1, 0, 0, 0, 2, 0, 0, 0, 0, -1, -1],
                              [1, 0, 0, 0, 0, 0, 2, 0, 0, -1, -1],
                              [0, 0, 1, 0, 0, 0, 2, 0, 0, -1, -1],
                              [0, 0, 1, 0, 0, 0, 0, 0, 2, -1, -1],
                              [0, 0, 0, 0, 1, 0, 0, 0, 2, -1, -1],
                              [1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 2],
                              [1, 1, 0, 0, 0, 2, 0, 0, 2, 0, 0],
                              [1, 0, 0, 1, 0, 0, 0, 2, 2, 0, 0],
                              [0, 0, 1, 1, 0, 0, 0, 2, 0, 0, 2],
                              [0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 2]
                          ]
        position = randint(0,9)
        if exp:
            i = 0
            for j in judge_position[position]:#调用上述列表
                if j ==0:
                    expression.append(exp[i])
                    if i < len(exp):
                        i += 1
                elif j ==1:
                    expression.append('(')
                elif j ==2:
                    expression.append(')')
        return expression

运行测试截图

 

 

 

 

功能3 限定题目数量,"精美"打印输出,避免重复

 

>f4 -c 3
1+2*(3+4)=                     15
(1+2)*3+5=                     14
((1/2)-4)*5=                   17.5
>f4 -c -200
题目数量必须是 正整数。
>f4 -c 3.5
题目数量必须是 正整数。
>f4 -c test
题目数量必须是 正整数。重难点1.如何规范化输出?
print('%-15s %-15s' % (expression, result))  # 规范输出格式

2.循环体

# 答案与题目横向对齐,使输出规范化,实现功能三
def normal(num):
    i = 0
    while i < num:
        generate = Expression()
        expression = generate.expre()
        expression1 = make_Expression(expression)  # 将中缀表达式转换为后缀表达式
        result = make_Value(expression1)  # 计算后缀表达式的值
        expression=expression+"="
        print('%-15s %-15s' % (expression, result))  # 规范输出格式
        i += 1

3.如何与功能2区分?

在主函数中判断‘-c’是否在输入的命令行参数里,在则功能3,否则功能2.

4.如何在输入的命令行参数是负数或者小数时报错?

 count=float(sys.argv[2]) # 获取生成题目的个数
        if count >=1:
            normal(count)

5.主函数

#定义主函数
def main(argv):
    if '-c' in sys.argv:  # 实现功能三
        count=float(sys.argv[2]) # 获取生成题目的个数
        if count >=1:
            normal(count)
        else:
            print("题目数量必须是正整数。")
    else:
        question()#实现功能一二


#主函数
if __name__ == "__main__":
    main(sys.argv[1:])

运行测试截图

 

 

 

 

 

 

 

 

总结

完成这个作业真的是花了很多功夫,因为自己的无知,很多时间都是在做无效的工作,但通过这次学习,我更加清楚了自己的弱势所在,更明白了该怎么去学习,谢谢前面人的工作,使我的学习有迹可循,在此特别感谢我的结对小伙伴梁梦瑶,能在我无比焦躁时安慰我的情绪,和我一起学习,一起努力。

 

 

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!