个人作业1——四则运算题目生成程序(基于控制台)
码云地址:https://git.oschina.net/lzx84/szys
题目:
从《构建之法》第一章的 “程序” 例子出发,像阿超那样,花二十分钟写一个能自动生成小学四则运算题目的命令行 “软件”。
满足以下需求:
- 除了整数以外,还要支持真分数的四则运算,真分数的运算,例如:1/6 + 1/8 = 7/24
- 运算符为 +, −, ×, ÷
- 并且要求能处理用户的输入,并判断对错,打分统计正确率。
- 要求能处理用户输入的真分数, 如 1/2, 5/12 等
- 使用 -n 参数控制生成题目的个数,例如执行下面命令将生成10个题目
Myapp.exe -n 10
需求分析:
- 需要处理分数,包括化简分数、识别整数等。并考虑特殊情况,如分数分母不为0等。考虑到题目要求小学水平,则分子分母数值不超过100。
- 需要编写分数四则运算的算法,并考虑特殊情况,如减法结果不能为负数,除法中除数不能为0等。
- 需统计用户正确的题目数,与总题目数。
- 需要实现字符串的识别与比较。
功能实现:
- 基本功能:能随机生成若干四则运算式,并检测用户答案,统计正确率。
- 扩展功能:实现多项运算、统计做题时长、避免重复题型、控制题目难度等(未实现)
- 高级功能:实现错题统计功能、实现多用户竞赛功能、实现更复杂的运算等(未实现)
设计实现:
Fraction类:
Calculate类:
Dofrac类:
代码说明:
Fraction类:
public class Fraction { private int fenzi; private int fenmu; public Fraction() { super(); } public Fraction(int fenzi, int fenmu) { super(); this.fenzi = fenzi; this.fenmu = fenmu; this.simplify(fenzi, fenmu); //在构造函数中直接化简分数(感觉此方法欠妥) } public void simplify(int fenzi, int fenmu) { int GCD = Dofrac.GCD(fenzi, fenmu); this.fenzi = fenzi / GCD; this.fenmu = fenmu / GCD; }//化简分数 @Override public String toString() { if (fenzi == 0) { return 0 + ""; } else if (fenzi % fenmu == 0) { return fenzi / fenmu + ""; } else return fenzi + "/" + fenmu; }//改写toString,输出为分数形式 public int getFenzi() { return fenzi; } public void setFenzi(int fenzi) { this.fenzi = fenzi; } public int getFenmu() { return fenmu; } public void setFenmu(int fenmu) { this.fenmu = fenmu; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + fenmu; result = prime * result + fenzi; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Fraction other = (Fraction) obj; if (fenmu != other.fenmu) return false; if (fenzi != other.fenzi) return false; return true; } }
Calculate类:
public class Calculate { public static Fraction add(Fraction f1, Fraction f2) { int fz1 = f1.getFenzi(); int fz2 = f2.getFenzi(); int fm1 = f1.getFenmu(); int fm2 = f2.getFenmu(); Fraction f = new Fraction(fz1 * fm2 + fm1 * fz2, fm1 * fm2); return f; }//加法运算 public static Fraction sub(Fraction f1, Fraction f2) { int fz1 = f1.getFenzi(); int fz2 = f2.getFenzi(); int fm1 = f1.getFenmu(); int fm2 = f2.getFenmu(); Fraction f = new Fraction(fz1 * fm2 - fm1 * fz2, fm1 * fm2); return f; }//减法运算 public static Fraction mul(Fraction f1, Fraction f2) { int fz1 = f1.getFenzi(); int fz2 = f2.getFenzi(); int fm1 = f1.getFenmu(); int fm2 = f2.getFenmu(); Fraction f = new Fraction(fz1 * fz2, fm1 * fm2); return f; }//乘法运算 public static Fraction div(Fraction f1, Fraction f2) { int fz1 = f1.getFenzi(); int fz2 = f2.getFenzi(); int fm1 = f1.getFenmu(); int fm2 = f2.getFenmu(); Fraction f = new Fraction(fz1 * fm2, fm1 * fz2); return f; }//除法运算 public static boolean compare(Fraction f1, Fraction f2) { int fz1 = f1.getFenzi(); int fz2 = f2.getFenzi(); int fm1 = f1.getFenmu(); int fm2 = f2.getFenmu(); if (fz1 * fm2 >= fz2 * fm1) { return true; } else{
return false;
}
}//比较两分数的大小 }
Dofrac类:
public class Dofrac { public static Fraction CreatFrac() { int fz, fm,co;
co=(int)(Math.random()*2);//co取[0,1]得随机值,分别代表分数和整数
if(co==0){
fm = (int) (2 + Math.random() * (100 - 2 + 1));//分母为2-100的随机数
fz =(int) (0 + Math.random() * (fm - 0 + 1));//分子为 0--fm 的随机数(确保真分数)
}else {
fm=1;
fz=(int) (0 + Math.random() * (100 - 0 + 1));
}
Fraction frac = new Fraction(fz, fm); return frac; }//创建随机分数 public static boolean check(String input) { if (input.matches("[0-9]+")||input.matches("[0-9]+/[0-9]+")) { return true; } else {
return false;
} }//利用正则表达式处理用户输入的答案
public static int GCD(int m, int n) { while (true) { if ((m = m % n) == 0) return n; if ((n = n % m) == 0) return m; } }//计算最大公约数
public static Fraction MakeFor(Fraction f1, Fraction f2, int op, int i) { Fraction result = new Fraction(); switch (op) { case 1: { result = Calculate.add(f1, f2); System.out.println("第" + i + "题:" + f1.toString() + "+" + f2.toString()); break; } case 2: { if (!Calculate.compare(f1, f2)) { Fraction temp = f1; f1 = f2; f2 = temp; }//比较两分数的大小,若减数小于被减数,则将两个数交换 result = Calculate.sub(f1, f2); System.out.println("第" + i + "题:" + f1.toString() + "-" + f2.toString()); break; } case 3: { result = Calculate.mul(f1, f2); System.out.println("第" + i + "题:" + f1.toString() + "*" + f2.toString()); break; } case 4: { if (f2.getFenzi() == 0) { f2.setFenzi((int) (1 + Math.random() * (10 - 1 + 1))); }//若除数分子为0,则分子重新取一个1——100的随机数 result = Calculate.div(f1, f2); System.out.println("第" + i + "题:" + f1.toString() + "÷" + f2.toString()); break; } } return result; } }
Generator类(执行类)
public class Generator { public static void main(String[] args) { try { int op = 0; String input; int flag = 0;//用于检测用户答对的题目数 Scanner sc = new Scanner(System.in); System.out.println("【四则运算题目生成器】"); System.out.println("请输入需要的题目数量:"); int n = sc.nextInt(); for (int i = 1; i <= n; i++) { Fraction f1 = Dofrac.CreatFrac(); Fraction f2 = Dofrac.CreatFrac(); op = (int) (Math.random() * 4 + 1); Fraction result = Dofrac.MakeFor(f1, f2, op, i); input = sc.next(); while (!Dofrac.check(input)) { System.out.println("输入有误,请重新输入:"); input = sc.next(); } if (input.equals(result.toString())) { System.out.println("回答正确"); System.out.println("---------------------------------------------"); flag++; } else { System.out.println("回答错误,正确答案是:" + result.toString()); System.out.println("---------------------------------------------"); } } System.out.println("---------------------------------------------"); System.out.println("答题完毕,你的正确率为" + 100 * flag / n + "%"); sc.close(); } catch (Exception e) { e.printStackTrace(); } } }
测试运行:
PSP表:
PSP2.1 | Personal Software Process Stages | Time (%) Senior Student | Time (%) |
Planning | 计划 | 5min | 30min |
· Estimate | 估计这个任务需要多少时间 | 8min | 10min |
Development | 开发 | 2h | 1h30min |
· Analysis | 需求分析 (包括学习新技术) | 10min | 8min |
· Design Spec | 生成设计文档 | 0 | 0 |
· Design Review | 设计复审 | 3min | 1min |
· Coding Standard | 代码规范 | 0 | 0 |
· Design | 具体设计 | 1h | 30min |
· Coding | 具体编码 | 1h | 40min |
· Code Review | 代码复审 | 0 | 0 |
· Test | 测试(自我测试,修改代码,提交修改) | 5min | 8min |
Reporting | 报告 | 30min | 40min |
· | 测试报告 | 0 | 0 |
· | 计算工作量 | 0 | 0 |
· | 并提出过程改进计划 | 0 | 0 |
总结:
此次作业整体难度不大,但是刚开始看到题目构思的时候,却一度陷入僵局。也许是因为太久没有编程,很多知识都忘记了,导致刚开始的时候不懂从何下手。在思考了很久,复习了很多以前的知识后,大体上有了思路,但也不是很清晰,想到什么写什么,迷迷糊糊就完成了。中间遇到的BUG也不是很多,但是调试花了很多时间,感觉这是自己编程思想不够系统,对软件的应用也不是很熟悉造成的,根本原因还是在于练习不够,经验不足。希望以后多加练习,可以更加进步。最后感谢老师们和助教的辛勤付出,你们辛苦了!