MathExamV2.0四则混合运算计算题生成器
MathExamV2.0四则混合运算计算题生成器----211606360 丁培晖 211606343 杨宇潇
一、预估与实际
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
• Estimate | • 估计这个任务需要多少时间 | 60 | 100 |
Development | 开发 | ||
• Analysis | • 需求分析 (包括学习新技术) | 360 | 440 |
• Design Spec | • 生成设计文档 | 20 | 20 |
• Design Review | • 设计复审 | 30 | 40 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 50 |
• Design | • 具体设计 | 120 | 180 |
• Coding | • 具体编码 | 350 | 550 |
• Code Review | • 代码复审 | 90 | 120 |
• Test | • 测试(自我测试,修改代码,提交修改) | 30 | 45 |
Reporting | 报告 | ||
• Test Repor | • 测试报告 | 30 | 30 |
• Size Measurement | • 计算工作量 | 30 | 35 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 60 |
合计 | 1210 | 1670 |
二、需求分析
我通过在网络搜索的方式了解到,小学三年级数学有如下的几个特点:
- 特点1:式子的运算无法得出负数。
- 特点2:数字范围增加,可以得出上千的结果。
- 特点3:除数不能为0。
- 特点4:在一个式子内会使用多个运算符号。
- 特点5:清楚加减乘除算式的优先级,并且明白括号的意思。
- 特点6:式子的结果大小限定在10000以内。
经过分析,我认为,这个程序应当:
- 使用的数字大小应为[0,1000)
- 并且判断除数的数字大小应为[1,1001)
- 生成的符号至少两个,并且至少两种。
三、设计
1. 设计思路
这一次的作业,由于需要使用逆波兰表达式,因此我们使用了和上次作业不同的输入文本的方式,这一次使用的是将字符串转为byte[],然后输入文本的方式。
我们还分出了多中方法体以及构造函数,在主函数main()里调用构造函数,在构造函数内调用各个方法体。(第一次作业只建立了一个方法体,并且在主函数调用,显得代码臃肿,因为将所有的算法都集中在一个方法体内,因此作出改变。)
- 根据题目要求,传入的参数有-n和-grade,因此使用if()判断了参数的-n和-grade的顺序,并建立了一个judge()的方法体,使用正则表达式判断参数的格式。
- 数字需要随机得出,因此需要建立随机数,随机数有多种。
- 随机出来的式子需要写入文本,因此创建了一个TxT()的方法,用于创建文本并将式子输入文本当中,使用String数组进行存储式子,并用Byte[]转换,最后输入文本。
- 答案需要的格式为“等式+答案”,而且不需要小数以及负数,因此将随机数类型定义为整型,并在最后判断答案是否符合要求。
- 判断加减乘除需要使用到优先级,因此创建了一个Level方法,返回值为0,1,2,用于判断符号的优先级。
- 因为三年级的式子为四则混合运算,因此使用中序表达式以及逆波兰,将String数组里的式子转化为线性表,最终调用reckon()方法计算线性表内的式子。并返回最终结果。
2. 实现方案
- 准备工作:先在Github上创建仓库,克隆到本地,并邀请结伴对象,将代码提交到一个仓库内。
- 技术关键点:
- 四则混合运算式子以及括号的判断,需要使用到优先级,因此建立一个关于判断优先级的Level()的方法。
- 使用随机数Random( )时,需要注意随机数生成范围,比如除数不能为0。
- 当式子内有减法,需要判断式子的答案是否大于等于0。
- 使用String数组将式子转换为Byte [] ,并将其全部输入文本。
- 使用正则表达式、Pattern、Matcher判断输入参数是否达标,不达标则提示输入错误,并结束程序。
- 使用 DateFormat( )获取系统当前时间。
四、编码
请说明你如何按照设计思路进行编码,并记录你在开发中遇到的问题,与解决过程
1. 调试日志
记录编码调试的日志,请记录下开发过程中的 debug 历程
- 数据传入栈中,会出现空指针,导致程序不能运行。
解决方案:检查随机数的生成,看随机数是否和判断条件相符合。- 命令行输入格式不对,会出错。
解决方案:通过字符匹配,如果输出格式不对,报错结束进程。- 除法计算,除数生成了0.
解决方案:在生成随机数时+1.- 输入题目个数输入过大,或者输入不是数字,会报错。
解决方案:用正则表达式来判断传入参数是否合理。- 使用逆波兰计算方法不能正确计算。
解决方案:检查传入参数是否正确,写的方法是否正确,使用方法是否正确。
2. 关键代码
请展示一段程序的关键代码,并解释代码的作用
- 通过main函数中String[] args的参数,将其传入构造函数内,并在构造函数中判断出-n与-grade的顺序,并将相应的年级和题目数量传入judge()方法体内,判断输入的格式是否正确。
- 通过了参数格式判断后,将参数传入calculate()和TxT()的方法内。
- 在calculate()判断传入的年级大小后,根据年级大小调用calculate_1(),calculate_2(),calculate_3()。分别对应一年级、二年级、三年级的式子生成方法。
- 使用random()随机生成数字。
- 这一段是调用三年级的式子生成方法。
private void calculate_3(int count) {
int i=0;
while(i<count){
int symbol_number=(int)(Math.random()*5+2); //随机生成数字,用于判断符号个数
int number_1=(int)(Math.random()*1000); //随机生成第一个数字
int number_2=(int)(Math.random()*1000+1); //随机生成第二个数字
int number_3=(int)(Math.random()*1000+1); //随机生成第三个数字
int symbol_1=(int)(Math.random()*4); //随机生成第一个符号
int symbol_2=(int)(Math.random()*4); //随机生成第二个符号
if(symbol_number == 2) {
if(symbol_1==symbol_2) //保证至少有两种运算符号。
{continue;}
if(Level(SymB[symbol_1])<Level(SymB[symbol_2])) { //比较第一个符号和第二个符号的优先级,并添加括号。
QT_1[i]="("+number_1+SymB[symbol_1]+number_2+")"+SymB[symbol_2]+number_3;
QT[i]="( "+number_1+" "+SymB[symbol_1]+" "+ number_2 +" ) "+SymB[symbol_2] +" " +number_3;
}
else if(Level(SymB[symbol_1])>Level(SymB[symbol_2])) {
QT_1[i]=+number_1+SymB[symbol_1]+"(" + number_2 +SymB[symbol_2]+number_3+")";
QT[i]=number_1+" "+SymB[symbol_1]+" ( "+ number_2 +" "+SymB[symbol_2] +number_3+" ) ";
}
else {
QT_1[i]=+number_1+SymB[symbol_1]+number_2+SymB[symbol_2]+number_3;
QT[i]=number_1+" "+SymB[symbol_1]+" "+ number_2 +" "+SymB[symbol_2] +" "+number_3;
}
}
//判断运算符为两个之后,开始判断符号优先级,并在式子里添加括号。
else if(symbol_number == 3) {
if(symbol_1==symbol_2) //保证式子内至少有两种运算符号
{continue;}
int number_4=(int)(Math.random()*1000+1);
int symbol_3=(int)(Math.random()*4);
if(Level(SymB[symbol_1])<Level(SymB[symbol_2])) {
QT_1[i]="("+number_1+SymB[symbol_1]+number_2+")"+SymB[symbol_2]+number_3+SymB[symbol_3]+number_4;
QT[i]="( "+number_1+" "+SymB[symbol_1]+" "+ number_2 +" ) "+SymB[symbol_2] +" " +number_3+" "+SymB[symbol_3]+" "+number_4;
}
else if(Level(SymB[symbol_1])>Level(SymB[symbol_2])) {
QT_1[i]=+number_1+SymB[symbol_1]+"(" + number_2 +SymB[symbol_2]+number_3+")"+SymB[symbol_3]+number_4;
QT[i]=number_1+" "+SymB[symbol_1]+" ( "+ number_2 +" "+SymB[symbol_2] +number_3+" ) "+SymB[symbol_3]+" "+number_4;
}
else if(Level(SymB[symbol_2])>Level(SymB[symbol_3])) {
QT_1[i]=+number_1+SymB[symbol_1]+ number_2 +SymB[symbol_2]+"("+number_3 +SymB[symbol_3]+number_4+")";
QT[i]=number_1+" "+SymB[symbol_1]+" "+ number_2 +" "+SymB[symbol_2] +" ( " +number_3+" "+SymB[symbol_3]+" "+number_4+" ) ";
}
else {
QT_1[i]=+number_1+SymB[symbol_1]+number_2+SymB[symbol_2]+number_3+SymB[symbol_3]+number_4;
QT[i]=number_1+" "+SymB[symbol_1]+" "+ number_2 +" "+SymB[symbol_2] +" "+number_3+" "+SymB[symbol_3]+" "+number_4;
}
}
//判断运算符为三个之后,开始判断符号优先级,并在式子里添加括号。
else if(symbol_number == 4) {
if(symbol_1==symbol_2) //保证式子至少有两种运算符号
{continue;}
int number_4=(int)(Math.random()*1000+1);
int number_5=(int)(Math.random()*1000+1);
int symbol_3=(int)(Math.random()*4);
int symbol_4=(int)(Math.random()*4);
if(Level(SymB[symbol_1])<Level(SymB[symbol_2])) {
QT_1[i]="("+number_1+SymB[symbol_1]+number_2+")"+SymB[symbol_2]+number_3+SymB[symbol_3]+number_4+SymB[symbol_4]+number_5;
QT[i]="( "+number_1+" "+SymB[symbol_1]+" "+ number_2 +" ) "+SymB[symbol_2] +" " +number_3+" "+SymB[symbol_3]+" "+number_4+" "+SymB[symbol_4]+" "+number_5;
}
else if(Level(SymB[symbol_1])>Level(SymB[symbol_2])) {
QT_1[i]=number_1+SymB[symbol_1]+"("+number_2+SymB[symbol_2]+number_3+")"+SymB[symbol_3]+number_4+SymB[symbol_4]+number_5;
QT[i]=number_1+" "+SymB[symbol_1]+" ( "+ number_2 +" "+SymB[symbol_2]+" "+number_3+" ) "+SymB[symbol_3]+" "+number_4+" "+SymB[symbol_4]+" "+number_5;
}
else if(Level(SymB[symbol_2])>Level(SymB[symbol_3])) {
QT_1[i]=number_1+SymB[symbol_1]+number_2+SymB[symbol_2]+"("+number_3+SymB[symbol_3]+number_4+")"+SymB[symbol_4]+number_5;
QT[i]=number_1+" "+SymB[symbol_1]+" "+ number_2 + " "+SymB[symbol_2]+" ( "+number_3+" "+SymB[symbol_3]+" "+number_4+" ) "+" "+SymB[symbol_4]+" "+number_5;
}
else if(Level(SymB[symbol_3])>Level(SymB[symbol_4])) {
QT_1[i]=number_1+SymB[symbol_1]+number_2+SymB[symbol_2]+number_3+SymB[symbol_3]+"("+number_4+SymB[symbol_4]+number_5+")";
QT[i]=number_1+" "+SymB[symbol_1]+" "+ number_2 + " "+SymB[symbol_2]+" "+number_3+" "+SymB[symbol_3]+" ( "+number_4+" "+SymB[symbol_4]+" "+number_5+" )";
}
else {
QT_1[i]=number_1+SymB[symbol_1]+ number_2+SymB[symbol_2]+number_3+SymB[symbol_3]+number_4+SymB[symbol_4]+number_5;
QT[i]=number_1+" "+SymB[symbol_1]+" "+ number_2 +" "+SymB[symbol_2] +" " +number_3+" "+SymB[symbol_3] +" "+number_4+" "+SymB[symbol_4]+" "+number_5;
}
}
//判断运算符为四个之后,开始判断符号优先级,并在式子里添加括号。
else {continue;} //当symbol_number随机出不需要的数字时,结束本次循环,重新开始新的循环。主要防止出现空指针。
List<String> rec= toInfixExpression(QT_1[i]); //调用中序表达式。
AS[i]=QT[i]+" = "+reckon(rec);
if(reckon(rec)<0 || reckon(rec)>10000) //当数字的结果大小为负数或者大于10000,结束本次循环,重新生成式子。
{continue;}
i++;
}
}
3. 代码规范
请给出本次实验使用的代码规范:
- 第一条:代码中的变量名不能以下划线开始也不能以下划线结束。
- 第二条:代码中的命名严禁使用拼音与英文混合,更不许使用中文命名。
- 第三条:常量命名全部大写,单词键用下划线隔开,力求语义表达完整,不要嫌名字长。
- 第四条:类型与中括号紧挨相连来定义数组。
- 第五条:杜绝完全不规范的缩写,避免忘文不知义。
- 第六条:第四条:不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护。并人工检查代码是否符合规范
五、测试
请思考并记录你认为必要的测试点,并记录测试用例与测试结果
测试编号 | 具体输入 | 预期结果 | 实际结果 |
---|---|---|---|
1 | -n 10 -grade 1 | 输出10题一年级题目 | 符合预期 |
2 | -n -5 -grade 1 | 提示错误,停止运行 | 符合预期 |
3 | -n 10 -grade 3 | 输出10题三年级题目 | 符合预期 |
4 | -grade 3 -n 10 | 输出10题三年级题目 | 符合预期 |
5 | A N | 提示错误,停止运行 | 符合预期 |
6 | -n 10.3 -grade 3.0 | 提示错误,停止运行 | 符合预期 |
7 | -n 99999 -grade 4 | 提示错误,停止运行 | 符合预期 |
六、总结
请总结过程中的教训和经验,思考
- 在这一次的作业中,由于使用了逆波兰以及中序表达式,并且还有堆栈和线性表的运用,由于基础薄弱,我和结伴对象在写代码之前,花费了大量的时间去查看相关知识,并查看相关的博客代码,询问班里的大神,最终成功理解了其运算方式。
- 结对作业和之前的个人作业并不一样,因为是两个人一起敲代码,并且我们的想法以及思路都不同,因此每敲一行,都会对同伴说出关于这一行代码我要用它来做什么,这一行代码的用处。同时,也会提出建议,一种不同的想法,最后撮合而成,出发点不一样,想法不一样。导致了我们可以对代码更好的优化,毕竟当局者迷,旁观者清,有的不必要的代码,确实在旁观看的人会看的更加清晰,并能指出一些错误逻辑。
- 有关于调用逆波兰和中序表达式两种方法的时候,我不只一次出现了空指针的错误,原因就是if()判断随机数生成的时候,并没有把所有可能列出来,导致出现了if()判断之外的数字,从而导致了需要接收式子的String数组 QT_1并没有获得式子,将一个空数组传入中序表达式内,最终导致程序报错,出现空指针的问题。
- 在我无法判断出错误地点之时,同伴的几句话,可能是无心,也可能是有意,却能惊醒我这个梦中人,使我发现错误的地方,同时进行修改,最后得出最终结果。
- 结对编程相比于个人作业,多了头脑风暴和灵感冲撞,在一次次的冲突碰撞之下,在一次次克服难题之下,我们磕磕碰碰,修修改改,最终提交了代码,完成了本次作业。
- 但是这次的代码依旧有许多不足,我使用了优先级进行判断,然后逐一添加括号,在我的想法中,其实不只是两个数字,甚至可以括三个、四个数字。然而想法是美好的,但真正写出来却只能实现一个括号,只能括两个数字。
- 代码仍具有局限性,我和结伴对象虽然讨论过,但却没有得出能够符合我们想法的代码,因此只能碍于时限,草草提交了本次作业。代码依旧有着许多不足,能够改进的地方还有很多,相信在下一次的作业中,我能够获得新的想法,同时改进本次的不足,逐一完善我的代码。
- 结对编程很有趣,两个人的想法冲突,两个人的意见冲突,不仅能给枯燥的编程添加点调味剂,同时也能因为灵感冲突、结合产生新的灵感,可以说是每写出一种想法就能蹦出另外一种更大胆的想法,让人忍不住去尝试,虽然结果往往都是错的,不过说实话,真理不就是在众多的错误中诞生的吗?
MathExamV2.0四则混合运算计算题生成器的更多相关文章
- MathExam小学一二年级计算题生成器V1.0
MathExam小学一二年级计算题生成器v1.0 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning ...
- java 解析四则混合运算表达式并计算结果
package ch8; import java.util.LinkedList; import java.util.List; import java.util.Stack; /** * 四则混合运 ...
- C语言编程学习:写的秒速计算四则混合运算项目
C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...
- 软件工程学习之小学四则混合运算出题软件 Version 1.00 设计思路及感想
对于小学四则混合运算出题软件的设计,通过分析设计要求,我觉得为了这个软件在今后便于功能上的扩充,可以利用上学期所学习的<编译原理>一课中的LL1语法分析及制导翻译的算法来实现.这样做的好处 ...
- 用C++实现的有理数(分数)四则混合运算计算器
实现目标 用C++实现下图所示的一个console程序: 其中: 1.加减乘除四种运算符号分别用+.-.*./表示, + 和 - 还分别用于表示正号和负号. 2.分数的分子和分母以符号 / 分隔. 3 ...
- 如何处理加括号的四则混合运算表达式——基于二叉树的实现(Eclipse平台 Java版)
记得上<数据结构>课程时,利用栈的特性解决过四则混合运算表达式.而如今在编写小型关系数据库的时候,编译部分要处理where后面的逻辑表达式——检查语法正确与否的同时,还要将信息传给下一个接 ...
- 软件工程学习之小学四则混合运算出题软件 Version 1.1 设计思路及感想
继上次采用形式文法来生成混合运算的算式,由于算法中没有引入控制参数而导致容易产生形式累赘(多余的括号等)的算式.本次更新决定采用一种更为简单有效的生成方式,由给出的一个随机的最终答案S,通过给定的一个 ...
- 带括号的四则混合运算的算符优先算法-----java实现
1:主方法 package com.baidu; import java.text.NumberFormat;import java.util.ArrayList;import java.util.S ...
- web四则混合运算3
一.程序要求: 可以控制下列参数: 是否有乘除法: 是否有括号(最多可以支持十个数参与计算): 数值范围: 加减有无负数: 除法有无余数! 二.设计思路 要求能够通过参数来控制有无乘除法,加减有无 ...
随机推荐
- Vector/Push_back
https://bbs.csdn.net/topics/370225285 https://blog.csdn.net/u013630349/article/details/46853297 http ...
- P1015 回文数解题思路(非原创)
测试 #include<bits/stdc++.h> using namespace std; int n,m,step; string nn; int len,nex; bool dfs ...
- Angular4 自制分页控件
过年后第一波,自制的分页控件,可能功能没有 PrimeNG 那么好,但是基本可以实现自定义翻页功能,包括:首页/最后一页/上一页/下一页. 用户可以自定义: 1. 当前默认页码(如未提供,默认为第一页 ...
- Angular4 自制华容道拼图(可以升级难度、关卡、更换图片)
前端工程师新手一枚,之前一直做些小设计,以及静态页面的编写工作.刚刚接触 Angular 没有多久,四个月前对于 js 也只是会写 alert 之流,现在进步算是很大,下面是自制的华容道拼图(可以升级 ...
- 使用树莓派拍摄延时动画,制作GIF图
本期教大家将编写一个小脚本用树莓派来捕获多个图像,然后可以将这些图像组合成动画GIF,使用延时摄影功能,可以在几秒钟内查看非常慢的事情. 我们需要用到ImageMagick,这是一个用于图像处理的命令 ...
- [Golang学习笔记] 04 程序实体1 变量声明
变量声明: Go语言的程序实体包含:变量.常量.函数.结构体和接口,是一门静态类型的编程语言. (在声明变量或常量的时候,需要指定类型,或者给予足够信息是的Go语言能够推导出类型) Go语言变量的类型 ...
- spark执行命令 监控执行命令
#!/bin/bash #/usr/hdp/current/flume-server/bin/flume-ng agent -c conf/ -f /usr/hdp/current/flume-ser ...
- 20155231 实验三 敏捷开发与XP实践
20155231 实验三 敏捷开发与XP实践 实验内容 XP基础 XP核心实践 相关工具 实验要求 没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器&g ...
- 2017-2018-1 20155321 《信息安全系统设计基础》课堂实践——实现mypwd
2017-2018-1 20155321 <信息安全系统设计基础>课堂实践--实现mypwd 学习pwd命令 pwd命令:输出当前工作目录的绝对路径 还可通过man pwd具体查看pwd的 ...
- Wcf服务测试自带工具
Visual Studio 安装包文件夹 \Common7\IDE\WcfTestClient.exe