结对项目----实现一个自动生成小学四则运算题目的命令行程序
Posted Johann丶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结对项目----实现一个自动生成小学四则运算题目的命令行程序相关的知识,希望对你有一定的参考价值。
一.Github项目地址:https://github.com/lyh27/exercise
团队成员:卢耀恒3118005065 莫政3118005067
二.需求
自然数:0, 1, 2, …。
- 真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。
- 运算符:+, −, ×, ÷。
- 括号:(, )。
- 等号:=。
- 分隔符:空格(用于四则运算符和等号前后)。
- 算术表达式:
e = n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),
其中e, e1和e2为表达式,n为自然数或真分数。
- 四则运算题目:e = ,其中e为算术表达式。
- 使用 -n 参数控制生成题目的个数,例如
Myapp.exe -n 10
将生成10个题目。
- 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如
Myapp.exe -r 10
将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。
- 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。
- 生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。
- 每道题目中出现的运算符个数不超过3个。
- 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。
生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:
- 四则运算题目1
- 四则运算题目2
……
其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。
- 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
- 答案1
- 答案2
特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。
- 程序应能支持一万道题目的生成。
- 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:
Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt
统计结果输出到文件Grade.txt,格式如下:
Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
三.PSP表格
|
Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) | |
Planning | 计划 | 60 | 60 | |
· Estimate | · 估计这个任务需要多少时间 | 0 | 0 | |
Development | 开发 | 1500 | 1550 | |
Analysis | 需求分析 (包括学习新技术) | 120 | 100 | |
Design Spec | 生成设计文档 | 60 | 55 | |
Design Review | 设计复审 (和同事审核设计文档) | 20 | 20 | |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 0 | 0 | |
Design | 具体设计 | 60 | 55 | |
Coding | 具体编码 | 1300 | 1350 | |
Code Review | 代码复审 | 100 | 80 | |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 140 | |
Reporting | 报告 | 30 | 25 | |
Test Report | 测试报告 | 20 | 20 | |
Size Measurement | 计算工作量 | 0 | 0 | |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 50 | |
合计 | 1870 | 2050 |
四.效能分析
生成1万道题时总的内存与CPU情况
具体各个类的情况,其中字符串占比最多
四.设计实现过程
Util类(主要的工具类)实现分数题目的形成,整数题目的形成,分数类题目的运算操作,将题目插入文本文件,以及答案的检查。
util类主要分成了AnswerCheckUtil(答案的检查,正确与错误),ExerciseFractionUtil(生成分数题目),ExerciseIntegerUtil(生成整数题目),ExerciseInsertUtil(将题目与答案输出,写入文本文件),FractionOperationUtil(分数的操作),其中
ExerciseFractionUtil中通过设置随机符号与随机符号数,分类实现,又Math.random函数实现随机,由用户输入题目个数以及题目中数值范围实现对随机题目的控制,当输入进后,由代码实现随机生成。
ExerciseIntegerUtil同分数类的情况
FractionOperationUtil中有方法simplifiedFraction,changeToProperFraction,simplified。simplified递归实现求最大公约数,simplifiedFraction对simplified的调用,实现对分数的化简,而changeToProperFraction则是将假分数变成真分数,化成x\'x/x的形式
ExerciseInsertUtil则是对生成的题目与答案输入到文本文件中
AnswerCheckUtil则是将用户输入的答案与标准答案进行对比,批改,若正确则记录,错误也记录,最终输入正确与错误的题号。
由于对于查重未知如何实现,所以最后没有做到查重的功能,而且对于整数部分的除法也未转换成分数的形式
五.代码说明
主方法,main函数
1 package exercise.main; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.util.Scanner; 6 7 import exercise.utils.AnswerCheckUtil; 8 import exercise.utils.ExerciseFractionUtil; 9 import exercise.utils.ExerciseIntegerUtil; 10 11 public class main { 12 13 @SuppressWarnings("resource") 14 public static void main(String[] args) { 15 //n表示输入题目数量,x表示输入数字的范围 16 int choose,n,x,over; 17 System.out.println("自动生成小学四则运算题目"); 18 while(true) { 19 Scanner scanner=new Scanner(System.in); 20 System.out.println("请选择你需要出的题目的类型,1是整数类型,2是分数类型"); 21 //判断是否输入为数字 22 if(!scanner.hasNextInt()) 23 continue; 24 choose=scanner.nextInt(); 25 if(choose==1) { 26 System.out.println("请输入出题的数量以及数字的范围"); 27 n=new Scanner(System.in).nextInt(); 28 x=new Scanner(System.in).nextInt(); 29 ExerciseIntegerUtil.getExerise(n, x); 30 File file=new File("1.txt"); 31 try { 32 if(!file.exists()) 33 file.createNewFile(); 34 } catch (IOException e) { 35 // TODO Auto-generated catch block 36 e.printStackTrace(); 37 } 38 System.out.println("请在1.txt中作答,答题完毕请输入1"); 39 over=scanner.nextInt(); 40 //判断是否输入正确 41 while(over!=1) { 42 System.out.println("输入有误,请重新输入"); 43 over=new Scanner(System.in).nextInt(); 44 } 45 AnswerCheckUtil.checkAnswer(); 46 } 47 else if(choose==2) { 48 System.out.println("请输入出题的数量以及数字的范围"); 49 n=new Scanner(System.in).nextInt(); 50 x=new Scanner(System.in).nextInt(); 51 ExerciseFractionUtil.getExercise(n, x); 52 File file=new File("1.txt"); 53 try { 54 if(!file.exists()) 55 file.createNewFile(); 56 } catch (IOException e) { 57 // TODO Auto-generated catch block 58 e.printStackTrace(); 59 } 60 System.out.println("请在1.txt中作答,答题完毕请输入1"); 61 over=scanner.nextInt(); 62 while(over!=1) { 63 System.out.println("输入有误,请重新输入"); 64 over=new Scanner(System.in).nextInt(); 65 } 66 AnswerCheckUtil.checkAnswer(); 67 } 68 else { 69 System.out.println("你输入有误"); 70 } 71 } 72 } 73 74 }
ExerciseFractionUtil类
1 package exercise.utils; 2 3 /** 4 * @author lyh 5 * 全部为分数的题目 6 */ 7 public class ExerciseFractionUtil { 8 9 // n为传入的题目数量,x为传入的数值范围 10 public static void getExercise(int n, int x) { 11 // 结果 12 int sum = 0; 13 // 题目数量 14 int count = 0; 15 // 数值,运算符,运算符个数 16 int a, b, c, d, e, f, g, h, operator1, operator2, operator3, nterms; 17 // 储存题目以及答案 18 String[] results = new String[n + 1]; 19 String[] exercise = new String[n + 1]; 20 // 随机运算符+-*/,0表示+,1表示-,2表示*,3表示/ 21 while (n != count) { 22 operator1 = (int) (Math.random() * 4); 23 operator2 = (int) (Math.random() * 4); 24 operator3 = (int) (Math.random() * 4); 25 a = (int) (Math.random() * x); 26 b = (int) (Math.random() * x); 27 c = (int) (Math.random() * x); 28 d = (int) (Math.random() * x); 29 e = (int) (Math.random() * x); 30 f = (int) (Math.random() * x); 31 g = (int) (Math.random() * x); 32 h = (int) (Math.random() * x); 33 nterms = (int) (Math.random() * 3); 34 //一个运算符的情况下 35 if (b != 0 && d != 0 && nterms == 0) { 36 if (operator1 == 0) { 37 exercise[++count] = a + "/" + b + "+" + c + "/" + d + "="; 38 // 储存临时值,方便化简 39 sum = a * d + b * c; 40 b = b * d; 41 //判断是否为假分数,下同 42 if (sum > b) 43 //将其转换成带分数,下同 44 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 45 else 46 //将分数化简,下同 47 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 48 } else if (operator1 == 1) { 49 if ((a / b) > (c / d)) { 50 exercise[++count] = a + "/" + b + "-" + c + "/" + d + "="; 51 // 储存临时值,方便化简 52 sum = a * d - b * c; 53 b = b * d; 54 if (sum > b) 55 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 56 else 57 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 58 } 59 } else if (operator1 == 2) { 60 exercise[++count] = a + "/" + b + "×" + c + "/" + d + "="; 61 // 储存临时值,方便化简 62 sum = a * c; 63 b = b * d; 64 if (sum > b) 65 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 66 else 67 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 68 } else if (operator1 == 3) { 69 // 防止C为0出错 70 if (c == 0) 71 continue; 72 exercise[++count] = a + "/" + b + "÷" + c + "/" + d + "="; 73 // 储存临时值,方便化简 74 sum = a * d; 75 b = b * c; 76 if (sum > b) 77 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 78 else 79 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 80 } 81 //两个运算符的情况下 82 } else if (b != 0 && d != 0 && f != 0 && nterms == 1) { 83 if (operator1 == 0) { 84 if (operator2 == 0) { 85 exercise[++count] = a + "/" + b + "+" + c + "/" + d + "+" + e + "/" + f + "="; 86 b = b * d * f; 87 sum = a * d * f + c * b * f + e * b * d; 88 if (sum > b) 89 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 90 else 91 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 92 } 93 } else if (operator2 == 1) { 94 if ((a / b + c / d - e / f) > 0) { 95 exercise[++count] = a + "/" + b + "+" + c + "/" + d + "-" + e + "/" + f + "="; 96 b = b * d * f; 97 sum = a * d * f + c * b * f - e * b * d; 98 if (sum > b) 99 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 100 else 101 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 102 } 103 } else if (operator2 == 2) { 104 exercise[++count] = a + "/" + b + "+" + c + "/" + d + "×" + e + "/" + f + "="; 105 sum = a * d * f + c * e * b; 106 b = b * d * f; 107 if (sum > b) 108 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 109 else 110 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 111 } else if (operator2 == 3 && e != 0) { 112 exercise[++count] = a + "/" + b + "+" + c + "/" + d + "÷" + e + "/" + f + "="; 113 sum = a * d * e + c * f * b; 114 b = b * d * e; 115 if (sum > b) 116 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 117 else 118 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 119 } else if (operator1 == 1) { 120 if (operator2 == 0) 121 if ((a / b - c / d + e / f) > 0) { 122 exercise[++count] = a + "/" + b + "-" + c + "/" + d + "+" + e + "/" + f + "="; 123 sum = a * d * f - c * b * f + e * b * d; 124 b = b * d * f; 125 if (sum > b) 126 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 127 else 128 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 129 } else if (operator2 == 1) 130 if ((a / b - c / d - e / f) > 0) { 131 exercise[++count] = a + "/" + b + "-" + c + "/" + d + "-" + e + "/" + f + "="; 132 sum = a * d * f - c * b * f - e * b * d; 133 b = b * d * f; 134 if (sum > b) 135 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 136 else 137 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 138 } else if (operator2 == 2) { 139 if ((a / b - (c / d) * (e / f)) > 0) { 140 exercise[++count] = a + "/" + b + "-" + c + "/" + d + "×" + e + "/" + f + "="; 141 sum = a * d * f - b * c * e; 142 b = b * d * f; 143 if (sum > b) 144 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 145 else 146 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 147 } 148 } else if (operator2 == 3) { 149 if ((a / b - (c / d) / (e / f)) > 0) { 150 exercise[++count] = a + "/" + b + "-" + c + "/" + d + "÷" + e + "/" + f + "="; 151 sum = a * d * e - b * c * f; 152 b = b * d * e; 153 if (sum > b) 154 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 155 else 156 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 157 } 158 } else if (operator1 == 2) { 159 exercise[++count] = a + "/" + b + "×" + c + "/" + d + "×" + e + "/" + f + "="; 160 sum = a * c * e; 161 b = b * d * f; 162 if (sum > b) 163 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 164 else 165 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 166 } else if (operator1 == 3) { 167 if (a / b * c / d * e / f >= 0) { 168 exercise[++count] = a + "/" + b + "÷" + c + "/" + d + "÷" + e + "/" + f + "="; 169 sum = a * d * f; 170 b = b * c * e; 171 if (sum > b) 172 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 173 else 174 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 175 } 176 } 177 //3个运算符的情况下,仅仅举出了较为简单的运算+法 178 } else if (b != 0 && d != 0 && f != 0 && h != 0 && nterms == 2) { 179 if (operator1 == 0 && operator2 == 0 && operator3 == 0) { 180 exercise[++count] = a + "/" + b + "+" + c + "/" + d + "+" + e + "/" + f + "+" + g + "/" + h 181 + "="; 182 sum = a * d * f * h + c * b * f * h + e * b * d * h + g * b * d * f; 183 b = b * d * f * h; 184 if (sum > b) 185 results[count] = FractionOperationUtil.changeToProperFraction(sum, b); 186 else 187 results[count] = FractionOperationUtil.simplifiedFraction(sum, b); 188 } 189 } 190 } 191 } 192 // 此处为实现将答案存入文本文件 193 ExerciseInsertUtil.insertExercise(exercise); 194 ExerciseInsertUtil.insertAnswer(results); 195 // 将答案存起来 196 AnswerCheckUtil.setResults(results); 197 } 198 }
ExerciseIntegerUtil类
1 package exercise.utils; 2 3 /** 4 * @author lyh 5 * 全部为整数的题目 6 */ 7 public class ExerciseIntegerUtil { 8 9 /* 10 * 未处理除法的情况下变为分数 11 * 仅仅是变成了两位小数输出 12 */ 13 14 //n为传入的题目数量,x为传入的数值范围 15 public static void getExerise(int n,int x) { 16 //结果 17 double sum=0; 18 //题目数量 19 int count=0; 20 double[] results=new double[n+1]; 21 String[] exercise=new String[n+1]; 22 while(count!=n) { 23 //四个数据a,b,c,d 24 double a=(int) (Math.random()*x)+1; 25 double b=(int) (Math.random()*x)+1; 26 double c=(int) (Math.random()*x)+1; 27 double d=(int) (Math.random()*x)+1; 28 //随机运算符+-*/,0表示+,1表示-,2表示*,3表示/ 29 int operator1=(int) (Math.random()*4); 30 int operator2=(int) (Math.random()*4); 31 int operator3=(int) (Math.random()*4); 32 //控制题目的项数,0表示2两项,1表示3项,2表示4项 33 int nterms=(int) (Math.random()*3); 34 //运算符为1个的情况下 35 if(operator1==0&&nterms==0) { 36 sum=a+b; 37 exercise[++count]=a+"+"+b+"="; 38 } 39 //运算符为2个的情况下 40 else if(operator1==0&&operator2==0&&nterms==1) { 41 sum=a+b+c; 42 exercise[++count]=a+"+"+b+"+"+c+"="; 43 } 44 else if(operator1==0&&operator2==2&&nterms==1) { 45 sum=a+b*c; 46 exercise[++count]=a+"+"+b+"×"+c+"="; 47 } 48 else if(operator1==0&&operator2==1&&nterms==1) { 49 if(a+b<c) { 50 sum=a+c-b; 51 exercise[++count]=a+"+"+c+"-"+b+"="; 52 } 53 else { 54 sum=a+b-c; 55 exercise[++count]=a+"+"+b+"-"+c+"="; 56 } 57 } 58 20165227 结对编程项目-四则运算 第一周