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.
95 lines
2.8 KiB
95 lines
2.8 KiB
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
class PrimaryQuestionGenerator extends BaseQuestionGenerator {
|
|
|
|
@Override
|
|
protected String generateQuestion() {
|
|
List<String> numbers = generateNumbers();
|
|
List<String> operators = generateOperators(numbers);
|
|
List<String> tokens = combineTokens(numbers, operators);
|
|
addRandomBrackets(tokens);
|
|
return String.join(" ", tokens);
|
|
}
|
|
|
|
/**
|
|
* 生成操作数列表.
|
|
*/
|
|
private List<String> generateNumbers() {
|
|
int ops = randInt(2, Constants.MAX_OPERANDS);
|
|
List<String> numbers = new ArrayList<>();
|
|
for (int i = 0; i < ops; i++) {
|
|
numbers.add(String.valueOf(randInt(1, Constants.MAX_VALUE)));
|
|
}
|
|
return numbers;
|
|
}
|
|
|
|
/**
|
|
* 生成操作符列表,保证减法不产生负数.
|
|
*/
|
|
private List<String> generateOperators(List<String> numbers) {
|
|
List<String> operators = new ArrayList<>();
|
|
String current = numbers.getFirst();
|
|
for (int i = 1; i < numbers.size(); i++) {
|
|
String op = randomBasicOperator();
|
|
if ("-".equals(op)) {
|
|
int left = Integer.parseInt(current.replaceAll("[^0-9]", ""));
|
|
int right = Integer.parseInt(numbers.get(i));
|
|
if (left < right) {
|
|
op = random.nextBoolean() ? "+" : "*";
|
|
}
|
|
}
|
|
operators.add(op);
|
|
current = computeIntermediate(current, numbers.get(i), op);
|
|
}
|
|
return operators;
|
|
}
|
|
|
|
/**
|
|
* 合成数字和运算符为 tokens 列表.
|
|
*/
|
|
private List<String> combineTokens(List<String> numbers, List<String> operators) {
|
|
List<String> tokens = new ArrayList<>();
|
|
tokens.add(numbers.getFirst());
|
|
for (int i = 1; i < numbers.size(); i++) {
|
|
tokens.add(operators.get(i - 1));
|
|
tokens.add(numbers.get(i));
|
|
}
|
|
return tokens;
|
|
}
|
|
|
|
/**
|
|
* 随机为子表达式添加一对括号,不包裹整个表达式.
|
|
*/
|
|
private void addRandomBrackets(List<String> tokens) {
|
|
int ops = (tokens.size() + 1) / 2;
|
|
if (ops < 2 || !random.nextBoolean()) {
|
|
return;
|
|
}
|
|
|
|
int pairCount = ops - 1;
|
|
int chosenOpIndex = random.nextInt(pairCount);
|
|
int leftIndex = chosenOpIndex * 2;
|
|
int rightIndex = chosenOpIndex * 2 + 2;
|
|
|
|
if (!(leftIndex == 0 && rightIndex == tokens.size() - 1)) {
|
|
tokens.add(leftIndex, "(");
|
|
tokens.add(rightIndex + 2, ")");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 计算当前中间值,用于保证减法不产生负数.
|
|
*/
|
|
private String computeIntermediate(String current, String next, String op) {
|
|
int c = Integer.parseInt(current);
|
|
int n = Integer.parseInt(next);
|
|
return switch (op) {
|
|
case "*" -> String.valueOf(c * n);
|
|
case "+" -> String.valueOf(c + n);
|
|
case "/" -> n != 0 ? String.valueOf(c / n) : String.valueOf(c);
|
|
default -> String.valueOf(c); // 避免减法导致负数
|
|
};
|
|
}
|
|
}
|