|
|
|
|
@ -13,7 +13,7 @@ import java.util.Random;
|
|
|
|
|
* 题目结构包含基本的四则运算和高级运算的组合。
|
|
|
|
|
*
|
|
|
|
|
* @author 杨博文
|
|
|
|
|
* @version 1.0
|
|
|
|
|
* @version 1.1
|
|
|
|
|
* @since 2025
|
|
|
|
|
*/
|
|
|
|
|
public class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
@ -55,31 +55,36 @@ public class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
List<String> parts = new ArrayList<>();
|
|
|
|
|
int operandCount = random.nextInt(5) + 1;
|
|
|
|
|
parts = generateBase(operandCount, parts);
|
|
|
|
|
// hasAdvancedOp用以检测下面的循环是否加入了高级运算符,如果没有就启动保底
|
|
|
|
|
|
|
|
|
|
boolean hasAdvancedOp = false;
|
|
|
|
|
|
|
|
|
|
if (operandCount == 1) {
|
|
|
|
|
// 对于单个操作数,直接添加高级运算符
|
|
|
|
|
if ("平方".equals(ADVANCED_OPS[random.nextInt(ADVANCED_OPS.length)])) {
|
|
|
|
|
parts.add("平方");
|
|
|
|
|
} else {
|
|
|
|
|
parts.add(0, "开根号");
|
|
|
|
|
// 为单个操作数的开根号添加括号
|
|
|
|
|
parts.set(0, "开根号 ( " + parts.get(0) + " )");
|
|
|
|
|
}
|
|
|
|
|
hasAdvancedOp = true;
|
|
|
|
|
} else {
|
|
|
|
|
// 遍历查找左括号的合理位置
|
|
|
|
|
for (int i = 0; i < parts.size() - 2; i++) {
|
|
|
|
|
// 遍历所有可能的操作数位置 (索引为偶数)
|
|
|
|
|
// 修复:循环条件确保最后一个操作数也能被检查
|
|
|
|
|
for (int i = 0; i < parts.size(); i += 2) { // 只检查操作数索引 (0, 2, 4, ...)
|
|
|
|
|
// 该位置要为操作数且随机添加括号
|
|
|
|
|
if (isNumeric(parts.get(i)) && random.nextBoolean()) {
|
|
|
|
|
// 随机数看取出来的是不是开根号运算符
|
|
|
|
|
// 随机选择高级运算符
|
|
|
|
|
if ("开根号".equals(ADVANCED_OPS[random.nextInt(ADVANCED_OPS.length)])) {
|
|
|
|
|
parts = generateRoot(parts, i);
|
|
|
|
|
} else { // 如果不是开根号就是平方运算
|
|
|
|
|
} else { // 平方运算
|
|
|
|
|
parts = generateSquare(parts, i);
|
|
|
|
|
}
|
|
|
|
|
hasAdvancedOp = true;
|
|
|
|
|
break;
|
|
|
|
|
break; // 添加成功后退出循环
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 启动保底强制加入一个高级运算符
|
|
|
|
|
if (!hasAdvancedOp) {
|
|
|
|
|
parts = forceAddAdvancedOp(parts);
|
|
|
|
|
@ -119,10 +124,13 @@ public class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
public List<String> forceAddAdvancedOp(List<String> parts) {
|
|
|
|
|
String advancedOp = ADVANCED_OPS[random.nextInt(ADVANCED_OPS.length)];
|
|
|
|
|
if ("平方".equals(advancedOp)) {
|
|
|
|
|
parts.add("平方");
|
|
|
|
|
// 对整个表达式进行平方
|
|
|
|
|
parts.add(0, "("); // 在开头添加左括号
|
|
|
|
|
parts.add(") 平方"); // 在末尾添加右括号和"平方"
|
|
|
|
|
} else { // 开根号
|
|
|
|
|
parts.set(0, "开根号 ( " + parts.get(0));
|
|
|
|
|
parts.set(parts.size() - 1, parts.get(parts.size() - 1) + " )");
|
|
|
|
|
// 对整个表达式进行开根号
|
|
|
|
|
parts.add(0, "开根号 ( "); // 在开头添加"开根号 ( "
|
|
|
|
|
parts.add(" )"); // 在末尾添加" )"
|
|
|
|
|
}
|
|
|
|
|
return parts;
|
|
|
|
|
}
|
|
|
|
|
@ -134,26 +142,19 @@ public class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
* 进行开根号,或者对一段子表达式进行开根号。
|
|
|
|
|
*
|
|
|
|
|
* @param parts 包含表达式各部分的列表
|
|
|
|
|
* @param i 开根号运算的起始位置
|
|
|
|
|
* @param i 开根号运算的起始位置 (操作数索引)
|
|
|
|
|
* @return 添加了开根号运算的表达式列表
|
|
|
|
|
*/
|
|
|
|
|
public List<String> generateRoot(List<String> parts, int i) {
|
|
|
|
|
if (random.nextBoolean()) {
|
|
|
|
|
// 对单个操作数进行开根号
|
|
|
|
|
parts.set(i, "开根号 ( " + parts.get(i) + " )");
|
|
|
|
|
} else {
|
|
|
|
|
parts.set(i, "开根号 ( " + parts.get(i));
|
|
|
|
|
// 为避免随机数上限出现0,此处要单独判断一下左括号正好括住倒数第二个操作数的情况
|
|
|
|
|
if (i == parts.size() - 3) {
|
|
|
|
|
parts.set(parts.size() - 1, parts.get(parts.size() - 1) + " )");
|
|
|
|
|
} else {
|
|
|
|
|
while (true) {
|
|
|
|
|
int i2 = random.nextInt(parts.size() - 3 - i) + 2;
|
|
|
|
|
if (isNumeric(parts.get(i + i2))) {
|
|
|
|
|
parts.set(i + i2, parts.get(i + i2) + " )");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 对子表达式进行开根号
|
|
|
|
|
parts.set(i, "开根号 ( " + parts.get(i)); // 在起始操作数前添加左括号和"开根号 ("
|
|
|
|
|
int endIndex = findMatchingEndIndex(parts, i); // 查找匹配的结束操作数索引
|
|
|
|
|
String currentEnd = parts.get(endIndex);
|
|
|
|
|
parts.set(endIndex, currentEnd + " )"); // 在结束操作数后添加右括号
|
|
|
|
|
}
|
|
|
|
|
return parts;
|
|
|
|
|
}
|
|
|
|
|
@ -164,23 +165,50 @@ public class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
* <p>该方法在表达式指定位置添加平方运算,对一段子表达式进行平方运算。
|
|
|
|
|
*
|
|
|
|
|
* @param parts 包含表达式各部分的列表
|
|
|
|
|
* @param i 平方运算的起始位置
|
|
|
|
|
* @param i 平方运算的起始位置 (操作数索引)
|
|
|
|
|
* @return 添加了平方运算的表达式列表
|
|
|
|
|
*/
|
|
|
|
|
public List<String> generateSquare(List<String> parts, int i) {
|
|
|
|
|
parts.set(i, "(" + parts.get(i));
|
|
|
|
|
// 为避免随机数上限出现0,此处要单独判断一下左括号正好括住倒数第二个操作数的情况
|
|
|
|
|
if (i == parts.size() - 3) {
|
|
|
|
|
parts.set(parts.size() - 1, parts.get(parts.size() - 1) + " )");
|
|
|
|
|
parts.set(i, "(" + parts.get(i)); // 在起始操作数前添加左括号
|
|
|
|
|
int endIndex = findMatchingEndIndex(parts, i); // 查找匹配的结束操作数索引
|
|
|
|
|
String currentEnd = parts.get(endIndex);
|
|
|
|
|
parts.set(endIndex, currentEnd + " ) 平方"); // 在结束操作数后添加右括号和"平方"
|
|
|
|
|
return parts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 辅助方法:查找子表达式的结束操作数索引。 从起始操作数索引 i 开始,随机决定子表达式的结束位置 (必须是操作数索引)。 为了简化,这里选择从 i+2
|
|
|
|
|
* 开始到最后一个操作数之间的随机一个操作数索引。
|
|
|
|
|
*
|
|
|
|
|
* @param parts 表达式各部分列表
|
|
|
|
|
* @param i 起始操作数索引
|
|
|
|
|
* @return 结束操作数索引
|
|
|
|
|
*/
|
|
|
|
|
private int findMatchingEndIndex(List<String> parts, int i) {
|
|
|
|
|
// 获取最后一个操作数的索引
|
|
|
|
|
int lastOperandIndex = parts.size() - 1;
|
|
|
|
|
if (lastOperandIndex % 2 != 0) {
|
|
|
|
|
lastOperandIndex--; // 如果列表长度是偶数,最后一个元素是运算符,需要减1得到最后一个操作数索引
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确保范围是有效的操作数索引
|
|
|
|
|
if (i >= lastOperandIndex) {
|
|
|
|
|
return lastOperandIndex; // 如果i已经是最后一个或超出,返回最后一个
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在 [i+2, lastOperandIndex] 范围内选择一个操作数索引 (步长为2)
|
|
|
|
|
// 确保至少包含一个运算符,所以从i+2开始
|
|
|
|
|
List<Integer> possibleEndIndices = new ArrayList<>();
|
|
|
|
|
for (int idx = i + 2; idx <= lastOperandIndex; idx += 2) {
|
|
|
|
|
possibleEndIndices.add(idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!possibleEndIndices.isEmpty()) {
|
|
|
|
|
// 随机选择一个可能的结束索引
|
|
|
|
|
return possibleEndIndices.get(random.nextInt(possibleEndIndices.size()));
|
|
|
|
|
} else {
|
|
|
|
|
while (true) {
|
|
|
|
|
int i2 = random.nextInt(parts.size() - 3 - i) + 2;
|
|
|
|
|
if (isNumeric(parts.get(i + i2))) {
|
|
|
|
|
parts.set(i + i2, parts.get(i + i2) + " ) 平方");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 理论上不应该到达这里,如果到达则返回起始索引
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return parts;
|
|
|
|
|
}
|
|
|
|
|
}
|