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.
double_project/src/model/QuestionGenerator.java

282 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package model;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;
import java.util.Random;
import java.text.DecimalFormat;
public class QuestionGenerator {
private Random random = new Random();
private DecimalFormat df = new DecimalFormat("#.##"); // 保留两位小数的格式化器
public List<Question> generateQuestions(int count, String difficulty) {
List<Question> questions = new ArrayList<>();
Set<String> existingQuestions = new HashSet<>();
while (questions.size() < count) {
Question question = generateQuestion(difficulty);
String questionKey = question.getQuestion() + Arrays.toString(question.getOptions());
if (!existingQuestions.contains(questionKey)) {
questions.add(question);
existingQuestions.add(questionKey);
}
}
return questions;
}
private Question generateQuestion(String difficulty) {
switch (difficulty) {
case "小学":
return generatePrimaryQuestion();
case "初中":
return generateMiddleSchoolQuestion();
case "高中":
return generateHighSchoolQuestion();
default:
return generatePrimaryQuestion();
}
}
private Question generatePrimaryQuestion() {
int num1 = random.nextInt(50) + 1;
int num2 = random.nextInt(50) + 1;
int num3 = random.nextInt(50) + 1;
char[] operators = {'+', '-', '*', '/'};
char operator1 = operators[random.nextInt(operators.length)];
char operator2 = operators[random.nextInt(operators.length)];
String question;
double correctAnswer;
// 随机决定是否使用括号
if (random.nextBoolean()) {
// 有括号的情况
switch (random.nextInt(3)) {
case 0: // (a op b) op c
correctAnswer = calculate(calculate(num1, num2, operator1), num3, operator2);
question = "(" + num1 + " " + getOperatorSymbol(operator1) + " " + num2 + ") " +
getOperatorSymbol(operator2) + " " + num3 + " = ?";
break;
case 1: // a op (b op c)
correctAnswer = calculate(num1, calculate(num2, num3, operator2), operator1);
question = num1 + " " + getOperatorSymbol(operator1) + " (" + num2 + " " +
getOperatorSymbol(operator2) + " " + num3 + ") = ?";
break;
default: // 无括号
correctAnswer = calculate(calculate(num1, num2, operator1), num3, operator2);
question = num1 + " " + getOperatorSymbol(operator1) + " " + num2 + " " +
getOperatorSymbol(operator2) + " " + num3 + " = ?";
break;
}
} else {
if (operator1 == '/') {
num2 = random.nextInt(10) + 1; // 避免除零
}
correctAnswer = calculate(num1, num2, operator1);
question = num1 + " " + getOperatorSymbol(operator1) + " " + num2 + " = ?";
}
correctAnswer = Double.parseDouble(df.format(correctAnswer));
String[] options = generateOptions(correctAnswer);
return new Question(question, options, getCorrectOptionIndex(options, correctAnswer), "小学");
}
private Question generateMiddleSchoolQuestion() {
String question;
double correctAnswer;
if (random.nextBoolean()) {
// 平方或平方根题目
int num = random.nextInt(20) + 1;
if (random.nextBoolean()) {
correctAnswer = Math.pow(num, 2);
question = num + "² = ?";
} else {
int squared = num * num;
correctAnswer = num;
question = "√" + squared + " = ?";
}
} else {
// 带加减乘除的题目
int num1 = random.nextInt(50) + 1;
int num2 = random.nextInt(50) + 1;
int num3 = random.nextInt(20) + 1;
char[] operators = {'+', '-', '*', '/'};
char operator1 = operators[random.nextInt(operators.length)];
char operator2 = operators[random.nextInt(operators.length)];
// 随机组合平方、平方根和基本运算
if (random.nextBoolean()) {
// 平方与基本运算组合
correctAnswer = calculate(Math.pow(num1, 2), num2, operator1);
question = num1 + "² " + getOperatorSymbol(operator1) + " " + num2 + " = ?";
} else {
// 平方根与基本运算组合
int squared = num3 * num3;
correctAnswer = calculate(num3, num2, operator1);
question = "√" + squared + " " + getOperatorSymbol(operator1) + " " + num2 + " = ?";
}
}
correctAnswer = Double.parseDouble(df.format(correctAnswer));
String[] options = generateOptions(correctAnswer);
return new Question(question, options, getCorrectOptionIndex(options, correctAnswer), "初中");
}
private Question generateHighSchoolQuestion() {
if (random.nextBoolean()) {
return HighSchoolQuestionOne();
} else {
// 三角函数与基本运算组合
return HighSchoolQuestionTwo();
}
}
private Question HighSchoolQuestionOne() {
String question;
double correctAnswer;
double angle = random.nextInt(360);
String[] trigFunctions = {"sin", "cos", "tan"};
String trigFunction = trigFunctions[random.nextInt(trigFunctions.length)];
switch (trigFunction) {
case "sin":
correctAnswer = Math.sin(Math.toRadians(angle));
question = "sin(" + angle + "°) = ?";
break;
case "cos":
correctAnswer = Math.cos(Math.toRadians(angle));
question = "cos(" + angle + "°) = ?";
break;
case "tan":
angle = getSafeTanAngle();
correctAnswer = Math.tan(Math.toRadians(angle));
question = "tan(" + angle + "°) = ?";
break;
default:
correctAnswer = 0;
question = "";
}
correctAnswer = Double.parseDouble(df.format(correctAnswer));
String[] options = generateOptions(correctAnswer);
return new Question(question, options, getCorrectOptionIndex(options, correctAnswer), "高中");
}
private Question HighSchoolQuestionTwo() {
String question;
double correctAnswer;
double angle = random.nextInt(360);
int num = random.nextInt(20) + 1;
char[] operators = {'+', '-', '*', '/'};
char operator = operators[random.nextInt(operators.length)];
String[] trigFunctions = {"sin", "cos", "tan"};
String trigFunction = trigFunctions[random.nextInt(trigFunctions.length)];
double trigValue;
switch (trigFunction) {
case "sin":
trigValue = Math.sin(Math.toRadians(angle));
question = "sin(" + angle + "°) " + getOperatorSymbol(operator) + " " + num + " = ?";
break;
case "cos":
trigValue = Math.cos(Math.toRadians(angle));
question = "cos(" + angle + "°) " + getOperatorSymbol(operator) + " " + num + " = ?";
break;
case "tan":
angle = getSafeTanAngle();
trigValue = Math.tan(Math.toRadians(angle));
question = "tan(" + angle + "°) " + getOperatorSymbol(operator) + " " + num + " = ?";
break;
default:
trigValue = 0;
question = "";
}
trigValue = Double.parseDouble(df.format(trigValue));
correctAnswer = calculate(trigValue, num, operator);
String[] options = generateOptions(correctAnswer);
return new Question(question, options, getCorrectOptionIndex(options, correctAnswer), "高中");
}
// 获取安全的tan角度更严格的范围
private double getSafeTanAngle() {
// 为tan函数提供更安全的角度范围避免无限大的值
// 排除85°-95°, 265°-275° 等接近90°和270°的角度
List<Double> safeTanAngles = new ArrayList<>();
for (int i = 0; i < 360; i++) {
if (isSafeForTan(i)) {
safeTanAngles.add((double) i);
}
}
return safeTanAngles.get(random.nextInt(safeTanAngles.size()));
}
// 检查角度是否对tan函数安全更严格的条件
private boolean isSafeForTan(double angle) {
// 排除接近90°、270°的角度以及排除tan值过大的角度
return !((angle >= 80 && angle <= 100) ||
(angle >= 260 && angle <= 280) ||
(angle >= 170 && angle <= 190) ||
(angle >= 350 || angle <= 10));
}
// 计算方法
private double calculate(double a, double b, char operator) {
switch (operator) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return b != 0 ? a / b : a; // 避免除零
default:
return 0;
}
}
// 获取运算符符号
private String getOperatorSymbol(char operator) {
switch (operator) {
case '+':
return "+";
case '-':
return "-";
case '*':
return "×";
case '/':
return "÷";
default:
return "";
}
}
private String[] generateOptions(double correctAnswer) {
String[] options = new String[4];
int correctIndex = random.nextInt(4);
for (int i = 0; i < 4; i++) {
if (i == correctIndex) {
options[i] = df.format(correctAnswer);
} else {
double wrongAnswer;
do {
double variation = (random.nextDouble() - 0.5) * 10;
wrongAnswer = correctAnswer + variation;
wrongAnswer = Double.parseDouble(df.format(wrongAnswer));
} while (Math.abs(wrongAnswer - correctAnswer) < 0.1);
options[i] = String.valueOf(wrongAnswer);
}
}
return options;
}
private int getCorrectOptionIndex(String[] options, double correctAnswer) {
for (int i = 0; i < options.length; i++) {
if (Double.parseDouble(options[i]) == correctAnswer) {
return i;
}
}
return 0;
}
}