diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..ac5cd7b --- /dev/null +++ b/doc/README.md @@ -0,0 +1,2 @@ +# smath + diff --git a/doc/shuoming.md b/doc/shuoming.md new file mode 100644 index 0000000..dccdaa1 --- /dev/null +++ b/doc/shuoming.md @@ -0,0 +1,38 @@ +# 1.项目需求 + 用户: +小学、初中和高中数学老师。 +功能: +1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高 +中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显 +示“当前选择为 XX 出题”,XX 为小学、初中和高中三个选项中的一个。否则 +提示“请输入正确的用户名、密码”,重新输入用户名、密码; +2、登录后,系统提示“准备生成 XX 数学题目,请输入生成题目数量(输入-1 +将退出当前用户,重新登录):”,XX 为小学、初中和高中三个选项中的一 +个,用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。 +每道题目的操作数在 1-5 个之间,操作数取值范围为 1-100; +3、题目数量的有效输入范围是“10-30”(含 10,30,或-1 退出登录),程序 +根据输入的题目数量生成符合小学、初中和高中难度的题目的卷子(具体要求 +见附表)。同一个老师的卷子中的题目不能与以前的已生成的卷子中的题目重 +复(以指定文件夹下存在的文件为准,见 5); +4、在登录状态下,如果用户需要切换类型选项,命令行输入“切换为 XX”, +XX 为小学、初中和高中三个选项中的一个,输入项不符合要求时,程序控制台 +提示“请输入小学、初中和高中三个选项中的一个”;输入正确后,显示“系 +统提示“准备生成 XX 数学题目,请输入生成题目数量”,用户输入所需出的卷 +子的题目数量,系统新设置的类型进行出题; +5、生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文 +件夹。每道题目有题号,每题之间空一行; +# 2.实现思路 +采用的是工厂模式,先声明了题目生成器这个抽象基类,然后分别声明小学、初中、高中的题目生成去来继承这个抽象基类,然后一些界面控制、将题目保存到文件等功能声明成函数、准备用函数来实现。接下来就是实现成员函数和函数了。 +# 3.重点方法 +GenerateLogic() : +生成一道题目,不同的题目生成器的逻辑不同 +SaveQuestionsToFile(): +将生成的题目保存为.txt文件 +DisplayQuestionGenerator(): +题目生成界面 + +# 4.存在的问题 +在进行切换后会创建新的题目生成器工厂,虽然不同难度的题目会不一样,但切换成其它的有切换回来可能会生成与之前没切换生成的题目重复的题目。 +# 5.开发环境及可执行文件 +使用的是c++语言进行开发,编译器为C++ 17 GUN标准,可执行文件的release版本在Windows系统的cmd和powershell都可运行,直接运行可执行文件即可 + diff --git a/scr/hanshu.cpp b/scr/hanshu.cpp new file mode 100644 index 0000000..a4fbdd9 --- /dev/null +++ b/scr/hanshu.cpp @@ -0,0 +1,164 @@ +#include "hanshu.h" +#include +#include +#include +#include +#include +#include + +using namespace std; + +// 预设用户数据 + vector presetusers = { + {"张三1", "123", "小学"}, + {"张三2", "123", "小学"}, + {"张三3", "123", "小学"}, + {"李四1", "123", "初中"}, + {"李四2", "123", "初中"}, + {"李四3", "123", "初中"}, + {"王五1", "123", "高中"}, + {"王五2", "123", "高中"}, + {"王五3", "123", "高中"} + +}; + +// 用户认证函数 +User* AuthenticateUser(const string& username, const string& password) { + for (auto& user : presetusers) { + if (user.username == username && user.password == password) { + return &user; + } + } + return nullptr; +} + +bool IsValidUserType(const string& type) { + return type == "小学" || type == "初中" || type == "高中"; +} + +// 文件操作函数 +void SaveQuestionsToFile(const vector& questions, + const string& username, + const string& type) { + CreateUserDirectory(username); + string filename = GetCurrentTimestamp() + ".txt"; + string fullPath = username + "/" + filename; + + ofstream file(fullPath); + if (file.is_open()) { + file << type << "数学题目\n"; + file << "生成时间: " << GetCurrentTimestamp() << "\n\n"; + + for (size_t i = 0; i < questions.size(); i++) { + file << i + 1 << ". " << questions[i] << "\n\n"; + } + file.close(); + cout << "题目已保存到: " << fullPath << endl; + } else { + cout << "保存文件失败: " << fullPath << endl; + } +} + +string GetCurrentTimestamp() { + time_t now = time(nullptr); + tm* localTime = localtime(&now); + + stringstream ss; + ss << localTime->tm_year + 1900 << "-" + << setw(2) << setfill('0') << localTime->tm_mon + 1 << "-" + << setw(2) << setfill('0') << localTime->tm_mday << "-" + << setw(2) << setfill('0') << localTime->tm_hour << "-" + << setw(2) << setfill('0') << localTime->tm_min << "-" + << setw(2) << setfill('0') << localTime->tm_sec; + + return ss.str(); +} + +void CreateUserDirectory(const string& username) { +#ifdef _WIN32 + string command = "md " + username; // Windows 命令 +#else + string command = "mkdir -p " + username; // Linux/Mac 命令 +#endif + system(command.c_str()); +} + +// 输入验证函数 +bool IsValidQuestionCount(int count) { + return (count >= 10 && count <= 30) || count == -1; +} + +bool IsSwitchCommand(const string& input, string& newtype) { + if (input.find("切换为") == 0) { + newtype = input.substr(6,input.length()-1); + + if(!IsValidUserType(newtype)) + { + cout << "请输入小学、初中和高中三个选项中的一个" << endl; + return false; + } + else return IsValidUserType(newtype); + } + return false; +} + + +// 系统流程函数 +void DisplayWelcomeMessage() { + cout << "=== 数学题目生成系统 ===" << endl; +} + +void DisplayCurrentMode(const string& type) { + cout << "当前选择为" << type << "出题" << endl; +} + + +void DisplayQuestionGenerator(std::unique_ptr generator,const User* users){ + // 主交互循环 + while (true) { + cout << "准备生成" << generator->GetType() + << "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):"; + + string input; + cin >> input; + + // 处理退出命令 + if (input == "-1") { + cout << "退出当前用户,重新登录..." << endl; + break; + } + + // 处理切换命令 + string newtype; + if (IsSwitchCommand(input, newtype)) { + generator = CreateQuestionGenerator(newtype); + cout << "准备生成" << newtype << "数学题目,请输入生成题目数量:"; + cin >> input; + } + + // 处理题目生成 + try { + int count = stoi(input); + if (count >= 10 && count <= 30) { + auto questions = generator->GenerateQuestion(count); + SaveQuestionsToFile(questions, users->username, generator->GetType()); + DisplayQuestionExamples(questions); + } else { + cout << "题目数量应在10-30之间" << endl; + } + } catch (const exception& e) { + cout << "请输入有效的数字" << endl; + } + } + + +} + +void DisplayQuestionExamples(const vector& questions) { + if (!questions.empty()) { + cout << "题目示例:" << endl; + for (int i = 0; i < min(3, (int)questions.size()); i++) { + cout << " " << questions[i] << endl; + } + } +} diff --git a/scr/hanshu.h b/scr/hanshu.h new file mode 100644 index 0000000..7b426e5 --- /dev/null +++ b/scr/hanshu.h @@ -0,0 +1,31 @@ +#ifndef HANSHU_H +#define HANSHU_H + +#include "question.h" +#include +#include + + + +// 用户认证函数 +User* AuthenticateUser(const std::string& username, const std::string& password); +bool IsValidUserType(const std::string& type); + +// 文件操作函数 +void SaveQuestionsToFile(const std::vector& questions, + const std::string& username, + const std::string& type); +std::string GetCurrentTimestamp(); +void CreateUserDirectory(const std::string& username); + +// 输入验证函数 +bool IsValidQuestionCount(int count); +bool IsSwitchCommand(const std::string& input, std::string& newtype); + +// 系统流程函数 +void DisplayWelcomeMessage(); +void DisplayQuestionGenerator(std::unique_ptr generator,const User* users); +void DisplayCurrentMode(const std::string& type); +void DisplayQuestionExamples(const std::vector& questions); + +#endif // HANSHU_H diff --git a/scr/main.cpp b/scr/main.cpp index 64cd9b1..250b2e4 100644 --- a/scr/main.cpp +++ b/scr/main.cpp @@ -1,9 +1,42 @@ +#include "question.h" +#include "hanshu.h" #include +#include using namespace std; -int main() -{ - cout << "Hello world!" << endl; +int main() { + while(1){ + string exit; + DisplayWelcomeMessage(); + // 登录循环 + User* currentuser = nullptr; + while (!currentuser) { + cout << "请输入用户名和密码(用空格隔开,输入exit结束程序):"; + string username, password; + cin >> username ; + if(username=="exit"){ + exit = username; + break; + } + cin>>password; + currentuser = AuthenticateUser(username, password); + if (!currentuser) { + cout << "请输入正确的用户名、密码" << endl; + } + } + if(exit == "exit"){ + cout << "程序已结束,感谢使用!"; + break; + } + + + // 创建题目生成器 + auto generator = CreateQuestionGenerator(currentuser->usertype); + DisplayCurrentMode(currentuser->usertype); + + DisplayQuestionGenerator(std::move(generator),currentuser); +} + return 0; } diff --git a/scr/question.cpp b/scr/question.cpp new file mode 100644 index 0000000..f9d3155 --- /dev/null +++ b/scr/question.cpp @@ -0,0 +1,261 @@ +#include "question.h" +#include +#include +#include + +using namespace std; + +// QuestionGenerator 基类实现 +vector QuestionGenerator::GenerateQuestion(int count) { + vector questions; + int attempts = 0; + const int max_attempts = count * 10; + + while (questions.size() < count && attempts < max_attempts) { + string question = GenerateLogic(); + + if (IsQuestionUnique(question)) { + questions.push_back(question); + existingqustions.insert(question); + } + + attempts++; + } + + return questions; +} + +int QuestionGenerator::GetRand(int min, int max) { + + uniform_int_distribution<> dis(min, max); + return dis(gen); +} + +char QuestionGenerator::GetOperator() { + char operators[] = {'+', '-', '*', '/'}; + return operators[GetRand(0, 3)]; +} + +bool QuestionGenerator::IsQuestionUnique(const string& question) const { + return existingqustions.find(question) == existingqustions.end(); +} + +void QuestionGenerator::ClearQuestions() { + existingqustions.clear(); +} + +// PrimaryQuestionGenerator 实现 +string PrimaryQuestionGenerator::GenerateLogic() { + int operands = GetRand(2, 5); + + // 50%概率使用带括号的表达式 + if (GetRand(0, 1) == 1 && operands >= 3) { + return GenerateWithParentheses(operands); + } + + // 生成基础表达式 + stringstream ss; + for (int i = 0; i < operands; i++) { + ss << GetRand(1, 100); + if (i < operands - 1) { + ss << " " << GetOperator() << " "; + } + } + ss << " = "; + return ss.str(); +} + +string PrimaryQuestionGenerator::GetType() const { + return "小学"; +} + +string PrimaryQuestionGenerator::ParenthesesCaceOne(int operands, + const vector& numbers) { + stringstream ss; + + ss << "(" << numbers[0] << " " << GetOperator() << " " << numbers[1] << ")"; + + for (int i = 2; i < operands; i++) { + ss << " " << GetOperator() << " " << numbers[i]; + } + + ss << " = "; + return ss.str(); +} + +string PrimaryQuestionGenerator::ParenthesesCaceTwo(int operands, + const vector& numbers) { + stringstream ss; + + ss << numbers[0] << " " << GetOperator() << " "; + ss << "(" << numbers[1] << " " << GetOperator() << " " << numbers[2] << ")"; + + for (int i = 3; i < operands; i++) { + ss << " " << GetOperator() << " " << numbers[i]; + } + + ss << " = "; + return ss.str(); +} +string PrimaryQuestionGenerator::ParenthesesCaceThree(int operands, + const vector& numbers) { + stringstream ss; + + if (operands >= 4) { + int mid = operands / 2; + ss << "("; + for (int i = 0; i < mid; i++) { + if (i > 0) ss << " " << GetOperator() << " "; + ss << numbers[i]; + } + ss << ") " << GetOperator() << " ("; + for (int i = mid; i < operands; i++) { + if (i > mid) ss << " " << GetOperator() << " "; + ss << numbers[i]; + } + ss << ")"; + } else { + ss << "(" << numbers[0] << " " << GetOperator() << " " << numbers[1] << ")"; + for (int i = 2; i < operands; i++) { + ss << " " << GetOperator() << " " << numbers[i]; + } + } + + ss << " = "; + return ss.str(); +} + +string PrimaryQuestionGenerator::GenerateWithParentheses(int operands) { + stringstream ss; + vector numbers; + string result; + + for (int i = 0; i < operands; i++) { + numbers.push_back(GetRand(1, 100)); + } + + int parenthesisType = GetRand(1, 3); + + switch (parenthesisType) { + case 1: + result = ParenthesesCaceOne(operands,numbers); + break; + + case 2: + result = ParenthesesCaceTwo(operands,numbers); + break; + + case 3: + result = ParenthesesCaceThree(operands,numbers); + break; + } + + + if (!IsValidParentheses(result)) { + return GenerateLogic(); // 重新生成 + } + + return result; +} + +bool PrimaryQuestionGenerator::IsValidParentheses(const string& expr) const { + stack st; + for (char c : expr) { + if (c == '(') st.push(c); + else if (c == ')') { + if (st.empty()) return false; + st.pop(); + } + } + return st.empty(); +} + +// JuniorQuestionGenerator 实现 +string JuniorQuestionGenerator::GenerateLogic() { + int operands = GetRand(1, 5); + stringstream ss; + + for (int i = 0; i < operands; i++) { + if(i==0){ + if (GetRand(0, 1) == 1) { + ss << GetRand(1, 20) << "^2"; + } else { + ss << "√" << GetRand(1, 100); + } + if (i < operands - 1) { + ss << " " << GetOperator() << " "; + } + continue; + + } + // 30%概率使用平方或开方 + if (GetRand(0, 2) == 0) { + if (GetRand(0, 1) == 1) { + ss << GetRand(1, 20) << "^2"; + } else { + ss << "√" << GetRand(1, 100); + } + } else { + ss << GetRand(1, 100); + } + + if (i < operands - 1) { + ss << " " << GetOperator() << " "; + } + } + ss << " = "; + return ss.str(); +} + +string JuniorQuestionGenerator::GetType() const { + return "初中"; +} + +// SeniorQuestionGenerator 实现 +string SeniorQuestionGenerator::GenerateLogic() { + int operands = GetRand(1, 5); + stringstream ss; + + for (int i = 0; i < operands; i++) { + if(i==0){ + string trigFuncs[] = {"sin", "cos", "tan"}; + string func = trigFuncs[GetRand(0, 2)]; + ss << func << "(" << GetRand(1, 90) << ")"; + if (i < operands - 1) { + ss << " " << GetOperator() << " "; + } + continue; + } + // 随机决定是否添加三角函数 + if (GetRand(0, 2) == 0 ) { + string trigFuncs[] = {"sin", "cos", "tan"}; + string func = trigFuncs[GetRand(0, 2)]; + ss << func << "(" << GetRand(1, 90) << ")"; + } + else{ + ss << GetRand(1, 100); + } + if (i < operands - 1) { + ss << " " << GetOperator() << " "; + } + + } + ss << " = "; + return ss.str(); +} + +string SeniorQuestionGenerator::GetType() const { + return "高中"; +} + +// 工厂函数实现 +unique_ptr CreateQuestionGenerator(const std::string& type) { + if (type == "小学") { + return make_unique(); + } else if (type == "初中") { + return make_unique(); + } else if (type == "高中") { + return make_unique(); + } + return nullptr; +} diff --git a/scr/question.h b/scr/question.h new file mode 100644 index 0000000..b87343a --- /dev/null +++ b/scr/question.h @@ -0,0 +1,70 @@ +#ifndef QUESTION_H +#define QUESTION_H +#include +#include +#include +#include +#include +#include + +struct User { + std::string username; + std::string password; + std::string usertype; +}; +//抽象基类 +class QuestionGenerator{ + protected: + std::set existingqustions;//已生成的问题 + std::mt19937 gen; + + public: + QuestionGenerator(){ + auto seed = std::chrono::system_clock::now().time_since_epoch().count(); + gen.seed(static_cast(seed)); + } + virtual std::string GenerateLogic()=0; + virtual ~QuestionGenerator() = default; + virtual std::vector GenerateQuestion(int count);//生成问题 + virtual std::string GetType() const = 0; + int GetRand(int min,int max);//产生随机数字 + char GetOperator(); + bool IsQuestionUnique(const std::string& question) const; + void ClearQuestions(); + +}; +//小学题目生成器 +class PrimaryQuestionGenerator : public QuestionGenerator { +public: + PrimaryQuestionGenerator() = default; + std::string GenerateLogic() override; + std::string GetType() const override; + +private: + std::string GenerateWithParentheses(int operands); + bool IsValidParentheses(const std::string& expr) const; + std::string ParenthesesCaceOne(int operands, const std::vector& numbers); + std::string ParenthesesCaceTwo(int operands, const std::vector& numbers); + std::string ParenthesesCaceThree(int operands, const std::vector& numbers); +}; + +// 初中题目生成器 +class JuniorQuestionGenerator : public QuestionGenerator { +public: + JuniorQuestionGenerator() = default; + std::string GenerateLogic() override; + std::string GetType() const override; +}; + +// 高中题目生成器 +class SeniorQuestionGenerator : public QuestionGenerator { +public: + SeniorQuestionGenerator() = default; + std::string GenerateLogic() override; + std::string GetType() const override; +}; + +// 工厂函数声明 +std::unique_ptr CreateQuestionGenerator(const std::string& type); + +#endif // QUESTION_H