任务1源码在Github的仓库主页链接地址: 需求分析:
1. 作业总体效果:随机产⽣n道加减乘除练习题;
2. 练习题的构成:数字和运算符且每个数字在 0 和 100 之间,运算符在3个到5个之间且每个练习题⾄少要包含2种运算符;3. 练习题的结果:练习题在运算过程中不出现负数与⾮整数;
4. 最终提交结果:学号与⽣成的n道练习题及其对应的正确答案;样例如下:
功能设计:
1. 表达式的⽣成模块。⾸先需要⽣成运算符与数字,每个等式中运算符的个数加⼀就等于该等式中的数字个数,之后将⽣成的符号与数字组合成String,传⼊逆波兰计算模块进⾏结果的输出。在此模块中将除法中分母为零的情况、运算符只有⼀种的情况以及分⼦分母除不尽的情况排除。
2. 表达式的计算模块。利⽤逆波兰表达式计算结果,在该模块中排除例如30/6/3这样的情况,在之前的模块中排除的只是除号前后的分⼦分母的情况,并未考虑除号连续的情况,当除号连续时,需要考虑第⼀个除号运算完之后的结果能否继续除以下⼀个数的情况,当遇到前后余数不为0的情况以及中间结果为负数的情况就跳出该函数,继续产⽣新的等式直⾄满⾜条件。写这个模块的时候借鉴这位博主的写法();
3. 结果写⼊⽂件模块。将⾃⼰的学号与根据⽤户输⼊的题⽬个数⽣成的等式写⼊⽂件。
4. 异常情况的处理。排除输⼊为⾮数字的情况以及输⼊的数字⼤于1000、⼩于1以及等于0的情况。基本功能:
实现每道练习题运算符在3个到5个之间,⾄少要包含2种运算符;运算结果⽆负数以及⾮整数;
将最终结果保存在⽂档中以样例为模板;
每道练习题的结果不超过⼀定的范围(考虑到⼩学⽣计算能⼒有限,当时问了郑⽼师,在⽼师的提⽰下,设置了⽤户输⼊想要⽣成结果的范围这⼀块内容,并进⾏了异常处理)。设计实现:
利⽤Visio进⾏流程图的绘制,具体流程图如下:其中ContentToTxt(将结果写⼊⽂件) Main(主程序可以从命令⾏接收参数)ReversePolish (逆波兰表达式) RandomEquation(产⽣等式) result.txt(运⾏后产⽣的结果)
测试运⾏:
核⼼代码:
1) 随机产⽣等式模块:为了看起来整洁,去掉了测试过程中注释掉的打印输出部分。等式⽣成是将⽣成的数字与运算符依次拼接,之后加上等号构成等式,在构建过程中去除运算符只有⼀种的情况、分母为0的情况,分⼦分母有余数的情况。
1 public class RandomEquation {
2 public static String randomEquation (){ 3
4 // Previous expressions 5
6 String sBefore = new String(); 7
8 // The later expression 9
10 String sLater = new String(); 11 char[] equation; 12 int k = 6; 13 int n; 14 int m; 15 int j; 16 int i;
17 int[] number; 18 char[] symbol;
19 number = new int[k]; 20 symbol = new char[k];
21 equation = new char[2 * k]; 22 char[] cSymbol = {'+','-','*','÷'};
23 Random random = new Random(); 24
25 // Generating operator 26
27 for(i = 0;i<(int)(Math.random()*3)+3;i++){
28 int index = random.nextInt(cSymbol .length); 29 char resultChar = cSymbol[index]; 30 symbol[i] = resultChar; 31 32 }
33 for(m = 0;m < i;m++){
34 if(symbol[i - 1] != symbol[m]){ 35 break; 36 } 37 } 38 39 /*
40 * Removal of only one operator
41 * If the last symbol is the same as the previous one, the last one generates a symbol at random. 42 */ 43
44 if(m == i){ 45 do{
46 int index = random.nextInt(cSymbol.length); 47 char resultChar = cSymbol[index]; 48 symbol[i - 1] = resultChar;
49 }while(symbol[i - 1] == symbol[i - 2]); 50 } 51
52 // Generating number 53
54 for(j = 0;j < i + 1;j++){ 55
56 int num = (int)(Math.random()*100); 57 number[j] = num; 58 59 } 60
61 // Generating equation
62
63 for(n = 0;n < i;n++){
64 sBefore += String.valueOf(number[n])+String.valueOf(symbol[n]); 65 }
66 sBefore += String.valueOf(number[i]); 67
68 // Save symbols and numbers into a equation array 69
70 for(n = 1;n < 2 * i;n = n+2){ 71
72 equation[n] = symbol[(n - 1) / 2]; 73 }
74 for(n = 0;n < 2 * j - 1;n = n+2){ 75
76 equation[n] = (char)number[(n + 1) / 2]; 77 78 } 79
80 // The removal ÷ denominator is 0 and the molecular denominator is incompatible 81
82 for(n = 1;n < i + j && n + 1 < i + j;n = n + 2){ 83 if(equation[n] == '÷'){
84 if(equation[n + 1]==0){ 85 do{
86 int num2 = (int)(Math.random()*100); 87 equation[n + 1] = (char)num2; 88 }while(equation[n + 1] == 0); 89 }
90 else if((int)equation[n - 1] % (int)equation[n + 1]!=0 || (int)equation[n - 1]<(int)equation[n + 1]){ 91 do{ 92
93 int num2 = (int)(Math.random()*100) + 1; 94 equation[n + 1] = (char)num2; 95 if(equation[n + 1] == 0){ 96 do{
97 int num3 = (int)(Math.random()*100); 98 equation[n + 1] = (char)num3; 99 }while(equation[n + 1] == 0);100 }101
102 }while((int)equation[n - 1] % (int)equation[n + 1]!= 0 || (int)equation[n - 1]<(int)equation[n + 1]);103 }104 105 }106 107 108 }
109 // The equation after excluding special circumstances110
111 for(n = 0;n < i+j && n + 1 < i + j;n = n + 2){112
113 sLater += String.valueOf((int)equation[n]);114 sLater += String.valueOf(equation[n + 1]);115 116 }
117 sLater += String.valueOf((int)equation[i + j - 1]);118 sLater += String.valueOf('=');119
120 return sLater;121 }122 123 }
2)逆波兰模块借鉴这位博主的写法,并在理解的基础上进⾏了代码的加⼯。当中间结果⼩于0或者a%b!=0时,利⽤return跳出该函数,并在下边的模块中利⽤返回值进⾏等式的重新⽣成。
1 public static int calcInt(int a, int b, String stmp) 2 {
3 int res = 0;
4 char s = stmp.charAt(0); 5 switch (s) { 6 case '+': { 7 res = a + b; 8 break; 9 }
10 case '-': {11 res = a - b;12 if(res < 0){13 return -1;14 }
15 break;16 }
17 case '*': {
18 res = a * b;19 break;20 }
21 case '÷': {22 res = a / b;23 if( a % b != 0){24 return -1;25 }
26 break;27 }28 }
29 return res;30 }
3)结果写⼊⽂件模块,由于随机产⽣等式,所以需要⼀直将该等式保存到字符串⾥,并对该字符串进⾏逆波兰求解,否则若随机产⽣式⼦randomEquation(),之后⼜利⽤ReversePolish(randomEquation()))产⽣的随机等式的结果,这样会出现等式计算结果与最终运算结果不匹配的情况。在该模块中利⽤返回值的不同进⾏结果的保存,若返回值为-1或者⼤于⽤户输⼊的结果值result,就将i的值⾃减,这样就相当于重新产⽣符合条件的式⼦。
1 for(int i = 0;i < questionAmount;i++){ 2
3 String randoms = randomEqual.randomEquation();
4 final boolean existed = reversePolish.reversePolish(randoms) != -1 && reversePolish.reversePolish(randoms) < 500; 5 if(existed){ 6
7 contentToTxt.contentToTxt(strFilePath,String.valueOf(randoms+reversePolish.reversePolish(randoms))); 8 contentToTxt.contentToTxt(strFilePath,String.valueOf(\"\\n\")); 9 }else{10 i--;11 }12 }
总结:
1. 在拿到题⽬的时候,并没有急着去完成代码⽽是⾸先进⾏了需求分析,根据需求分析将本次作业分为三⼤模块,并对这三个模块进⾏了功能的划分,每个模块都有要实现的功能,且尽量降低模块之间的联系。以这样的做法书写下来发现思路很清晰,由于不再在⼀个函数体内书写程序,⼀个模块出了问题不必全篇找,直接在这个模块中修改即可。
2. 由于参加完蓝桥杯之后就没有与java打交道了,⼀直与c语⾔打交道,所以java当中的语法也遗忘了不少,使⽤new这⼀关键字创建对象也给忘记啦,突然想到⼀则笑话(甲说都⼤三了,连⼥朋友都没有。⼄说:new⼀个‘对象’),这下⼦就忘不了啦。
3. 在书写代码的过程中使⽤了do while语句,不需要判断循环次数,以前⼀直在使⽤while语句,这次在产⽣表达式的过程中⼤量使⽤了do while,深刻体会到了该语句的妙处。
4. 在考虑情况的时候并不是⼀次性完成的,⽽是在编写代码的过程中慢慢想出来的,到了最后计算结果的时候发现结果已经有上万的啦,所以将输出结果限制在⽤户要求的范围内,这样就和⼩学⽣实际情况相符合。
5. 在⽣成表达式中去除分⼦分母不能整除的时候,例如a/b/c判断,若a/b不能整除就再随机产⽣a,b;若同时b/c不能整除则再随机产⽣b,c;这样下来发现会产⽣a/b不能整除的情况,因为b随机了两次,后⼀次随机就⽆法保证a/b是整数了,所以想到在逆波兰计算的时候进⼀步排除连续除号除不尽的情况。
6. 最后写的是⽂件模块,由于是将之前写的⽂档import进去的,在测试是否写好⽂件的时候发现在⽬录JRE System Library下边没有产⽣⽂件,最后在打开的⽂件夹中找到了,所以之后的每⼀次运⾏就拿Windows⾃带的记事本打开,明明写了换⾏符但仍在⼀⾏上,测试了好⼏次都不对,最后和同学交流了才发现这个问题,利⽤notepad++打开结果就是合适的。
7. 本来是想进⾏附加功能的添加,然⽽做的时候将⼀些特殊请款考虑到⽣成表达式的模块中,导致这些附加功能⽆法实现,⽐如真分数的计算,在⽣成表达式的过程中,将分⼦分母除不尽的情况已经排除,另外就是加括号的情况,在此模块中将除法中出现的分母为零的情况排除,排除的时候只看除号后边的数字,如果加上括号就没办法进⾏特殊情况的判断。所以还是在写的时候全盘考虑,不能只想着实现这些基本功能,使得算法没有拓展性。PSP:
PSP2.1PlanningEstimate DevelopmentAnalysis Design SpecDesign Review Coding StandardDesignCodingCode ReviewTest ReportingTest ReportSize Measurement
任务内容计划
估计这个任务需要多少时间,并规划⼤致⼯作步骤 开发
需求分析 (包括学习新技术)⽣成设计⽂档
设计复审 (和同事审核设计⽂档) 代码规范 (为⽬前的开发制定合适的规范) 具体设计 具体编码代码复审
测试(⾃我测试,修改代码,提交修改)报告测试报告计算⼯作量
计划完成需要的时间(min)实际完成需要的时间(min)
20 20 36010 10 10 2030 240 20 20 20 5 5 10
25 25 418 10 815 2035 280 25 25 27 5 12 10
Postmortem & Process Improvement Plan事后总结 ,并提出过程改进计划
因篇幅问题不能全部显示,请点此查看更多更全内容