中小学数学卷子自动生成程序队友代码分析

发布时间 2023-09-20 11:01:45作者: 硼铝镓铟铊

引言

项目背景和目的:

在教育领域,手动生成数学卷子是一项既耗时又耗力的工作,需要老师投入大量的时间和精力。为了减轻老师的负担,提高教学效率,同时提供更加灵活和个性化的卷子生成服务,这个项目提出了自动化生成数学卷子的解决方案。同时,在课程设置方面,这个项目旨在提高我们独立编程、规范编码的能力。

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

用户:小学、初中和高中数学老师。

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

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

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

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

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

 

 代码分析:

 代码结构:

代码源码由function.h和paper.cpp组成。

在function.h头文件中,首先定义了抽象类IUer,定义了所有用户类具有的基本行为,即获取账号类型、名称、密码等。

接着定义了UserNode类,用于封装用户信息,并且提供了一些方法来获取账密等私有信息的公有接口。

最后User类继承了UserNode类的属性和方法,并添加了友元函数,例如:

1 class User:public UserNode{
2   private: 
3     friend void ReadUserInformation(UserNode** user_list);
4     friend void GenerateQuestions(int questioncount, string username, string current_account_type);
5     friend void LoginPage(string username,string current_account_type);
6 };

允许User类访问UserNode类的私有成员,封装性是否被破坏仍然是我思考的一个点,希望有同学能够解答。

在类的定义部分具有层次化的结构。

在function.h中,队友还声明了一些函数,如下所示:

 1 //函数声明 :与函数定义顺序相同 
 2 //登录页面,输入用户名和当前类型,无返回值 
 3 //可以按需输入需要题目的数量、退出登录、进入更改类型函数 
 4 void LoginPage(string username,string current_account_type);
 5 //更换出题类型,输入原本类型,输出新的类型 
 6 //如果要更换的类型与原本类型重复会提示,输入格式不对会提示 
 7 string AccountChangeType(string account_type);
 8 //读入文件,输入用户链表,无返回值 
 9 void ReadUserInformation(UserNode** user_list); 
10 //获取该目录下的其他文件 
11 vector<string> GetFilesInDirectory(const string& directory);
12 //生成输入年级类型对应的输入数量的题目,并在输入用户的文件夹下新建txt保存,无返回值
13 //题目生成后会确认没有与之前生成的题目重复,之后存入文件 
14 //文件名为类型-年-月-日-时-分-秒.txt(比要求的格式多了类型以便用户区分) 
15 void GenerateQuestions(int questioncount, string username, 
16                        string current_account_type);
17 //查重函数(查看该目录下其他文件中是否有重复的)
18 //注:对于仅调换数字顺序的算式,根据要求只去除两个操作数时的重复 
19 bool CheckDuplicate(string question,vector<string> files,string paperpath); 
20 //随机生成小学题目并返回 ,输入题目数量 
21 string GetPramaryQuestion(string question);
22 //随机生成初中题目并返回 ,输入题目数量 
23 string GetMiddleQuestion(string question);
24 //随机生成高中题目并返回 ,输入题目数量 
25 string GetHighQuestion(string question);                     
26 //输出输入范围内的随机值 
27 int GetRandomNumber(int min, int max);
28 //获取当前时间,以规定格式输出 
29 string CurrentTime();

在函数声明部分,有着清晰的函数划分,明确的功能和输入输出,有助于确保代码的正确性和可读性。

paper.cpp包含了此程序的主函数。

代码质量:

在代码规范方面,代码命名稍有不妥,例如参照Google C++ Style Guide 中文版 6.4变量命名,要求类的成员变量以下划线结尾,然而该同学在类的声明时,类的成员变量没有以下划线结尾。如下:

 1 class UserNode {
 2   public: 
 3     UserNode(string uname, string pwd, string type) : 
 4         username(uname), password(pwd), account_type(type), next(NULL) { }
 5     ...
 6     UserNode* next;
 7   private:
 8     string username;
 9     string password;
10     string account_type;
11 };

但优点在于,代码有丰富的注释,方法内代码行数均不超过40行,可读性较强。

代码复杂度方面,一些函数的输入参数可能过于复杂。例如,ReadUserInformation函数的输入参数是一个指向UserNode的指针的指针,这可能会增加代码的复杂性,并可能导致潜在的错误。

性能:

由于队友coping使用的平台为DevC++,而我使用CLion,其代码在我的电脑上测试会有bug,然而在其自己电脑上运行没有问题。(可能由于C++标准的不一致)

 我的电脑运行结果如下(异常):

队友本地运行结果如下(正常):

 功能点基本实现,但在出题的题目方面有些欠缺,一些不太合理的地方,例如上图中

一整个数学算式外侧再添加括号是多余且不太合理的,正确的算术题中不应该有这样的情况发生。

可拓展性:

个人看来,队友的代码模块化仍然做的不太好,所有的代码仅仅放在一个头文件和一个主函数的cpp文件中,除了User类的声明定义外,一些功能函数并不属于任何类的方法,太多太零散,没有充分运用面向对象的设计方法(虽然C++更多的是过程化编程,但我个人觉得,功能函数有许多相似之处还是可以作为一个类的方法的),在模块化这方面,仍有很大的提升空间。可拓展性一般。

结论:

队友的代码整体上完成了所有的功能点,命名较为规范,注释丰富,可读性强,但细节方面可以做的更好,模块化方面仍有较大提升空间。

个人水平有限,如有分析不足或错误之处,请斧正!