个人项目互评

结队编程,分析结队队友的代码能够让小组队员之间更加了解彼此的风格。指出队友的优缺点,既能两个人互相提醒改进,也可以在往后的结队编程项目达到更好的效果。后续我将分析队友方缘的C++代码的功能及性能。

基本功能实现

基本要求:

用户:

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

功能:

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

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

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

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

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

功能测试:

基本功能实现:

 功能基本完成,但是文件名有一些不符合规范。

更改部分输入:

 登录部分,在用户名与密码空行的情况下也可登录

 切换部分,在错误的输入条件下会出现提示,无法切换,输入正确时才可以继续

 在输入的内容不符合条件时报错

 

 出题部分,在输入的题目数量不在范围内时会出现提醒,但是在输入小数的时候正常生成了题目,会导致出现如下bug:

 功能部分总评:

基本功能都能够实现,且分了不同的文件夹以便于查重与查看;但是在输入命令、数字或者-1的模块提示信息太不明确,并且在输入不符合条件的话语时会产生报错,中断程序。同时在生成题目的模块,没有做到对输入的内容一定是整数的限制。界面显示上,没有空行及清屏等操作,观赏性不强。感觉没有必要每次生成题目都有显示。

代码分析

main函数

int main() {
    srand(static_cast<unsigned>(time(nullptr)));

    User elementaryUsers[] = {User("张三1", "123", "小学"), User("张三2", "123", "小学"), User("张三3", "123", "小学")};
    User middleSchoolUsers[] = {User("李四1", "123", "初中"), User("李四2", "123", "初中"), User("李四3", "123", "初中")};
    User highSchoolUsers[] = {User("王五1", "123", "高中"), User("王五2", "123", "高中"), User("王五3", "123", "高中")};

    User *currentUser = nullptr;

    while (true) {
        cout << "请输入用户名和密码(用户名 密码): ";
        string username, password;
        cin >> username >> password;

        bool validUser = false;

        // 检查所有用户
        for (int i = 0; i < 3; ++i) {
            if (elementaryUsers[i].login(username, password)) {
              currentUser = &elementaryUsers[i];
              validUser = true;
              cout << "当前选择为" << currentUser->getCurrentLevel() << "出题" << endl;
              break;
            } else if (middleSchoolUsers[i].login(username, password)) {
              currentUser = &middleSchoolUsers[i];
              validUser = true;
              cout << "当前选择为" << currentUser->getCurrentLevel() << "出题" << endl;
              break;
            } else if (highSchoolUsers[i].login(username, password)) {
              currentUser = &highSchoolUsers[i];
              validUser = true;
              cout << "当前选择为" << currentUser->getCurrentLevel() << "出题" << endl;
              break;
            }
        }

        if (!validUser) {
          cout << "请输入正确的用户名、密码" << endl;
          continue;
        }

        if (currentUser->isLoggedIn()) {
          string folderName = currentUser->getUsername() + "_papers";
          if (_access(folderName.c_str(), 0) != 0) {
                if (_mkdir(folderName.c_str()) != 0) {
                  cerr << "Error creating folder: " << folderName << endl;
                  return 1;
                }
            }

            int problemCount = 1;

            while (true) {
                string input;
                cout << "请输入命令或题目数量或切换为XX(题目数量在10-30,输入-1退出当前用户,重新登录,输入切换为XX可更改出题类型): ";
                cin >> input;

                if (input == "-1") {
                  currentUser->logout();
                  currentUser = nullptr;
                  break;
                } else if (input.find("切换为") != string::npos) {
                  string newLevel = input.substr(6); // 获取"切换为"后的内容
                    if (newLevel == "小学" || newLevel == "初中" || newLevel == "高中") {
                      currentUser->setCurrentLevel(newLevel);
                      cout << "当前选择为" << currentUser->getCurrentLevel() << "出题" << endl;
                    } else {
                      cout << "请输入小学、初中和高中三个选项中的一个" << endl;
                    }
                    continue;
                }

                int numProblems = stoi(input);
                if (numProblems >= 10 && numProblems <= 30) {
                    MathProblem *mathProblem = nullptr;
                    if (currentUser->getCurrentLevel() == "小学") {
                       mathProblem = new ElementaryMathProblem();
                    } else if (currentUser->getCurrentLevel() == "初中") {
                       mathProblem = new MiddleSchoolMathProblem();
                    } else if (currentUser->getCurrentLevel() == "高中") {
                       mathProblem = new HighSchoolMathProblem();
                    }


                    stringstream fileNameStream;
                    fileNameStream << getCurrentTime() << "_ProblemSet" << problemCount << ".txt";
                    string fileName = fileNameStream.str();
                    string filePath = folderName + "/" + fileName;

                    ofstream file(filePath);
                    if (!file.is_open()) {
                      cerr << "Error opening file: " << filePath << endl;
                      return 1;
                    }

                    for (int i = 0; i < numProblems; ++i) {
                        string problem = mathProblem->generateProblem();
                        string rpnExpression = generateRPNExpression(problem);
                        file << "题目" << problemCount << "" << problem << "?" << endl;
                        cout << "生成题目" << problemCount << "已保存到:" << filePath << endl;
                        problemCount++;
                        file << endl;
                    }

                    file.close();
                    delete mathProblem;
                } else {
                    cout << "题目数量的有效输入范围是10-30" << endl;
                }
            }
        }
    }
    return 0;
}

流程都写在main函数里面,可拓展性很差,main方法太长了

出题部分函数

以小学数学题部分为例

class MathProblem {
    public:
        virtual string generateProblem() = 0;
};

class ElementaryMathProblem : public MathProblem { private: char operators[4] = {'+', '-', '*', '/'}; public: //生成小学数学题 string generateProblem() override { int numOperands = rand() % 4 + 2; // 随机生成2到5个操作数 stringstream ss; bool addParentheses = false; // 用于标记是否添加括号 int numOperators = 0; for (int i = 0; i < numOperands; ++i) { if (i > 0) { char op = operators[rand() % 4]; ss << " " << op << " "; numOperators++; // 随机决定是否添加括号,确保不是第一个和最后一个操作数,且已经有一个操作符存在 if (i > 1 && i < numOperands - 1 && numOperators > 1 && !addParentheses && rand() % 2 == 0) { addParentheses = true; ss << "("; // 添加左括号 } } int operand = rand() % 100 + 1; // 随机生成1到100的操作数值 ss << operand; } // 如果添加了左括号,则添加右括号 if (addParentheses) { ss << ")"; } ss << " ="; return ss.str(); } };

随机生成题目而不是在题库里面找题,题目类型更丰富,用逆波兰表达式,便于使用者阅读

 

代码部分总评

优点:

1.语句书写规范,且在很多地方都有注释,代码的可读性很高。

2.代码的逻辑清晰,能够直接生成题目。

3.代码的复用不多,几乎没有重复的代码。

缺点:

1.类和方法的数量太少,没有分块,可拓展性弱。

2.对用户的不规范输入没有加以处理,会造成程序运行失败。

3.界面内容太多太杂且没有空行,使用起来不舒适。

 

posted @ 2023-09-20 11:25  北一北一  阅读(513)  评论(0)    收藏  举报