GitHub地址https://github.com/TaoTaoLv1/arithmetic

结对伙伴:叶文涛

项目要求:

实现一个自动生成小学四则运算题目的命令行程序.

  • 使用 -n 参数控制生成题目的个数(完成)
  • 使用 -r 参数控制题目中数值的范围, 。该参数可以设置为1或其他自然数。(完成)
  • 生成的题目中计算过程不能产生负数(完成)
  • 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。(完成)
  • 程序一次运行生成的题目不能重复,生成的题目存入执行程序的当前目录下的Exercises.txt文件(完成)
  • 每道题目中出现的运算符个数不超过3个(完成)
  • 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件(完成)
  • 程序应能支持一万道题目的生成。(完成)
  • 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。(完成)

设计:

分为两个部分,第一是生成题目,生成表达式及答案后写入当前目录下的文件,第二是判断答案是否正确,读取文件后判断,再将结果写入当前目录下的文件。

代码

主函数

  1. public static void main(String[] args){
  2.  
  3. System.out.println("请选择功能:");
  4. System.out.println(" 1. 四则运算生成器");
  5. System.out.println(" 2. 答案对比");
  6. System.out.print("请输入你的选择[1/2]:");
  7. int choose = new Scanner(System.in).nextInt();
  8.  
  9. switch (choose){
  10. case 1:
  11. ProducerController producerController = new ProducerController();
  12. producerController.ConstructProblem();break;
  13. case 2:
  14. JudgeAnswerController judgeAnswerController = new JudgeAnswerController();
  15. judgeAnswerController.start();break;
  16. default:
  17. System.out.println("输入不正确,请输入1或2");main(args);break;
  18. }
  19. }

整数生成器与真分数生成器函数

  1. public String[] createProblem(int range){
  2. Random random = new Random();
  3. int operatorCount = 1 + random.nextInt(3); //随机操作符的个数(1-3个)
  4. int operand[] = new int[operatorCount + 1]; //操作数个数
  5. int[] operatorIndex = index(operatorCount, 4, random);
  6.  
  7. for(int i = 0; i < operatorCount + 1; i++){
  8. operand[i] = random.nextInt(range);
  9. }
  10.  
  11. String formula = stitchingFormula(operatorCount, operand, operatorIndex);
  12.  
  13. //计算结果
  14. Calculator calculator = new Calculator();
  15. int res = calculator.algorithm(formula);
  16. String formulaRes[] = new String[2];
  17.  
  18. if (res > 0){
  19. formulaRes[0] = formula;
  20. formulaRes[1] = String.valueOf(res);
  21. }else {
  22. return createProblem(range);
  23. }
  24. return formulaRes;
  25. }
  1. public String[] createProblem(int range){
  2. Random random = new Random();
  3. int operatorCount = 1 + random.nextInt(3); //操作符的个数1-3
  4.  
  5. CreateInteger create = new CreateInteger();
  6. int[] operatorIndex = create.index(operatorCount,2, random); //操作符的下标
  7.  
  8. //生成第一个操作数
  9. int[] coprimeNumber1 = createCoprimeNumbers(range, random);
  10. int x = coprimeNumber1[0];
  11. int y = coprimeNumber1[1];
  12.  
  13. String s = shamToProperFraction(x, y);
  14.  
  15. for(int i=0; i < operatorCount; i++){
  16. //生成剩下的操作数
  17. int[] coprimeNumber = createCoprimeNumbers(range, random);
  18. int numx = coprimeNumber[0];
  19. int numy = coprimeNumber[1];
  20.  
  21. String currentOpreator = OPERATOR[operatorIndex[i]];
  22.  
  23. if(currentOpreator.equals("+")){ //加法
  24. x = x * numy + y * numx;
  25. y = y * numy;
  26. }else { //减法
  27. int count = 0;
  28. while(x * numy - y * numx < 0){ //差为负数
  29. coprimeNumber = createCoprimeNumbers(range, random);
  30. numx = coprimeNumber[0];
  31. numy = coprimeNumber[1];
  32. count++;
  33. if (count >= 5){
  34. numx = x - 1;
  35. numy = y;
  36. }
  37. }
  38. x = x * numy - y * numx;
  39. y = y * numy;
  40. }
  41.  
  42. String num = shamToProperFraction(numx, numy);
  43. s += currentOpreator + num;
  44. }
  45.  
  46. int greatFactor = greatFactor(x,y);
  47. x /= greatFactor; //最终结果化简
  48. y /= greatFactor;
  49.  
  50. String res = shamToProperFraction(x, y);
  51. s += "=";
  52.  
  53. String formulaRes[] = {s, res};
  54. return formulaRes;
  55. }
  56.  
  57. /**
  58. * 假分数转化为真分数
  59. * @param x 分子
  60. * @param y 分母
  61. * @return
  62. */
  63. public String shamToProperFraction(int x, int y){
  64. if (x > y){
  65. int n = x / y;
  66. x = (x - n * y);
  67. if (x == 0){
  68. return String.valueOf(n);
  69. }
  70. return n + "'" + x + "/" + y;
  71. }else if (x == y){
  72. return "1";
  73. }else if (y == 1){
  74. return String.valueOf(x);
  75. }else if (x == 0){
  76. return "0";
  77. }
  78. return x + "/" + y;
  79. }
  80. }

