|
|
|
|
@ -4,75 +4,63 @@ import com.mathgenerator.model.ChoiceQuestion;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
|
|
|
import java.util.regex.Matcher;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 初中选择题生成器 (已修正)。
|
|
|
|
|
* 通过构造而非随机的方式,确保题目包含平方或开根号,且最终解为整数。
|
|
|
|
|
* 初中选择题生成器 (最终版 - 采用结构化插入)。
|
|
|
|
|
* 通过直接在表达式结构中插入运算项,确保语法正确性和高性能。
|
|
|
|
|
*/
|
|
|
|
|
public class JuniorHighSchoolGenerator extends PrimarySchoolGenerator {
|
|
|
|
|
|
|
|
|
|
private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+");
|
|
|
|
|
private static final int[] PERFECT_SQUARES = {4, 9, 16, 25, 36, 49, 64, 81, 100};
|
|
|
|
|
private static final int[] PERFECT_SQUARES = {1, 4, 9, 16, 25, 36, 49, 64, 81, 100};
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public ChoiceQuestion generateSingleQuestion() {
|
|
|
|
|
String questionText;
|
|
|
|
|
int correctAnswer;
|
|
|
|
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
|
|
|
|
int operandCount = random.nextInt(2, 5); // 2到4个操作数
|
|
|
|
|
|
|
|
|
|
// 循环直到生成一个有效的、有整数解的题目
|
|
|
|
|
while (true) {
|
|
|
|
|
// 1. 获取一个基础的小学题目字符串
|
|
|
|
|
String basicQuestionText = super.generateBasicQuestionText();
|
|
|
|
|
|
|
|
|
|
// 2. 随机选择在题目中加入平方还是开根号
|
|
|
|
|
boolean useSquare = ThreadLocalRandom.current().nextBoolean();
|
|
|
|
|
|
|
|
|
|
if (useSquare) {
|
|
|
|
|
// --- 平方策略 ---
|
|
|
|
|
// 随机找到一个数字,给它加上平方
|
|
|
|
|
Matcher matcher = NUMBER_PATTERN.matcher(basicQuestionText);
|
|
|
|
|
List<String> numbers = new ArrayList<>();
|
|
|
|
|
while (matcher.find()) { numbers.add(matcher.group()); }
|
|
|
|
|
if (numbers.isEmpty()) continue;
|
|
|
|
|
// 1. 生成基础的表达式组件列表
|
|
|
|
|
List<String> parts = new ArrayList<>();
|
|
|
|
|
// 使用 getOperand() 和 getRandomOperator() 这些继承自父类的方法
|
|
|
|
|
parts.add(String.valueOf(getOperand()));
|
|
|
|
|
for (int i = 1; i < operandCount; i++) {
|
|
|
|
|
parts.add(getRandomOperator());
|
|
|
|
|
parts.add(String.valueOf(getOperand()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String numToSquare = numbers.get(ThreadLocalRandom.current().nextInt(numbers.size()));
|
|
|
|
|
questionText = basicQuestionText.replaceFirst(Pattern.quote(numToSquare), numToSquare + "²");
|
|
|
|
|
// 2. 结构化地插入初中特色运算
|
|
|
|
|
int modificationIndex = random.nextInt(operandCount) * 2; // 随机选择一个操作数的位置
|
|
|
|
|
boolean useSquare = random.nextBoolean();
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// --- 开根号策略 (保证整数解) ---
|
|
|
|
|
// a. 随机找到一个数字
|
|
|
|
|
Matcher matcher = NUMBER_PATTERN.matcher(basicQuestionText);
|
|
|
|
|
List<String> numbers = new ArrayList<>();
|
|
|
|
|
while (matcher.find()) { numbers.add(matcher.group()); }
|
|
|
|
|
if (numbers.isEmpty()) continue;
|
|
|
|
|
String numToReplace = numbers.get(ThreadLocalRandom.current().nextInt(numbers.size()));
|
|
|
|
|
if (useSquare) {
|
|
|
|
|
// 平方策略:直接在数字后附加平方符号
|
|
|
|
|
parts.set(modificationIndex, parts.get(modificationIndex) + "²");
|
|
|
|
|
} else {
|
|
|
|
|
// 开根号策略:用一个完美的开根号表达式替换整个数字
|
|
|
|
|
int perfectSquare = PERFECT_SQUARES[random.nextInt(PERFECT_SQUARES.length)];
|
|
|
|
|
parts.set(modificationIndex, "√" + perfectSquare);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// b. 随机选一个完美的平方数
|
|
|
|
|
int perfectSquare = PERFECT_SQUARES[ThreadLocalRandom.current().nextInt(PERFECT_SQUARES.length)];
|
|
|
|
|
// 3. (可选)为增强后的表达式添加括号
|
|
|
|
|
if (operandCount > 2 && random.nextBoolean()) {
|
|
|
|
|
super.addParentheses(parts); // 调用父类的protected方法
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// c. 用 "√(平方数)" 替换掉原数字
|
|
|
|
|
String sqrtExpression = "√" + perfectSquare;
|
|
|
|
|
questionText = basicQuestionText.replaceFirst(Pattern.quote(numToReplace), sqrtExpression);
|
|
|
|
|
}
|
|
|
|
|
String finalQuestionText = String.join(" ", parts);
|
|
|
|
|
|
|
|
|
|
// 3. 验证修改后的题目是否有整数解
|
|
|
|
|
try {
|
|
|
|
|
Object result = evaluateExpression(questionText);
|
|
|
|
|
if (result instanceof Number && ((Number) result).doubleValue() == ((Number) result).intValue()) {
|
|
|
|
|
correctAnswer = ((Number) result).intValue();
|
|
|
|
|
break; // 成功!得到整数解,跳出循环
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 如果表达式计算出错(例如语法错误),则忽略并重试
|
|
|
|
|
}
|
|
|
|
|
// 4. 计算答案
|
|
|
|
|
double finalCorrectAnswer;
|
|
|
|
|
try {
|
|
|
|
|
Object result = evaluateExpression(finalQuestionText);
|
|
|
|
|
finalCorrectAnswer = ((Number) result).doubleValue();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 发生意外,安全返回一个小学题
|
|
|
|
|
return super.generateSingleQuestion();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 为最终的题目生成选项
|
|
|
|
|
List<String> options = generateOptions(correctAnswer);
|
|
|
|
|
int correctIndex = options.indexOf(String.valueOf(correctAnswer));
|
|
|
|
|
// 5. 生成选项
|
|
|
|
|
List<String> options = generateDecimalOptions(finalCorrectAnswer);
|
|
|
|
|
int correctIndex = options.indexOf(formatNumber(finalCorrectAnswer));
|
|
|
|
|
|
|
|
|
|
return new ChoiceQuestion(questionText, options, correctIndex);
|
|
|
|
|
return new ChoiceQuestion(finalQuestionText, options, correctIndex);
|
|
|
|
|
}
|
|
|
|
|
}
|