|
|
|
|
@ -0,0 +1,454 @@
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <set>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
#include <ctime>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
// 用户账户结构
|
|
|
|
|
class User {
|
|
|
|
|
public:
|
|
|
|
|
string username;
|
|
|
|
|
string password;
|
|
|
|
|
string userType; // "小学", "初中", "高中"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 题目生成接口
|
|
|
|
|
class QuestionGenerator {
|
|
|
|
|
public:
|
|
|
|
|
virtual string generateQuestion() = 0;
|
|
|
|
|
virtual bool meetsRequirements(const string& question) = 0;
|
|
|
|
|
virtual ~QuestionGenerator() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 小学题目生成器
|
|
|
|
|
class PrimaryQuestionGenerator : public QuestionGenerator {
|
|
|
|
|
public:
|
|
|
|
|
string generateQuestion() override;
|
|
|
|
|
bool meetsRequirements(const string& question) override;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 初中题目生成器
|
|
|
|
|
class JuniorQuestionGenerator : public QuestionGenerator {
|
|
|
|
|
public:
|
|
|
|
|
string generateQuestion() override;
|
|
|
|
|
bool meetsRequirements(const string& question) override;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 高中题目生成器
|
|
|
|
|
class SeniorQuestionGenerator : public QuestionGenerator {
|
|
|
|
|
public:
|
|
|
|
|
string generateQuestion() override;
|
|
|
|
|
bool meetsRequirements(const string& question) override;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 文件管理器类
|
|
|
|
|
class FileManager {
|
|
|
|
|
public:
|
|
|
|
|
static bool createUserFolder(const string& username);
|
|
|
|
|
static string generateFileName(const string& username);
|
|
|
|
|
static void saveQuestionsToFile(const string& filename, const vector<string>& questions);
|
|
|
|
|
static set<string> loadExistingQuestions(const string& username);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 用户认证类
|
|
|
|
|
class UserAuthenticator {
|
|
|
|
|
private:
|
|
|
|
|
vector<User> presetUsers;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
UserAuthenticator();
|
|
|
|
|
bool authenticate(const string& username, const string& password, User& user);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 应用程序主类
|
|
|
|
|
class MathTestGeneratorApp {
|
|
|
|
|
private:
|
|
|
|
|
User currentUser;
|
|
|
|
|
bool isLoggedIn;
|
|
|
|
|
set<string> generatedQuestions;
|
|
|
|
|
map<string, QuestionGenerator*> generators;
|
|
|
|
|
|
|
|
|
|
QuestionGenerator* currentGenerator;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
MathTestGeneratorApp();
|
|
|
|
|
~MathTestGeneratorApp();
|
|
|
|
|
|
|
|
|
|
void run();
|
|
|
|
|
void login();
|
|
|
|
|
void generatePaper();
|
|
|
|
|
void switchUserType(const string& newType);
|
|
|
|
|
bool isQuestionDuplicate(const string& question);
|
|
|
|
|
void addQuestionToHistory(const string& question);
|
|
|
|
|
string getCurrentTimeString();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 预设账户
|
|
|
|
|
UserAuthenticator::UserAuthenticator() {
|
|
|
|
|
presetUsers = {
|
|
|
|
|
{"张三1", "123", "小学"},
|
|
|
|
|
{"张三2", "123", "小学"},
|
|
|
|
|
{"张三3", "123", "小学"},
|
|
|
|
|
{"李四1", "123", "初中"},
|
|
|
|
|
{"李四2", "123", "初中"},
|
|
|
|
|
{"李四3", "123", "初中"},
|
|
|
|
|
{"王五1", "123", "高中"},
|
|
|
|
|
{"王五2", "123", "高中"},
|
|
|
|
|
{"王五3", "123", "高中"}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UserAuthenticator::authenticate(const string& username, const string& password, User& user) {
|
|
|
|
|
for (const auto& u : presetUsers) {
|
|
|
|
|
if (u.username == username && u.password == password) {
|
|
|
|
|
user = u;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 小学题目生成实现
|
|
|
|
|
string PrimaryQuestionGenerator::generateQuestion() {
|
|
|
|
|
int numOperands = rand() % 4 + 2; // 2-5个操作数
|
|
|
|
|
stringstream question;
|
|
|
|
|
vector<string> operators = {"+", "-", "*", "/"};
|
|
|
|
|
|
|
|
|
|
bool hasParentheses = (rand() % 2 == 0);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numOperands; i++) {
|
|
|
|
|
int operand = rand() % 100 + 1;
|
|
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
if (hasParentheses && numOperands > 2 && rand() % 2 == 0) {
|
|
|
|
|
question << "(";
|
|
|
|
|
}
|
|
|
|
|
question << operand;
|
|
|
|
|
} else {
|
|
|
|
|
string op = operators[rand() % operators.size()];
|
|
|
|
|
question << " " << op << " " << operand;
|
|
|
|
|
|
|
|
|
|
if (hasParentheses && i == 1 && rand() % 2 == 0) {
|
|
|
|
|
question << ")";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
question << " = ";
|
|
|
|
|
return question.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PrimaryQuestionGenerator::meetsRequirements(const string& question) {
|
|
|
|
|
// 小学题目只能包含 + - * / 和括号
|
|
|
|
|
for (char c : question) {
|
|
|
|
|
if (isalpha(c) && c != 's' && c != 'i' && c != 'n' && c != 'c' && c != 'o' && c != 't' && c != 'a') {
|
|
|
|
|
// 简单检查,实际需要更复杂的逻辑
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初中题目生成实现
|
|
|
|
|
string JuniorQuestionGenerator::generateQuestion() {
|
|
|
|
|
int numOperands = rand() % 4 + 2; // 2-5个操作数
|
|
|
|
|
stringstream question;
|
|
|
|
|
vector<string> operators = {"+", "-", "*", "/", "²", "√"};
|
|
|
|
|
|
|
|
|
|
bool hasSquareOrRoot = false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numOperands; i++) {
|
|
|
|
|
int operand = rand() % 100 + 1;
|
|
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
question << operand;
|
|
|
|
|
} else {
|
|
|
|
|
string op = operators[rand() % operators.size()];
|
|
|
|
|
|
|
|
|
|
if (op == "²") {
|
|
|
|
|
question << "² " << operators[rand() % 4] << " " << operand;
|
|
|
|
|
hasSquareOrRoot = true;
|
|
|
|
|
} else if (op == "√") {
|
|
|
|
|
question << "√" << operand << " " << operators[rand() % 4] << " " << operand;
|
|
|
|
|
hasSquareOrRoot = true;
|
|
|
|
|
} else {
|
|
|
|
|
question << " " << op << " " << operand;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确保至少有一个平方或开根号
|
|
|
|
|
if (!hasSquareOrRoot) {
|
|
|
|
|
int pos = rand() % numOperands;
|
|
|
|
|
// 简化处理,在实际应用中需要更复杂的逻辑
|
|
|
|
|
string temp = question.str();
|
|
|
|
|
size_t found = temp.find_last_of(" ");
|
|
|
|
|
if (found != string::npos) {
|
|
|
|
|
question.str("");
|
|
|
|
|
question << temp.substr(0, found) << "²" << temp.substr(found);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
question << " = ";
|
|
|
|
|
return question.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JuniorQuestionGenerator::meetsRequirements(const string& question) {
|
|
|
|
|
// 检查是否包含平方或开根号
|
|
|
|
|
return question.find("²") != string::npos || question.find("√") != string::npos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 高中题目生成实现
|
|
|
|
|
string SeniorQuestionGenerator::generateQuestion() {
|
|
|
|
|
int numOperands = rand() % 4 + 2; // 2-5个操作数
|
|
|
|
|
stringstream question;
|
|
|
|
|
vector<string> operators = {"+", "-", "*", "/", "sin", "cos", "tan"};
|
|
|
|
|
|
|
|
|
|
bool hasTrigonometry = false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numOperands; i++) {
|
|
|
|
|
int operand = rand() % 100 + 1;
|
|
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
if (rand() % 2 == 0) {
|
|
|
|
|
string trig = operators[4 + rand() % 3]; // sin, cos, tan
|
|
|
|
|
question << trig << "(" << operand << ")";
|
|
|
|
|
hasTrigonometry = true;
|
|
|
|
|
} else {
|
|
|
|
|
question << operand;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
string op = operators[rand() % operators.size()];
|
|
|
|
|
|
|
|
|
|
if (op == "sin" || op == "cos" || op == "tan") {
|
|
|
|
|
question << " " << op << "(" << operand << ")";
|
|
|
|
|
hasTrigonometry = true;
|
|
|
|
|
} else {
|
|
|
|
|
question << " " << op << " " << operand;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确保至少有一个三角函数
|
|
|
|
|
if (!hasTrigonometry) {
|
|
|
|
|
string trig = operators[4 + rand() % 3];
|
|
|
|
|
int operand = rand() % 100 + 1;
|
|
|
|
|
question << " " << trig << "(" << operand << ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
question << " = ";
|
|
|
|
|
return question.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SeniorQuestionGenerator::meetsRequirements(const string& question) {
|
|
|
|
|
// 检查是否包含三角函数
|
|
|
|
|
return question.find("sin") != string::npos ||
|
|
|
|
|
question.find("cos") != string::npos ||
|
|
|
|
|
question.find("tan") != string::npos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 文件管理实现
|
|
|
|
|
bool FileManager::createUserFolder(const string& username) {
|
|
|
|
|
try {
|
|
|
|
|
filesystem::create_directory(username);
|
|
|
|
|
return true;
|
|
|
|
|
} catch (...) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string FileManager::generateFileName(const string& username) {
|
|
|
|
|
time_t now = time(0);
|
|
|
|
|
tm* localTime = localtime(&now);
|
|
|
|
|
|
|
|
|
|
stringstream ss;
|
|
|
|
|
ss << username << "/"
|
|
|
|
|
<< 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 << ".txt";
|
|
|
|
|
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FileManager::saveQuestionsToFile(const string& filename, const vector<string>& questions) {
|
|
|
|
|
ofstream file(filename);
|
|
|
|
|
if (file.is_open()) {
|
|
|
|
|
for (size_t i = 0; i < questions.size(); i++) {
|
|
|
|
|
file << i + 1 << ". " << questions[i] << endl;
|
|
|
|
|
if (i < questions.size() - 1) {
|
|
|
|
|
file << endl; // 题目之间空一行
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
file.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set<string> FileManager::loadExistingQuestions(const string& username) {
|
|
|
|
|
set<string> questions;
|
|
|
|
|
// 简化实现,实际需要读取所有文件并提取题目
|
|
|
|
|
return questions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 应用程序实现
|
|
|
|
|
MathTestGeneratorApp::MathTestGeneratorApp() : isLoggedIn(false) {
|
|
|
|
|
generators["小学"] = new PrimaryQuestionGenerator();
|
|
|
|
|
generators["初中"] = new JuniorQuestionGenerator();
|
|
|
|
|
generators["高中"] = new SeniorQuestionGenerator();
|
|
|
|
|
currentGenerator = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MathTestGeneratorApp::~MathTestGeneratorApp() {
|
|
|
|
|
for (auto& pair : generators) {
|
|
|
|
|
delete pair.second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MathTestGeneratorApp::run() {
|
|
|
|
|
srand(time(0));
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
if (!isLoggedIn) {
|
|
|
|
|
login();
|
|
|
|
|
} else {
|
|
|
|
|
cout << "准备生成" << currentUser.userType << "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):";
|
|
|
|
|
string input;
|
|
|
|
|
cin >> input;
|
|
|
|
|
|
|
|
|
|
if (input == "-1") {
|
|
|
|
|
isLoggedIn = false;
|
|
|
|
|
cout << "退出当前用户,重新登录..." << endl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (input.find("切换为") == 0) {
|
|
|
|
|
string newType = input.substr(3); // 跳过"切换为"
|
|
|
|
|
switchUserType(newType);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
int questionCount = stoi(input);
|
|
|
|
|
if (questionCount >= 10 && questionCount <= 30) {
|
|
|
|
|
generatePaper();
|
|
|
|
|
} else {
|
|
|
|
|
cout << "题目数量应在10-30之间" << endl;
|
|
|
|
|
}
|
|
|
|
|
} catch (const exception& e) {
|
|
|
|
|
cout << "请输入有效的数字" << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MathTestGeneratorApp::login() {
|
|
|
|
|
cout << "请输入用户名和密码(用空格隔开):";
|
|
|
|
|
string username, password;
|
|
|
|
|
cin >> username >> password;
|
|
|
|
|
|
|
|
|
|
UserAuthenticator authenticator;
|
|
|
|
|
if (authenticator.authenticate(username, password, currentUser)) {
|
|
|
|
|
isLoggedIn = true;
|
|
|
|
|
currentGenerator = generators[currentUser.userType];
|
|
|
|
|
cout << "当前选择为" << currentUser.userType << "出题" << endl;
|
|
|
|
|
|
|
|
|
|
// 加载已存在的题目用于查重
|
|
|
|
|
generatedQuestions = FileManager::loadExistingQuestions(currentUser.username);
|
|
|
|
|
} else {
|
|
|
|
|
cout << "请输入正确的用户名、密码" << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MathTestGeneratorApp::generatePaper() {
|
|
|
|
|
cout << "准备生成" << currentUser.userType << "数学题目,请输入生成题目数量:";
|
|
|
|
|
string input;
|
|
|
|
|
cin >> input;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
int questionCount = stoi(input);
|
|
|
|
|
if (questionCount < 10 || questionCount > 30) {
|
|
|
|
|
cout << "题目数量应在10-30之间" << endl;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建用户文件夹
|
|
|
|
|
FileManager::createUserFolder(currentUser.username);
|
|
|
|
|
|
|
|
|
|
// 生成题目
|
|
|
|
|
vector<string> questions;
|
|
|
|
|
for (int i = 0; i < questionCount; i++) {
|
|
|
|
|
string question;
|
|
|
|
|
int attempts = 0;
|
|
|
|
|
do {
|
|
|
|
|
question = currentGenerator->generateQuestion();
|
|
|
|
|
attempts++;
|
|
|
|
|
} while ((isQuestionDuplicate(question) || !currentGenerator->meetsRequirements(question)) && attempts < 100);
|
|
|
|
|
|
|
|
|
|
if (attempts >= 100) {
|
|
|
|
|
cout << "警告:无法生成符合要求的不重复题目" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
questions.push_back(question);
|
|
|
|
|
addQuestionToHistory(question);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保存到文件
|
|
|
|
|
string filename = FileManager::generateFileName(currentUser.username);
|
|
|
|
|
FileManager::saveQuestionsToFile(filename, questions);
|
|
|
|
|
cout << "题目已生成到文件:" << filename << endl;
|
|
|
|
|
|
|
|
|
|
} catch (const exception& e) {
|
|
|
|
|
cout << "请输入有效的数字" << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MathTestGeneratorApp::switchUserType(const string& newType) {
|
|
|
|
|
if (newType == "小学" || newType == "初中" || newType == "高中") {
|
|
|
|
|
currentUser.userType = newType;
|
|
|
|
|
currentGenerator = generators[newType];
|
|
|
|
|
cout << "准备生成" << currentUser.userType << "数学题目,请输入生成题目数量:";
|
|
|
|
|
} else {
|
|
|
|
|
cout << "请输入小学、初中和高中三个选项中的一个" << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MathTestGeneratorApp::isQuestionDuplicate(const string& question) {
|
|
|
|
|
return generatedQuestions.find(question) != generatedQuestions.end();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MathTestGeneratorApp::addQuestionToHistory(const string& question) {
|
|
|
|
|
generatedQuestions.insert(question);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string MathTestGeneratorApp::getCurrentTimeString() {
|
|
|
|
|
time_t now = time(0);
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
MathTestGeneratorApp app;
|
|
|
|
|
app.run();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|