import java.util.Random; import java.util.Set; import java.util.LinkedHashSet; import java.util.List; import java.util.ArrayList; import java.util.Arrays; import java.util.stream.Collectors; /** * 工具类:负责生成不同难度的数学题目。 */ public class Generator { private static final Random RAND = new Random(); private static final int MAX_ATTEMPTS = 2000; /** * 内部类:按用户难度等级生成题目。 */ static class QuestionGenerator { private final Login.Level level; private final Set existing; QuestionGenerator(Login.Level level, List existingQuestions) { this.level = level; this.existing = existingQuestions.stream().map(String::trim).collect(Collectors.toSet()); } /** * 生成一份试卷。 * * @param n 需要生成的题目数量 * @return 生成的题目列表 */ List generatePaper(int n) { Set generated = new LinkedHashSet<>(); // 防止死循环 int attempts = 0; while (generated.size() < n && attempts < MAX_ATTEMPTS) { attempts++; String q = generateOneQuestion(); // 统一去掉题号与多余空白来比对 String key = normalize(q); //与文件内+本次前面生成的查重 if (!existing.contains(key) && !generated.contains(key)) { generated.add(q); } } if (generated.size() < n) { System.out.println( "注意:无法生成足够的不重复题目,已生成 " + generated.size() + " 道题(请求 " + n + " 道)"); } return new ArrayList<>(generated); } //去空格 private String normalize(String s) { return s.replaceAll("\\s+", "").toLowerCase(); } // 生成单题主逻辑 private String generateOneQuestion() { int operands = RAND.nextInt(5) + 1; // 保证 1..5 个操作数 int operands_p = RAND.nextInt(4) + 2; // 保证 2..5 个操作数 return switch (level) { case PRIMARY -> genPrimary(operands_p); case MIDDLE -> genMiddle(operands); case HIGH -> genHigh(operands); }; } // 生成小学题(只有 + - * / 和括号) private String genPrimary(int operands) { if (operands == 1) { return String.valueOf(randInt(1, 100)); } List ops = Arrays.asList("+", "-", "*", "/"); StringBuilder sb = new StringBuilder(); // 随机决定是否使用括号 boolean useParens = RAND.nextBoolean(); if (useParens && operands >= 3 && RAND.nextBoolean()) { // 构造 (a op b) op c ... sb.append("("); sb.append(randInt(1, 100)).append(" ").append(randomChoice(ops)).append(" ") .append(randInt(1, 100)); sb.append(")"); for (int i = 2; i < operands; i++) { sb.append(" ").append(randomChoice(ops)).append(" ").append(randInt(1, 100)); } } else { // 直连 sb.append(randInt(1, 100)); for (int i = 1; i < operands; i++) { sb.append(" ").append(randomChoice(ops)).append(" ").append(randInt(1, 100)); } } return sb.toString(); } // 生成初中题:至少包含一个 ^2 或 sqrt() private String genMiddle(int operands) { // 基本表达式生成,后插入平方或开根号 String expr = genPrimary(operands); // 基本算术 // 2选1 if (RAND.nextBoolean()) { // 找一个数字位置并替换为 (x)^2 expr = applySquare(expr); } else { expr = applySqrt(expr); } return expr; } // 生成高中题:至少包含 sin/cos/tan private String genHigh(int operands) { String expr = genPrimary(operands); expr = applyTrig(expr); return expr; } // 把表达式中某个数字替换为 (x)^2 private String applySquare(String expr) { // 寻找所有数字的片段 List spans = findNumberSpans(expr); if (spans.isEmpty()) { return expr + "^2"; } int[] s = spans.get(RAND.nextInt(spans.size())); String before = expr.substring(0, s[0]); String num = expr.substring(s[0], s[1]); String after = expr.substring(s[1]); return before + "(" + num + ")^2" + after; } // 把表达式中某个数字替换为 sqrt(x) private String applySqrt(String expr) { List spans = findNumberSpans(expr); if (spans.isEmpty()) { return "sqrt(" + expr + ")"; } int[] s = spans.get(RAND.nextInt(spans.size())); String before = expr.substring(0, s[0]); String num = expr.substring(s[0], s[1]); String after = expr.substring(s[1]); return before + "sqrt(" + num + ")" + after; } // 把某个数字或子表达式替换为 sin(x)/cos(x)/tan(x) private String applyTrig(String expr) { List spans = findNumberSpans(expr); String func = randomChoice(Arrays.asList("sin", "cos", "tan")); if (spans.isEmpty()) { return func + "(" + expr + ")"; } int[] s = spans.get(RAND.nextInt(spans.size())); String before = expr.substring(0, s[0]); String num = expr.substring(s[0], s[1]); String after = expr.substring(s[1]); return before + func + "(" + num + ")" + after; } // 找出数字位置 private List findNumberSpans(String expr) { List spans = new ArrayList<>(); char[] chs = expr.toCharArray(); int i = 0, n = chs.length; while (i < n) { if (Character.isDigit(chs[i])) { int j = i; while (j < n && (Character.isDigit(chs[j]))) { j++; } spans.add(new int[]{i, j}); i = j; } else { i++; } } return spans; } //a..b随机数 private int randInt(int a, int b) { return RAND.nextInt(b - a + 1) + a; } //抽签功能 private T randomChoice(List list) { return list.get(RAND.nextInt(list.size())); } } }