diff --git a/doc/MathPaperGenerator.jar b/doc/MathPaperGenerator.jar index 066e36f..8dd6d55 100644 Binary files a/doc/MathPaperGenerator.jar and b/doc/MathPaperGenerator.jar differ diff --git a/doc/README.md b/doc/README.md index b779114..34816e9 100644 --- a/doc/README.md +++ b/doc/README.md @@ -27,6 +27,7 @@ ├── Assign.java # 调度核心逻辑,负责用户登录和功能调用 ├── Function.java # 用户交互与出题数量输入处理 ├── Create.java # 调用生成器并保存试卷 +├── QuestionGenerator.java # Generator的父类 ├── Generator.java # 随机数学题生成器(小学/初中/高中) ├── LoadFile.java # 读取用户已有题目,避免重复 ├── Save.java # 保存生成的试卷到本地 diff --git a/doc/宋奇峰个人项目使用大模型后人工修改代码一览表.docx b/doc/宋奇峰个人项目使用大模型后人工修改代码一览表.docx new file mode 100644 index 0000000..e6db900 Binary files /dev/null and b/doc/宋奇峰个人项目使用大模型后人工修改代码一览表.docx differ diff --git a/src/Create.java b/src/Create.java index 18b921d..1cdb695 100644 --- a/src/Create.java +++ b/src/Create.java @@ -4,7 +4,7 @@ public class Create { public static void create(int n,Login.Level currentLevel,Login.Account user) { List existing = LoadFile.loadExistingQuestions(user.username); - Generator.QuestionGenerator qg = new Generator.QuestionGenerator(currentLevel, existing); + Generator qg = new Generator(currentLevel, existing); List paper = qg.generatePaper(n); if (paper.isEmpty()) { System.out.println("未能生成题目(可能因去重约束导致)。"); diff --git a/src/Generator.java b/src/Generator.java index d9dfdce..00d3cee 100644 --- a/src/Generator.java +++ b/src/Generator.java @@ -1,196 +1,190 @@ -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.LinkedHashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; 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 { +public class Generator extends QuestionGenerator { - private final Login.Level level; - private final Set existing; + public static final Random RAND = new Random(); + public static final int MAX_ATTEMPTS = 2000; - QuestionGenerator(Login.Level level, List existingQuestions) { - this.level = level; - this.existing = existingQuestions.stream().map(String::trim).collect(Collectors.toSet()); - } + public final Login.Level level; + public final Set existing; - /** - * 生成一份试卷。 - * - * @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); - } - } + Generator(Login.Level level, List existingQuestions) { + this.level = level; + this.existing = existingQuestions.stream().map(String::trim).collect(Collectors.toSet()); + } - if (generated.size() < n) { - System.out.println( - "注意:无法生成足够的不重复题目,已生成 " - + generated.size() + " 道题(请求 " + n + " 道)"); + /** + * 生成一份试卷。 + * + * @param n 需要生成的题目数量 + * @return 生成的题目列表 + */ + public 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); } - return new ArrayList<>(generated); } - //去空格 - private String normalize(String s) { - return s.replaceAll("\\s+", "").toLowerCase(); + if (generated.size() < n) { + System.out.println( + "注意:无法生成足够的不重复题目,已生成 " + + generated.size() + " 道题(请求 " + n + " 道)"); } + return new ArrayList<>(generated); + } - // 生成单题主逻辑 - 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); - }; - } + //去空格 + public String normalize(String s) { + return s.replaceAll("\\s+", "").toLowerCase(); + } + + // 生成单题主逻辑 + public 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)); + // 生成小学题(只有 + - * / 和括号) + public 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)); } - 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)); - } + } 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(); } + 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; + // 生成初中题:至少包含一个 ^2 或 sqrt() + public 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; - } + // 生成高中题:至少包含 sin/cos/tan + public 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; + // 把表达式中某个数字替换为 (x)^2 + public 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; + // 把表达式中某个数字替换为 sqrt(x) + public 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; + // 把某个数字或子表达式替换为 sin(x)/cos(x)/tan(x) + public 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++; + // 找出数字位置 + public 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; } + return spans; + } - //a..b随机数 - private int randInt(int a, int b) { - return RAND.nextInt(b - a + 1) + a; - } + //a..b随机数 + public 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())); - } + //抽签功能 + public T randomChoice(List list) { + return list.get(RAND.nextInt(list.size())); } } diff --git a/src/QuestionGenerator.java b/src/QuestionGenerator.java new file mode 100644 index 0000000..60a1918 --- /dev/null +++ b/src/QuestionGenerator.java @@ -0,0 +1,46 @@ +import java.util.List; + +public abstract class QuestionGenerator { + + + protected QuestionGenerator() { + } + + + public abstract List generatePaper(int n); + + //去空格 + public abstract String normalize(String s); + + // 生成单题主逻辑 + public abstract String generateOneQuestion(); + + + // 生成小学题(只有 + - * / 和括号) + public abstract String genPrimary(int operands); + + // 生成初中题:至少包含一个 ^2 或 sqrt() + public abstract String genMiddle(int operands); + + // 生成高中题:至少包含 sin/cos/tan + public abstract String genHigh(int operands); + + // 把表达式中某个数字替换为 (x)^2 + public abstract String applySquare(String expr); + + // 把表达式中某个数字替换为 sqrt(x) + public abstract String applySqrt(String expr); + + // 把某个数字或子表达式替换为 sin(x)/cos(x)/tan(x) + public abstract String applyTrig(String expr); + + // 找出数字位置 + public abstract List findNumberSpans(String expr); + + //a..b随机数 + public abstract int randInt(int a, int b); + + //抽签功能 + public abstract T randomChoice(List list); + +}