HNU个人项目互评博客

发布时间 2023-09-20 12:28:20作者: 尊嘟假嘟?

HNU个人项目——中小学数学卷子自动生成程序

一.前言

本次个人项目中我的搭档袁秀广同学使用了Java进行开发。袁秀广同学的代码实现了自动生成题目的基本功能,注解详细,内容丰富,但在一些细节上也存在一些可优化的地方。

二.需求分析

1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号),如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为小学、初中和高中三个选项中的一个。否则提示“请输入正确的用户名、密码”,重新输入用户名、密码;

2、登录后,系统提示“准备生成XX数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”,XX为小学、初中和高中三个选项中的一个,用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。每道题目的操作数在1-5个之间,操作数取值范围为1-100;

3、题目数量的有效输入范围是“10-30”(含10,30,或-1退出登录),程序根据输入的题目数量生成符合小学、初中和高中难度的题目的卷子。同一个老师的卷子中的题目不能与以前的已生成的卷子中的题目重复(以指定文件夹下存在的文件为准);

4、在登录状态下,如果用户需要切换类型选项,命令行输入“切换为XX”,XX为小学、初中和高中三个选项中的一个,输入项不符合要求时,程序控制台提示“请输入小学、初中和高中三个选项中的一个”;输入正确后,显示“”系统提示“准备生成XX数学题目,请输入生成题目数量”,用户输入所需出的卷子的题目数量,系统新设置的类型进行出题;

5、生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文件夹。每道题目有题号,每题之间空一行;

三.代码分析

1.updateTeacherTxt函数

public static void updateTeacherTxt(ArrayList<Teacher> teachers, Teacher teacher) throws IOException {
  for(int i = 0; i < teachers.size(); ++i) {
    if (((Teacher)teachers.get(i)).getAccount().equals(teacher.getAccount()) && !((Teacher)teachers.get(i)).getType().equals(teacher.getType())) {
      ((Teacher)teachers.get(i)).setType(teacher.getType());
    }
  }

  BufferedWriter bw = new BufferedWriter(new FileWriter(new File("src\\teacher.txt")));

  for(int i = 0; i < teachers.size(); ++i) {
    String var10001 = ((Teacher)teachers.get(i)).getAccount();
    bw.write(var10001 + " " + ((Teacher)teachers.get(i)).getPassword() + " " + ((Teacher)teachers.get(i)).getType());
    bw.newLine();
    bw.flush();
  }

  bw.close();
}

该函数使用ArrayList存储教师对象,方便获取和修改对象信息,通过遍历ArrayList,根据账号匹配对象,实现指定教师类型的修改,使用FileWriter写入文件,操作简单直观;

2.getAllQuestions函数

public static ArrayList<String> getAllQuestions(Teacher teacher) throws IOException {
  ArrayList<String> questions = new ArrayList();
  String path = "src\\" + teacher.getAccount() + "\\all.txt";
  BufferedReader br = new BufferedReader(new FileReader(new File(path)));
  String line = null;

  while((line = br.readLine()) != null) {
    String[] info = line.split(" ");
    questions.add(info[0]);
  }

  br.close();
  return questions;
}

该函数用于获取指定教师的所有题目,使用ArrayList来存储题目信息,操作方便,根据教师账号动态获取文件路径,便于管理不同教师的题库,但没有对参数teacher进行校验,可能传入null值。

3.saveQuestions函数

