You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
7.0 KiB
262 lines
7.0 KiB
#include "question.h"
|
|
#include <stack>
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
|
|
using namespace std;
|
|
|
|
// QuestionGenerator 基类实现
|
|
vector<string> QuestionGenerator::GenerateQuestion(int count) {
|
|
vector<string> 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<int>& 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<int>& 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<int>& 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<int> 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<char> 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<QuestionGenerator> CreateQuestionGenerator(const std::string& type) {
|
|
if (type == "小学") {
|
|
return make_unique<PrimaryQuestionGenerator>();
|
|
} else if (type == "初中") {
|
|
return make_unique<JuniorQuestionGenerator>();
|
|
} else if (type == "高中") {
|
|
return make_unique<SeniorQuestionGenerator>();
|
|
}
|
|
return nullptr;
|
|
}
|