1,操作数随机生成,包含整数和真分数
2,运算符的种类的顺序随机生成
3,能判断对错并计分
4,生成的题目数量可以控制
以及四个附加要求:
1,运算符的个数随机生成
2,根据题目难度分配分值
4,防止题目重复
首先考虑基本要求:根据用户输入的题目数量,随机生成字符串,打印出来就能得到一个题目,由于要与用户输入的答案比较,所以应当知道这个字符串的值是多少。而题目是操作数与操作符交错的,只要确定了操作符,然后插入随机的操作数就能得到一个题目。
考虑附加要求1:把运算符存在一个列表中,然后随机生成序号,取出对应的运算符就好
考虑附加要求2:用题目的长短(操作符的个数)和乘除法占的多少来衡量一个题目难易与否,把难度量化,根据难度分配分值,满分默认为100分
考虑附加要求4:把所有已生成的题目都存起来,每得到一个新题目,就到题库里去比,如果重复就重新生成一个新题目。
三,设计实现过程
基本功能点:
用户交互得到题目数量与运算范围:首先由用户决定需要多少题以及操作符的运算范围是多大,使程序的适用性更强
随机生成操作符:把所有的操作符都存在一个列表中,例如【‘+’,‘-’,‘*’,‘/’】,然后随机从中抽取。后来考虑到小学运算的难度,我调整了加减号和乘除号的比例,为2:1。即建立一个【‘+’,‘-’,‘+’,‘-’,‘*’,‘/’】列表,然后从中随机抽取操作符
随机生成操作数:首先获取一个在(1,2)中的随机整数,如果为1,则返回一个整数,如果为2,则返回一个真分数,保证了操作数的随机性。与调整操作符种类比例类似,可以调整操作数的范围来改变返回整数与真分数的比值。返回整数直接在操作数运算范围中随机得到一个就行,如果是返回真分数,可以获取两个随机数。python有一个Fraction类可以进行分数的数值运算和自动约分。
随机得到题目(包含运算符个数随机生成):首先在(1~10)中随机获取操作符的个数,这也确定了题目的长度。然后调用已经得到的随机获取操作符和随机获取操作数的函数,交错得到一道题目。
把题目写入txt文件中:每得到一道新题就写一道新题,便于后续查看与打印。当前只能写题,后续将开发把题目,参考答案和回答答案、每题的对错和对应的分数全部写入,即打印成绩单。
计算题目的答案:这部分困扰我最久。我把一道题目存在一个列表中,列表中的元素是操作数或者操作符。比如:
【‘5’,‘+’,‘1/2’,‘*’,‘4’,‘-’,‘2’】
在没有括号的情况下,乘除运算先于加减。于是我从左到右遍历这个列表,如果有乘除号,那么使用乘除号和前后的两个操作数进行一次乘除运算,把结果赋给前一个操作数,并删除操作符和后一个操作数:
【‘5’,‘+’,‘2’,‘-’,‘2’】
做完所有的乘除法后,就用前三个元素做加减运算,同样把值赋给前一个操作数,并删除操作符和下一个操作数:
【‘7’,‘-’,‘2’】
直到列表只剩最后一个元素:
【‘5’】
这个数就是表达式的答案。
但是我这种有一个很明显的缺点,就是无法处理包含括号的字符串运算。
题目判重:用一个列表存题,每生成一道题目就去题库中比较一次,如果不一样就添加到题库中,如果一样就重新随机生成。
根据用户输入判断答题对错:到这里已经得到了题目和答案,分别用两个列表存储。如果用户的输入与答案相符,输出“回答正确!”,反之输出“回答错误!”
根据题目难易分配分值:首先是量化难易度。回溯到随机操作符和操作数的时候,如果随机得到了一个加减号,则认为难度+1,乘除号,则难度+2;如果随机得到一个整数,则难度+1,真分数,则难度+1.5。在随机生成题目的时候,设置初始难度为0,每得到一个操作数和一个操作符就把难度累加起来,得到一个难度的判据。把难度也可以存在一个列表中。所有的题目可以累加得到一个总难度,根据每一题的难度占总难度的比值就可以换算为百分制的分数。每做对一题,就把获得的分数加起来,得到一个初始分数。当前代码使用整数表示分数,当题目过多时,可能出现每一题都是零分的情况,后续应当修改为浮点数。
grade=(grade*time_limite)/time_use
来调整分数
四,代码说明
算法思路已经在第三部分讲解得比较详细了,这一部分主要用注释来说明。
1,随机生成操作符:
defgetoperators():operatorslist=('+','-','*','/','+','-')#在列表中调整四种运算符出现的比值operators=random.choice(operatorslist)#从列表中随机选一个元素,保证了随机性ifoperators=='*':#乘除号难度赋值为2length=2elifoperators=='/':length=2else:length=1#加减号难度赋值为1returnoperators,length#返回操作符与其难度
2,随机生成操作数:
defgetoperands(range):operandstype=random.randint(1,2)#得到一个随机数,确定返回的数据类型degree=0#难度初始化为0ifoperandstype==1:#返回整数,有三个参数:字符串,用于打印与显示;数值,用于计算;难度,用于分配分数operands=random.randint(1,range)operandsvalue=Fraction(operands,1)#整数可以看做是一个分母为1的分数,统一为fraction格式可以方便后面的数值运算operands=str(operands)#字符串degree=1#整数难度为1else:#返回真分数operands1=random.randint(1,range)#得到两个随机数operands2=random.randint(1,range)degree=1.5#真分数难度为1.5ifoperands1 3,随机得到题目: symbolnumber=random.randint(1,5)#随机得到操作符的个数,题目要求是1~10,这里是1~5,原理一样question=''#每一题用字符串存questionstack=[]#用列表存下题目的每一个操作数和操作符,以用自定义的方法计算答案ans=0#用于后文计算答案,初始化为0length_ques=0#用于后文分配分值,初始化难度为0 foriinrange(1,symbolnumber+1):#根据有多少个操作数,逐一得到操作数与操作符(op,va,de)=getoperands(ran)operands=op#传递字符串value=va#传递数值(operators,length)=getoperators()question=question+operands+operatorsquestionstack.append(value)#生成列表questionstack.append(operators)length_ques=length_ques+length+de#难度累加(op,va,de)=getoperands(ran)operands=opvalue=vaquestion=question+operands#得到了一道题目questionstack.append(value)#得到了便于计算答案的题目的列表格式length_ques=length_ques+de#难度累加 4,计算答案: condition=0#条件,乘除法计算完毕时变为1whilelen(questionstack)>1:#计算至最后一个元素foriinrange(0,len(questionstack)):ifquestionstack[i]=='*':#先算乘除,questionstack[i-1]=questionstack[i-1]*questionstack[i+1]#一次运算并赋值delquestionstack[i]#删除元素delquestionstack[i]breakelifquestionstack[i]=='/':questionstack[i-1]=questionstack[i-1]/questionstack[i+1]delquestionstack[i]delquestionstack[i]breakelse:condition=1#表示乘除法已经计算完毕ifcondition==1:iflen(questionstack)>1:questionstack[0]=calculate(questionstack[0],questionstack[2],questionstack[1])#始终在前三位进行运算,意思是从左到右执行加减法delquestionstack[1]delquestionstack[1]else:ans=questionstack[0]#最后剩下的元素就是答案 5,题目查重: questionfile=file('questionlist.txt','w')#准备把题目写入txt#根据输入的题目个数生成题目清单,每一个新生成的题会与现有题进行比较,重复不则重新生成#将生成的题目写入文件中,便于查看与打印whilelen(questionlist) 6,根据权重分配分值: foriinrange(0,len(lengthlist)):scorelist.append(round(lengthlist[i]*100/totalscore))#totalscore是总难度,每一题的难度占比转换为百分制的分数 7,判断对错: foriinrange(0,questionnumber):#总共有questionnumber道题print'第',i+1,'题是:'printquestionlist[i],'='print'分值为',scorelist[i],'分'print'答案是:',anslist[i]ans_user=raw_input('请输入你的答案:')print'您的答案是:',ans_userifans_user==str(anslist[i]):print'回答正确!'grade=grade+scorelist[i]#答对的分值累加起来,得到初始成绩else:print'回答错误!' 五,测试运行 展示两个运行结果 一: 二: 同时,题目已经被写入到txt文件里: 六,项目小结 总的来说,本次项目的要求均已完成。由于本次项目不复杂,在编代码之前就能够很清晰的想清楚该做些什么。遇到的最大的困难是对python语言不熟悉,很多功能不清楚。 psp表格已经在博客的开头给出了,代码复审和单元测试还没有进行,后续会学习,尽快培养出良好的软件开发习惯。