|
|
|
|
@ -9,19 +9,15 @@ public class PrimaryQuestionGenerator implements QuestionGenerator {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Question generateQuestion() {
|
|
|
|
|
int operandCount = RANDOM.nextInt(2) + 2;
|
|
|
|
|
// 操作数数量2-5个
|
|
|
|
|
int operandCount = RANDOM.nextInt(4) + 2; // nextInt(4)→0-3,+2→2-5
|
|
|
|
|
List<Integer> operands = new ArrayList<>();
|
|
|
|
|
List<Character> ops = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < operandCount; i++) {
|
|
|
|
|
operands.add(RANDOM.nextInt(100) + 1);
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < operandCount - 1; i++) {
|
|
|
|
|
ops.add(OPERATORS[RANDOM.nextInt(OPERATORS.length)]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleDivision(operands, ops);
|
|
|
|
|
// 生成合法表达式(修复后)
|
|
|
|
|
buildValidExpression(operands, ops, operandCount);
|
|
|
|
|
|
|
|
|
|
// 拼接题目内容
|
|
|
|
|
StringBuilder contentSb = new StringBuilder();
|
|
|
|
|
for (int i = 0; i < operandCount; i++) {
|
|
|
|
|
contentSb.append(operands.get(i));
|
|
|
|
|
@ -30,27 +26,135 @@ public class PrimaryQuestionGenerator implements QuestionGenerator {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
String content = contentSb.toString() + " = ?";
|
|
|
|
|
|
|
|
|
|
// 计算正确答案
|
|
|
|
|
String correctAnswer = calculateAnswer(operands, ops);
|
|
|
|
|
|
|
|
|
|
// 生成选项
|
|
|
|
|
List<String> options = generateOptions(correctAnswer);
|
|
|
|
|
|
|
|
|
|
// 打乱选项
|
|
|
|
|
int correctIndex = shuffleOptions(options, correctAnswer);
|
|
|
|
|
|
|
|
|
|
return new Question(content, correctAnswer, options, correctIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void handleDivision(List<Integer> operands, List<Character> ops) {
|
|
|
|
|
for (int i = 0; i < ops.size(); i++) {
|
|
|
|
|
if (ops.get(i) == '/') {
|
|
|
|
|
int divisor = operands.get(i + 1);
|
|
|
|
|
if (divisor == 0) {
|
|
|
|
|
divisor = 1;
|
|
|
|
|
operands.set(i + 1, divisor);
|
|
|
|
|
/**
|
|
|
|
|
* 修复核心:确保operands和ops长度匹配(operands.size() = ops.size() + 1)
|
|
|
|
|
* 每次循环只添加1个运算符+1个操作数,避免重复
|
|
|
|
|
*/
|
|
|
|
|
private void buildValidExpression(List<Integer> operands, List<Character> ops, int operandCount) {
|
|
|
|
|
// 第一个操作数:1-50
|
|
|
|
|
int firstOperand = RANDOM.nextInt(50) + 1;
|
|
|
|
|
operands.add(firstOperand);
|
|
|
|
|
|
|
|
|
|
// 循环生成“1个运算符+1个操作数”(共operandCount-1组)
|
|
|
|
|
for (int i = 0; i < operandCount - 1; i++) {
|
|
|
|
|
int nextOperand;
|
|
|
|
|
char op;
|
|
|
|
|
// 循环重试:直到生成能让中间结果非负的组合
|
|
|
|
|
while (true) {
|
|
|
|
|
// 1. 只生成1个运算符(无重复)
|
|
|
|
|
op = OPERATORS[RANDOM.nextInt(OPERATORS.length)];
|
|
|
|
|
// 2. 计算当前中间结果(此时ops还没加新op,operands也没加新数,长度匹配)
|
|
|
|
|
int currentMidResult = tempCalculate(operands, ops);
|
|
|
|
|
// 3. 基于当前中间结果生成合法操作数
|
|
|
|
|
nextOperand = generateValidNextOperand(currentMidResult, op);
|
|
|
|
|
// 4. 临时添加运算符和操作数(此时才开始添加,确保成对)
|
|
|
|
|
ops.add(op);
|
|
|
|
|
operands.add(nextOperand);
|
|
|
|
|
// 5. 检查新的中间结果是否非负
|
|
|
|
|
int newMidResult = tempCalculate(operands, ops);
|
|
|
|
|
if (newMidResult >= 0) {
|
|
|
|
|
// 合格,保留当前组合
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
// 不合格,回滚(移除刚加的运算符和操作数,长度恢复匹配)
|
|
|
|
|
ops.remove(ops.size() - 1);
|
|
|
|
|
operands.remove(operands.size() - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 临时计算中间结果(无修改,确保参数长度匹配即可)
|
|
|
|
|
*/
|
|
|
|
|
private int tempCalculate(List<Integer> tempOperands, List<Character> tempOps) {
|
|
|
|
|
// 防御性判断:避免极端情况下长度不匹配
|
|
|
|
|
if (tempOperands.size() != tempOps.size() + 1) {
|
|
|
|
|
return -1; // 触发重试
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<Integer> nums = new ArrayList<>(tempOperands);
|
|
|
|
|
List<Character> operators = new ArrayList<>(tempOps);
|
|
|
|
|
|
|
|
|
|
// 先处理乘除
|
|
|
|
|
int i = 0;
|
|
|
|
|
while (i < operators.size()) {
|
|
|
|
|
char op = operators.get(i);
|
|
|
|
|
if (op == '*' || op == '/') {
|
|
|
|
|
int left = nums.get(i);
|
|
|
|
|
int right = nums.get(i + 1); // 现在长度匹配,不会越界
|
|
|
|
|
int result = (op == '*') ? left * right : left / right;
|
|
|
|
|
nums.set(i, result);
|
|
|
|
|
nums.remove(i + 1);
|
|
|
|
|
operators.remove(i);
|
|
|
|
|
} else {
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 再处理加减
|
|
|
|
|
int midResult = nums.get(0);
|
|
|
|
|
for (i = 0; i < operators.size(); i++) {
|
|
|
|
|
int next = nums.get(i + 1);
|
|
|
|
|
midResult = (operators.get(i) == '+') ? midResult + next : midResult - next;
|
|
|
|
|
}
|
|
|
|
|
int quotient = RANDOM.nextInt(10) + 1;
|
|
|
|
|
operands.set(i, divisor * quotient);
|
|
|
|
|
return midResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成合法操作数
|
|
|
|
|
*/
|
|
|
|
|
private int generateValidNextOperand(int currentMidResult, char op) {
|
|
|
|
|
switch (op) {
|
|
|
|
|
case '+':
|
|
|
|
|
return RANDOM.nextInt(30) + 1;
|
|
|
|
|
case '-':
|
|
|
|
|
// 基于中间结果生成,确保非负
|
|
|
|
|
return currentMidResult <= 0 ? 1 : RANDOM.nextInt(currentMidResult) + 1;
|
|
|
|
|
case '*':
|
|
|
|
|
return RANDOM.nextInt(5) + 1;
|
|
|
|
|
case '/':
|
|
|
|
|
List<Integer> divisors = getDivisors(currentMidResult);
|
|
|
|
|
return divisors.get(RANDOM.nextInt(divisors.size()));
|
|
|
|
|
default:
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取除数
|
|
|
|
|
*/
|
|
|
|
|
private List<Integer> getDivisors(int num) {
|
|
|
|
|
List<Integer> divisors = new ArrayList<>();
|
|
|
|
|
for (int i = 1; i <= num / 2; i++) {
|
|
|
|
|
if (num % i == 0) {
|
|
|
|
|
divisors.add(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (divisors.isEmpty()) {
|
|
|
|
|
divisors.add(1);
|
|
|
|
|
}
|
|
|
|
|
return divisors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 计算答案
|
|
|
|
|
*/
|
|
|
|
|
private String calculateAnswer(List<Integer> operands, List<Character> ops) {
|
|
|
|
|
<<<<<<< HEAD
|
|
|
|
|
// Simplified calculation for primary school (no operator precedence)
|
|
|
|
|
int result = operands.get(0);
|
|
|
|
|
for (int i = 0; i < ops.size(); i++) {
|
|
|
|
|
@ -68,37 +172,66 @@ public class PrimaryQuestionGenerator implements QuestionGenerator {
|
|
|
|
|
case '/':
|
|
|
|
|
result /= nextOperand;
|
|
|
|
|
break;
|
|
|
|
|
=======
|
|
|
|
|
List<Integer> nums = new ArrayList<>(operands);
|
|
|
|
|
List<Character> operators = new ArrayList<>(ops);
|
|
|
|
|
|
|
|
|
|
// 先处理乘除
|
|
|
|
|
int i = 0;
|
|
|
|
|
while (i < operators.size()) {
|
|
|
|
|
char op = operators.get(i);
|
|
|
|
|
if (op == '*' || op == '/') {
|
|
|
|
|
int left = nums.get(i);
|
|
|
|
|
int right = nums.get(i + 1);
|
|
|
|
|
int result = (op == '*') ? left * right : left / right;
|
|
|
|
|
nums.set(i, result);
|
|
|
|
|
nums.remove(i + 1);
|
|
|
|
|
operators.remove(i);
|
|
|
|
|
} else {
|
|
|
|
|
i++;
|
|
|
|
|
>>>>>>> develop
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 再处理加减
|
|
|
|
|
int finalResult = nums.get(0);
|
|
|
|
|
for (i = 0; i < operators.size(); i++) {
|
|
|
|
|
int next = nums.get(i + 1);
|
|
|
|
|
switch (operators.get(i)) {
|
|
|
|
|
case '+':
|
|
|
|
|
finalResult += next;
|
|
|
|
|
break;
|
|
|
|
|
case '-':
|
|
|
|
|
finalResult -= next;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return String.valueOf(result);
|
|
|
|
|
|
|
|
|
|
return String.valueOf(finalResult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在 PrimaryQuestionGenerator.java 中
|
|
|
|
|
/**
|
|
|
|
|
* 生成选项
|
|
|
|
|
*/
|
|
|
|
|
private List<String> generateOptions(String correctAnswer) {
|
|
|
|
|
Set<String> options = new HashSet<>(); // 使用Set来自动处理重复问题
|
|
|
|
|
Set<String> options = new HashSet<>();
|
|
|
|
|
options.add(correctAnswer);
|
|
|
|
|
int correctNum = Integer.parseInt(correctAnswer);
|
|
|
|
|
|
|
|
|
|
// ★★★ 修正后的逻辑 ★★★
|
|
|
|
|
while (options.size() < 4) {
|
|
|
|
|
int offset = RANDOM.nextInt(20) + 1; // 偏移量 1-20
|
|
|
|
|
// 随机生成一个错误答案,确保它不等于正确答案
|
|
|
|
|
int wrongNum = (RANDOM.nextBoolean()) ? correctNum + offset : correctNum - offset;
|
|
|
|
|
|
|
|
|
|
// 确保错误答案是正数且不等于正确答案
|
|
|
|
|
if (wrongNum > 0 && wrongNum != correctNum) {
|
|
|
|
|
options.add(String.valueOf(wrongNum));
|
|
|
|
|
} else {
|
|
|
|
|
// 如果生成的不好,就再生成一个绝对不会重复的
|
|
|
|
|
options.add(String.valueOf(correctNum + options.size() + 1));
|
|
|
|
|
int offset = RANDOM.nextInt(20) + 1;
|
|
|
|
|
int wrongNum = RANDOM.nextBoolean() ? correctNum + offset : correctNum - offset;
|
|
|
|
|
if (wrongNum <= 0) {
|
|
|
|
|
wrongNum = correctNum + offset + 10;
|
|
|
|
|
}
|
|
|
|
|
options.add(String.valueOf(wrongNum));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<String> result = new ArrayList<>(options);
|
|
|
|
|
return result; // 返回最终的选项列表
|
|
|
|
|
return new ArrayList<>(options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 打乱选项
|
|
|
|
|
*/
|
|
|
|
|
private int shuffleOptions(List<String> options, String correctAnswer) {
|
|
|
|
|
Collections.shuffle(options);
|
|
|
|
|
return options.indexOf(correctAnswer);
|
|
|
|
|
|