|
|
|
@ -8,27 +8,28 @@ public class MathQuestion implements QuestionInterface {
|
|
|
|
|
private String questionText;
|
|
|
|
|
private DifficultyLevel difficulty;
|
|
|
|
|
private Random random;
|
|
|
|
|
private boolean isValid;
|
|
|
|
|
|
|
|
|
|
public MathQuestion(DifficultyLevel difficulty) {
|
|
|
|
|
this.difficulty = difficulty;
|
|
|
|
|
this.random = new Random();
|
|
|
|
|
this.questionText = generateQuestion();
|
|
|
|
|
this.isValid = validateQuestion();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String generateQuestion() {
|
|
|
|
|
int operandCount = random.nextInt(5) + 1;
|
|
|
|
|
StringBuilder question = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
switch (difficulty) {
|
|
|
|
|
case PRIMARY:
|
|
|
|
|
question.append(generatePrimaryQuestion(operandCount));
|
|
|
|
|
question.append(generatePrimaryQuestion());
|
|
|
|
|
break;
|
|
|
|
|
case JUNIOR:
|
|
|
|
|
question.append(generateJuniorQuestion(operandCount));
|
|
|
|
|
question.append(generateJuniorQuestion());
|
|
|
|
|
break;
|
|
|
|
|
case SENIOR:
|
|
|
|
|
question.append(generateSeniorQuestion(operandCount));
|
|
|
|
|
question.append(generateSeniorQuestion());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -38,7 +39,67 @@ public class MathQuestion implements QuestionInterface {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isValid() {
|
|
|
|
|
return questionText != null && !questionText.trim().isEmpty();
|
|
|
|
|
return isValid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean validateQuestion() {
|
|
|
|
|
if (questionText == null || questionText.trim().isEmpty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查括号是否匹配
|
|
|
|
|
if (!isParenthesesBalanced(questionText)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查是否有不合理的括号位置(如运算符后面直接跟右括号)
|
|
|
|
|
if (hasInvalidParentheses(questionText)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 小学题目必须至少有2个操作数
|
|
|
|
|
if (difficulty == DifficultyLevel.PRIMARY) {
|
|
|
|
|
String expr = questionText.replace(" = ", "");
|
|
|
|
|
// 更严格的验证:必须包含至少一个运算符
|
|
|
|
|
boolean hasOperator = expr.contains("+") || expr.contains("-") ||
|
|
|
|
|
expr.contains("*") || expr.contains("/");
|
|
|
|
|
// 并且不能是单个数字的情况
|
|
|
|
|
boolean isSingleNumber = expr.matches("^\\d+$") ||
|
|
|
|
|
expr.matches("^\\(\\d+\\)$") ||
|
|
|
|
|
expr.matches("^√\\d+$") ||
|
|
|
|
|
expr.matches("^\\(\\d+\\)²$");
|
|
|
|
|
return hasOperator && !isSingleNumber;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isParenthesesBalanced(String expression) {
|
|
|
|
|
int balance = 0;
|
|
|
|
|
for (char c : expression.toCharArray()) {
|
|
|
|
|
if (c == '(') balance++;
|
|
|
|
|
if (c == ')') balance--;
|
|
|
|
|
if (balance < 0) return false; // 右括号出现在左括号之前
|
|
|
|
|
}
|
|
|
|
|
return balance == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean hasInvalidParentheses(String expression) {
|
|
|
|
|
// 检查是否有不合理的括号模式
|
|
|
|
|
String[] invalidPatterns = {
|
|
|
|
|
"\\(\\s*[+\\-*/]", // 左括号后直接跟运算符
|
|
|
|
|
"[+\\-*/]\\s*\\)", // 运算符后直接跟右括号
|
|
|
|
|
"\\(\\s*\\)", // 空括号
|
|
|
|
|
"\\d\\s*\\(", // 数字后直接跟左括号(应该是运算符后跟左括号)
|
|
|
|
|
"\\)\\s*\\d" // 右括号后直接跟数字(应该是运算符后跟数字)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (String pattern : invalidPatterns) {
|
|
|
|
|
if (expression.matches(".*" + pattern + ".*")) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -51,36 +112,127 @@ public class MathQuestion implements QuestionInterface {
|
|
|
|
|
return difficulty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String generatePrimaryQuestion(int operandCount) {
|
|
|
|
|
private String generatePrimaryQuestion() {
|
|
|
|
|
// 小学题目:确保至少有2个操作数(2-5个)
|
|
|
|
|
int operandCount = random.nextInt(4) + 2; // 2-5个操作数
|
|
|
|
|
String[] operators = {"+", "-", "*", "/"};
|
|
|
|
|
StringBuilder question = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
// 生成所有操作数
|
|
|
|
|
int[] operands = new int[operandCount];
|
|
|
|
|
for (int i = 0; i < operandCount; i++) {
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
question.append(" ").append(operators[random.nextInt(operators.length)]).append(" ");
|
|
|
|
|
}
|
|
|
|
|
question.append(random.nextInt(100) + 1);
|
|
|
|
|
operands[i] = random.nextInt(100) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (operandCount > 2 && random.nextDouble() < 0.3) {
|
|
|
|
|
question.insert(0, "(").append(")");
|
|
|
|
|
}
|
|
|
|
|
// 构建基础表达式(不带括号)
|
|
|
|
|
question.append(operands[0]);
|
|
|
|
|
for (int i = 1; i < operandCount; i++) {
|
|
|
|
|
question.append(" ").append(operators[random.nextInt(operators.length)]).append(" ");
|
|
|
|
|
question.append(operands[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 只在有3个及以上操作数时考虑添加括号,且概率降低
|
|
|
|
|
if (operandCount >= 3 && random.nextDouble() < 0.3) {
|
|
|
|
|
return addProperParentheses(question.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return question.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String generateJuniorQuestion(int operandCount) {
|
|
|
|
|
String question = generatePrimaryQuestion(operandCount);
|
|
|
|
|
if (random.nextBoolean()) {
|
|
|
|
|
return "√" + (random.nextInt(100) + 1) + " + " + question;
|
|
|
|
|
} else {
|
|
|
|
|
return "(" + (random.nextInt(10) + 1) + ")² + " + question;
|
|
|
|
|
private String addProperParentheses(String expression) {
|
|
|
|
|
String[] parts = expression.split(" ");
|
|
|
|
|
|
|
|
|
|
// 只在合适的运算符位置添加括号
|
|
|
|
|
for (int attempt = 0; attempt < 10; attempt++) {
|
|
|
|
|
int opIndex = random.nextInt(parts.length / 2) * 2 + 1; // 随机选择一个运算符位置
|
|
|
|
|
|
|
|
|
|
if (opIndex >= 1 && opIndex < parts.length - 2) {
|
|
|
|
|
// 构建带括号的表达式
|
|
|
|
|
StringBuilder newExpr = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
// 添加括号前的部分
|
|
|
|
|
for (int i = 0; i < opIndex - 1; i++) {
|
|
|
|
|
newExpr.append(parts[i]).append(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加左括号和第一个操作数
|
|
|
|
|
newExpr.append("(").append(parts[opIndex - 1]).append(" ");
|
|
|
|
|
|
|
|
|
|
// 添加运算符和第二个操作数
|
|
|
|
|
newExpr.append(parts[opIndex]).append(" ").append(parts[opIndex + 1]);
|
|
|
|
|
|
|
|
|
|
// 添加右括号
|
|
|
|
|
newExpr.append(")");
|
|
|
|
|
|
|
|
|
|
// 添加剩余部分
|
|
|
|
|
for (int i = opIndex + 2; i < parts.length; i++) {
|
|
|
|
|
newExpr.append(" ").append(parts[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String result = newExpr.toString();
|
|
|
|
|
// 验证生成的表达式是否合理
|
|
|
|
|
if (!hasInvalidParentheses(result) && isParenthesesBalanced(result)) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果多次尝试都失败,返回原表达式(不带括号)
|
|
|
|
|
return expression;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String generateJuniorQuestion() {
|
|
|
|
|
// 初中题目:可以有1个操作数(涉及平方、开根号)
|
|
|
|
|
int choice = random.nextInt(4);
|
|
|
|
|
|
|
|
|
|
switch (choice) {
|
|
|
|
|
case 0:
|
|
|
|
|
// 单个操作数:开根号
|
|
|
|
|
return "√" + (random.nextInt(100) + 1);
|
|
|
|
|
case 1:
|
|
|
|
|
// 单个操作数:平方
|
|
|
|
|
return "(" + (random.nextInt(10) + 1) + ")²";
|
|
|
|
|
case 2:
|
|
|
|
|
// 多个操作数:基础运算 + 平方/开根号
|
|
|
|
|
String baseQuestion = generatePrimaryQuestion();
|
|
|
|
|
if (random.nextBoolean()) {
|
|
|
|
|
return "√" + (random.nextInt(100) + 1) + " + " + baseQuestion;
|
|
|
|
|
} else {
|
|
|
|
|
return "(" + (random.nextInt(10) + 1) + ")² + " + baseQuestion;
|
|
|
|
|
}
|
|
|
|
|
case 3:
|
|
|
|
|
// 纯基础运算(多个操作数)
|
|
|
|
|
return generatePrimaryQuestion();
|
|
|
|
|
default:
|
|
|
|
|
return generatePrimaryQuestion();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String generateSeniorQuestion(int operandCount) {
|
|
|
|
|
String question = generatePrimaryQuestion(operandCount);
|
|
|
|
|
private String generateSeniorQuestion() {
|
|
|
|
|
// 高中题目:可以有1个操作数(涉及三角函数)
|
|
|
|
|
int choice = random.nextInt(4);
|
|
|
|
|
String[] trigFunctions = {"sin", "cos", "tan"};
|
|
|
|
|
return trigFunctions[random.nextInt(trigFunctions.length)] +
|
|
|
|
|
"(" + (random.nextInt(90) + 1) + "°) + " + question;
|
|
|
|
|
|
|
|
|
|
switch (choice) {
|
|
|
|
|
case 0:
|
|
|
|
|
// 单个操作数:三角函数
|
|
|
|
|
return trigFunctions[random.nextInt(trigFunctions.length)] +
|
|
|
|
|
"(" + (random.nextInt(90) + 1) + "°)";
|
|
|
|
|
case 1:
|
|
|
|
|
// 三角函数 + 基础运算
|
|
|
|
|
String baseQuestion = generatePrimaryQuestion();
|
|
|
|
|
return trigFunctions[random.nextInt(trigFunctions.length)] +
|
|
|
|
|
"(" + (random.nextInt(90) + 1) + "°) + " + baseQuestion;
|
|
|
|
|
case 2:
|
|
|
|
|
// 复杂组合:三角函数 + 平方/开根号 + 基础运算
|
|
|
|
|
String complexBase = generateJuniorQuestion();
|
|
|
|
|
return trigFunctions[random.nextInt(trigFunctions.length)] +
|
|
|
|
|
"(" + (random.nextInt(90) + 1) + "°) + " + complexBase;
|
|
|
|
|
case 3:
|
|
|
|
|
// 纯基础运算(多个操作数)
|
|
|
|
|
return generatePrimaryQuestion();
|
|
|
|
|
default:
|
|
|
|
|
return generatePrimaryQuestion();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|