|
|
package com.mathapp.problemGenerators;
|
|
|
|
|
|
import com.mathapp.models.Equation;
|
|
|
import com.mathapp.models.Operator;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
/**
|
|
|
* 高中题目生成器(最终修正版)。
|
|
|
* 采用更稳健的“追加”策略,从根本上避免所有索引越界和除零错误。
|
|
|
*/
|
|
|
public class HighSchoolProblemGenerator extends MiddleSchoolProblemGenerator {
|
|
|
|
|
|
private static final int[] PREDEFINED_ANGLES = {0, 30, 45, 60, 90};
|
|
|
private static final String[] TRIG_FUNCTIONS = {"sin", "cos", "tan"};
|
|
|
|
|
|
@Override
|
|
|
protected Equation createProblem() {
|
|
|
// 1. 调用父类方法生成一个包含平方或开方的基础题目
|
|
|
Equation middleSchoolEquation = super.createProblem();
|
|
|
List<String> operands = new ArrayList<>(middleSchoolEquation.operands());
|
|
|
List<Operator> operators = new ArrayList<>(middleSchoolEquation.operators());
|
|
|
|
|
|
String trigExpression;
|
|
|
Operator connectingOperator;
|
|
|
|
|
|
// 2.【最终修正策略】使用健壮性检查循环,直到生成一个绝对安全的组合
|
|
|
while (true) {
|
|
|
// 2a. 生成三角函数部分,并确保它不是 tan(90°)
|
|
|
String function;
|
|
|
int angleInDegrees;
|
|
|
do {
|
|
|
function = TRIG_FUNCTIONS[random.nextInt(TRIG_FUNCTIONS.length)];
|
|
|
angleInDegrees = PREDEFINED_ANGLES[random.nextInt(PREDEFINED_ANGLES.length)];
|
|
|
} while (function.equals("tan") && angleInDegrees == 90);
|
|
|
|
|
|
trigExpression = String.format("%s(%s)", function, getRadianString(angleInDegrees));
|
|
|
|
|
|
// 2b. 随机选择一个连接运算符
|
|
|
connectingOperator = Operator.values()[random.nextInt(Operator.values().length)];
|
|
|
|
|
|
// 2c.【健壮性检查】检查这个新运算符是否会与三角函数的值构成除零错误
|
|
|
boolean isTrigValueZero = (function.equals("sin") && angleInDegrees == 0) ||
|
|
|
(function.equals("tan") && angleInDegrees == 0);
|
|
|
|
|
|
// 如果新运算符是除法,且三角函数的值是0,则这是一个非法组合,必须重试
|
|
|
if (connectingOperator == Operator.DIVIDE && isTrigValueZero) {
|
|
|
continue; // 非法组合,重新循环
|
|
|
}
|
|
|
|
|
|
// 如果代码能执行到这里,说明组合是安全的,可以退出循环
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
// 3.【安全的追加操作】将生成的安全组合追加到表达式末尾
|
|
|
// 这种方法永远不会导致 IndexOutOfBoundsException
|
|
|
operands.add(trigExpression);
|
|
|
operators.add(connectingOperator);
|
|
|
|
|
|
return new Equation(operands, operators);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 将特殊的角度值转换为 exp4j 可以计算的、基于 pi 的弧度字符串。
|
|
|
*/
|
|
|
private String getRadianString(int angleInDegrees) {
|
|
|
switch (angleInDegrees) {
|
|
|
case 0: return "0";
|
|
|
case 30: return "pi/6";
|
|
|
case 45: return "pi/4";
|
|
|
case 60: return "pi/3";
|
|
|
case 90: return "pi/2";
|
|
|
default: return "0";
|
|
|
}
|
|
|
}
|
|
|
} |