Java实现 四则运算生成 (戴国权 & 关绍华)
Posted 6324tv-upup
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java实现 四则运算生成 (戴国权 & 关绍华)相关的知识,希望对你有一定的参考价值。
GitHub仓库:https://github.com/BiuBiuBangBoom/mathcreate
项目要求:
题目:实现一个自动生成小学四则运算题目的命令行程序说明:
说明:
自然数: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为算术表达式。
需求:
1.(完成)使用 -n 参数控制生成题目的个数
2.(完成)使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,该参数可以设置为1或其他自然数。
3.(完成)生成的题目中计算过程不能产生负数
4.(完成)生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数
5.(完成)每道题目中出现的运算符个数不超过3个。
6.(完成)程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。生成的题目存入执行程序的当前目录下的Exercises.txt文件
7.(完成)在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件
8.(完成)程序应能支持一万道题目的生成。
9.(完成)程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。统计结果输出到文件Grade.txt,格式如下:
Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
设计实现过程
生成表达式:
创建Fraction类的对象,该类把所有的数值定义为分子/分母的形式,在Expression类中创建表达式,存储于hashset中,hashset能帮我们实现查重。
当e1-e2时,倘若e1<e2,把-号更改为÷号,当e1÷e2时,倘若e1>e2,把÷号更改为-号。
使用switch来控制生成的表达式有多少个操作数。
代码说明:
分数类:
package po; import java.util.Stack; public class Fraction {
//定义分子跟分母 private int numerator = 0; private int denominator = 1; private int symbol; public int getNumerator() { return numerator; } public void setNumerator(int numerator) { this.numerator = numerator; } public int getDenominator() { return denominator; } public void setDenominator(int denominator) { this.denominator = denominator; } public int getSymbol() { return symbol; } public void setSymbol(int symbol) { this.symbol = symbol; } public Fraction(int number1, int number2) { numerator = Math.abs(number1); denominator = Math.abs(number2); symbol = number1 * number2 < 0 ? -1 : 1; if(numerator != 0) this.simplify(); } //求最小公约数 private int gcd(int a, int b) { int mod = a % b; return mod == 0 ? b : gcd(b, mod); } //化简 private void simplify() { int a = gcd(numerator, denominator); if(a == 0) System.out.println("ERROR"); numerator /= a; denominator /= a; } //加法 public Fraction add(Fraction addend) { int newnum = this.symbol * this.numerator * addend.denominator + addend.symbol * addend.numerator * this.denominator; int newden = this.denominator * addend.denominator; return new Fraction(newnum, newden); } //乘法 public Fraction sub(Fraction subtrahend) { int newnum = this.symbol * this.numerator * subtrahend.denominator - subtrahend.symbol * subtrahend.numerator * subtrahend.denominator; int newden = this.denominator * subtrahend.denominator; return new Fraction(newnum, newden); } //除法 public Fraction mul(Fraction multiplicator) { int newnum = this.symbol * this.numerator * multiplicator.symbol * multiplicator.numerator; int newden = this.denominator * multiplicator.denominator; return new Fraction(newnum, newden); } public Fraction div(Fraction divisor) { int newnum = this.symbol * this.numerator * divisor.symbol * divisor.denominator; int newden = this.denominator * divisor.numerator; return new Fraction(newnum, newden); } //根据表达式计算出结果 public static Fraction calculateStringExp(String sIn) { Stack<Fraction> fractionStack = new Stack<>(); Stack<Character> symbolStack = new Stack<>(); String s = sIn.replaceAll(" ",""); s += "="; StringBuffer temp = new StringBuffer(); for(int i = 0; i < s.length();i++) { char ch = s.charAt(i); if((ch >= ‘0‘ && ch <= ‘9‘) || ch == ‘‘‘ || ch == ‘/‘) temp.append(ch); else { String tempStr = temp.toString(); if(!tempStr.isEmpty()) { Fraction f = Fraction.string2Fraction(tempStr); fractionStack.push(f); temp = new StringBuffer(); } while(!comparePriority(ch, symbolStack) && !symbolStack.empty()) { Fraction numberB = fractionStack.pop(); Fraction numberA = fractionStack.pop(); switch(symbolStack.pop()) { case ‘+‘: fractionStack.push(numberA.add(numberB)); break; case ‘-‘: fractionStack.push(numberA.sub(numberB)); break; case ‘x‘: fractionStack.push(numberA.mul(numberB)); break; case ‘÷‘: fractionStack.push(numberA.div(numberB)); break; default: break; } } if(ch != ‘=‘) { symbolStack.push(ch); if (ch == ‘)‘) { symbolStack.pop(); symbolStack.pop(); } } } } return fractionStack.pop(); } //比较符号优先 private static boolean comparePriority(char symbol, Stack<Character> symbolStack) { if (symbolStack.empty()) return true; char top = symbolStack.peek(); if (top == ‘(‘) return true; switch (symbol) { case ‘(‘: return true; case ‘ב: if (top == ‘+‘ || top == ‘-‘) return true; else return false; case ‘÷‘: if (top == ‘+‘ || top == ‘-‘) return true; else return false; case ‘+‘: return false; case ‘-‘: return false; case ‘)‘: return false; case ‘=‘: return false; default: break; } return true; } //将指定string转化为Fraction类 public static Fraction string2Fraction(String s) { int curnum = 0; int curden = 1; String[] strings = s.substring(s.indexOf("‘") + 1).split("/"); if (strings.length <= 0) throw new NumberFormatException(); curnum = Integer.parseInt(strings[0]); if (strings.length >= 2) curden = Integer.parseInt(strings[1]); if (s.contains("‘")) curnum = Integer.parseInt(s.substring(0, s.indexOf("‘"))) * curden + curnum; return new Fraction(curnum, curden); } //将Fraction类转化为String public String toString() { StringBuilder fs = new StringBuilder(); if(numerator == 0) fs.append(0); else if(numerator > denominator) { fs.append(numerator / denominator); if(numerator % denominator != 0) { fs.append("‘"); fs.append(numerator % denominator); fs.append("/"); fs.append(denominator); } } else if(numerator < denominator) { fs.append(numerator); fs.append("/"); fs.append(denominator); } else fs.append(1); return fs.toString(); } }
表达式类:
用来实现生成表达式跟计算答案及批改功能
package po; import java.io.*; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; /** *随机生成四则运算表达式 * */ public class Expression { //表达式运算数的数值范围(0~range不包括range) private int range; //需要生成表达式的数目 private int sum; //随机数生成器 private Random random = new Random(System.currentTimeMillis()); //使用hashSet来筛选出不重复的表达式 private HashSet<String> hashSet = new HashSet<>(); //字符串类型的表达式 private String expression; public Expression(int range, int sum) { this.range = range; this.sum = sum; } /** * 取计算数 * @return 返回0~range 的数值,不包括range */ public Fraction getValue() { int denominator = random.nextInt(range - 1) + 1; int numerator = random.nextInt(denominator*denominator) - 1; return new Fraction(numerator, denominator); } /** *取计算符号 * @return 返回+,-,*,/中任一个 */ public String getOperation() { String c = " "; int temp = random.nextInt(4); switch (temp) { case 0: c = "+"; break; case 1: c = "-"; break; case 2: c = "x"; break; case 3: c = "÷"; break; } return c; } /** * 比较两个分数的大小 * @return true 大, false 小 */ private boolean isLarge(Fraction value1, Fraction value2) { if(value1.getNumerator()*value2.getDenominator() > value2.getNumerator()*value1.getDenominator()) { return true; } else return false; } /** * 第一种修改表达式方式 * @param expression1 */ public String change1(String expression1, Fraction value, String operation) { Fraction value1 = new Fraction(1, 1); if(operation == "-") { value1 = value1.calculateStringExp(expression1); if(!isLarge(value1, value)) { if (value.getNumerator() != 0) { operation = "÷"; } else operation = "+"; } } if(operation == "÷") { value1 = value1.calculateStringExp(expression1); if(!isLarge(value1, value)) { operation = "-"; } if(value.getNumerator() == 0) { operation = "x"; } } return operation; } /** * 第二种修改表达式方式 * @param expression1 */ private String change2(String expression1, Fraction value, String operation) { Fraction value1 = new Fraction(1, 1); value1 = value1.calculateStringExp(expression1); if (operation == "-") { if (!isLarge(value1, value)) { if (value.getNumerator() != 0) { operation = "÷"; } else { operation = "+"; } } } if (operation == "÷") { if (isLarge(value1, value)) { operation = "-"; } else if (value.getNumerator() == 0) { operation = "x"; } } return operation; } private String change3 (String expression, String operation1, Fraction value1, String operatin2, Fraction value2) { Fraction value = new Fraction(1, 1); value = value.calculateStringExp(expression); String expression1; if (operatin2 == "-" || operatin2 == "x" || operatin2 == "÷") { if (operation1 == "+") { if (operatin2 == "-") { expression1 = value + "+" + value1; operatin2 = change1(expression1, value2, operatin2); expression = "(" + expression + ")" + operation1 + value1 + operatin2 + value2; } if (operatin2 == "÷") { if (isLarge(value1, value2)) { value = value1; value1 = value2; value2 = value; } else if(value2.getNumerator() == 0) { operatin2 = "x"; } expression = "(" + expression + ")" + operation1 + value1 + operatin2 + value2; } } if (operation1 == "-") { if (operatin2 == "-") { operation1 = change1(expression, value1, operation1); expression1 = value + operation1 + value1; operatin2 = change1(expression1, value2, operatin2); expression = "(" + expression + ")" + operation1 + value1 + operatin2 + value2; } if (operatin2 == "x" || operatin2 == "÷") { Fraction value3 = new Fraction(1, 1); if (operatin2 == "÷") { if (isLarge(value1, value2)) { value = value1; value1 = value2; value2 = value; } else if(value2.getNumerator() == 0) { operatin2 = "x"; } } value3 = value3.calculateStringExp(value1 + operatin2 + value2); operation1 = change1(expression, value3, operation1); expression = "(" + expression + ")" + operation1 + value1 + operatin2 + value2; } } if (operation1 == "x") { if (operatin2 == "-" || operatin2 == "÷") { expression1 = value + operation1 + value1; operatin2 = change1(expression1, value2, operatin2); expression = "(" + expression + ")" + operation1 + value1 + operatin2 + value2; } } if (operation1 == "÷") { if (isLarge(value, value1)) { operation1 = "-"; if (operatin2 == "x" || operatin2 == "÷") { expression1 = value + operation1 + value1; if (operatin2 == "÷") { operatin2 = change1(expression1, value2, operatin2); } expression = "(" + "(" + expression + ")" + operation1 + value1 + ")" + operatin2 + value2; } expression = "(" + expression + ")" + operation1 + value1 + operatin2 + value2; } else if(value1.getNumerator() != 0) { operation1 = "x"; if(operatin2 == "-") { operatin2 = "+"; } expression = "(" + "(" + expression + ")" + operation1 + value1 + ")" + operatin2 + value2; } } } return expression; } /** * 把表达式加载进hashset */ public void getExpression () { int r = random.nextInt(3) + 1; while (hashSet.size() < sum) { switch (r) { case 1: hashSet.add(twoNumber()); break; case 2: hashSet.add(threeNumber()); break; case 3: hashSet.add(fourNumber()); break; } } } /** * 构造表达式的方式如a+b * @return String类型的表达式 */ private String firstModel () { Fraction value1 = getValue(); Fraction value2 = getValue(); String operation = getOperation(); if (isLarge(value1, value2)) { if (operation.equals("÷")) { operation = "-"; } } if (!isLarge(value1, value2)) { if (operation.equals("-")) { if(value2.getNumerator() != 0) { operation = "÷"; } else { operation = "+"; } } } expression = value1.toString() + operation + value2.toString(); return expression; } /** * 两个操作数的表达式 * @return String类型的表达式 */ private String twoNumber () { expression = firstModel(); return expression; } /** * 三个操作数的表达式 * @return String类型的表达式 */ private String threeNumber () { String expression1 = firstModel(); String operation = getOperation(); Fraction value = getValue(); int flag = random.nextInt(3); switch (flag) { case 0: expression = expression1 + "+" + value; break; case 1: operation = change1(expression1, value, operation); expression = "(" + expression1 + ")" + operation + value; break; case 2: operation = change2(expression1, value, operation); expression = value + operation + "(" + expression1 + ")"; } return expression; } /** * 四个操作数的表达式 * @return String类型的表达式 */ private String fourNumber () { String expression1 = firstModel(); String expression2 = firstModel(); String operation1 = getOperation(); String operation2 = getOperation(); Fraction value = getValue(); Fraction value1 = getValue(); int flag = random.nextInt(4); switch (flag) { case 0: if (operation1.equals("-") || operation1.equals("÷")) { Fraction value2 = new Fraction(1, 1); value2 = value2.calculateStringExp(expression1); if (operation1.equals("-")) { if (!isLarge(value, value2)) { if(value2.getNumerator() != 0) { operation1 = "÷"; } else { operation1 = "+"; } } } else { if (isLarge(value, value2)) { operation1 = "-"; } } } expression = "(" + expression1 + ")" + operation1 + "(" + expression2 + ")"; break; case 1: expression = change3(expression1, operation1, value, operation2, value1); break; case 2: if (operation1 == "-" || operation1 == "x" || operation1 == "÷") { if (operation1 == "-") { if (!isLarge(value, value.calculateStringExp(expression1))) { if(value.calculateStringExp(expression1).getNumerator() != 0) { operation1 = "÷"; } else { operation1 = "+"; } int i = random.nextInt(2); if (i == 0) operation2 = "+"; if (i == 1) { operation2 = "-"; Fraction value2 = new Fraction(1, 1); value2 = value2.calculateStringExp(value + operation1 + value.calculateStringExp(expression1)); if (!isLarge(value2, value1)) { if(value1.getNumerator() != 0) { operation2 = "÷"; } else { operation1 = "+"; } } } } } if (operation1 == "÷") { if (isLarge(value1, value.calculateStringExp(expression1))) { operation1 = "-"; int i = random.nextInt(2); if (i == 0) operation2 = "+"; if (i == 1) { operation2 = "-"; Fraction value3 = new Fraction(1, 1); value3 = value3.calculateStringExp(value + operation1 + value.calculateStringExp(expression1)); if (!isLarge(value3, value1)) { if(value1.getNumerator() != 0) { operation2 = "÷"; } else { operation2 = "+"; } } } } } if (operation1 == "x") { value = value.calculateStringExp(value + operation1 + expression1); if (operation2 == "-") { if (!isLarge(value, value1)) { if(value1.getNumerator() != 0) { operation2 = "÷"; } else { operation2 = "+"; } } } if (operation2 == "÷") { if (isLarge(value, value1)) { operation2 = "-"; } if(value1.getNumerator() != 0) { operation2 = "x"; } } } } expression = value + operation1 + "(" + expression1 + ")" + operation2 + value1; break; case 3: if (operation1 == "-") { if (operation2 == "-") { if (!isLarge(value, value1)) { if(value1.getNumerator() != 0) { operation1 = "÷"; } else { operation1 = "+"; } Fraction value4 = new Fraction(1, 1); if (isLarge(value4.calculateStringExp(value + operation1 + value1), value.calculateStringExp(expression1))) { operation2 = "-"; } } } if (operation2 == "x" || operation2 == "÷") { if (operation2 == "÷") { if (isLarge(value1, value.calculateStringExp(expression1))) { operation2 = "x"; } if (!isLarge(value, value1.calculateStringExp(value1 + operation2 + value.calculateStringExp(expression1)))) { operation1 = "+"; } } } } if (operation1 == "÷") { if (isLarge(value, value1)) { operation1 = "x"; if (operation2 == "-") { if (!isLarge(value.calculateStringExp(value + operation1 + value1), value.calculateStringExp(expression1))) { operation2 = "+"; } } if (operation2 == "÷") { if (isLarge(value.calculateStringExp(value + operation1 + value1), value.calculateStringExp(expression1))) { operation2 = "-"; } else if(value.calculateStringExp(expression1).getNumerator() == 0) { operation2 = "x"; } } } } expression = value + operation1 + value1 + operation2 + "(" + expression1 + ")"; break; } return expression; } /** * 把表达式写到file文件中 * @param file */ public void create(File exfile, File anfile) throws IOException { Iterator<String> lt = hashSet.iterator(); BufferedWriter ew = new BufferedWriter(new FileWriter(exfile)); BufferedWriter aw = new BufferedWriter(new FileWriter(anfile)); int count = 1; while(lt.hasNext()) { String s = String.valueOf(count) + "." + " "; String a = String.valueOf(count) + "." + " "; String temp = lt.next(); a = a + Fraction.calculateStringExp(temp).toString(); s = s + temp; aw.write(a); ew.write(s); aw.newLine(); ew.newLine(); count++; } } public static void check(File exfile, File anfile) throws IOException { List<Integer> cor = new ArrayList<Integer>(); List<Integer> wor = new ArrayList<Integer>(); BufferedReader er = new BufferedReader(new FileReader(exfile)); BufferedReader ar = new BufferedReader(new FileReader(anfile)); String curerline = null; String curarline = null; while((curerline = er.readLine()) != null && (curarline = ar.readLine()) != null) { int temp = curerline.indexOf("."); String a = curerline; int tihao = Integer.parseInt(a.substring(0, temp)); String ertemp = curerline.substring(curerline.lastIndexOf(" ") + 1); String artemp = curarline.substring(curarline.lastIndexOf(" ") + 1); String coranswer = Fraction.calculateStringExp(ertemp).toString(); if(artemp.equals(coranswer)) cor.add(tihao); else wor.add(tihao); } er.close(); ar.close(); File gradef = new File("grade.txt"); BufferedWriter gradew = new BufferedWriter(new FileWriter(gradef)); gradew.write("correct:" + cor.size()); gradew.newLine(); gradew.write(cor.toString()); gradew.newLine(); gradew.write("wrong:" + wor.size()); gradew.newLine(); gradew.write(wor.toString()); gradew.newLine(); gradew.close(); System.out.println("批改完成"); } }
用户接口类:
package po; import java.io.File; import java.io.IOException; public class UserStart { public static void main(String[] args) { int range = -1, num = -1; boolean r_exist = false; for (int i = 0; i < args.length; i += 2) { switch (args[i]) { case "-r": if (Integer.parseInt(args[i + 1]) > 0) { r_exist = true; range = Integer.parseInt(args[i + 1]); } if (range > 10) { System.out.println("-r can‘t greater than 10"); System.exit(0); } break; case "-n": num = Integer.parseInt(args[i + 1]); break; case "-e": String exerciseFileName = args[i + 1]; String answerFileName = args[i + 3]; File exerciseFile = new File(exerciseFileName); File answerFile = new File(answerFileName); try { Expression.check(exerciseFile, answerFile); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } default: break; } } if (!r_exist) { System.exit(0); } else { Expression ex = new Expression(range, num); File exfile = new File("Expression.txt"); File anfile = new File("answer.txt"); ex.getExpression(); try { ex.create(exfile, anfile); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
测试运行
生成的表达式
答案
批改功能:
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 |
60 |
· Estimate |
· 估计这个任务需要多少时间 |
60 |
90 |
Development |
开发 |
300 |
330 |
· Analysis |
· 需求分析 (包括学习新技术) |
240 |
360 |
· Design Spec |
· 生成设计文档 |
40 |
60 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
30 |
45 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
15 |
20 |
· Design |
· 具体设计 |
60 |
90 |
· Coding |
· 具体编码 |
360 |
420 |
· Code Review |
· 代码复审 |
30 |
30 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
120 |
150 |
Reporting |
报告 |
90 |
120 |
· Test Report |
· 测试报告 |
60 |
90 |
· Size Measurement |
· 计算工作量 |
45 |
60 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 |
40 |
合计 |
|
1450 |
1965 |
总结:本次结对编程我主要负责Fraction类跟用户接口的的编写,关绍华同志负责了Expression的编写。在合作过程中,经常出现编写过程中方法参数及返回值没有匹配好,出现了较多问题。但最后都因为良好的沟通解决了。两人结对编程也能够在自己思路中断的时候能够从队友的思路中得到新的idea,并且能够互相检查彼此的代码有无累赘,学习到了很多。另外没有将代码分为多个类,很多功能写在了同一个类里,进行代码复审的时候修改代码十分麻烦,出现遗漏的情况,以后书写代码应该更加规范。
以上是关于Java实现 四则运算生成 (戴国权 & 关绍华)的主要内容,如果未能解决你的问题,请参考以下文章