结对项目

结对项目

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/SoftwareEngineering2024
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/SoftwareEngineering2024/homework/13137
这个作业的目标 完成团队协作
姓名 黄诃华 欧文杰
学号 3122004572 3122004702

github:https://github.com/hhuang1231/3122004572/tree/master/java/jiedui

PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 10
Estimate 估计这个任务需要多少时间 15 10
Development 开发 60 60
Analysis 需求分析 (包括学习新技术) 120 120
Design Spec 生成设计文档 30 20
Design Review 设计复审 5 5
Coding Standard 代码规范 (为目前的开发制定合适的规范) 5 5
Design 具体设计 30 20
Coding 具体编码 65 65
Code Review 代码复审 35 35
Test 测试(自我测试,修改代码,提交修改) 30 30
Reporting 报告 30 40
Test Repor 测试报告 30 30
Size Measurement 计算工作量 100 100
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 20 20
合计 590 580

效能分析

可以发现是生成表达式和写入文件的时间比较长

  • 对于io来说,可能不好优化
  • 但是对于生成表达式来说,使用多线程并发可能可以提高性能

设计实现过程

  • 一个启动类JieduiApplication,用于接收命令行参数
  • 一个表达式生成器Generator,用于生成符合条件的四则运算,并且将题目和答案输出到文件中
  • 一个表达式解析器Parser,用于解析生成的表达式并生成字符串答案
  • 一个转换器Convertor,将字符串答案转为int类型答案
  • 一个统计器GradeCalculator,将表达式文件和答案文件对比,得出统计文件

代码说明

  1. 使用 -n 参数控制生成题目的个数

    • 例如Myapp.exe -n 10
    for (int i = 0; i < numExercises; i++) {
                String expression = generateExpression(rangeLimit);
                int answer = Comparator.evaluateExpression(expression);
                if (answer < 0) {
                    i--;
                } else {
                    exercises.add(expression);
                    answers.add(Integer.toString(answer));
                }
            }
    
    • 此处会将生成的表达式存入列表,然后返回
    private static String generateExpression(int rangeLimit) {
            Random random = new Random();
            StringBuilder expression = new StringBuilder();
            expression.append(random.nextInt(rangeLimit) + 1);
    
            // Random number of operators (1 to 3)
            int numOperators = random.nextInt(3) + 1;
            for (int i = 0; i < numOperators; i++) {
                String operator = OPERATORS[random.nextInt(OPERATORS.length)];
                expression.append(" ").append(operator).append(" ");
                if (operator.equals("÷")) {
                    int denominator = random.nextInt(rangeLimit) + 1;
                    int numerator = random.nextInt(denominator) + 1;
                    expression.append(numerator).append("/").append(denominator);
                } else {
                    expression.append(random.nextInt(rangeLimit) + 1);
                }
            }
            return expression.toString();
        }
    
    • 以上是生成表达式的核心流程
  2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围

    • 例如Myapp.exe -r 10
    • 将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息
    expression.append(random.nextInt(rangeLimit) + 1);
    
    • 核心就是随机数需要限制
  3. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。

    String expression = generateExpression(rangeLimit);
                int answer = Comparator.evaluateExpression(expression);
                if (answer < 0) {
                    i--;
                } else {
                    exercises.add(expression);
                    answers.add(Integer.toString(answer));
                }
    
    • 核心就是检测答案,如果为负数则重新生成
  4. 生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。

  5. 每道题目中出现的运算符个数不超过3个。

    int numOperators = random.nextInt(3) + 1;
    for (int i = 0; i < numOperators; i++) {}
    
    • 循环限制在三次之内
  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

      • 四则运算题目2

      • 其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

  7. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件。格式如下:

    • 答案1

    • 答案2

    private static void writeToFile(String filename, List<String> lines) {
            try (PrintWriter writer = new PrintWriter(filename)) {
                for (String line : lines) {
                    writer.println(line);
                }
            } catch (IOException e) {
                log.error("结果输出至文件异常", e);
            }
        }
    
  8. 程序应能支持一万道题目的生成

  9. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。

    • 输入参数如下:

      • Myapp.exe -e .txt -a .txt
    • 统计结果输出到文件Grade.txt,格式如下:

      • Correct: 5 (1, 3, 5, 7, 9)

      • Wrong: 5 (2, 4, 6, 8, 10)

      • 其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。

      public static void calculateGrade(String exercisesFile, String answersFile) {
              try {
                  List<String> exercises = readLines(exercisesFile);
                  List<String> answers = readLines(answersFile);
                  List<Integer> correctIndices = new ArrayList<>();
                  List<Integer> wrongIndices = new ArrayList<>();
      
                  for (int i = 0; i < exercises.size(); i++) {
                      int expectedAnswer = Integer.parseInt(answers.get(i));
                      int actualAnswer = Comparator.evaluateExpression(exercises.get(i));
                      if (actualAnswer == expectedAnswer) {
                          correctIndices.add(i + 1);
                      } else {
                          wrongIndices.add(i + 1);
                      }
                  }
      
                  writeToFile(correctIndices, wrongIndices);
              } catch (IOException e) {
                  log.error("结果输出至文件异常", e);
              }
          }
      
          /**
           * 读取配置文件
           */
          private static List<String> readLines(String filename) throws IOException {
              List<String> lines = new ArrayList<>();
              try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
                  String line;
                  while ((line = reader.readLine()) != null) {
                      lines.add(line);
                  }
              }
              return lines;
          }
      
          private static void writeToFile(List<Integer> correctIndices, List<Integer> wrongIndices) {
              try (PrintWriter writer = new PrintWriter("Grade.txt")) {
                  writer.println("Correct: " + correctIndices.size() + " (" + formatIndices(correctIndices) + ")");
                  writer.println("Wrong: " + wrongIndices.size() + " (" + formatIndices(wrongIndices) + ")");
              } catch (FileNotFoundException e) {
                  log.error("结果输出至文件异常", e);
              }
          }
      
          /**
           * 格式化输出
           */
          private static String formatIndices(List<Integer> indices) {
              StringBuilder builder = new StringBuilder();
              for (int i = 0; i < indices.size(); i++) {
                  builder.append(indices.get(i));
                  if (i < indices.size() - 1) {
                      builder.append(", ");
                  }
              }
              return builder.toString();
          }
      