public static void saveQuestions(Teacher teacher, ArrayList<String> questions) throws IOException {
  Instant instant = Instant.now();
  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
  String datetime = instant.atZone(ZoneId.systemDefault()).format(formatter);
  String var10000 = teacher.getAccount();
  String path1 = "src\\" + var10000 + "\\" + datetime + ".txt";
  File file1 = new File(path1);
  file1.createNewFile();
  String path2 = "src\\" + teacher.getAccount() + "\\all.txt";
  File file2 = new File(path2);
  BufferedWriter bw1 = new BufferedWriter(new FileWriter(new File(path1)));
  BufferedWriter bw2 = new BufferedWriter(new FileWriter(file2, true));

  for(int i = 0; i < questions.size(); ++i) {
    String var10001 = String.valueOf(i + 1);
    bw1.write(var10001 + ".  " + (String)questions.get(i));
    bw1.newLine();
    bw1.newLine();
    bw1.flush();
    bw2.write((String)questions.get(i));
    bw2.newLine();
    bw2.flush();
    PrintStream var12 = System.out;
    var10001 = String.valueOf(i + 1);
    var12.println(var10001 + ".  " + (String)questions.get(i));
    System.out.println();
  }

  bw1.close();
  bw2.close();
}

该函数用于保存指定教师的题目到文件,使用BufferedWriter,高效写入文件内容。遍历列表写入每道题,同时打印到控制台,检查结果。

4.primary函数

public static void primary(Teacher teacher, int sum) throws IOException {
  String[] primarySymbol = new String[]{"+", "-", "*", "/"};
  ArrayList<String> questions = new ArrayList();
  Random rd = new Random();

  for(int i = 0; i < sum; ++i) {
    String question = "";
    int leftSubRight = 0;
    int operandSum = 0;
    int isExit = false;

    while(true) {
      int k = rd.nextInt(5);
      if (k == 1) {
        question = question + "(";
        ++leftSubRight;
      }

      int flag = rd.nextInt(100) + 1;
      question = question + flag;
      ++operandSum;
      if (k == 2 && leftSubRight > 0) {
        question = question + ")";
        --leftSubRight;
      }

      int isExit = rd.nextInt(3);
      if (operandSum > 1 && (isExit == 1 || operandSum == 5)) {
        for(k = 0; k < leftSubRight; ++k) {
          question = question + ")";
        }

        ArrayList<String> getQuestions = getAllQuestions(teacher);
        int flag = false;
        flag = check(getQuestions, question);
        if (flag == -1) {
          questions.add(question);
        } else {
          --i;
        }
        break;
      }

      int symbolNum = rd.nextInt(4);
      question = question + primarySymbol[symbolNum];
    }
  }

  saveQuestions(teacher, questions);
}

该函数用于生成小学难度的题目,使用随机数生成各种运算符和操作数,题目具有随机性,考虑了括号的嵌套情况,生成结构较复杂的表达式,检查生成的题目是否重复,避免重复保存,调用了题目保存和读取的封装方法,代码结构清晰。

四.结果测试

1.登录

账户和密码输入正确

账户和密码输入不正确

2.生成题目

题目数量符合范围


题目数量不符合范围

3.切换题目类型

题目类型输入错误

4.退出当前账号

五.总结

经过我的测试,我可爱的搭档袁秀广同学编写的代码基本实现了有关功能,优缺点如下:

优点:

1.使用数组定义不同的运算符号,便于进行选择,也比较容易区分难易程度;

2.考虑到生成题目的随机性,采用了随机数生成与操作数、括号和运算符,大大增加了题目的丰富性,是题目结构更为立体;

3.运用了面向对象的思想,使用了三个类和一个接口,提高了代码的封装性和结构性,便于后期维护;

4.将获取题目、检查重复和保存题目等函数分开编写,既提高了代码的可读性又有利于维护;

5.通过javadoc详细解释了每一个类和每一个方法的用途、参数以及返回值,是代码便于理解。

缺点:

1.随机数范围设置比较简单,可能生成结构不合理的题目,如连续两个括号等。

2.在查重机制上,由于仅检查题目字符串,从而无法识别等价表达的题目,如操作符左右互换;

3.将过多的函数方法实现放在了mian类中,类的结构性没有很好的体现出来,函数粒度较大,后期扩展性不足;

总体来说,这份代码实现了自动生成题目的基本功能,利用随机数提高随机性,但在结构控制、重复判断、题型支持等方面还有待优化,后期维护难度较大。