#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #define MKDIR(path) _mkdir(path) #endif using namespace std; // 题目生成器接口:用于生成不同类型的数学题目 class IQuestionGenerator { public: virtual ~IQuestionGenerator() = default; virtual string generateQuestion() = 0; virtual string getType() const = 0; }; // 用户管理器接口:用于管理用户登录、切换类型、记录题目等 class IUserManager { public: virtual ~IUserManager() = default; virtual bool login(const string& username, const string& password) = 0; virtual void logout() = 0; virtual bool switchType(const string& type) = 0; virtual bool isQuestionDuplicate(const string& question) = 0; virtual void addQuestionToUserRecord(const string& question) = 0; virtual string getCurrentUser() const = 0; virtual string getCurrentType() const = 0; virtual bool getIsLoggedIn() const = 0; }; // 文件操作接口:用于处理文件和目录相关操作 class IFileManager { public: virtual ~IFileManager() = default; virtual bool createDirectory(const string& path) = 0; virtual bool directoryExists(const string& path) = 0; virtual vector getFilesInDirectory(const string& path) = 0; virtual string trim(const string& str) = 0; }; // 账户结构体:存储用户的用户名、密码和题目类型 struct Account { string username; string password; string type; }; // 文件操作具体实现:实现文件和目录的创建、判断、遍历等功能 class FileManager : public IFileManager { public: bool createDirectory(const string& path) override { return MKDIR(path.c_str()) == 0; } bool directoryExists(const string& path) override { DIR* dir = opendir(path.c_str()); if (dir) { closedir(dir); return true; } return false; } vector getFilesInDirectory(const string& path) override { vector files; DIR* dir = opendir(path.c_str()); if (dir) { struct dirent* entry; while ((entry = readdir(dir)) != nullptr) { string filename = entry->d_name; if (filename != "." && filename != "..") { files.push_back(filename); } } closedir(dir); } return files; } string trim(const string& str) override { size_t start = str.find_first_not_of(" \t\n\r"); size_t end = str.find_last_not_of(" \t\n\r"); if (start == string::npos || end == string::npos) { return ""; } return str.substr(start, end - start + 1); } }; // 题目生成器基类:为题目生成器提供公共的随机数和表达式构建方法 class BaseQuestionGenerator : public IQuestionGenerator { protected: int randomNumber(int min, int max) { return rand() % (max - min + 1) + min; } bool shouldAddParentheses(int operandCount) { if (operandCount <= 2) return false; return randomNumber(0, 1) == 1; } string addParenthesesToExpression(const vector& operands, const vector& operators) { if (operands.size() <= 2) { return buildExpression(operands, operators); } int parenthesesPos = randomNumber(0, operands.size() - 2); string expression; for (size_t i = 0; i < operands.size(); i++) { if (i == parenthesesPos) { expression += "("; } expression += to_string(operands[i]); if (i == parenthesesPos + 1) { expression += ")"; } if (i < operators.size()) { expression += " " + string(1, operators[i]) + " "; } } return expression; } string buildExpression(const vector& operands, const vector& operators) { string expression = to_string(operands[0]); for (size_t i = 0; i < operators.size(); i++) { expression += " " + string(1, operators[i]) + " " + to_string(operands[i + 1]); } return expression; } }; // 小学题目生成器:生成小学难度的数学题目 class PrimaryQuestionGenerator : public BaseQuestionGenerator { public: string generateQuestion() override { int operandCount = randomNumber(2, 5); vector operands; vector operators; operands.push_back(randomNumber(1, 100)); for (int i = 0; i < operandCount - 1; i++) { int opType = randomNumber(0, 3); int prev = operands.back(); int next; switch (opType) { case 0: next = randomNumber(1, 100); operators.push_back('+'); operands.push_back(next); break; case 1: next = randomNumber(1, prev); operators.push_back('-'); operands.push_back(next); break; case 2: next = randomNumber(1, 100); operators.push_back('*'); operands.push_back(next); break; case 3: { next = randomNumber(1, 10); int result = randomNumber(1, 10); int dividend = next * result; operands.back() = dividend; operators.push_back('/'); operands.push_back(next); } break; } } if (shouldAddParentheses(operandCount)) { return addParenthesesToExpression(operands, operators); } else { return buildExpression(operands, operators); } } string getType() const override { return "小学"; } }; // 初中题目生成器:生成初中难度的数学题目,包含平方和根号 class MiddleQuestionGenerator : public BaseQuestionGenerator { private: string addParenthesesToAdvancedExpression(const string& expression, const vector& operators) { if (operators.size() <= 1) return expression; vector opPositions; size_t pos = 0; for (const auto& op : operators) { pos = expression.find(op, pos); if (pos != string::npos) { opPositions.push_back(pos); pos += op.length(); } } if (opPositions.size() <= 1) return expression; int parenthesesPos = randomNumber(0, opPositions.size() - 2); string result = expression; size_t leftPos = opPositions[parenthesesPos]; if (parenthesesPos > 0) { size_t prevOpEnd = opPositions[parenthesesPos - 1] + operators[parenthesesPos - 1].length(); size_t numStart = result.find_first_not_of(" ", prevOpEnd); leftPos = numStart; } else { leftPos = 0; } result.insert(leftPos, "("); size_t rightPos = opPositions[parenthesesPos + 1]; size_t numEnd = result.find_first_of("+-*/", rightPos + 1); if (numEnd == string::npos) { numEnd = result.length(); } else { numEnd--; } result.insert(numEnd, ")"); return result; } public: string generateQuestion() override { int operandCount = randomNumber(2, 5); vector operands; vector operators; for (int i = 0; i < operandCount; i++) { operands.push_back(randomNumber(1, 100)); } bool hasSquareOrRoot = false; string expression = ""; for (int i = 0; i < operandCount; i++) { if (i > 0) { int opType = randomNumber(0, 3); switch (opType) { case 0: operators.push_back("+"); break; case 1: operators.push_back("-"); break; case 2: operators.push_back("*"); break; case 3: operators.push_back("/"); break; } } int specialOp = randomNumber(0, 3); if ((!hasSquareOrRoot && i == operandCount - 1) || (specialOp == 0 && i < operandCount - 1)) { if (randomNumber(0, 1) == 0) { expression += to_string(operands[i]) + "²"; } else { expression += "√" + to_string(operands[i]); } hasSquareOrRoot = true; } else { expression += to_string(operands[i]); } } if (!hasSquareOrRoot) { int pos = randomNumber(0, operandCount - 1); size_t numStart = 0; for (int i = 0; i < pos; i++) { size_t opPos = expression.find_first_of("+-*/", numStart); if (opPos != string::npos) { numStart = opPos + 3; } } if (randomNumber(0, 1) == 0) { expression.insert(numStart, "("); expression.insert(expression.find(' ', numStart), ")²"); } else { expression.insert(numStart, "√("); expression.insert(expression.find(' ', numStart), ")"); } } if (shouldAddParentheses(operandCount)) { expression = addParenthesesToAdvancedExpression(expression, operators); } return expression; } string getType() const override { return "初中"; } }; // 高中题目生成器:生成高中难度的数学题目,包含三角函数等 class HighQuestionGenerator : public BaseQuestionGenerator { private: string addParenthesesToAdvancedExpression(const string& expression, const vector& operators) { if (operators.size() <= 1) return expression; vector opPositions; size_t pos = 0; for (const auto& op : operators) { pos = expression.find(op, pos); if (pos != string::npos) { opPositions.push_back(pos); pos += op.length(); } } if (opPositions.size() <= 1) return expression; int parenthesesPos = randomNumber(0, opPositions.size() - 2); string result = expression; size_t leftPos = opPositions[parenthesesPos]; if (parenthesesPos > 0) { size_t prevOpEnd = opPositions[parenthesesPos - 1] + operators[parenthesesPos - 1].length(); size_t numStart = result.find_first_not_of(" ", prevOpEnd); leftPos = numStart; } else { leftPos = 0; } result.insert(leftPos, "("); size_t rightPos = opPositions[parenthesesPos + 1]; size_t numEnd = result.find_first_of("+-*/", rightPos + 1); if (numEnd == string::npos) { numEnd = result.length(); } else { numEnd--; } result.insert(numEnd, ")"); return result; } public: string generateQuestion() override { int operandCount = randomNumber(2, 5); vector operands; for (int i = 0; i < operandCount; i++) { operands.push_back(randomNumber(1, 100)); } bool hasTrigonometry = false; vector operators; string expression = ""; for (int i = 0; i < operandCount; i++) { if (i > 0) { int opType = randomNumber(0, 3); switch (opType) { case 0: operators.push_back("+"); break; case 1: operators.push_back("-"); break; case 2: operators.push_back("*"); break; case 3: operators.push_back("/"); break; } } int specialOp = randomNumber(0, 5); if ((!hasTrigonometry && i == operandCount - 1) || specialOp >= 2) { int opChoice = randomNumber(0, 4); switch (opChoice) { case 0: expression += to_string(operands[i]) + "²"; break; case 1: expression += "√" + to_string(operands[i]); break; case 2: expression += "sin(" + to_string(operands[i]) + ")"; hasTrigonometry = true; break; case 3: expression += "cos(" + to_string(operands[i]) + ")"; hasTrigonometry = true; break; case 4: expression += "tan(" + to_string(operands[i]) + ")"; hasTrigonometry = true; break; } } else { expression += to_string(operands[i]); } } if (!hasTrigonometry) { int pos = randomNumber(0, operandCount - 1); size_t numStart = 0; for (int i = 0; i < pos; i++) { size_t opPos = expression.find_first_of("+-*/", numStart); if (opPos != string::npos) { numStart = opPos + 3; } } int trigChoice = randomNumber(0, 2); switch (trigChoice) { case 0: expression.insert(numStart, "sin("); expression.insert(expression.find(' ', numStart), ")"); break; case 1: expression.insert(numStart, "cos("); expression.insert(expression.find(' ', numStart), ")"); break; case 2: expression.insert(numStart, "tan("); expression.insert(expression.find(' ', numStart), ")"); break; } } if (shouldAddParentheses(operandCount)) { expression = addParenthesesToAdvancedExpression(expression, operators); } return expression; } string getType() const override { return "高中"; } }; // 用户管理器具体实现:实现用户登录、切换类型、题目去重等功能 class UserManager : public IUserManager { private: vector accounts; string currentUser; string currentType; bool isLoggedIn; map> userQuestions; shared_ptr fileManager; public: UserManager(shared_ptr fm) : fileManager(fm) { isLoggedIn = false; currentUser = ""; currentType = ""; accounts = { {"张三1", "123", "小学"}, {"张三2", "123", "小学"}, {"张三3", "123", "小学"}, {"李四1", "123", "初中"}, {"李四2", "123", "初中"}, {"李四3", "123", "初中"}, {"王五1", "123", "高中"}, {"王五2", "123", "高中"}, {"王五3", "123", "高中"} }; for (const auto& account : accounts) { string folderPath = account.username; if (!fileManager->directoryExists(folderPath)) { fileManager->createDirectory(folderPath); } loadUserQuestions(account.username); } } void loadUserQuestions(const string& username) { userQuestions[username].clear(); string folderPath = username; if (!fileManager->directoryExists(folderPath)) { return; } vector files = fileManager->getFilesInDirectory(folderPath); for (const string& filename : files) { if (filename.length() > 4 && filename.substr(filename.length() - 4) == ".txt") { string filepath = folderPath + "/" + filename; ifstream file(filepath); string line; while (getline(file, line)) { if (!line.empty() && isdigit(line[0])) { size_t dotPos = line.find('.'); if (dotPos != string::npos && dotPos + 2 < line.length()) { string question = line.substr(dotPos + 2); userQuestions[username].insert(question); } } } file.close(); } } } bool login(const string& username, const string& password) override { for (const auto& account : accounts) { if (account.username == username && account.password == password) { currentUser = username; currentType = account.type; isLoggedIn = true; return true; } } return false; } void logout() override { isLoggedIn = false; currentUser = ""; currentType = ""; } bool switchType(const string& type) override { string trimmedType = fileManager->trim(type); if (trimmedType == "小学" || trimmedType == "初中" || trimmedType == "高中") { currentType = trimmedType; return true; } return false; } bool isQuestionDuplicate(const string& question) override { return userQuestions[currentUser].find(question) != userQuestions[currentUser].end(); } void addQuestionToUserRecord(const string& question) override { userQuestions[currentUser].insert(question); } string getCurrentUser() const override { return currentUser; } string getCurrentType() const override { return currentType; } bool getIsLoggedIn() const override { return isLoggedIn; } }; // 题目生成器工厂:根据类型创建对应的题目生成器 class QuestionGeneratorFactory { public: static unique_ptr createGenerator(const string& type) { if (type == "小学") { return make_unique(); } else if (type == "初中") { return make_unique(); } else if (type == "高中") { return make_unique(); } return nullptr; } }; // 数学卷子生成主类:负责题目生成、保存、用户交互等主流程 class MathPaperGenerator { private: shared_ptr userManager; unique_ptr questionGenerator; shared_ptr fileManager; public: MathPaperGenerator(shared_ptr um, shared_ptr fm) : userManager(um), fileManager(fm) {} vector generateQuestions(int count) { vector questions; set generatedSet; int attempts = 0; const int MAX_ATTEMPTS = count * 10; questionGenerator = QuestionGeneratorFactory::createGenerator(userManager->getCurrentType()); if (!questionGenerator) { cout << "题目生成器创建失败!" << endl; return questions; } while (questions.size() < count && attempts < MAX_ATTEMPTS) { string question = questionGenerator->generateQuestion(); if (!userManager->isQuestionDuplicate(question) && generatedSet.find(question) == generatedSet.end()) { questions.push_back(question); generatedSet.insert(question); userManager->addQuestionToUserRecord(question); } attempts++; } while (questions.size() < count) { string question; string currentType = userManager->getCurrentType(); if (currentType == "小学") { question = to_string(rand() % 100 + 1) + " + " + to_string(rand() % 100 + 1); } else if (currentType == "初中") { question = to_string(rand() % 100 + 1) + "² + " + to_string(rand() % 100 + 1); } else { question = "sin(" + to_string(rand() % 100 + 1) + ") + " + to_string(rand() % 100 + 1); } if (!userManager->isQuestionDuplicate(question)) { questions.push_back(question); userManager->addQuestionToUserRecord(question); } } return questions; } void saveQuestions(const vector& questions) { time_t now = time(nullptr); tm* localTime = localtime(&now); stringstream filename; filename << setfill('0') << localTime->tm_year + 1900 << "-" << setw(2) << localTime->tm_mon + 1 << "-" << setw(2) << localTime->tm_mday << "-" << setw(2) << localTime->tm_hour << "-" << setw(2) << localTime->tm_min << "-" << setw(2) << localTime->tm_sec << ".txt"; string filepath = userManager->getCurrentUser() + "/" + filename.str(); ofstream file(filepath); if (file.is_open()) { for (size_t i = 0; i < questions.size(); i++) { file << i + 1 << ". " << questions[i] << "\n"; if (i < questions.size() - 1) { file << "\n"; } } file.close(); cout << "题目已保存到: " << filepath << endl; } else { cout << "文件保存失败!" << endl; } } void processInput() { string input; getline(cin, input); input = fileManager->trim(input); if (input == "-1") { userManager->logout(); return; } if (input.find("切换为") == 0) { string type = input.substr(3); type = fileManager->trim(type); if (userManager->switchType(type)) { cout << "切换成功!当前类型为:" << userManager->getCurrentType() << endl; return; } else { cout << "请输入小学、初中和高中三个选项中的一个" << endl; return; } } processCountInput(input); } void processCountInput(const string& input) { try { int count = stoi(input); if (count >= 10 && count <= 30) { vector questions = generateQuestions(count); saveQuestions(questions); } else { cout << "题目数量应在10-30之间" << endl; } } catch (const exception& e) { cout << "请输入有效的数字" << endl; } } void run() { srand(time(nullptr)); cout << "=== 中小学数学卷子自动生成程序 ===" << endl; while (true) { if (!userManager->getIsLoggedIn()) { cout << "请输入用户名和密码(用空格隔开): "; string username, password; cin >> username >> password; cin.ignore(); if (userManager->login(username, password)) { cout << "登录成功!当前选择为" << userManager->getCurrentType() << "出题" << endl; } else { cout << "请输入正确的用户名、密码" << endl; continue; } } while (userManager->getIsLoggedIn()) { cout << endl << "准备生成" << userManager->getCurrentType() << "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录)" << endl; cout << "或者输入\"切换为小学/初中/高中\"来切换题目类型: "; cin.clear(); processInput(); } } } }; int main() { auto fileManager = make_shared(); auto userManager = make_shared(fileManager); MathPaperGenerator generator(userManager, fileManager); generator.run(); return 0; }