week2的作业弄到现在week3才开始着手做,所幸截止日期还有几天。
Coding.net源码仓库地址:https://git.coding.net/Agustin_Leonard_DPS/Calculation.git
计划
明确需求及相关因素,指明时间成本和依赖关系
首先,我们这个作业给出了他的需求如下:
-
程序可接收一个输入参数n,然后随机产生n道加减乘除(分别使用符号+-*÷来表示)练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间。
-
为了让小学生得到充分锻炼,每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3÷5+2=2.6,2-5+10=7等算式。
-
练习题生成好后,将你的学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中,不要输出额外信息,文件目录与程序目录一致。
-
当程序接收的参数为4时,以下为一个输出文件示例。
其中,这个作业要求用java语言编写,由于java语言有一段时间没有用(平时多用C),所以找来了以前java的课本复习一下……
开发
分析需求
在生成的n道题中,要求有:
①运算数字:在0~100范围;
②运算符:要有3~5个,且至少要有两种不同的运算符;
③结果&过程:不得出现负数和非整数;
④格式:输出文件为txt形式,即“result.txt”。
生成设计文档(暂无)
设计复审(暂无)
代码规范
与《构建之法》P70所的代码风格规范略有不同,如缩进为Tab,这是个人习惯,在以后的设计过程中会慢慢改正。
具体设计
这个项目开发并不复杂,其中Main和Lib构架设计如下:
Lib:
其中,生成题目的方法有多种,我参考了许征航同学的博客,他是在生成题目的过程中多加限制,确保生成的题目绝对符合规范。此外,我还想到了两种方法:
①在生成题目的过程中,每添加一个运算符和运算数就进行一次判定,判断每个步骤的结果和最终结果是否都符合规范,如果不符合,返回上一步,重新随机生成运算符和运算数;
②先生成若干道题目,编写算法对每个题目都进行一次判定,完全符合规范的题目则通过并添加到“result.txt”文件中,若不符合规范则不添加,重新生成。
我想使用①方法与许征航同学的方法相结合,在少量限定生成的符号与运算数时,每个步骤进行一次判定。
编辑于
2018-03-21)
具体编码
实践永远高于理论,设计时的方案总要通过实践来测试是否可行。其中我修改了许多方案,其中包括多加多层嵌套(if-else)判定,并且多加一个方法用以判断该运算是否符合要求。
最后式子运算的方法总是出错,借用了同学的方法,最后大致成功了,但是或多或少还是有一点bug,出于自己羸弱的代码能力和deadline,这些个问题以后请教同学后慢慢解决。
lib文件:
package src; import java.io.*; public class Lib { private static char[] sign = new char[] {'+', '-', '*', '÷'}; public static int Random(int min, int max){ return (int) (Math.random()*(max - min) + min + 0.5); } public static void CreateQues(String Ques[] ,int QuesNum ) {/*创建问题,QuseNum是问题数,OpNum是每个问题的运算符数 */ char Sign[] = new char[20];/*运算符*/ int Num[] = new int [20];/*运算数*/ for(int i = 0;i<QuesNum;i++) { Num[0] = Random(1,100); int OpNum = Random(3,5); int result[] = new int [10];/*储存算式中每个不走的运算结果*/ for(int j = 0;j<OpNum;j++) { int flag = 1; addSignNum(Sign,Num,j); if(j==0) { result[j] = calQues(Num,Sign[j],j); flag = isCorrect(Num,Sign[j],j); if(flag == -1) { result[0]= Num[0];j--;continue; } } else if (j>0) { if (Sign[j]=='*'||Sign[j]=='÷') { if(j == 1) result[0] = Num[0]; else result[j-1] = result[j-2]; result[j] = calQues(Num,Sign[j],j); flag = isCorrect(Num,Sign[j],j); if(flag == -1) { result[j] = result[j-1];j--;continue; } result[j] = calQues(result,Sign[j-1],j-1); flag = isCorrect(result,Sign[j-1],j-1); if(flag == -1) { result[j] = result[j-1];j--;continue; } } if(Sign[j]=='-'||Sign[j]=='+') { if(result[j-1]<0) { j=j-2;continue; } result[j] = Num[j+1]; result[j] = calQues(result,Sign[j],j-1); flag = isCorrectPlus(result[j]); if(flag == -1) { result[j] = result[j-1];j--;continue; } } } } /*for(int k=0;k<result.length;k++) System.out.println(result[k]);-*/ String question = "" + Num[0]; for(int k = 0;k<OpNum;k++) question = question + Sign[k] + Num[k+1]; question = question + "=" +calQuestion(question); System.out.println(question); Ques[i] = question; } } public static void addSignNum(char a[] , int b[],int c) { if(c!=0 &&(a[c-1]== '*'||a[c-1]== '÷')) a[c] = sign[Random(0,1)]; else a[c] = sign[Random(0,3)]; if(a[c] == '÷') b[c+1] = Random(2,10); else b[c+1] = Random(0,100); /*这里考虑到除号后面不能为0,进行一步限制*/ } public static int calQues(int a[],char b,int c) { if(b == '+') return a[c]+a[c+1]; else if(b == '-') return a[c]-a[c+1]; else if(b == '*') return a[c]*a[c+1]; else if(b == '÷') return a[c]/a[c+1]; return -1; } public static int isCorrect(int a[],char b,int c) { int flag = 1; if(b == '-'&& a[c] - a[c+1]<0) flag = -1; if(b == '÷'&& a[c] % a[c+1]!=0) flag = -1; return flag; } public static int isCorrectPlus(int a) { if(a<0) return -1; else return 1; } static public void filePrint(String[] Ques, int QuesNum, String path) throws IOException{ FileOutputStream fs = new FileOutputStream(new File(path)); PrintStream p = new PrintStream(fs); p.println("2016012033"); for(int i=0; i<QuesNum; i++) p.println(Ques[i]); p.close(); } static private int calQuestion(String question){ char[] ch = new char[50]; char[] oc = new char[15]; int[] num = new int[15]; int temp = 0, pn = -1, pc = -1; ch = question.toCharArray(); for(int i=0; i<ch.length; i++){ if(Character.isDigit(ch[i])) { temp = temp*10 + ch[i]-'0'; if(i == ch.length-1) num[++pn] = temp; } else { num[++pn] = temp; temp = 0; while(pc!=-1 && getw(oc[pc]) >= getw(ch[i]) ) { int num1 = num[pn--]; int num2 = num[pn--]; char ch1 = oc[pc--]; num[++pn] = calc(num2, num1, ch1); } //if(pc == -1) oc[++pc] = ch[i]; oc[++pc] = ch[i]; } } while(pc != -1) { int num1 = num[pn--]; int num2 = num[pn--]; char ch1 = oc[pc--]; num[++pn] = calc(num2, num1, ch1); } return num[0]; } static private int getw(char c){ if(c=='*' || c=='÷') return 2; else if(c=='+' || c=='-') return 1; else return -1; } static private int calc(int a, int b, char c) { //System.out.println("" + a +c + b); if(c == '+') return a + b; else if(c == '-') return a - b; else if(c == '*') return a * b; else if(c == '÷') return a / b; else return -1; } }
main文件:
package src; import java.io.IOException; import java.util.*; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); String path = "result.txt"; String[] Ques = new String[100]; int QuesNum; System.out.println("现在!让我们决定要多少道(0~100)四则运算题,然后我们把它们rua出来!"); QuesNum = input.nextInt(); Lib.CreateQues(Ques, QuesNum); try { Lib.filePrint(Ques, QuesNum, path); } catch(IOException ioe) { ioe.printStackTrace(); } input.close(); } }
总结
整出一个四则运算题出题系统其实不难(我之前一篇博客:http://www.cnblogs.com/longaotian/p/8526473.html),不过当时的要求少,而且不限语言,我自然用的是我熟练的C语言,但是在加了这么多条件和限制后,这两个问题的难度就不是一个等级的了。同时受限于自身的代码能力(被自己菜哭了)……其中仍然会有一些bug如偶尔还是会出现结果为负数的情况,这些我会在以后的课余时间里请教同学并且修复这些问题。在这里要感谢许征航同学的帮助,他帮我找出了我的代码里许多导致bug的地方并提出一些修改建议,在这个过程中我也学到了许多,如控制变量并且进行简单的单元测试等,获益良多。
PSP展示
花费时间(单位:h) | 花费时间百分比(%) | |
计划 | 0.5 | 1 |
明确需求 | 0.5 | 1 |
开发 | 24.6 | 90 |
需求分析 | 0.5 | 1 |
代码规范 | 0.1 | 0.2 |
具体设计 | 3 | 11 |
具体编码 | 18 | 66 |
代码复审&测试 | 3 | 11 |
报告 | 2 | 4 |
测试报告 | 1 | 2 |
计算工作量 | 0.5 | 1 |
事后总结 | 0.5 | 1 |
dpackage src;import java.io.*;public class Lib {private static char[] sign = new char[] {'+', '-', '*', '÷'};public static int Random(int min, int max){ return (int) (Math.random()*(max - min) + min + 0.5); }public static void CreateQues(String Ques[] ,int QuesNum ) {/*创建问题,QuseNum是问题数,OpNum是每个问题的运算符数 */char Sign[] = new char[20];/*运算符*/int Num[] = new int [20];/*运算数*/for(int i = 0;i<QuesNum;i++) {Num[0] = Random(1,100);int OpNum = Random(3,5);
int result[] = new int [10];/*储存算式中每个不走的运算结果*/for(int j = 0;j<OpNum;j++) {int flag = 1;addSignNum(Sign,Num,j);if(j==0) {result[j] = calQues(Num,Sign[j],j);flag = isCorrect(Num,Sign[j],j);if(flag == -1) {result[0]= Num[0];j--;continue;}}else if (j>0){if (Sign[j]=='*'||Sign[j]=='÷'){if(j == 1)result[0] = Num[0];elseresult[j-1] = result[j-2];result[j] = calQues(Num,Sign[j],j);flag = isCorrect(Num,Sign[j],j);if(flag == -1) {result[j] = result[j-1];j--;continue;}result[j] = calQues(result,Sign[j-1],j-1);flag = isCorrect(result,Sign[j-1],j-1);if(flag == -1) {result[j] = result[j-1];j--;continue;}}if(Sign[j]=='-'||Sign[j]=='+'){if(result[j-1]<0) {j=j-2;continue;}result[j] = Num[j+1];result[j] = calQues(result,Sign[j],j-1);flag = isCorrectPlus(result[j]);if(flag == -1) {result[j] = result[j-1];j--;continue;}}}}/*for(int k=0;k<result.length;k++)System.out.println(result[k]);-*/String question = "" + Num[0];for(int k = 0;k<OpNum;k++) question = question + Sign[k] + Num[k+1];question = question + "=" +calQuestion(question);System.out.println(question);Ques[i] = question;}}public static void addSignNum(char a[] , int b[],int c) {if(c!=0 &&(a[c-1]== '*'||a[c-1]== '÷')) a[c] = sign[Random(0,1)];else a[c] = sign[Random(0,3)];if(a[c] == '÷') b[c+1] = Random(2,10);else b[c+1] = Random(0,100); /*这里考虑到除号后面不能为0,进行一步限制*/}public static int calQues(int a[],char b,int c) {if(b == '+') return a[c]+a[c+1];else if(b == '-') return a[c]-a[c+1];else if(b == '*') return a[c]*a[c+1];else if(b == '÷') return a[c]/a[c+1];return -1;}public static int isCorrect(int a[],char b,int c) {int flag = 1;if(b == '-'&& a[c] - a[c+1]<0) flag = -1;if(b == '÷'&& a[c] % a[c+1]!=0) flag = -1;return flag;}public static int isCorrectPlus(int a) {if(a<0) return -1;else return 1;}static public void filePrint(String[] Ques, int QuesNum, String path) throws IOException{ FileOutputStream fs = new FileOutputStream(new File(path)); PrintStream p = new PrintStream(fs); p.println("2016012033"); for(int i=0; i<QuesNum; i++) p.println(Ques[i]); p.close(); } static private int calQuestion(String question){ char[] ch = new char[50]; char[] oc = new char[15]; int[] num = new int[15]; int temp = 0, pn = -1, pc = -1; //temp用于存放中间数值,pn用于在num数组中模拟栈顶, pc用于在ch数组中模拟栈顶 ch = question.toCharArray(); for(int i=0; i<ch.length; i++){ if(Character.isDigit(ch[i])) { temp = temp*10 + ch[i]-'0'; if(i == ch.length-1) num[++pn] = temp; //最后一个数入栈 } else { num[++pn] = temp; //temp入栈 temp = 0; while(pc!=-1 && getw(oc[pc]) >= getw(ch[i]) ) { int num1 = num[pn--]; int num2 = num[pn--]; char ch1 = oc[pc--]; num[++pn] = calc(num2, num1, ch1); } //if(pc == -1) oc[++pc] = ch[i]; oc[++pc] = ch[i]; } } while(pc != -1) { int num1 = num[pn--]; int num2 = num[pn--]; char ch1 = oc[pc--]; num[++pn] = calc(num2, num1, ch1); } return num[0]; } static private int getw(char c){ if(c=='*' || c=='÷') return 2; else if(c=='+' || c=='-') return 1; else return -1; } static private int calc(int a, int b, char c) { //System.out.println("" + a +c + b); if(c == '+') return a + b; else if(c == '-') return a - b; else if(c == '*') return a * b; else if(c == '÷') return a / b; else return -1; }}