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.
124 lines
5.1 KiB
124 lines
5.1 KiB
import java.text.DecimalFormat;
|
|
import java.util.Random;
|
|
|
|
/**
|
|
* 抽象题目生成器:封装公共工具方法与共享状态
|
|
*/
|
|
public abstract class AbstractProblemGenerator {
|
|
protected final Random random;
|
|
protected final DecimalFormat df;
|
|
|
|
protected AbstractProblemGenerator(Random random, DecimalFormat df) {
|
|
this.random = random;
|
|
this.df = df;
|
|
}
|
|
|
|
/**
|
|
* 子类实现具体题目生成逻辑
|
|
*/
|
|
public abstract MathProblem generate();
|
|
|
|
// 构建带括号的表达式(只包两个操作数)
|
|
protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) {
|
|
StringBuilder expression = new StringBuilder();
|
|
for (int i = 0; i < operands.length; i++) {
|
|
if (i == startPos) {
|
|
expression.append("(");
|
|
}
|
|
expression.append(operands[i]);
|
|
if (i == startPos + 1) {
|
|
expression.append(")");
|
|
}
|
|
if (i < operands.length - 1) {
|
|
expression.append(" ").append(operators[i]).append(" ");
|
|
}
|
|
}
|
|
return expression.toString();
|
|
}
|
|
|
|
// 计算带括号的表达式结果(只合并两个操作数)
|
|
protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) {
|
|
double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]);
|
|
int newOperandCount = operands.length - 1;
|
|
int[] newOperands = new int[newOperandCount];
|
|
String[] newOperators = new String[newOperandCount - 1];
|
|
for (int i = 0; i < startPos; i++) newOperands[i] = operands[i];
|
|
newOperands[startPos] = (int) bracketResult;
|
|
for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1];
|
|
for (int i = 0; i < newOperandCount - 1; i++) {
|
|
if (i < startPos) newOperators[i] = operators[i];
|
|
else newOperators[i] = operators[i + 1];
|
|
}
|
|
double result = newOperands[0];
|
|
for (int i = 0; i < newOperandCount - 1; i++) {
|
|
result = applyOperator(result, newOperands[i + 1], newOperators[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** 应用运算符(整数右操作数) */
|
|
protected double applyOperator(double left, int right, String operator) {
|
|
switch (operator) {
|
|
case "+": return left + right;
|
|
case "-": return left - right;
|
|
case "*": return left * right;
|
|
case "/": return right != 0 ? left / right : left; // 避免除以零
|
|
default: return left;
|
|
}
|
|
}
|
|
|
|
/** 计算三角函数值 */
|
|
protected double calculateTrigFunction(String function, int angle) {
|
|
double radians = Math.toRadians(angle);
|
|
switch (function) {
|
|
case "sin": return Math.sin(radians);
|
|
case "cos": return Math.cos(radians);
|
|
case "tan":
|
|
if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义
|
|
return Math.tan(radians);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
/** Double 版本的运算符应用(用于包含三角函数的计算) */
|
|
protected double applyOperatorDouble(double left, double right, String operator) {
|
|
switch (operator) {
|
|
case "+": return left + right;
|
|
case "-": return left - right;
|
|
case "*": return left * right;
|
|
case "/": return right != 0.0 ? left / right : left; // 避免除以零
|
|
default: return left;
|
|
}
|
|
}
|
|
|
|
/** 将 int 数组转 double 数组 */
|
|
protected double[] toDoubleArray(int[] arr) {
|
|
double[] out = new double[arr.length];
|
|
for (int i = 0; i < arr.length; i++) out[i] = arr[i];
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1
|
|
*/
|
|
protected int findBracketStart(double[] values, String[] operators, double probability) {
|
|
if (values == null || operators == null) return -1;
|
|
if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义
|
|
if (random.nextDouble() >= probability) return -1;
|
|
int maxStart = values.length - 2; // 仅包两个操作数
|
|
int[] candidateStarts = new int[Math.max(0, maxStart + 1)];
|
|
int candidateCount = 0;
|
|
for (int s = 0; s <= maxStart; s++) {
|
|
boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]);
|
|
boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1]));
|
|
boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1]));
|
|
if (insideLow && (leftHigh || rightHigh)) {
|
|
candidateStarts[candidateCount++] = s;
|
|
}
|
|
}
|
|
if (candidateCount == 0) return -1;
|
|
int candidate = candidateStarts[random.nextInt(candidateCount)];
|
|
double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);
|
|
return (bracketResult != 0.0) ? candidate : -1;
|
|
}
|
|
} |