题目生成修改

huangsihui_branch
柳意 2 months ago
parent a196139e9a
commit 0d80514510

@ -11,7 +11,7 @@ public class QuestionGenerator {
public List<Question> generateQuestions(String level, int count) {
List<Question> questions = new ArrayList<>();
Set<String> questionTexts = new HashSet<>(); // 防止重复题目
Set<String> questionTexts = new HashSet<>();
for (int i = 0; i < count; i++) {
Question question;
@ -44,225 +44,275 @@ public class QuestionGenerator {
}
private Question generatePrimaryQuestion(int index) {
// 小学操作数2-5个确保结果不为负数
int operandCount = random.nextInt(4) + 2; // 2-5个操作数
int operandCount = random.nextInt(4) + 2;
List<Integer> operands = new ArrayList<>();
List<Character> operators = new ArrayList<>();
// 生成操作数 (1-100)
for (int i = 0; i < operandCount; i++) {
operands.add(random.nextInt(100) + 1);
}
// 生成运算符 (+, -, *, /)
for (int i = 0; i < operandCount - 1; i++) {
operators.add(getRandomOperation("+-*/"));
}
// 生成操作数和运算符,确保结果非负
generateSafePrimaryExpression(operands, operators, operandCount);
// 构建表达式并计算结果,确保不为负数
String questionText;
int result;
int attempts = 0;
do {
// 随机决定是否使用括号
boolean useParentheses = random.nextBoolean() && operandCount >= 3;
if (useParentheses) {
// 使用括号的表达式
int parenPos = random.nextInt(operandCount - 1);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operandCount; i++) {
if (i == parenPos) {
sb.append("(");
}
sb.append(operands.get(i));
if (i == parenPos + 1) {
sb.append(")");
}
if (i < operandCount - 1) {
sb.append(" ").append(operators.get(i)).append(" ");
}
}
questionText = sb.toString();
result = evaluateExpressionWithParentheses(operands, operators, parenPos);
questionText = buildParenthesesExpression(operands, operators, parenPos);
result = evaluateWithParentheses(operands, operators, parenPos);
} else {
// 不使用括号的表达式
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operandCount; i++) {
sb.append(operands.get(i));
if (i < operandCount - 1) {
sb.append(" ").append(operators.get(i)).append(" ");
}
}
questionText = sb.toString();
questionText = buildSimpleExpression(operands, operators);
result = evaluateSequential(operands, operators);
}
attempts++;
// 如果结果为负数,重新生成操作数和运算符
if (result < 0) {
operands.clear();
operators.clear();
for (int i = 0; i < operandCount; i++) {
operands.add(random.nextInt(100) + 1);
}
for (int i = 0; i < operandCount - 1; i++) {
operators.add(getRandomOperation("+-*/"));
}
// 重新生成安全的表达式
generateSafePrimaryExpression(operands, operators, operandCount);
}
} while (result < 0 && attempts < 10);
// 如果还是负数,强制使用加法
if (result < 0) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operandCount; i++) {
sb.append(operands.get(i));
if (i < operandCount - 1) {
sb.append(" + ");
}
for (int i = 0; i < operators.size(); i++) {
operators.set(i, '+');
}
questionText = sb.toString();
result = operands.stream().mapToInt(Integer::intValue).sum();
questionText = buildSimpleExpression(operands, operators);
result = evaluateSequential(operands, operators);
}
return generateOptions(questionText + " = ?", result, "小学");
return generateIntOptions(questionText + " = ?", result, "小学");
}
private void generateSafePrimaryExpression(List<Integer> operands, List<Character> operators, int operandCount) {
operands.clear();
operators.clear();
// 首先生成所有操作数
for (int i = 0; i < operandCount; i++) {
operands.add(random.nextInt(100) + 1);
}
// 然后生成安全的运算符序列
int currentValue = operands.get(0);
for (int i = 1; i < operandCount; i++) {
char op;
if (currentValue < operands.get(i)) {
// 如果当前值小于下一个操作数,避免减法导致负数
if (random.nextBoolean()) {
op = '+';
currentValue += operands.get(i);
} else {
op = (random.nextBoolean() && currentValue > 0) ? '*' : '+';
if (op == '*') currentValue *= operands.get(i);
else currentValue += operands.get(i);
}
} else {
// 可以安全使用减法
op = getRandomOperation("+-*/");
switch (op) {
case '+': currentValue += operands.get(i); break;
case '-': currentValue -= operands.get(i); break;
case '*': currentValue *= operands.get(i); break;
case '/':
if (operands.get(i) != 0) currentValue /= operands.get(i);
else currentValue += operands.get(i);
break;
}
}
operators.add(op);
}
}
private Question generateMiddleSchoolQuestion(int index) {
// 初中操作数1-5个至少包含平方或开根号
int operandCount = random.nextInt(5) + 1; // 1-5个操作数
boolean hasSquareOrSqrt = false;
String questionText;
int result;
int attempts = 0;
int type = random.nextInt(4);
MathExpression expression = new MathExpression();
switch (type) {
case 0:
expression = createSquareExpression();
break;
case 1:
expression = createSqrtExpression();
break;
case 2:
expression = createSquareProductExpression();
break;
case 3:
expression = createSquareDivisionExpression();
break;
}
do {
int type = random.nextInt(4);
switch (type) {
case 0:
// a² ± b × c
int a = random.nextInt(10) + 1; // 1-10的平方
int b = random.nextInt(100) + 1;
int c = random.nextInt(100) + 1;
char op = random.nextBoolean() ? '+' : '-';
questionText = a + "² " + op + " " + b + " × " + c;
result = (op == '+') ? (a * a + b * c) : (a * a - b * c);
hasSquareOrSqrt = true;
break;
// 确保初中题目结果非负
if (expression.result < 0) {
expression = createSquareExpression(); // 重新生成一个肯定为正的题目
}
case 1:
// √a ± b
int sqrtBase = findPerfectSquare(100); // 100以内的完全平方数
int sqrtVal = (int) Math.sqrt(sqrtBase);
int d = random.nextInt(100) + 1;
char op2 = random.nextBoolean() ? '+' : '-';
questionText = "√" + sqrtBase + " " + op2 + " " + d;
result = (op2 == '+') ? (sqrtVal + d) : (sqrtVal - d);
hasSquareOrSqrt = true;
break;
return generateIntOptions(expression.questionText + " = ?", expression.result, "初中");
}
case 2:
// a × b² ± c
int e = random.nextInt(100) + 1;
int f = random.nextInt(10) + 1;
int g = random.nextInt(100) + 1;
char op3 = random.nextBoolean() ? '+' : '-';
questionText = e + " × " + f + "² " + op3 + " " + g;
result = (op3 == '+') ? (e * f * f + g) : (e * f * f - g);
hasSquareOrSqrt = true;
break;
private MathExpression createSquareExpression() {
int a = random.nextInt(10) + 1;
int b = random.nextInt(100) + 1;
int c = random.nextInt(100) + 1;
// 只使用加法确保结果为正
char op = '+';
default:
// (a + b)² ÷ c
int h = random.nextInt(50) + 1;
int i = random.nextInt(50) + 1;
int j = random.nextInt(20) + 1;
questionText = "(" + h + " + " + i + ")² ÷ " + j;
result = (h + i) * (h + i) / j;
hasSquareOrSqrt = true;
break;
}
attempts++;
} while (!hasSquareOrSqrt && attempts < 10);
String questionText = a + "² " + op + " " + b + " × " + c;
int result = a * a + b * c;
return generateOptions(questionText + " = ?", result, "初中");
return new MathExpression(questionText, result);
}
private MathExpression createSqrtExpression() {
int sqrtBase = findPerfectSquare(100);
int sqrtVal = (int) Math.sqrt(sqrtBase);
int d = random.nextInt(100) + 1;
// 只使用加法确保结果为正
char op = '+';
String questionText = "√" + sqrtBase + " " + op + " " + d;
int result = sqrtVal + d;
return new MathExpression(questionText, result);
}
private MathExpression createSquareProductExpression() {
int e = random.nextInt(100) + 1;
int f = random.nextInt(10) + 1;
int g = random.nextInt(100) + 1;
// 只使用加法确保结果为正
char op = '+';
String questionText = e + " × " + f + "² " + op + " " + g;
int result = e * f * f + g;
return new MathExpression(questionText, result);
}
private MathExpression createSquareDivisionExpression() {
int h = random.nextInt(50) + 1;
int i = random.nextInt(50) + 1;
int sum = h + i;
int square = sum * sum;
int j = findDivisor(square);
String questionText = "(" + h + " + " + i + ")² ÷ " + j;
int result = square / j;
return new MathExpression(questionText, result);
}
private Question generateHighSchoolQuestion(int index) {
// 高中操作数1-5个至少包含sin,cos,tan
int operandCount = random.nextInt(5) + 1; // 1-5个操作数
boolean hasTrigFunction = false;
String questionText;
double result;
int attempts = 0;
int type = random.nextInt(4);
TrigExpression expression = new TrigExpression();
switch (type) {
case 0:
expression = createSinExpression();
break;
case 1:
expression = createCosExpression();
break;
case 2:
expression = createTanExpression();
break;
case 3:
expression = createSinCosExpression();
break;
}
// 常见角度值
double[] angles = {0, 30, 45, 60, 90, 120, 135, 150, 180};
String[] angleStrs = {"0°", "30°", "45°", "60°", "90°", "120°", "135°", "150°", "180°"};
double[] sinValues = {0, 0.5, Math.sqrt(2)/2, Math.sqrt(3)/2, 1, Math.sqrt(3)/2, Math.sqrt(2)/2, 0.5, 0};
double[] cosValues = {1, Math.sqrt(3)/2, Math.sqrt(2)/2, 0.5, 0, -0.5, -Math.sqrt(2)/2, -Math.sqrt(3)/2, -1};
double[] tanValues = {0, Math.sqrt(3)/3, 1, Math.sqrt(3), Double.POSITIVE_INFINITY, -Math.sqrt(3), -1, -Math.sqrt(3)/3, 0};
return generateDoubleOptions(expression.questionText + " = ?", expression.result, "高中");
}
do {
int type = random.nextInt(4);
switch (type) {
case 0:
// sin(a) ± b
int idx1 = random.nextInt(angles.length);
int b = random.nextInt(100) + 1;
char op = random.nextBoolean() ? '+' : '-';
questionText = "sin(" + angleStrs[idx1] + ") " + op + " " + b;
result = (op == '+') ? (sinValues[idx1] + b) : (sinValues[idx1] - b);
hasTrigFunction = true;
break;
private TrigExpression createSinExpression() {
String[] angles = {"0°", "30°", "45°", "60°", "90°"};
double[] sinValues = {0, 0.5, 0.71, 0.87, 1.0};
case 1:
// a × cos(b)
int a = random.nextInt(100) + 1;
int idx2 = random.nextInt(angles.length);
questionText = a + " × cos(" + angleStrs[idx2] + ")";
result = a * cosValues[idx2];
hasTrigFunction = true;
break;
int idx = random.nextInt(angles.length);
int b = random.nextInt(100) + 1;
// 只使用加法确保结果为正
char op = '+';
case 2:
// tan(a) ÷ b (避免tan(90°))
int idx3 = random.nextInt(angles.length);
while (angles[idx3] == 90) {
idx3 = random.nextInt(angles.length);
}
int c = random.nextInt(20) + 1;
questionText = "tan(" + angleStrs[idx3] + ") ÷ " + c;
result = tanValues[idx3] / c;
hasTrigFunction = true;
break;
String questionText = "sin(" + angles[idx] + ") " + op + " " + b;
double result = sinValues[idx] + b;
default:
// sin(a) × cos(b) ± c
int idx4 = random.nextInt(angles.length);
int idx5 = random.nextInt(angles.length);
int d = random.nextInt(100) + 1;
char op2 = random.nextBoolean() ? '+' : '-';
questionText = "sin(" + angleStrs[idx4] + ") × cos(" + angleStrs[idx5] + ") " + op2 + " " + d;
result = (op2 == '+') ? (sinValues[idx4] * cosValues[idx5] + d) : (sinValues[idx4] * cosValues[idx5] - d);
hasTrigFunction = true;
break;
}
attempts++;
} while (!hasTrigFunction && attempts < 10);
return new TrigExpression(questionText, result);
}
private TrigExpression createCosExpression() {
String[] angles = {"0°", "30°", "45°", "60°"};
double[] cosValues = {1.0, 0.87, 0.71, 0.5};
int idx = random.nextInt(angles.length);
int a = random.nextInt(100) + 1;
String questionText = a + " × cos(" + angles[idx] + ")";
double result = a * cosValues[idx];
return generateOptions(questionText + " = ?", result, "高中");
return new TrigExpression(questionText, result);
}
private TrigExpression createTanExpression() {
String[] angles = {"0°", "30°", "45°", "60°"};
double[] tanValues = {0, 0.58, 1.0, 1.73};
int idx = random.nextInt(angles.length);
int c = random.nextInt(20) + 1;
String questionText = "tan(" + angles[idx] + ") ÷ " + c;
double result = tanValues[idx] / c;
return new TrigExpression(questionText, result);
}
private TrigExpression createSinCosExpression() {
String[] angles = {"0°", "30°", "45°", "60°"};
double[] sinValues = {0, 0.5, 0.71, 0.87};
double[] cosValues = {1.0, 0.87, 0.71, 0.5};
int idx1 = random.nextInt(angles.length);
int idx2 = random.nextInt(angles.length);
int d = random.nextInt(100) + 1;
// 只使用加法确保结果为正
char op = '+';
String questionText = "sin(" + angles[idx1] + ") × cos(" + angles[idx2] + ") " + op + " " + d;
double product = sinValues[idx1] * cosValues[idx2];
double result = product + d;
return new TrigExpression(questionText, result);
}
// 辅助方法
private char getRandomOperation(String operations) {
return operations.charAt(random.nextInt(operations.length()));
}
private String buildSimpleExpression(List<Integer> operands, List<Character> operators) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operands.size(); i++) {
sb.append(operands.get(i));
if (i < operands.size() - 1) {
sb.append(" ").append(operators.get(i)).append(" ");
}
}
return sb.toString();
}
private String buildParenthesesExpression(List<Integer> operands, List<Character> operators, int parenPos) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operands.size(); i++) {
if (i == parenPos) sb.append("(");
sb.append(operands.get(i));
if (i == parenPos + 1) sb.append(")");
if (i < operands.size() - 1) {
sb.append(" ").append(operators.get(i)).append(" ");
}
}
return sb.toString();
}
private int evaluateSequential(List<Integer> operands, List<Character> operators) {
int result = operands.get(0);
for (int i = 0; i < operators.size(); i++) {
@ -271,11 +321,8 @@ public class QuestionGenerator {
return result;
}
private int evaluateExpressionWithParentheses(List<Integer> operands, List<Character> operators, int parenPos) {
// 先计算括号内的值
private int evaluateWithParentheses(List<Integer> operands, List<Character> operators, int parenPos) {
int parenResult = calculate(operands.get(parenPos), operands.get(parenPos + 1), operators.get(parenPos));
// 构建新的操作数和运算符列表
List<Integer> newOperands = new ArrayList<>();
List<Character> newOperators = new ArrayList<>();
@ -293,39 +340,43 @@ public class QuestionGenerator {
}
}
// 顺序计算剩余部分
return evaluateSequential(newOperands, newOperators);
}
private int calculate(int a, int b, char op) {
switch (op) {
case '+': return a + b;
case '-':
// 确保减法结果不为负数
return Math.max(a - b, 0);
case '-': return Math.max(a - b, 0);
case '*': return a * b;
case '/':
// 确保除法能整除且除数不为0
if (b == 0) return a;
return a / b;
case '/': return (b == 0) ? a : a / b;
default: return a + b;
}
}
private int findPerfectSquare(int max) {
// 找到小于等于max的完全平方数
List<Integer> perfectSquares = new ArrayList<>();
List<Integer> squares = new ArrayList<>();
for (int i = 1; i * i <= max; i++) {
perfectSquares.add(i * i);
squares.add(i * i);
}
return perfectSquares.get(random.nextInt(perfectSquares.size()));
return squares.get(random.nextInt(squares.size()));
}
private Question generateOptions(String questionText, int answer, String level) {
private int findDivisor(int number) {
List<Integer> divisors = new ArrayList<>();
for (int i = 2; i <= Math.min(20, number); i++) {
if (number % i == 0) {
divisors.add(i);
}
}
return divisors.isEmpty() ? 1 : divisors.get(random.nextInt(divisors.size()));
}
private Question generateIntOptions(String questionText, int answer, String level) {
String[] options = new String[4];
Set<Integer> usedValues = new HashSet<>();
options[0] = String.valueOf(answer);
String correctAnswer = String.valueOf(answer);
options[0] = correctAnswer;
usedValues.add(answer);
for (int i = 1; i < 4; i++) {
@ -335,27 +386,25 @@ public class QuestionGenerator {
int range = Math.max(3, Math.abs(answer) / 5 + 1);
int offset = random.nextInt(range * 2 + 1) - range;
wrongAnswer = answer + offset;
// 确保错误答案不为负数
wrongAnswer = Math.max(wrongAnswer, 0);
wrongAnswer = Math.max(wrongAnswer, 0); // 确保错误答案也不为负
attempts++;
} while (usedValues.contains(wrongAnswer) && attempts < 20);
if (usedValues.contains(wrongAnswer)) {
wrongAnswer = answer + i * 10 + 5;
wrongAnswer = Math.max(wrongAnswer, 0);
}
if (attempts > 20) {
wrongAnswer = answer + (i + 1) * 10 + 5;
break;
}
} while (wrongAnswer == answer || usedValues.contains(wrongAnswer));
options[i] = String.valueOf(wrongAnswer);
usedValues.add(wrongAnswer);
}
shuffleArray(options);
int correctIndex = findCorrectIndex(options, String.valueOf(answer));
int correctIndex = findCorrectIndex(options, correctAnswer);
return new Question(questionText, options, correctIndex, level);
}
private Question generateOptions(String questionText, double answer, String level) {
private Question generateDoubleOptions(String questionText, double answer, String level) {
String[] options = new String[4];
Set<String> usedValues = new HashSet<>();
@ -367,11 +416,15 @@ public class QuestionGenerator {
String wrongAnswer;
int attempts = 0;
do {
double offset = (random.nextDouble() - 0.5) * 2.0;
double offset = (random.nextDouble() - 0.5) * Math.max(1, Math.abs(answer) * 0.3);
double wrongValue = answer + offset;
wrongAnswer = formatDouble(wrongValue);
wrongAnswer = formatDouble(Math.max(wrongValue, 0)); // 确保错误答案不为负
attempts++;
} while (usedValues.contains(wrongAnswer) && attempts < 20);
if (attempts > 20) {
wrongAnswer = formatDouble(answer + (i + 1) * 2.5);
break;
}
} while (usedValues.contains(wrongAnswer) || wrongAnswer.equals(correctAnswer));
options[i] = wrongAnswer;
usedValues.add(wrongAnswer);
@ -384,21 +437,15 @@ public class QuestionGenerator {
}
private String formatDouble(double value) {
if (Double.isInfinite(value)) {
return "∞";
}
if (Double.isNaN(value)) {
return "无解";
}
// 保留3位小数去除多余的0
return String.format("%.3f", value).replaceAll("0*$", "").replaceAll("\\.$", "");
if (Double.isInfinite(value)) return "∞";
if (Double.isNaN(value)) return "无解";
if (Math.abs(value) < 0.001) return "0";
return String.format("%.2f", value).replaceAll("0*$", "").replaceAll("\\.$", "");
}
private int findCorrectIndex(String[] options, String correctAnswer) {
for (int i = 0; i < options.length; i++) {
if (options[i].equals(correctAnswer)) {
return i;
}
if (options[i].equals(correctAnswer)) return i;
}
return 0;
}
@ -411,4 +458,29 @@ public class QuestionGenerator {
array[i] = temp;
}
}
// 辅助类来存储题目和答案
private static class MathExpression {
String questionText;
int result;
MathExpression() {}
MathExpression(String questionText, int result) {
this.questionText = questionText;
this.result = result;
}
}
private static class TrigExpression {
String questionText;
double result;
TrigExpression() {}
TrigExpression(String questionText, double result) {
this.questionText = questionText;
this.result = result;
}
}
}
Loading…
Cancel
Save