计算结果函数

  1. public int algorithm(String s) {
  2. Stack<Integer> numStack = new Stack<>(); //放数字
  3. Stack<String> operatorStack = new Stack<>(); //放操作符
  4. HashMap<String, Integer> hashMap = new HashMap<>(); //存放运算符优先级
  5. hashMap.put("(", 0);
  6. hashMap.put("+", 1);
  7. hashMap.put("-", 1);
  8. hashMap.put("*", 2);
  9. hashMap.put("÷", 2);
  10.  
  11. String formula = s.replaceAll(" ", "");
  12.  
  13. for (int i = 0; i < formula.length();) {
  14. StringBuilder digit = new StringBuilder(); //StringBuilder类中的方法主要偏重于对于字符串的变化,例如追加、插入和删除等,这个也是StringBuffer和String类的主要区别。
  15. char c = formula.charAt(i); //将式子字符串切割为c字符
  16. while (Character.isDigit(c)) { //判断字符是否为10进制数字,将一个数加入digit
  17. digit.append(c);
  18. i++;
  19. if (i < formula.length()){
  20. c = formula.charAt(i);
  21. }else {
  22. break;
  23. }
  24. }
  25. if (digit.length() == 0){ //当前digit里面已经无数字,即当前处理符号
  26. switch (c) {
  27. case '(': {
  28. operatorStack.push(String.valueOf(c));//如果是( 转化为字符串压入字符栈
  29. break;
  30. }
  31. case ')': { //遇到右括号了计算,因为(的优先级最高
  32. String stmp = operatorStack.pop(); //如果是),将符号栈栈顶元素取到
  33. while (!operatorStack.isEmpty() && !stmp.equals("(")) { //当前符号栈里面还有+ - * /
  34. int a = numStack.pop(); //取操作数a,b
  35. int b = numStack.pop();
  36. int result = calculate(b, a, stmp); //计算
  37. if(result < 0)
  38. return -1;
  39. numStack.push(result); //将结果压入栈
  40. stmp = operatorStack.pop(); //符号指向下一个计算符号
  41. }
  42. break;
  43. }
  44. case '=': { //遇到等号了计算
  45. String stmp;
  46. while (!operatorStack.isEmpty()) { //当前符号栈里面还有+ - * /,即还没有算完
  47. stmp = operatorStack.pop();
  48. int a = numStack.pop();
  49. int b = numStack.pop();
  50. int result = calculate(b, a, stmp);
  51. if(result < 0)
  52. return -1;
  53. numStack.push(result);
  54. }
  55. break;
  56. }
  57. default: { //不满足之前的任何情况
  58. String stmp;
  59. while (!operatorStack.isEmpty()) { //如果符号栈有符号
  60. stmp = operatorStack.pop(); //当前符号栈,栈顶元素
  61. if (hashMap.get(stmp) >= hashMap.get(String.valueOf(c))) { //比较优先级
  62. int a = numStack.pop();
  63. int b = numStack.pop();
  64. int result =calculate (b, a, stmp);
  65. if(result < 0)
  66. return -1;
  67. numStack.push(result);
  68. }
  69. else {
  70. operatorStack.push(stmp);
  71. break;
  72. }
  73.  
  74. }
  75. operatorStack.push(String.valueOf(c)); //将符号压入符号栈
  76. break;
  77. }
  78. }
  79. }
  80. else { //处理数字,直接压栈
  81. numStack.push(Integer.valueOf(digit.toString())); //Integer.valueof()返回的是Integer对象,而Integer.parseInt()返回的是int型
  82. continue; //结束本次循环,回到for语句进行下一次循环,即不执行i++(因为此时i已经指向符号了)
  83. }
  84. i++;
  85. }
  86. return numStack.peek(); //返回栈底数字即等式的答案。
  87. }

