实现一个自动生成小学四则运算题目的命令行程序(java实现)
2018-09-30 22:18 Derjykuf 阅读(2251) 评论(0) 编辑 收藏 举报Github项目地址:https://github.com/xiaobaot/wordcount/tree/master/sizeyusuan
团队成员:谢家明(代码生成) 谢竣(测试完善)
项目需求:
1. 使用 -n 参数控制生成题目的个数,例如
Myapp.exe -n 10
将生成10个题目。
2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如
Myapp.exe -r 10
将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。
3. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 − e2的子表达式,那么e1 ≥ e2。
4. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。
5. 每道题目中出现的运算符个数不超过3个。
6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,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. 四则运算题目1
2. 四则运算题目2
……
其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。
7. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
1. 答案1
2. 答案2
特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。
8. 程序应能支持一万道题目的生成。
9. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:
Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt
统计结果输出到文件Grade.txt,格式如下:
Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。
PSP开发耗时
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
60 |
100 |
· Estimate |
· 估计这个任务需要多少时间 |
100 |
120 |
Development |
开发 |
600 |
660 |
· Analysis |
· 需求分析 (包括学习新技术) |
120 |
150 |
· Design Spec |
· 生成设计文档 |
40 |
50 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
50 |
60 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
40 |
40 |
· Design |
· 具体设计 |
60 |
60 |
· Coding |
· 具体编码 |
120 |
120 |
· Code Review |
· 代码复审 |
60 |
90 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
60 |
60 |
Reporting |
报告 |
90 |
90 |
· Test Report |
· 测试报告 |
60 |
60 |
· Size Measurement |
· 计算工作量 |
30 |
30 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 |
30 |
合计 |
|
1520 |
1720 |
设计思路
1.我们首先想到的是整数化分数的运算,再对分子分母进行化简,我们试图生成两个分子和两个分母(分母至少一个为零时则全置为1,从而达到生成整数而用分数去运算的效果)来实现让整数和分数的计算可以同步。
2.对分数(不论是结果还是题目)进行判断,是假分数则化为带分数的形式,是真分数保持不变。
3.通过对不同文件的操作输出题目,答案以及统计答题者情况。
4.程序需求中的查重功能没有实现。
具体代码实现
main函数部分代码:
public static void main(String[] args){ Scanner sc= new Scanner(System.in); System.out.println("请输入产生几以内的数字:"); range=sc.nextInt(); System.out.println("请输入产生多少个运算表达式:"); int num=sc.nextInt(); int rightcount[]=new int[num+2]; int wrongcount[]=new int[num+2]; int right1=0; int wrong1=0; String[] results=new String[num];int i; for( i=0;i<num;i++){
/*具体的功能如下面的代码(两个class除外)*/
}
生成题目:
String expArr[]=new String[2];//定义生成的题目 int a= (int) (random.nextInt(range));//分子 int b= (int) (random.nextInt(range));//分母 int c= (int) (random.nextInt(range));//另一个分子 int d= (int) (random.nextInt(range));//另一个分母 int fuhao;//运算符 fuhao= (int) (random.nextInt(4)); if(b!=0&&d!=0) {//分母均不为0时生成带有分数的计算题,同时计算结果 if(fuhao==0) { int fenzi=a*d+b*c; int fenmu=b*d; expArr[0]=biaodashi(a,b)+'+'+biaodashi(c,d)+'='; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu); } if(fuhao==1&&a*d-b*c>=0) { int fenzi=a*d-b*c; int fenmu=b*d; expArr[0]=biaodashi(a,b)+'-'+biaodashi(c,d)+'='; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu); } if(fuhao==1&&a*d-b*c<0) { int fenzi=b*c-a*d; int fenmu=b*d; expArr[0]=biaodashi(a,b)+'-'+biaodashi(c,d)+'='; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu); } if(fuhao==2) { int fenzi=a*c; int fenmu=b*d; expArr[0]=biaodashi(a,b)+'×'+biaodashi(c,d)+'='; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu); } if(fuhao==3&&c!=0) { int fenzi=a*d; int fenmu=b*c; expArr[0]=biaodashi(a,b)+'÷'+biaodashi(c,d)+'='; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu); } if(fuhao==3&&c==0) { break; /*c=1; int fenzi=a*d; int fenmu=b*c; expArr[0]=biaodashi(a,b)+'÷'+biaodashi(c,d)+'='; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu);*/ } } else {//分母至少一个为0时生成只含有整式的运算式,同时计算结果 b=1; d=1; if(fuhao==0) { int fenzi=a*d+b*c; int fenmu=b*d; expArr[0]=a+"+"+c+"="; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu);//计算结果 } if(fuhao==1&&a*d-b*c>=0) { int fenzi=a*d-b*c; int fenmu=b*d; expArr[0]=a+"-"+c+"="; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu);//计算结果
} if(fuhao==1&&a*d-b*c<0) { int fenzi=b*c-a*d; int fenmu=b*d; expArr[0]=c+"-"+a+"="; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu);//计算结果
} if(fuhao==2) { int fenzi=a*c; int fenmu=b*d; expArr[0]=c+"×"+a+"="; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu);//计算结果
} if(fuhao==3&&c!=0) { int fenzi=a*d; int fenmu=b*c; expArr[0]=a+"÷"+c+"="; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu);//计算结果
} if(fuhao==3&&c==0) { break;//排除分母为零的情况 /*c=1; int fenzi=a*d; int fenmu=b*c; expArr[0]=a+"÷"+c+"="; System.out.println(expArr[0]); results[i]=reductionofFraction(fenzi, fenmu);*/ }
对分数的处理:
public static String reductionofFraction(int a, int b) {// 结果的分数约分,用于计算结果 int y = 1; for (int i = a; i >= 1; i--) { if (a % i == 0 && b % i == 0) { y = i; break; } } int z = a / y;// 分子 int m = b / y;// 分母 if (z == 0) { return "0"; } if(m==1) return z+""; else return biaodashi(z,m); } public static String biaodashi(int a,int b) {//判断假分数,并化假分数为带分数 if(a>=b) { int c; c=a/b; int d; d=a%b; {if(d==0) {return c+"";} return c+"'"+d+"/"+b;} }return a+"/"+b; }
生成题目文件及答案文件:
FileWriter fw = null; try { File f=new File("Exersies.txt");//题目写入 fw = new FileWriter(f, true); } catch (IOException e) { e.printStackTrace(); }if(expArr[0]!=null) { PrintWriter pw = new PrintWriter(fw); pw.println(i+1+"."+expArr[0]); pw.flush(); try { fw.flush(); pw.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); }}FileWriter fn = null; try { File f=new File("Answer.txt");//答案写入 fn = new FileWriter(f, true); } catch (IOException e) { e.printStackTrace(); }if(expArr[0]!=null) { PrintWriter pn = new PrintWriter(fn); pn.println(i+1+"."+results[i]); pn.flush(); try { fn.flush(); pn.close(); fn.close(); } catch (IOException e) { e.printStackTrace(); }}
统计并输出答题者的情况:
System.out.println("输入ok提交!");//答题完成后输入ok即可提交 Scanner sc1=new Scanner(System.in); String submit=sc1.nextLine(); if(submit.equals("ok")){ String array[]=new String[num]; try { int k=0; FileReader fr = new FileReader("H://eclipse2//eclipse3//sizeyusuan//Your_answers.txt"); BufferedReader br = new BufferedReader(fr); String s ; while((s = br.readLine())!=null) {//读取小学生的答案 array[k]=s; k++; }br.close(); fr.close(); }catch(IOException e){ System.out.println("指定文件不存在"); } for(int j=0;j<num;j++){ if(array[j].equals(results[j])) {//验证答案,统计正确和错误的个数 rightcount[j]=j+1; right1++; } else { wrongcount[j]=j+1; wrong1++; } } FileWriter fg = null; try { //反馈正确与错误题目的信息 File f=new File("Grade.txt"); fg = new FileWriter(f, true); } catch (IOException e) { e.printStackTrace(); } PrintWriter pg = new PrintWriter(fg); pg.println(" "); pg.print("Correct:"+right1+"("); for (int j = 0; j <= num; j++) { if (rightcount[j] != 0) { pg.print(rightcount[j] + ","); } } pg.println(")"); pg.print("Wrong:"+wrong1+"("); for (int j = 0; j <= num; j++) { if (wrongcount[j] != 0) { pg.print(wrongcount[j] + ","); } } pg.print(")"); pg.flush(); try { fg.flush(); pg.close(); fg.close(); } catch (IOException e) { e.printStackTrace(); }}
测试运行
题目文件
答案文件
答题者答案文件
校对文件
项目小结
1.每道题目中出现的运算符个数我们只实现了单个运算符,当我们后来试图扩展多个运算符的时候发现时间不够了,因此只能上交较为简单的版本。
2.查重功能以我们的算法和我们的能力感觉实现有难度,所以并不在我们的计划中。
3.遇到的困难主要是数组越界,通过严谨的检查以及步步验证的方式找出了错误并解决了。另一个须待解决的问题是生成题目的速度有些缓慢,因此完善了多次的算法来提高代码的执行效率。
4.总的来说,在结对编程中我们有各自的想法,通过代码的形式来进行人与人之间的交流不失为一种好的方法,在这个过程中我们培养了团队协作的能力和与他人交际的能力,同时也促使自身的编程能力不断提高,这使我们都受益匪浅。当然如果还有机会的话,我还是希望可以实现带括号的运算式的生成以及答案的计算。