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 generateQuestions(int count, String difficulty) { List questions = new ArrayList<>(); Set 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 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; } }