判断结果函数

  1. public void start(){
  2. System.out.print("请输入待验证答案路径:");
  3. Scanner scanner = new Scanner(System.in);
  4. String exerciseFilePath = scanner.next();
  5. System.out.print("请输入程序生成答案文件路径:");
  6. String answerFilePath = scanner.next();
  7.  
  8. try {
  9. List<String> exerciseAnswers = exerciseFileReader(exerciseFilePath);
  10. List<String> answers = answerReader(answerFilePath);
  11.  
  12. List<String> correct = new ArrayList<>();
  13. List<String> wrong = new ArrayList<>();
  14.  
  15. int max = Math.max(exerciseAnswers.size(), answers.size());
  16. int num = 1;
  17. for (int i = 0; i < max; i++){
  18. if (exerciseAnswers.get(i).equals(answers.get(i))){
  19. correct.add(String.valueOf(num++));
  20. }else {
  21. wrong.add(String.valueOf(num++));
  22. }
  23. }
  24.  
  25. File grade = new File("Grade.txt");
  26. if (grade.exists()){
  27. grade.delete();
  28. }
  29. if (grade.createNewFile()){
  30. FileOutputStream gradeOutput = new FileOutputStream(grade);
  31. PrintStream gradePrintStream = new PrintStream(gradeOutput);
  32. String corrects = String.join(",", correct);
  33. gradePrintStream.println("Correct:" + correct.size() +
  34. " (" + corrects + ")");
  35. String wrongs = String.join(",", wrong);
  36. gradePrintStream.println("Wrong:" + wrong.size() +
  37. " (" + wrongs + ")");
  38. }
  39.  
  40. System.out.println("判定完成");
  41.  
  42. } catch (FileNotFoundException e) {
  43. System.out.println("文件不存在");
  44. } catch (IOException e) {
  45. System.out.println("文件读入异常");
  46. }
  47. }
  48.  
  49. public List<String> exerciseFileReader(String path) throws IOException {
  50. BufferedReader exerciseReader = new BufferedReader(new FileReader(path));
  51. String exerciseAnswer = "";
  52. List<String> exerciseAnswers = new ArrayList<>();
  53. while ((exerciseAnswer = exerciseReader.readLine()) != null){
  54. String[] split = exerciseAnswer.split("=");
  55. if (split[1] != null){
  56. exerciseAnswers.add(split[1]);
  57. }else {
  58. exerciseAnswers.add(" ");
  59. }
  60. }
  61. return exerciseAnswers;
  62. }

测试

1.随机生成10道10以内的四则运算

2.判断题目的正确与否

3.支持生成一万道题目

由于题目过多,因此直接在连接中打开

测试题目文件

测试答案文件

以上就是所有功能的测试

PSP表格

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

10

5

· Estimate

· 估计这个任务需要多少时间

800

1200

Development

开发

480

630

· Analysis

· 需求分析 (包括学习新技术)

60

30

· Design Spec

· 生成设计文档

60

80

· Design Review

· 设计复审 (和同事审核设计文档)

30

45

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

30

30

· Design

· 具体设计

30

60

· Coding

· 具体编码

120

360

· Code Review

· 代码复审

30

45

· Test

· 测试(自我测试,修改代码,提交修改)

120

120

Reporting

报告

120

120

· Test Report

· 测试报告

60

30

· Size Measurement

· 计算工作量

30

30

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

30

30

合计

 

1200

1610

总结

在这次编程作业中,我和叶文涛同学一起讨论,他主要负责编写代码,后期的测试和报告则由我负责,在这一次的作业中,我也从伙伴身上学习到了很多,认识到自己与他人之间的差距,他在编程过程中也耐心的解答我的疑惑,在这个过程中不断的完善代码。两个人一起处理问题,互相汲取对方好的想法,有些细节没有考虑到的,另一个人可以帮忙补充,这样使得效率也大大提高。例如在我们进行最后测试的过程中,我发现当计算答案时如果答案为空则会出错,在这个情况下我们进行讨论之后也克服了这个问题。

