【结对编程互评-C++】中小学数学卷子自动生成程序

发布时间 2023-09-20 11:57:46作者: 穹垂

【结对编程互评-C++】中小学数学卷子自动生成程序


项目名称:中小学数学卷子自动生成程序
编程语言:C++
代码作者:李义
评价人:张恒硕

目录

  • [1.项目要求]
    • [1.1目标用户]
    • [1.2实现功能]
  • [2.代码分析]
  • [3.功能测试]
    • [3.1登录功能测试]
    • [3.2出题功能测试]
  • [4.优缺点分析与总结]

1.项目要求

1.1 目标用户:

小学、初中和高中数学老师。

1.2 实现功能:

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
小学 张三2 123
小学 张三3 123
初中 李四1 123
初中 李四2 123
初中 李四3 123
高中 王五1 123
高中 王五2 123
高中 王五3 123

附表-2:小学、初中、高中题目难度要求

阶段 小学 初中 高中
难度要求 +,-,*./ 平方,开根号 sin,cos,tan
备注 只能有+,-,*./和() 题目中至少有一个平方或开根号的运算1=符 题目中至少有一个sin,cos或tan的运算符

2.代码分析

主函数

int main() {
  while (true) {
    Login logins;
    logins.UserLogin();
    if (exitflag) {
      std::cout << "----------------------------------------" << std::endl;
      std::cout << "         退出程序成功!欢迎下次使用!        " << std::endl;
      std::cout << "----------------------------------------" << std::endl;
      break;
    } else {
      flag_of_success_login = false;
    }
  }
  return 0;
}

简单明了,调用登录函数,不断循环直到信号为退出信号

class User {
 public:
  User(std::string names, std::string passwords, std::string types) {
    this->password_ = passwords;
    this->name_ = names;
    this->type_ = types;
  }
  std::string Getname() {
    return this->name_;
  }
  std::string Getpassword() {
    return this->password_;
  }
  std::string Gettype() {
    return this->type_;
  }
 private:
  std::string name_;
  std::string password_;
  std::string type_;
};

标准用户类,存储用户信息,这里就是用户名、密码和用户类型

class AbstractElementMaker {
 public:
  AbstractElementMaker() {
    primary_symbol_ = {"+", "-", "*", "/"};
    junior_symbol_ = {"√", "^2"};
    senior_symbol_ = {"sin", "cos", "tan"};
  }
  virtual bool Quitornot(
      std::default_random_engine &random,
      int count) = 0;
  virtual void Addnum(
      std::default_random_engine &random,
      std::string *string_buffer) = 0;
  virtual std::pair<bool, int> AddLeftBracket(
      int bracket,
      std::default_random_engine &random,
      bool quit, std::string *string_buffer) = 0;
  virtual int AddRightBracket(
      int bracket,
      std::default_random_engine &random,
      bool left_bracket_or_not, std::string *string_buffer) = 0;
  virtual void AddSqrt(
      std::default_random_engine &random,
      std::string *string_buffer) = 0;
  virtual int AddSquare(
      int square_or_not,
      std::default_random_engine &random,
      std::string *string_buffer) = 0;
  virtual int AddTriangle(
      int triangle,
      std::default_random_engine &random,
      std::string *string_buffer) = 0;
  virtual void AddSymbol(
      std::default_random_engine &random,
      std::string *string_buffer) = 0;
  virtual void FinalBrackets(int bracket, std::string *string_buffer) = 0;
  std::string GetprimarySym(int index) {
    return primary_symbol_[index];
  }
  std::string GetseniorSym(int index) {
    return senior_symbol_[index];
  }
  std::string GetjuniorSym(int index) {
    return junior_symbol_[index];
  }

 private:
  std::vector<std::string> primary_symbol_;
  std::vector<std::string> junior_symbol_;
  std::vector<std::string> senior_symbol_;
};

由随机数随机生成符号,包括题目要求的小学符号"+", "-", "*", "/",初中符号"√", "^2"和高中符号"sin", "cos", "tan"以及左右括号

class AbstractTestMaker {
 public:
  virtual void CreatePrimary(std::default_random_engine &random,
                             std::string *test) = 0;
  virtual void CreateJunior(std::default_random_engine &random,
                            std::string *test) = 0;
  virtual void CreateSenior(std::default_random_engine &random,
                            std::string *test) = 0;
};

