对个人项目中小学数学卷子自动生成程序的编程分析

发布时间 2023-09-21 17:34:01作者: 艺术大黄狗

一:项目要求
用户:
小学、初中和高中数学老师。
功能:
1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为小学、初中和高中三个选项中的一个。否则提示“请输入正确的用户名、密码”,重新输入用户名、密码;
2、登录后,系统提示“准备生成XX数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”,XX为小学、初中和高中三个选项中的一个,用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。每道题目的操作数在1-5个之间,操作数取值范围为1-100;
3、题目数量的有效输入范围是“10-30”(含10,30,或-1退出登录),程序根据输入的题目数量生成符合小学、初中和高中难度的题目的卷子(具体要求见附表)。同一个老师的卷子中的题目不能与以前的已生成的卷子中的题目重复(以指定文件夹下存在的文件为准,见5);
4、在登录状态下,如果用户需要切换类型选项,命令行输入“切换为XX”,XX为小学、初中和高中三个选项中的一个,输入项不符合要求时,程序控制台提示“请输入小学、初中和高中三个选项中的一个”;输入正确后,显示“”系统提示“准备生成XX数学题目,请输入生成题目数量”,用户输入所需出的卷子的题目数量,系统新设置的类型进行出题;
5、生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文件夹。每道题目有题号,每题之间空一行;

二:项目的实际实现

进行了一系列功能性的测试,可以很好实现项目要求的功能。

1.当输入正确的账户和密码,比如张三1 123,可以顺利登录进,输入错误的账号密码,比如说fasada 245,会被要求重新登录

2.当账号和密码均输入正确时,转入出题阶段,输入数字16,进行出题,同时生成对应的文件夹和文件,输入数字-1,退出

3.当输入“切换为xxx改变出题难度时”,当输入内容是“小学”,“初中”,“高中”三个选项,成功进行切换,当输入的选项在这三个之外,例如大学,会要求重新输入

4.转换成功,系统提示“请输入生成题目的数量”,重复2内容

5.附上生成的文件夹以及生成的部分题目

总结:很好实现了项目需要的功能,并且界面很简洁,没有多余的信息,对于不规范的输入也有提示

 

三:项目代码分析

public class User {
    private String name;
    private String password;
    private int grade;

    public String getName() {return name;}

    public String getPassword() {
        return password;
    }

    public int getGrade() {
        return grade;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setGrade(int grade) {
        this.grade = grade;
    }
}

1.使用User类,封装了用户信息,没有其他多余的内容,简介不凌乱,使得这个项目各部分写了什么内容还有各部分之间的关系都一目了然。

main主类中的内容较多,遂不逐一分析,只贴出代码重要部分,以及能体现优缺点的部分进行分析。

public static String dir = "C:\\Users\\21473\\Desktop\\出题器\\2\\";
File infile = new File(dir + "users.txt");//获得所有用户的信息;

2.这部分设置了一个文件夹,并且在下面创建了一个对应的文件,不过这部分内容并不够完善,若电脑并没有该文件夹,系统不会自动创建,只会报错,必须用户自己将文件夹创建好,并且将对应的user.txt文件放入创建好的文件夹下面,程序才能正常进行。这部分内容可以进行改进。

 1 while (true) {
 2                 problem = new StringBuilder(" ");
 3                 int length = 0;
 4                 int sum = r.nextInt(3);//随机括号的数量
 5                 int left = 0;//左括号的数量
 6                 int wide = 0;//括号的跨度
 7                 while (true) {
 8                     if (r.nextInt(2) == 0 && sum > 0) {
 9                         problem.append("(");
10                         sum--;
11                         left++;
12                         wide = 0;
13                     }
14                     int num = r.nextInt(99) + 1;//随机1·100的数
15                     problem.append(num);
16                     wide++;
17                     if (r.nextInt(2) == 0 && left > 0 && wide >= 2) {
18                         problem.append(")");
19                         left--;
20                     }
21                     if (length >= 2 && left <= 0 && sum <= 0) {
22                         break;
23                     }
24                     problem.append(f[r.nextInt(4)]);
25                     length++;
26                 }
27                 if (length < 5 && wide < 3)
28                     break;
29             }

3.举例小学出题的例子进行分析,通过随机数,使操作数之前有1/2的概率添加括号,又通过left和wide进行控制,防止有多余的左括号或者右括号生成,最后又通过

if (length < 5 && wide < 3)该语句防止操作数和括号过多,最后也是通过随机数来进行退出。

 

HashSet<String> past=Find(name);
        String dirPath = dir+name;//文件路径
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
        String newDate = df.format(new Date());
        String path=dirPath+"\\"+newDate+".txt";
        try {
            FileWriter fw  = new FileWriter(path,true);//能够不断对路径的文件添加
            for(int i=0;i<num;i++){
                String problem=chuti(mode);
                if(!past.contains(problem)){//当文件中
String path = dir+name;
        File file = new File(path);
        if(!file.exists()){
            file.mkdirs();
        }
        File[] fs = file.listFiles();
        HashSet<String> pp = new HashSet<>();
        for(File f:fs){
            if(!f.isDirectory()){
                try {
                    BufferedReader br = new BufferedReader(new FileReader(f));
                    String line;
                    while ((line = br.readLine()) != null) {
                        // 一次读入一行数据并加入到结果的hashset中
                        pp.add(line);
                    }
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return  pp;

  

不存在这一题目时,添加进去 problem= i + 1 +"."+problem; fw.write(problem+"\n"+"\n"); } }

4.这部分将生成的题目写入对应文件中,顺便考虑到了不存在题目的情况,不过缺点也存在,没有考虑查重操作,不能筛选重复的题目。

 HashSet<String> past=Find(name);
        String dirPath = dir+name;//文件路径
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
        String newDate = df.format(new Date());
        String path=dirPath+"\\"+newDate+".txt";
        try {
            FileWriter fw  = new FileWriter(path,true);//能够不断对路径的文件添加
            for(int i=0;i<num;i++){
                String problem=chuti(mode);
                if(!past.contains(problem)){//当文件中不存在这一题目时,添加进去
                    problem= i + 1 +"."+problem;
                    fw.write(problem+"\n"+"\n");
                }
            }
            System.out.println("卷子生成完毕");
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

 

5.这部分继续生成用户文件夹下面的文件,并且完成了项目要求--生成的文件按照当前时间进行命名

总结:

优点:使用用了类,建立了工程使得这个项目各部分写了什么内容还有各部分之间的关系都一目了然,代码写的很简洁,没有使用不必要的临时变量,只用了很少的代码就实现了要求的功能。代码变量命名也符合规范。可读性也比较好,创建文件虽然不够灵活,但是也并不需要修改大量内容,也比较合格。

缺点:主函数中的内容太多,这些内容可以多拆分成几个类,实际上违反了“40行”规则,注释其实也可以适当添加,对于一些函数的功能进行解释,方便其他人理解该代码。

 不过瑕不掩瑜,陈同学的代码可读性好,函数封装程度高,仍然比较优秀