java实现小学生四则运算的更多相关文章

  1. java的小学生四则运算

    import java.awt.*; import java.awt.event.*; import java.io.FileNotFoundException; import java.io.IOE ...

  2. java小学生四则运算带面板版 但我不知道为什么同类变量却进不了动作监听中去

    ---恢复内容开始--- package yun; import java.util.*; import java.awt.*; import java.awt.event.ActionEvent; ...

  3. 3.结对编程成果报告(小学生四则运算的出题程序,Java实现)

    程序名称:小学生四则运算的出题程序 先附上代码: package com.makequestion; import java.text.DecimalFormat;import java.util.R ...

  4. 小学生四则运算出题软件-基于java控制台的实现

    .题目描述: 1. 使用 -n 参数控制生成题目的个数,例如 Myapp.exe -n 10 -o Exercise.txt 将生成10个题目. 2. 使用 -r 参数控制题目中数值(自然数.真分数和 ...

  5. 20175305张天钰Java结对编程四则运算(二)

    Java结对编程四则运算(二) 一.题目描述及要求 Git提交粒度不要太粗,建议一个文件/一个类/一个函数/一个功能/一个bug修复都进行提交,不能一天提交一次,更不能一周一次,参考Commit Me ...

  6. Java实现小学四则运算练习系统(UI)

    github项目地址 :https://github.com/feser-xuan/Arithmetic_test3_UI 小伙伴的博客链接:http://www.cnblogs.com/fukang ...

  7. 作业六:小学生四则运算之NABCD模型与产品Backlog。

    NABCD模型与产品Backlog NABCD模型 ) N (Need 需求) 方便了老师和学生,使他们可以想要的时候随时可以得到,省时省力,快速出题,马上得到答案. ) A (Approach 做法 ...

  8. 30道小学生四则运算题C/C++编程

    软件工程科课上,老师通过实例讲解什么是程序,程序和软件的区别,要求我们通过短时间写一道编程题, 题目就是编写30道小学生四则运算题.以下就是源代码: #include<iostream.h> ...

  9. 20175305张天钰Java结对编程四则运算

    Java结对编程四则运算 一.题目描述:如何对表达式进行求值运算呢 1.中缀表达式与后缀表达式(娄老师讲解) 中缀表达式就是运算符号在运算数中间的表达式,比如1+2,顾名思义,后缀表达式就是运算符在运 ...

随机推荐

  1. 解决AssetBundle包加载预制体时,Shader显示异常的问题

    现象: 预制体上的粒子效果显示为紫色方块. 原因:shader在打成AB包后与指定平台产生相关性,Editor中无法正常读取. 解决办法: 遍历所有加载的对象,重新赋值Shader 代码: //修正s ...

  2. Linux 在文件夹的所有文件中查找某字符

    命令: grep -r -e string directory eg: 在 /home 目录下的所有文件中查找包含 test 字符串的文件. grep -r -e "test" / ...

  3. 手把手使用Docker搭建SpringBoot微服务镜像

    一.环境准备 1.安装好Docker环境的Linux机器(安装教程) 2.准备好SpringBoot项目打包好的可运行jar包 二.编写Dockerfile 1.首先将SpringBoot打包好的ja ...

  4. 踏上编程大道 从 Python 开始成为神级 Coder

    电脑科学,或说计算机科学,是个在美国不断成长的产业,薪资报酬也很高.市场上永远存在著对天赋异禀的新锐工程师的需求,这就是为什麽「学习程式语言」一直是一件有魅力的事情. 但是,就跟任何技能一样,我们常常 ...

  5. PyInstaller 打包 python程序成exe

    pychaim下PyInstaller 打包 python程序 主题是使用PyInstaller 打包python时遇到一些问题以及解决方案,其中将要打包的程序是用tensorflow做的LSTM算法 ...

  6. python列表类型

    列表类型简介 列表类型是一个容器,它里面可以存放任意数量.任意类型的数据. 例如下面的几个列表中,有存储数值的.字符串的.内嵌列表的.不仅如此,还可以存储其他任意类型. >>> L ...

  7. Docker镜像管理基础与基于容器的镜像制作示例

    一.Docker镜像 Docker镜像是启动Docker容器的一个非常重要的组件.Docker各组件之间的关系如图: Docker镜像含有启动容器所需要的文件系统及其内容,因此Docker镜像用于创建 ...

  8. javascript小实例,在页面中输出当前客户端时间

    时间对象(Date())比较简单,本文旨在为初学者入门使用,大牛可略过! 本文承接基础知识实例,说一下实例的要求: 在页面中输出当前客户端时间(2015年1月1日星期一10:10:10这样的格式),每 ...

  9. C# WPF 获取窗体和控件的句柄

    窗体: IntPtr hwnd = new WindowInteropHelper(this).Handle; 控件: IntPtr hwnd = ((HwndSource)PresentationS ...

  10. webAPI 控制器(Controller)太多怎么办?

    写过接口的同学都知道,接口会越来越多,那么控制器也会越来越多.这时候就需要根据某种业务或特性对controller进行分类然后建立文件夹. 我想到一个折中的方案:伪Areas! 在Areas文件夹下建 ...