、题目描述:
1. 使用 -n 参数控制生成题目的个数,例如
Myapp.exe -n 10 -o Exercise.txt
将生成10个题目。
2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如
Myapp.exe -r 10
将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。
3. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。
4. 每道题目中出现的运算符个数不超过3个。
5. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,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。
6. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
1. 答案1
2. 答案2
特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。
7. 程序应能支持一万道题目的生成。
8. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,并会输出所有题目中重复的题目,输入参数如下:
Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt -o Grade.txt
统计结果输出到文件Grade.txt,格式如下:
Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
Repeat:2
RepeatDetail:
(1) 2,45+32 Repeat 3,32+45
(2) 5,3+(2+1) Repeat 7,1+2+3
解释:
Correct: 5 ----5道题目正确,正确的题号 1,3,5,7,9
Wrong:5 -----5道题目错误,错误的题号 2,4,6,8,10
Repeat:2 2---组题目重复
(1) 第一组 题号2,题目 45+32 与题号3的题目重复,题号3为 32+45
(2)第二组 题号5,题目 3+(2+1) 与题号7的题目重复,题号7为 1+2+3
二、需求分析
一个基于java控制台的四则运算,要求能够实现生成并计算含有真,假分数,整数的不超过三个运算符带有括号的四则运算表达式,并且能根据用户所提交的答案生成答题报告,答题报告中主要包括,本次答题的正确,错误,和重复表达式出现的情况。生成的表达式和答案要存入文件中。
从整个需求来看,大致可以分为三个模块,生成表达式,表达式计算(包括将表达式和答案写入文件),答题报告的生成(包括表达式的查重和根据输入完成的校验)。
生成表达式模块:通过随机数可以生成运算数,但需要通过字符串和数字的结合生成运算符号;
表达式计算:可采用将随机生成的表达式转换为后缀,在对后缀表达式进行计算完成。
答题报告的生成:关键在于查重的实现,通过二叉树可以实现
三、功能设计
通过控制台进行选择要执行的操作,生成四则运算表达式,并进行查重,然后进行批改,最后生成批改报告
四、设计实现
1.测试类(test.java)
2.分数类(fen.java)//对分数的定义,用于实现分数的运算。
主函数:
public static void main(String[] args) { String corr = ""; String wro = ""; // String s = ""; String[] repeat = null; int re = 0; Scanner scanner = new Scanner(System.in); while (true) { System.out.println("********四则运算程序********"); System.out.println("请选择操作"); System.out.println("1.生成题目"); System.out.println("2.进行批改(需要进入txt中答题)"); System.out.println("3.退出"); int choice = scanner.nextInt(); if (choice == 1) {//生成题目 System.out.print("请输入生成题目的个数为:"); String s1=getScannerStr(); while (!isInt(s1)) {//判断是否为整型 System.out.println("输入错误,不是整数类型,请重新输入!"); s1 = getScannerStr(); } String[] strr = new String[Integer.parseInt(s1) + 1]; String[] strr2 = new String[Integer.parseInt(s1) + 1]; repeat = new String[Integer.parseInt(s1) + 1]; re = 0; System.out.print("请输入生成题目中数值的范围:"); String s2=getScannerStr(); while (!isInt(s2)) {//判断是否为整型 System.out.println("输入错误,不是整数类型,请重新输入!"); s2 = getScannerStr(); } char[] ch = { '+', '-', '*', '÷' }; // 清除之前的文件内容 try { FileWriter fw = new FileWriter( "G:/test/Exercises.txt"); fw.write(""); fw.close(); } catch (IOException e) {//异常处理 System.out.println("文件写入失败!" + e); } try { FileWriter fw = new FileWriter( "G:/test/Answers.txt"); fw.write(""); fw.close(); } catch (IOException e) {//异常处理 System.out.println("文件写入失败!" + e); } // 生成表达式 for (int i = 1; i <= Integer.parseInt(s1); i++) { str = ""; int x = (int) (Math.random() * 2);//随机数 int y = (int) (Math.random() * 3);//随机数 int t1 = 0; int t2 = 0; String num = ""; String opera = ""; String ex = ""; for (int j = 0; j <= x; j++) { int a = (int) (Math.random() * 2);//表达式符号 if (a == 0) { num = (1 + (int) (Math.random() * (Integer.parseInt(s2) - 1))) + ""; } else if (a == 1) { int b = (int) (Math.random() * (Integer.parseInt(s2))); int q = 2 + (int) (Math.random() * (Integer.parseInt(s2) - 1)); if (b == 0) { num = (1 + (int) (Math.random() * (q - 1))) + "/" + q; } else { num = b + "'" + (1 + (int) (Math.random() * (q - 1))) + "/" + q; } } opera = ch[(int) (Math.random() * 4)] + ""; if (t1 != 0) { if ((int) (Math.random() * 2) == 1) { ex = ex + num + ")" + opera; t1--; } } if (y == 0) { ex = ex + num + opera; } else if (y == 1) { ex = ex + "(" + num + opera; t1++; } else if (y == 2) { ex = "(" + ex + num + opera; t1++; } } ex = ex + (1 + (int) (Math.random() * (Integer.parseInt(s2) - 1))); while (true) { if (t1 == 0) break; ex = ex + ")"; t1--; } for (int u = 0; u <= x; u++) { if (ex.substring(0, 1).equals("(")) { t2++; for (int k = 1; k < ex.length(); k++) { if (ex.substring(k, k + 1).equals("(")) t2++; if (ex.substring(k, k + 1).equals(")")) { t2--; if (k != ex.length() - 1) { if (t2 == 0) break; } else { ex = ex.substring(1, ex.length()); ex = ex.substring(0, ex.length() - 1); } } } } } String ex1 = generate(ex); suffixExpression2Tree(ex1); strr[i] = str; strr2[i] = ex; int xy = 1; for (int h = 1; h < i; h++) { if (strr[h].equals(str)) { xy = 0; repeat[re] = h + "," + strr2[h] + " Repeat " + i + "," + ex; re++; break; } } if (xy == 0) { i--; continue; } else { // System.out.print(i + ". "); // System.out.print(ex + "="); // String an = new String(); // an=scanner.next(); String result = PRNCal(ex1); // System.out.print("......." + ex1 + "="); String[] ary = result.split("/"); int a = Integer.parseInt(ary[0].trim()); int b = Integer.parseInt(ary[1].trim()); if ((Math.abs(a) < Math.abs(b)) && (a != 0) && (b != 0)) { result = a + "/" + b; } else if (a == b) { result = 1 + ""; } else if (a == -b) { result = -1 + ""; } else { int yu; int da; if (a == 0 || b == 0) { yu = 0; da = 0; } else { yu = a % b; da = a / b; } if (yu == 0) result = da + ""; else result = da + "'" + Math.abs(yu) + "/" + Math.abs(b); } // 存入文件 try { FileWriter fw = new FileWriter( "G:/test/Exercises.txt", true); fw.write(i + "."); fw.write(ex); fw.write("=" + " " + "\r\n"); fw.close(); } catch (IOException e) { System.out.println("文件写入失败!" + e); } try { FileWriter fw = new FileWriter( "G:/test/Answers.txt", true); fw.write(i + ":"); fw.write(result); fw.write("\r\n"); fw.close(); } catch (IOException e) { System.out.println("文件写入失败!" + e); } } } } else if (choice == 2) { try { System.out.print("批改结果如下:"); InputStreamReader reader = new InputStreamReader( new FileInputStream( "G:/test/Answers.txt"), "gbk"); BufferedReader br = new BufferedReader(reader); String s = null; InputStreamReader reader1 = new InputStreamReader( new FileInputStream( "G:/test/Exercises.txt"), "gbk"); BufferedReader br1 = new BufferedReader(reader1); String s1 = null; int i = 0; corr = "";//正确题号 wro = "";//错误题号 int wrong = 0;//定义错误个数 int correct = 0;//定义正确个数 while (((s = br.readLine()) != null) && (s1 = br1.readLine()) != null) { i++; String[] st = s.split(":"); String[] st1 = s1.split("="); // System.out.println(st[1] + "......" + st1[1]); if (st[1].trim().equals(st1[1].trim())) { correct++; corr = corr + i + ","; } else { wrong++; wro = wro + i + ","; } } System.out.print("Correct:" + correct);//输出正确格式 if (corr.length() <= 1) System.out.println("(" + ")"); else System.out.println("(" + corr.substring(0, corr.length() - 1) + ")"); System.out.print("Wrong:" + wrong);//输出错误格式 if (wro.length() <= 1) System.out.println("(" + ")"); else System.out.println("(" + wro.substring(0, wro.length() - 1) + ")"); System.out.println("Repeat:" + (re)); System.out.println("RepeatDetail:"); for (int u = 0; u < re; u++) { System.out.print("(" + (u + 1) + ")"); System.out.print(" "); System.out.println(repeat[u]); } } catch (Exception e) { e.printStackTrace(); } } else if (choice == 3) { System.out.println("退出成功!"); break; } else { System.out.println("输入的命令错误,请重新输入!"); } } }
五、测试运行
1.运行程序
生成题目并输入相应的参数
3.题目文档
4.正确答案文档
5.答题文档
6.进行批改,批改结果
六、源代码
代码地址:https://gitee.com/buildup/operations.git
七、小结
此程序并未做好封装,所以函数以及排版显得杂乱无章,下次应当注意改进。