|
|
|
|
@ -16,8 +16,9 @@ public class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 0: // 基本四则运算(考虑优先级)
|
|
|
|
|
questionText = generateArithmeticQuestion();
|
|
|
|
|
correctAnswerValue = evaluateExpression(questionText.replace(" = ?", ""));
|
|
|
|
|
ExpressionResult exprResult = generateArithmeticQuestion();
|
|
|
|
|
questionText = exprResult.expression;
|
|
|
|
|
correctAnswerValue = exprResult.value;
|
|
|
|
|
isIntegerAnswer = (correctAnswerValue == (int)correctAnswerValue);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
@ -61,48 +62,143 @@ public class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
return new Question(questionText, options, correctIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成考虑优先级的算术题目
|
|
|
|
|
private String generateArithmeticQuestion() {
|
|
|
|
|
int operandCount = random.nextInt(3) + 2; // 2-4个操作数
|
|
|
|
|
StringBuilder question = new StringBuilder();
|
|
|
|
|
List<String> tokens = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
// 生成操作数
|
|
|
|
|
for (int i = 0; i < operandCount; i++) {
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
// 随机选择运算符,考虑优先级
|
|
|
|
|
String[] availableOps;
|
|
|
|
|
if (i == 1 && operandCount > 2) {
|
|
|
|
|
// 第一个运算符倾向于用乘除,确保优先级测试
|
|
|
|
|
availableOps = new String[]{"×", "÷", "+", "-"};
|
|
|
|
|
} else {
|
|
|
|
|
availableOps = new String[]{"+", "-", "×", "÷"};
|
|
|
|
|
}
|
|
|
|
|
String op = availableOps[random.nextInt(availableOps.length)];
|
|
|
|
|
tokens.add(op);
|
|
|
|
|
question.append(" ").append(op).append(" ");
|
|
|
|
|
}
|
|
|
|
|
// 表达式和结果封装类
|
|
|
|
|
private static class ExpressionResult {
|
|
|
|
|
String expression;
|
|
|
|
|
double value;
|
|
|
|
|
|
|
|
|
|
ExpressionResult(String expression, double value) {
|
|
|
|
|
this.expression = expression;
|
|
|
|
|
this.value = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成合适的操作数
|
|
|
|
|
int num;
|
|
|
|
|
if (tokens.size() > 0 && (tokens.get(tokens.size()-1).equals("÷"))) {
|
|
|
|
|
// 除法:生成能整除的数
|
|
|
|
|
num = generateDivisibleNumber();
|
|
|
|
|
// 生成考虑优先级的算术题目并同时计算结果
|
|
|
|
|
private ExpressionResult generateArithmeticQuestion() {
|
|
|
|
|
// 使用预定义的简单表达式模板,确保可计算
|
|
|
|
|
String[][] templates = {
|
|
|
|
|
{"%d + %d × %d", "先乘后加"},
|
|
|
|
|
{"%d × %d + %d", "先乘后加"},
|
|
|
|
|
{"%d - %d × %d", "先乘后减"},
|
|
|
|
|
{"%d × %d - %d", "先乘后减"},
|
|
|
|
|
{"%d + %d ÷ %d", "先除后加"},
|
|
|
|
|
{"%d ÷ %d + %d", "先除后加"},
|
|
|
|
|
{"%d - %d ÷ %d", "先除后减"},
|
|
|
|
|
{"%d ÷ %d - %d", "先除后减"},
|
|
|
|
|
{"%d × (%d + %d)", "先加后乘"},
|
|
|
|
|
{"(%d + %d) × %d", "先加后乘"},
|
|
|
|
|
{"%d × (%d - %d)", "先减后乘"},
|
|
|
|
|
{"(%d - %d) × %d", "先减后乘"}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
String[] template = templates[random.nextInt(templates.length)];
|
|
|
|
|
String pattern = template[0];
|
|
|
|
|
String description = template[1];
|
|
|
|
|
|
|
|
|
|
// 生成合适的数字,确保计算有效
|
|
|
|
|
int a, b, c = 1;
|
|
|
|
|
double result = 0;
|
|
|
|
|
|
|
|
|
|
// 根据模板类型生成合适的数字
|
|
|
|
|
if (pattern.contains("÷")) {
|
|
|
|
|
// 除法模板:确保除数不为0且能整除
|
|
|
|
|
if (pattern.startsWith("%d ÷")) {
|
|
|
|
|
// 第一个操作数是除法:确保b能整除a
|
|
|
|
|
b = random.nextInt(9) + 1; // 1-9
|
|
|
|
|
a = b * (random.nextInt(5) + 1); // a是b的倍数
|
|
|
|
|
c = random.nextInt(10) + 1;
|
|
|
|
|
result = (double)a / b + (pattern.contains("+") ? c : -c);
|
|
|
|
|
} else if (pattern.contains("÷ %d +") || pattern.contains("÷ %d -")) {
|
|
|
|
|
// 其他位置的除法:确保除数不为0
|
|
|
|
|
a = random.nextInt(10) + 1;
|
|
|
|
|
b = random.nextInt(9) + 1; // 1-9
|
|
|
|
|
c = random.nextInt(10) + 1;
|
|
|
|
|
result = (double)a / b + (pattern.contains("+") ? c : -c);
|
|
|
|
|
} else {
|
|
|
|
|
num = random.nextInt(30) + 1; // 1-30
|
|
|
|
|
// 中间的除法
|
|
|
|
|
a = random.nextInt(10) + 1;
|
|
|
|
|
b = random.nextInt(9) + 1; // 1-9
|
|
|
|
|
c = random.nextInt(10) + 1;
|
|
|
|
|
if (pattern.contains("+ %d ÷")) {
|
|
|
|
|
result = a + (double)b / c;
|
|
|
|
|
} else if (pattern.contains("- %d ÷")) {
|
|
|
|
|
result = a - (double)b / c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tokens.add(String.valueOf(num));
|
|
|
|
|
question.append(num);
|
|
|
|
|
} else if (pattern.contains("(")) {
|
|
|
|
|
// 括号模板
|
|
|
|
|
a = random.nextInt(10) + 1;
|
|
|
|
|
b = random.nextInt(10) + 1;
|
|
|
|
|
c = random.nextInt(10) + 1;
|
|
|
|
|
if (pattern.contains("× (") && pattern.contains(" + ")) {
|
|
|
|
|
result = a * (b + c);
|
|
|
|
|
} else if (pattern.contains("× (") && pattern.contains(" - ")) {
|
|
|
|
|
result = a * (b - c);
|
|
|
|
|
} else if (pattern.contains(" + ") && pattern.contains(") ×")) {
|
|
|
|
|
result = (a + b) * c;
|
|
|
|
|
} else if (pattern.contains(" - ") && pattern.contains(") ×")) {
|
|
|
|
|
result = (a - b) * c;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 基本四则运算
|
|
|
|
|
a = random.nextInt(10) + 1;
|
|
|
|
|
b = random.nextInt(10) + 1;
|
|
|
|
|
c = random.nextInt(10) + 1;
|
|
|
|
|
|
|
|
|
|
// 根据运算符计算结果
|
|
|
|
|
if (pattern.equals("%d + %d × %d")) {
|
|
|
|
|
result = a + b * c;
|
|
|
|
|
} else if (pattern.equals("%d × %d + %d")) {
|
|
|
|
|
result = a * b + c;
|
|
|
|
|
} else if (pattern.equals("%d - %d × %d")) {
|
|
|
|
|
result = a - b * c;
|
|
|
|
|
} else if (pattern.equals("%d × %d - %d")) {
|
|
|
|
|
result = a * b - c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果还没有计算结果,使用安全的表达式计算
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
result = safeEvaluateExpression(pattern, a, b, c);
|
|
|
|
|
}
|
|
|
|
|
question.append(" = ?");
|
|
|
|
|
|
|
|
|
|
return question.toString();
|
|
|
|
|
String expression = String.format(pattern, a, b, c) + " = ?";
|
|
|
|
|
|
|
|
|
|
return new ExpressionResult(expression, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成能整除的数(用于除法运算)
|
|
|
|
|
private int generateDivisibleNumber() {
|
|
|
|
|
int[] smallNumbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
|
return smallNumbers[random.nextInt(smallNumbers.length)];
|
|
|
|
|
// 安全的表达式计算
|
|
|
|
|
private double safeEvaluateExpression(String pattern, int a, int b, int c) {
|
|
|
|
|
try {
|
|
|
|
|
if (pattern.equals("%d + %d × %d")) {
|
|
|
|
|
return a + b * c;
|
|
|
|
|
} else if (pattern.equals("%d × %d + %d")) {
|
|
|
|
|
return a * b + c;
|
|
|
|
|
} else if (pattern.equals("%d - %d × %d")) {
|
|
|
|
|
return a - b * c;
|
|
|
|
|
} else if (pattern.equals("%d × %d - %d")) {
|
|
|
|
|
return a * b - c;
|
|
|
|
|
} else if (pattern.equals("%d + %d ÷ %d")) {
|
|
|
|
|
return a + (double)b / c;
|
|
|
|
|
} else if (pattern.equals("%d ÷ %d + %d")) {
|
|
|
|
|
return (double)a / b + c;
|
|
|
|
|
} else if (pattern.equals("%d - %d ÷ %d")) {
|
|
|
|
|
return a - (double)b / c;
|
|
|
|
|
} else if (pattern.equals("%d ÷ %d - %d")) {
|
|
|
|
|
return (double)a / b - c;
|
|
|
|
|
} else if (pattern.equals("%d × (%d + %d)")) {
|
|
|
|
|
return a * (b + c);
|
|
|
|
|
} else if (pattern.equals("(%d + %d) × %d")) {
|
|
|
|
|
return (a + b) * c;
|
|
|
|
|
} else if (pattern.equals("%d × (%d - %d)")) {
|
|
|
|
|
return a * (b - c);
|
|
|
|
|
} else if (pattern.equals("(%d - %d) × %d")) {
|
|
|
|
|
return (a - b) * c;
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.err.println("计算表达式失败: " + String.format(pattern, a, b, c) + ", 错误: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算简单运算(支持负数)
|
|
|
|
|
@ -115,66 +211,8 @@ public class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算表达式(考虑运算优先级)- 使用自定义解析器避免ScriptEngine问题
|
|
|
|
|
private double evaluateExpression(String expression) {
|
|
|
|
|
try {
|
|
|
|
|
// 移除空格
|
|
|
|
|
expression = expression.replaceAll(" ", "");
|
|
|
|
|
|
|
|
|
|
// 使用递归下降解析器计算表达式
|
|
|
|
|
return evaluate(expression);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.err.println("计算表达式失败: " + expression + ", 错误: " + e.getMessage());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 递归计算表达式
|
|
|
|
|
private double evaluate(String expr) {
|
|
|
|
|
if (expr.isEmpty()) return 0;
|
|
|
|
|
|
|
|
|
|
// 处理加减法
|
|
|
|
|
String[] plusMinus = expr.split("(?=[+-])", 2);
|
|
|
|
|
if (plusMinus.length > 1) {
|
|
|
|
|
double left = evaluate(plusMinus[0]);
|
|
|
|
|
double right = evaluate(plusMinus[1].substring(1));
|
|
|
|
|
return plusMinus[1].charAt(0) == '+' ? left + right : left - right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理乘除法
|
|
|
|
|
String[] multDiv = expr.split("(?=[×÷])", 2);
|
|
|
|
|
if (multDiv.length > 1) {
|
|
|
|
|
double left = evaluateTerm(multDiv[0]);
|
|
|
|
|
double right = evaluateTerm(multDiv[1].substring(1));
|
|
|
|
|
return multDiv[1].charAt(0) == '×' ? left * right : left / right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理基本项(数字或括号表达式)
|
|
|
|
|
return evaluateTerm(expr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算基本项
|
|
|
|
|
private double evaluateTerm(String term) {
|
|
|
|
|
if (term.startsWith("(") && term.endsWith(")")) {
|
|
|
|
|
return evaluate(term.substring(1, term.length() - 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理平方符号
|
|
|
|
|
if (term.endsWith("²")) {
|
|
|
|
|
double base = evaluateTerm(term.substring(0, term.length() - 1));
|
|
|
|
|
return base * base;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return Double.parseDouble(term);
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
System.err.println("解析数字失败: " + term);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int getPerfectSquare() {
|
|
|
|
|
int[] perfectSquares = {1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400};
|
|
|
|
|
int[] perfectSquares = {1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144};
|
|
|
|
|
return perfectSquares[random.nextInt(perfectSquares.length)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -190,32 +228,51 @@ public class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
used.add(correctStr);
|
|
|
|
|
|
|
|
|
|
// 生成3个错误选项
|
|
|
|
|
while (options.size() < 4) {
|
|
|
|
|
int attempts = 0;
|
|
|
|
|
while (options.size() < 4 && attempts < 50) {
|
|
|
|
|
attempts++;
|
|
|
|
|
double wrongValue;
|
|
|
|
|
String wrongStr;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
// 根据正确答案的大小调整变化范围
|
|
|
|
|
double range = Math.max(5, Math.abs(correctAnswer) * 0.3);
|
|
|
|
|
double variation = (random.nextDouble() * range) + 1;
|
|
|
|
|
boolean positive = random.nextBoolean();
|
|
|
|
|
// 根据正确答案调整变化范围
|
|
|
|
|
double baseRange = Math.max(2, Math.abs(correctAnswer) * 0.3);
|
|
|
|
|
double variation = (random.nextDouble() * baseRange) + 1;
|
|
|
|
|
boolean positive = random.nextBoolean();
|
|
|
|
|
|
|
|
|
|
wrongValue = correctAnswer + (positive ? variation : -variation);
|
|
|
|
|
wrongValue = correctAnswer + (positive ? variation : -variation);
|
|
|
|
|
|
|
|
|
|
if (isInteger) {
|
|
|
|
|
wrongValue = Math.round(wrongValue);
|
|
|
|
|
wrongStr = String.valueOf((int)wrongValue);
|
|
|
|
|
} else {
|
|
|
|
|
wrongValue = Math.round(wrongValue * 100) / 100.0;
|
|
|
|
|
wrongStr = String.format("%.2f", wrongValue);
|
|
|
|
|
}
|
|
|
|
|
} while (used.contains(wrongStr) || Double.isNaN(wrongValue) || Double.isInfinite(wrongValue));
|
|
|
|
|
if (isInteger) {
|
|
|
|
|
wrongValue = Math.round(wrongValue);
|
|
|
|
|
wrongStr = String.valueOf((int)wrongValue);
|
|
|
|
|
} else {
|
|
|
|
|
wrongValue = Math.round(wrongValue * 100) / 100.0;
|
|
|
|
|
wrongStr = String.format("%.2f", wrongValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!used.contains(wrongStr)) {
|
|
|
|
|
options.add(wrongStr);
|
|
|
|
|
used.add(wrongStr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果选项不够,添加一些固定选项
|
|
|
|
|
while (options.size() < 4) {
|
|
|
|
|
String extraOption;
|
|
|
|
|
if (isInteger) {
|
|
|
|
|
int extraValue = (int)correctAnswer + options.size() * 2 + 1;
|
|
|
|
|
extraOption = String.valueOf(extraValue);
|
|
|
|
|
} else {
|
|
|
|
|
double extraValue = correctAnswer + options.size() * 0.5 + 0.1;
|
|
|
|
|
extraOption = String.format("%.2f", extraValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
options.add(wrongStr);
|
|
|
|
|
used.add(wrongStr);
|
|
|
|
|
if (!used.contains(extraOption)) {
|
|
|
|
|
options.add(extraOption);
|
|
|
|
|
used.add(extraOption);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Collections.shuffle(options);
|
|
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|