负责每个不同类型试题的生成

class AbstractExamMaker {
 public:
  virtual std::vector<std::string> PrimaryExamMaker(
      int num,
      std::default_random_engine &random) = 0;
  virtual std::vector<std::string> JuniorExamMaker(
      int num,
      std::default_random_engine &random) = 0;
  virtual std::vector<std::string> SeniorExamMaker(
      int num,
      std::default_random_engine &random) = 0;
  virtual void PaperMaker(char *p, int nums, std::vector<std::string> *temp,
                          std::default_random_engine &random) = 0;
};

不同类型试卷的生成和最后试卷组装类型的判断

class AbstractFileWriter {
 public:
  virtual std::string GetTime() = 0;
  virtual std::string MakeFile(std::vector<std::string> set_of_test) = 0;
  virtual bool CheckRepeat(const std::string &path,
                           std::vector<std::string> test) = 0;
  virtual std::wstring ConvertUtf8ToWide(const std::string &utf8str) = 0;
};

负责文件写入,包括获取当前时间,创建文件,查重以及转换字符编码

class AbstractLogin {
 public:
  virtual int UserLogin() = 0;
  AbstractLogin() {
    usermap_.insert(std::make_pair("张三1", User("张三1", "123", "小学")));
    usermap_.insert(std::make_pair("张三2", User("张三2", "123", "小学")));
    usermap_.insert(std::make_pair("张三3", User("张三3", "123", "小学")));
    usermap_.insert(std::make_pair("李四1", User("李四1", "123", "初中")));
    usermap_.insert(std::make_pair("李四2", User("李四2", "123", "初中")));
    usermap_.insert(std::make_pair("李四3", User("李四3", "123", "初中")));
    usermap_.insert(std::make_pair("王五1", User("王五1", "123", "高中")));
    usermap_.insert(std::make_pair("王五2", User("王五2", "123", "高中")));
    usermap_.insert(std::make_pair("王五3", User("王五3", "123", "高中")));
  }
  std::unordered_map<std::string, User> GetInfo() {
    return this->usermap_;
  }
  virtual void Operations() = 0;
 private:
  std::unordered_map<std::string, User> usermap_;
};

用于负责匹配用户密码以及登录后的操作

3.功能测试

3.1登录功能测试

image

初始界面,可以看到第一行有提醒此为中小学试卷生成系统,下面分割,然后提醒输入账号密码,以空格分隔
image

测试时,第一次正常输入,没有问题。
第二次无论在姓名前还是姓名与密码中加入多少括号,系统都能检测出来,十分优秀,值得夸赞。
但是第三次如果我输入姓名后直接回车再输入密码,系统竟然也能检测,与题目要求空格检测有些出入,希望李义同学多加注意。
image

如果输错呢?第一次我输入不存在的用户名,系统正常报错。第二次我输入错误密码,系统竟然卡死在这里了,查看代码发现其登录函数在找到用户名后不断循环判断密码正确而没有退出,这个地方有待改进。
image

使用切换功能,可以看到输入“切换为高中”,系统正确切换,输入“切换为大学”,系统提醒输入错误,完全没有问题

3.2出题功能测试

image

登录小学老师张三1的账号出题,先是出5道题,系统提醒不符合题目数,再输入10,系统提醒输入成功并写入文件。此时去相应的文件目录下查找,果然发现了新生成的文件如下图:image
image

切换为初中和高中题目,检查也并无发现问题!image
image

联系输入几次也并无发现重复题目,且随机性良好,值得称赞。

4.优缺点分析与总结

整体来说,李义同学的代码逻辑清晰、注释明确、格式规范,使用多个抽象类来明确分工函数功能,代码结构合理,可拓展性很好。在细节上,甚至注意到了账号前空格和账号与密码中多个空格的问题,但是仍有一些我在之前提过的一点小瑕疵,不过无伤大雅,改掉即可。代码完成度也很高,达到了预期的水准。通过对他代码的分析,我意识到了自己的代码的许多问题和改进之处,许多地方都可以向这位同学学习。希望李义同学能继续再接再厉,蒸蒸日上,达到更好的标准,遥遥领先!