测试运行

  1. 生成题目和答案:

    • 输入:-n 10 -r 10
    • 预期输出:Exercises and answers generated successfully!
  2. 生成题目和答案,但提供了负数题目数量:

    • 输入:-n -10 -r 10
    • 预期输出:Invalid arguments. Both -n and -r values must be positive integers.
  3. 生成题目和答案,但提供了负数范围限制:

    • 输入:-n 10 -r -10
    • 预期输出:Invalid arguments. Both -n and -r values must be positive integers.
  4. 根据给定的题目文件和答案文件计算分数:

    • 输入:-e Exercises.txt -a Answers.txt
    • 预期输出:Grading completed. Results written to Grade.txt
  5. 根据给定的题目文件和答案文件计算分数,但题目文件不存在:

    • 输入:-e NonExistentExercises.txt -a Answers.txt
    • 预期输出:结果输出至文件异常
  6. 根据给定的题目文件和答案文件计算分数,但答案文件不存在:

    • 输入:-e Exercises.txt -a NonExistentAnswers.txt
    • 预期输出:结果输出至文件异常
  7. 提供了无效的参数个数:

    • 输入:-n 10 -r
    • 预期输出:Invalid arguments. Usage: ...
  8. 提供了无效的参数组合:

    • 输入:-n 10 -a Answers.txt
    • 预期输出:Invalid arguments. Usage: ...
  9. 提供了无效的参数标记:

    • 输入:-n 10 -x 10
    • 预期输出:Invalid arguments. Usage: ...
  10. 没有提供参数:

    • 输入:(无参数)
    • 预期输出:Invalid arguments. Usage: ...

项目小结

  1. 模块化设计: 将程序分解成了多个模块,每个模块负责一个特定的功能,
  2. 参数解析: 能够正确解析命令行参数,
  3. 异常处理: 在关键的地方进行了异常处理,
  4. 测试覆盖: 设计了多组测试用例,但是测试用例不够完整
  5. 性能优化: 可以优化生成表达式使用多线程并发来提高生成表达式的效率
  6. 协作:主要是设计前期需要分配好工作,各司其职则可以更好的完整需求
posted @ 2024-03-25 22:48  hhuang1231  阅读(55)  评论(0)    收藏  举报