From 8aa2e927790a01dc22e9e18a29091bf9ba665b67 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 13:35:26 +0800 Subject: [PATCH 01/42] ADD file via upload --- AbstractProblemGenerator.java | 124 ++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 AbstractProblemGenerator.java diff --git a/AbstractProblemGenerator.java b/AbstractProblemGenerator.java new file mode 100644 index 0000000..82b61a2 --- /dev/null +++ b/AbstractProblemGenerator.java @@ -0,0 +1,124 @@ +import java.text.DecimalFormat; +import java.util.Random; + +/** + * 抽象题目生成器:封装公共工具方法与共享状态 + */ +public abstract class AbstractProblemGenerator { + protected final Random random; + protected final DecimalFormat df; + + protected AbstractProblemGenerator(Random random, DecimalFormat df) { + this.random = random; + this.df = df; + } + + /** + * 子类实现具体题目生成逻辑 + */ + public abstract MathProblem generate(); + + // 构建带括号的表达式(只包两个操作数) + protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + StringBuilder expression = new StringBuilder(); + for (int i = 0; i < operands.length; i++) { + if (i == startPos) { + expression.append("("); + } + expression.append(operands[i]); + if (i == startPos + 1) { + expression.append(")"); + } + if (i < operands.length - 1) { + expression.append(" ").append(operators[i]).append(" "); + } + } + return expression.toString(); + } + + // 计算带括号的表达式结果(只合并两个操作数) + protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); + int newOperandCount = operands.length - 1; + int[] newOperands = new int[newOperandCount]; + String[] newOperators = new String[newOperandCount - 1]; + for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; + newOperands[startPos] = (int) bracketResult; + for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; + for (int i = 0; i < newOperandCount - 1; i++) { + if (i < startPos) newOperators[i] = operators[i]; + else newOperators[i] = operators[i + 1]; + } + double result = newOperands[0]; + for (int i = 0; i < newOperandCount - 1; i++) { + result = applyOperator(result, newOperands[i + 1], newOperators[i]); + } + return result; + } + + /** 应用运算符(整数右操作数) */ + protected double applyOperator(double left, int right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 计算三角函数值 */ + protected double calculateTrigFunction(String function, int angle) { + double radians = Math.toRadians(angle); + switch (function) { + case "sin": return Math.sin(radians); + case "cos": return Math.cos(radians); + case "tan": + if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 + return Math.tan(radians); + default: return 0; + } + } + + /** Double 版本的运算符应用(用于包含三角函数的计算) */ + protected double applyOperatorDouble(double left, double right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0.0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 将 int 数组转 double 数组 */ + protected double[] toDoubleArray(int[] arr) { + double[] out = new double[arr.length]; + for (int i = 0; i < arr.length; i++) out[i] = arr[i]; + return out; + } + + /** + * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 + */ + protected int findBracketStart(double[] values, String[] operators, double probability) { + if (values == null || operators == null) return -1; + if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 + if (random.nextDouble() >= probability) return -1; + int maxStart = values.length - 2; // 仅包两个操作数 + int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; + int candidateCount = 0; + for (int s = 0; s <= maxStart; s++) { + boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); + boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); + boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); + if (insideLow && (leftHigh || rightHigh)) { + candidateStarts[candidateCount++] = s; + } + } + if (candidateCount == 0) return -1; + int candidate = candidateStarts[random.nextInt(candidateCount)]; + double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]); + return (bracketResult != 0.0) ? candidate : -1; + } +} \ No newline at end of file -- 2.34.1 From 1f1b75f220c27e73bb24e8d7c15434928d18dcc2 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:23:59 +0800 Subject: [PATCH 02/42] ADD file via upload --- ElementaryProblemGenerator.java | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 ElementaryProblemGenerator.java diff --git a/ElementaryProblemGenerator.java b/ElementaryProblemGenerator.java new file mode 100644 index 0000000..612612d --- /dev/null +++ b/ElementaryProblemGenerator.java @@ -0,0 +1,67 @@ +import java.text.DecimalFormat; +import java.util.Random; + +public class ElementaryProblemGenerator extends AbstractProblemGenerator { + public ElementaryProblemGenerator(Random random, DecimalFormat df) { + super(random, df); + } + + @Override + public MathProblem generate() { + // 小学题目要求:答案不得为负数。最多尝试若干次生成,若仍为负则回退到简单加法题。 + int maxAttempts = 50; + for (int attempt = 0; attempt < maxAttempts; attempt++) { + int operandCount = random.nextInt(4) + 2; // 2-5个操作数 + String[] operators = {"+", "-", "*", "/"}; + int[] operands = new int[operandCount]; + String[] selectedOperators = new String[operandCount - 1]; + for (int i = 0; i < operandCount; i++) operands[i] = random.nextInt(100) + 1; + // 运算符选择(避免连乘/连除,调整概率) + String previousOperator = null; + double pPlus = 0.45, pMinus = 0.35, pTimes = 0.15, pDivide = 0.05; + for (int i = 0; i < operandCount - 1; i++) { + String operator; + if ("*".equals(previousOperator) || "/".equals(previousOperator)) { + double randValue = random.nextDouble(); + double total = pPlus + pMinus; + operator = randValue < (pPlus / total) ? "+" : "-"; + } else { + double randValue = random.nextDouble(); + if (randValue < pPlus) operator = "+"; + else if (randValue < pPlus + pMinus) operator = "-"; + else if (randValue < pPlus + pMinus + pTimes) operator = "*"; + else operator = "/"; + } + selectedOperators[i] = operator; + previousOperator = operator; + } + // 括号选择 + int startPos = findBracketStart(toDoubleArray(operands), selectedOperators, 0.3); + String expression; + double result; + if (startPos != -1) { + expression = buildExpressionWithBrackets(operands, selectedOperators, startPos); + result = evaluateExpressionWithBrackets(operands, selectedOperators, startPos); + } else { + StringBuilder expBuilder = new StringBuilder(); + expBuilder.append(operands[0]); + result = operands[0]; + for (int i = 0; i < operandCount - 1; i++) { + expBuilder.append(" ").append(selectedOperators[i]).append(" ").append(operands[i + 1]); + result = applyOperator(result, operands[i + 1], selectedOperators[i]); + } + expression = expBuilder.toString(); + } + if (result >= 0) { + return new MathProblem(expression, df.format(result), "小学"); + } + // 如果为负数,继续下一次尝试 + } + // 回退:生成一个保证非负的简单加法题 + int a = random.nextInt(100) + 1; + int b = random.nextInt(100) + 1; + String expression = a + " + " + b; + double result = a + b; + return new MathProblem(expression, df.format(result), "小学"); + } +} \ No newline at end of file -- 2.34.1 From 92d03bb7767c458808663e806100373a19b78c95 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:24:31 +0800 Subject: [PATCH 03/42] ADD file via upload --- FileManager.java | 137 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 FileManager.java diff --git a/FileManager.java b/FileManager.java new file mode 100644 index 0000000..e132798 --- /dev/null +++ b/FileManager.java @@ -0,0 +1,137 @@ +import java.io.*; +import java.nio.file.*; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +/** + * 文件管理类,负责题目的保存和历史题目的管理 + */ +public class FileManager { + private static final String BASE_DIR = "math_papers"; + private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"); + + /** + * 保存题目到文件 + * @param user 用户信息 + * @param problems 题目列表 + * @param difficulty 难度级别(当前选择) + * @return 保存的文件路径 + */ + public String savePaperToFile(User user, List problems, String difficulty) throws IOException { + // 创建用户文件夹 + String userDir = BASE_DIR + File.separator + user.getUsername(); + Files.createDirectories(Paths.get(userDir)); + + // 生成文件名 + String timestamp = LocalDateTime.now().format(formatter); + String fileName = timestamp + ".txt"; + String filePath = userDir + File.separator + fileName; + + // 写入题目到文件 + try (PrintWriter writer = new PrintWriter(new FileWriter(filePath, StandardCharsets.UTF_8))) { + writer.println("数学题目卷子"); + writer.println("用户: " + user.getUsername()); + writer.println("类型: " + difficulty); + writer.println("生成时间: " + timestamp.replace("-", "/").replace("-", ":")); + writer.println("题目数量: " + problems.size()); + writer.println("=" + "=".repeat(50)); + writer.println(); + + for (int i = 0; i < problems.size(); i++) { + writer.println((i + 1) + ". " + problems.get(i).toString()); + writer.println(); // 每题之间空一行 + } + } + + return filePath; + } + + /** + * 获取用户历史题目,用于重复检测 + * @param username 用户名 + * @return 历史题目集合 + */ + public Set getUserHistoryProblems(String username) { + Set historyProblems = new HashSet<>(); + String userDir = BASE_DIR + File.separator + username; + + try { + Path userPath = Paths.get(userDir); + if (!Files.exists(userPath)) { + return historyProblems; + } + + // 遍历用户文件夹中的所有txt文件 + Files.walk(userPath) + .filter(path -> path.toString().endsWith(".txt")) + .forEach(path -> { + try { + List lines = Files.readAllLines(path, StandardCharsets.UTF_8); + for (String line : lines) { + // 提取题目表达式(格式:数字. 表达式 = ?) + if (line.matches("^\\d+\\. .+ = \\?$")) { + String expression = line.substring(line.indexOf(". ") + 2, line.lastIndexOf(" = ?")); + historyProblems.add(expression); + } + } + } catch (IOException e) { + System.err.println("读取文件失败: " + path); + } + }); + } catch (IOException e) { + System.err.println("访问用户目录失败: " + userDir); + } + + return historyProblems; + } + + /** + * 检查题目是否重复 + * @param username 用户名 + * @param problem 要检查的题目 + * @return 是否重复 + */ + public boolean isDuplicateProblem(String username, MathProblem problem) { + Set historyProblems = getUserHistoryProblems(username); + return historyProblems.contains(problem.getExpression()); + } + + /** + * 生成不重复的题目列表 + * @param user 用户信息 + * @param generator 题目生成器 + * @param count 题目数量 + * @param difficulty 难度级别 + * @return 不重复的题目列表 + */ + public List generateUniqueProblems(User user, MathProblemGenerator generator, + int count, String difficulty) { + List problems = new ArrayList<>(); + Set historyProblems = getUserHistoryProblems(user.getUsername()); + Set currentProblems = new HashSet<>(); + + int attempts = 0; + int maxAttempts = count * 10; // 最多尝试次数,避免无限循环 + + while (problems.size() < count && attempts < maxAttempts) { + MathProblem problem = generator.generateProblem(difficulty); + String expression = problem.getExpression(); + + // 检查是否与历史题目或当前题目重复 + if (!historyProblems.contains(expression) && !currentProblems.contains(expression)) { + problems.add(problem); + currentProblems.add(expression); + } + + attempts++; + } + + if (problems.size() < count) { + System.out.println("警告: 只生成了 " + problems.size() + " 道题目,可能存在重复限制。"); + } + + return problems; + } +} \ No newline at end of file -- 2.34.1 From 74c7adc92fe2689a479269ee0d152546b724d736 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:24:52 +0800 Subject: [PATCH 04/42] ADD file via upload --- HighSchoolProblemGenerator.java | 85 +++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 HighSchoolProblemGenerator.java diff --git a/HighSchoolProblemGenerator.java b/HighSchoolProblemGenerator.java new file mode 100644 index 0000000..12c7570 --- /dev/null +++ b/HighSchoolProblemGenerator.java @@ -0,0 +1,85 @@ + import java.text.DecimalFormat; +import java.util.Random; + +public class HighSchoolProblemGenerator extends AbstractProblemGenerator { + public HighSchoolProblemGenerator(Random random, DecimalFormat df) { + super(random, df); + } + + @Override + public MathProblem generate() { + int operandCount = random.nextInt(3) + 3; // 3-5 个操作数 + double[] operandsVal = new double[operandCount]; + String[] displayOperands = new String[operandCount]; + String[] selectedOperators = new String[operandCount - 1]; + + // 生成基本操作数 + for (int i = 0; i < operandCount; i++) { + int v = random.nextInt(100) + 1; + operandsVal[i] = v; + displayOperands[i] = String.valueOf(v); + } + // 运算符选择(更均衡,避免连乘/连除) + String previousOperator = null; + double pPlus = 0.35, pMinus = 0.25, pTimes = 0.25, pDivide = 0.15; + for (int i = 0; i < operandCount - 1; i++) { + String operator; + if ("*".equals(previousOperator) || "/".equals(previousOperator)) { + double randValue = random.nextDouble(); + double total = pPlus + pMinus; + operator = randValue < (pPlus / total) ? "+" : "-"; + } else { + double randValue = random.nextDouble(); + if (randValue < pPlus) operator = "+"; + else if (randValue < pPlus + pMinus) operator = "-"; + else if (randValue < pPlus + pMinus + pTimes) operator = "*"; + else operator = "/"; + } + selectedOperators[i] = operator; + previousOperator = operator; + } + + // 三角函数 + int trigIndex = random.nextInt(operandCount); + String[] functions = {"sin", "cos", "tan"}; + String function = functions[random.nextInt(functions.length)]; + int[] angles = {0, 30, 45, 60, 90}; + int angle = angles[random.nextInt(angles.length)]; + if ("tan".equals(function) && angle == 90) angle = 60; // 避免 tan(90°) + double trigVal = calculateTrigFunction(function, angle); + operandsVal[trigIndex] = trigVal; + displayOperands[trigIndex] = function + angle; + + // 括号选择(显示用 displayOperands,计算用 operandsVal) + boolean addedBracket = false; + int startPos = findBracketStart(operandsVal, selectedOperators, 0.3); + StringBuilder expBuilder = new StringBuilder(); + for (int i = 0; i < operandCount; i++) { + if (startPos != -1 && i == startPos) expBuilder.append("("); + expBuilder.append(displayOperands[i]); + if (startPos != -1 && i == startPos + 1) expBuilder.append(")"); + if (i < operandCount - 1) expBuilder.append(" ").append(selectedOperators[i]).append(" "); + } + String expression = expBuilder.toString(); + + // 计算结果(double) + double result; + if (startPos != -1) { + double bracketResult = applyOperatorDouble(operandsVal[startPos], operandsVal[startPos + 1], selectedOperators[startPos]); + int newCount = operandCount - 1; + double[] newVals = new double[newCount]; + String[] newOps = new String[newCount - 1]; + for (int i = 0; i < startPos; i++) newVals[i] = operandsVal[i]; + newVals[startPos] = bracketResult; + for (int i = startPos + 1; i < newCount; i++) newVals[i] = operandsVal[i + 1]; + for (int i = 0; i < newCount - 1; i++) newOps[i] = (i < startPos) ? selectedOperators[i] : selectedOperators[i + 1]; + result = newVals[0]; + for (int i = 0; i < newCount - 1; i++) result = applyOperatorDouble(result, newVals[i + 1], newOps[i]); + } else { + result = operandsVal[0]; + for (int i = 0; i < operandCount - 1; i++) result = applyOperatorDouble(result, operandsVal[i + 1], selectedOperators[i]); + } + + return new MathProblem(expression, df.format(result), "高中"); + } +} \ No newline at end of file -- 2.34.1 From 5b15395d522bfac68768ff4eb5bce693ce0a2493 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:25:14 +0800 Subject: [PATCH 05/42] ADD file via upload --- MathPaperGenerator.java | 161 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 MathPaperGenerator.java diff --git a/MathPaperGenerator.java b/MathPaperGenerator.java new file mode 100644 index 0000000..6782cb5 --- /dev/null +++ b/MathPaperGenerator.java @@ -0,0 +1,161 @@ +import java.io.IOException; +import java.util.List; +import java.util.Scanner; + +/** + * 数学卷子自动生成程序主类 + */ +public class MathPaperGenerator { + private UserManager userManager; + private MathProblemGenerator problemGenerator; + private FileManager fileManager; + private Scanner scanner; + + public MathPaperGenerator() { + this.userManager = new UserManager(); + this.problemGenerator = new MathProblemGenerator(); + this.fileManager = new FileManager(); + this.scanner = new Scanner(System.in); + } + + /** + * 程序主入口 + */ + public static void main(String[] args) { + MathPaperGenerator generator = new MathPaperGenerator(); + generator.run(); + } + + /** + * 运行主程序 + */ + public void run() { + System.out.println("欢迎使用中小学数学卷子自动生成程序!"); + System.out.println("=" + "=".repeat(40)); + + while (true) { + User currentUser = login(); + if (currentUser != null) { + handleUserSession(currentUser); + } + } + } + + /*用户登录*/ + private User login() { + while (true) { + System.out.print("请输入用户名和密码(用空格隔开): "); + String input = scanner.nextLine().trim(); + + if (input.isEmpty()) { + System.out.println("输入不能为空,请重新输入。"); + continue; + } + + String[] parts = input.split("\\s+"); + String username = parts[0]; + String password = parts[1]; + + User user = userManager.authenticate(username, password); + if (user != null) { + System.out.println("登录成功!当前选择为 " + user.getUserType() + " 出题"); + return user; + } else { + System.out.println("请输入正确的用户名、密码"); + } + } + } + + /** + * 处理用户会话 + * @param user 当前登录用户 + */ + private void handleUserSession(User user) { + String currentDifficulty = user.getUserType(); + + while (true) { + System.out.println("准备生成 " + currentDifficulty + " 数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):"); + String input = scanner.nextLine().trim(); + + // 检查是否要切换类型 + if (input.startsWith("切换为")) { + String newType = input.substring(3).trim(); + if (userManager.isValidUserType(newType)) { + currentDifficulty = newType; + System.out.println("已切换为 " + newType + " 出题模式"); + continue; + } else { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + continue; + } + } + + try { + int count = Integer.parseInt(input); + + if (count == -1) { + System.out.println("退出当前用户,重新登录..."); + System.out.println(); + return; + } + + if (count < 10 || count > 30) { + System.out.println("题目数量必须在10-30之间,请重新输入。"); + continue; + } + + // 生成题目 + generateAndSavePaper(user, currentDifficulty, count); + + } catch (NumberFormatException e) { + System.out.println("请输入有效的数字。"); + } + } + } + + /** + * 生成并保存题目 + * @param user 用户 + * @param difficulty 难度 + * @param count 题目数量 + */ + private void generateAndSavePaper(User user, String difficulty, int count) { + try { + System.out.println("正在生成 " + count + " 道 " + difficulty + " 数学题目..."); + + // 生成不重复的题目 + List problems = fileManager.generateUniqueProblems( + user, problemGenerator, count, difficulty); + + if (problems.size() < count) { + System.out.println("注意:由于重复限制,实际生成了 " + problems.size() + " 道题目。"); + } + + // 保存到文件 + String filePath = fileManager.savePaperToFile(user, problems, difficulty); + + System.out.println("题目生成完成!"); + System.out.println("文件已保存至: " + filePath); + System.out.println("题目预览:"); + System.out.println("-" + "-".repeat(30)); + + // 显示前5道题目作为预览 + int previewCount = Math.min(5, problems.size()); + for (int i = 0; i < previewCount; i++) { + System.out.println((i + 1) + ". " + problems.get(i).toString()); + } + + if (problems.size() > 5) { + System.out.println("... 还有 " + (problems.size() - 5) + " 道题目"); + } + + System.out.println("-" + "-".repeat(30)); + System.out.println(); + + } catch (IOException e) { + System.err.println("保存文件时出错: " + e.getMessage()); + } catch (Exception e) { + System.err.println("生成题目时出错: " + e.getMessage()); + } + } +} \ No newline at end of file -- 2.34.1 From f12493d1a50d4df2d511a846038587563e2ad898 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:25:30 +0800 Subject: [PATCH 06/42] ADD file via upload --- MathProblem.java | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 MathProblem.java diff --git a/MathProblem.java b/MathProblem.java new file mode 100644 index 0000000..29019f9 --- /dev/null +++ b/MathProblem.java @@ -0,0 +1,44 @@ +/** + * 数学题目类,表示一道数学题 + */ +public class MathProblem { + private String expression; // 题目表达式 + private String answer; // 答案 + private String difficulty; // 难度级别 + + public MathProblem(String expression, String answer, String difficulty) { + this.expression = expression; + this.answer = answer; + this.difficulty = difficulty; + } + + public String getExpression() { + return expression; + } + + public String getAnswer() { + return answer; + } + + public String getDifficulty() { + return difficulty; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + MathProblem that = (MathProblem) obj; + return expression.equals(that.expression); + } + + @Override + public int hashCode() { + return expression.hashCode(); + } + + @Override + public String toString() { + return expression + " = ?"; + } +} \ No newline at end of file -- 2.34.1 From b40bf8a8476bbfd5ec8a0c41cbbdd789d0f80cb7 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:25:54 +0800 Subject: [PATCH 07/42] ADD file via upload --- MathProblemGenerator.java | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 MathProblemGenerator.java diff --git a/MathProblemGenerator.java b/MathProblemGenerator.java new file mode 100644 index 0000000..3a65350 --- /dev/null +++ b/MathProblemGenerator.java @@ -0,0 +1,34 @@ +import java.text.DecimalFormat; +import java.util.Random; + +/** + * 数学题目生成器,根据不同难度生成相应的数学题目(外观类) + * 将具体生成逻辑委托给对应子类,保持对外 API 不变。 + */ +public class MathProblemGenerator { + private final Random random; + private final DecimalFormat df; + + public MathProblemGenerator() { + this.random = new Random(); + this.df = new DecimalFormat("#.##"); + } + + /** + * 根据难度生成数学题目 + * @param difficulty 难度级别(小学、初中、高中) + * @return 生成的数学题目 + */ + public MathProblem generateProblem(String difficulty) { + switch (difficulty) { + case "小学": + return new ElementaryProblemGenerator(random, df).generate(); + case "初中": + return new MiddleSchoolProblemGenerator(random, df).generate(); + case "高中": + return new HighSchoolProblemGenerator(random, df).generate(); + default: + throw new IllegalArgumentException("不支持的难度级别: " + difficulty); + } + } +} \ No newline at end of file -- 2.34.1 From 0ca93eb99c5d41a140c14df8225fa96dfe033c56 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:26:18 +0800 Subject: [PATCH 08/42] ADD file via upload --- MiddleSchoolProblemGenerator.java | 69 +++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 MiddleSchoolProblemGenerator.java diff --git a/MiddleSchoolProblemGenerator.java b/MiddleSchoolProblemGenerator.java new file mode 100644 index 0000000..4035743 --- /dev/null +++ b/MiddleSchoolProblemGenerator.java @@ -0,0 +1,69 @@ +import java.text.DecimalFormat; +import java.util.Random; + +public class MiddleSchoolProblemGenerator extends AbstractProblemGenerator { + public MiddleSchoolProblemGenerator(Random random, DecimalFormat df) { + super(random, df); + } + + @Override + public MathProblem generate() { + int operandCount = random.nextInt(3) + 3; // 3-5 个操作数 + int[] operands = new int[operandCount]; + String[] selectedOperators = new String[operandCount - 1]; + String[] displayOperands = new String[operandCount]; + String[] operatorPool = {"+", "-", "*", "/"}; + + for (int i = 0; i < operandCount; i++) { + operands[i] = random.nextInt(100) + 1; + displayOperands[i] = String.valueOf(operands[i]); + } + for (int i = 0; i < operandCount - 1; i++) { + selectedOperators[i] = operatorPool[random.nextInt(operatorPool.length)]; + } + + // 平方或根号 + int specialOperandIndex = random.nextInt(operandCount); + boolean useSquareRoot = random.nextBoolean(); + if (useSquareRoot) { + int base = random.nextInt(24) + 2; //2-25 + int perfectSquare = base * base; + operands[specialOperandIndex] = base; // √(base^2) = base + displayOperands[specialOperandIndex] = "√" + perfectSquare; + } else { + int base = random.nextInt(9) + 2; // 2-10 + int square = base * base; + operands[specialOperandIndex] = square; + displayOperands[specialOperandIndex] = base + "²"; + } + + // 括号选择 + boolean addedBracket = false; + int bracketStartIndex = findBracketStart(toDoubleArray(operands), selectedOperators, 0.3); + String expression; + double result; + if (bracketStartIndex != -1) { + // 构建带括号(显示用 displayOperands) + StringBuilder expressionBuilder = new StringBuilder(); + for (int i = 0; i < operandCount; i++) { + if (i == bracketStartIndex) expressionBuilder.append("("); + expressionBuilder.append(displayOperands[i]); + if (i == bracketStartIndex + 1) expressionBuilder.append(")"); + if (i < operandCount - 1) expressionBuilder.append(" ").append(selectedOperators[i]).append(" "); + } + expression = expressionBuilder.toString(); + result = evaluateExpressionWithBrackets(operands, selectedOperators, bracketStartIndex); + } else { + StringBuilder expressionBuilder = new StringBuilder(); + expressionBuilder.append(displayOperands[0]); + result = operands[0]; + for (int i = 0; i < operandCount - 1; i++) { + expressionBuilder.append(" ").append(selectedOperators[i]).append(" ").append(displayOperands[i + 1]); + result = applyOperator(result, operands[i + 1], selectedOperators[i]); + } + expression = expressionBuilder.toString(); + } + + return new MathProblem(expression, df.format(result), "初中"); + } +} \ No newline at end of file -- 2.34.1 From adfce719ed19c54a135543fbc217b22a0a59eda3 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:26:50 +0800 Subject: [PATCH 09/42] ADD file via upload --- UserManager.java | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 UserManager.java diff --git a/UserManager.java b/UserManager.java new file mode 100644 index 0000000..6458b12 --- /dev/null +++ b/UserManager.java @@ -0,0 +1,58 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * 用户管理类,负责用户验证和账户管理 + */ +public class UserManager { + private Map users; + + public UserManager() { + initializeUsers(); + } + + /** + * 初始化预设用户账户 + */ + private void initializeUsers() { + users = new HashMap<>(); + + // 小学账户 + users.put("张三1", new User("张三1", "123", "小学")); + users.put("张三2", new User("张三2", "123", "小学")); + users.put("张三3", new User("张三3", "123", "小学")); + + // 初中账户 + users.put("李四1", new User("李四1", "123", "初中")); + users.put("李四2", new User("李四2", "123", "初中")); + users.put("李四3", new User("李四3", "123", "初中")); + + // 高中账户 + users.put("王五1", new User("王五1", "123", "高中")); + users.put("王五2", new User("王五2", "123", "高中")); + users.put("王五3", new User("王五3", "123", "高中")); + } + + /** + * 验证用户登录 + * @param username 用户名 + * @param password 密码 + * @return 验证成功返回用户对象,失败返回null + */ + public User authenticate(String username, String password) { + User user = users.get(username); + if (user != null && user.getPassword().equals(password)) { + return user; + } + return null; + } + + /** + * 检查用户类型是否有效 + * @param userType 用户类型 + * @return 是否有效 + */ + public boolean isValidUserType(String userType) { + return "小学".equals(userType) || "初中".equals(userType) || "高中".equals(userType); + } +} \ No newline at end of file -- 2.34.1 From fd81aadd7adfcab0ab7068a8c9cd0e55c4f91013 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:27:14 +0800 Subject: [PATCH 10/42] ADD file via upload --- User.java | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 User.java diff --git a/User.java b/User.java new file mode 100644 index 0000000..6cc1bbf --- /dev/null +++ b/User.java @@ -0,0 +1,42 @@ +/** + * 用户类,用于管理账户信息 + */ +public class User { + private String username; + private String password; + private String userType; // 小学、初中、高中 + + public User(String username, String password, String userType) { + this.username = username; + this.password = password; + this.userType = userType; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getUserType() { + return userType; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + User user = (User) obj; + return username.equals(user.username) && password.equals(user.password); + } + + @Override + public String toString() { + return "User{" + + "username='" + username + '\'' + + ", userType='" + userType + '\'' + + '}'; + } +} \ No newline at end of file -- 2.34.1 From 42ab37bdef44466f6ea7ee3437ff963e04054819 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:51:52 +0800 Subject: [PATCH 11/42] Delete 'UserManager.java' --- UserManager.java | 58 ------------------------------------------------ 1 file changed, 58 deletions(-) delete mode 100644 UserManager.java diff --git a/UserManager.java b/UserManager.java deleted file mode 100644 index 6458b12..0000000 --- a/UserManager.java +++ /dev/null @@ -1,58 +0,0 @@ -import java.util.HashMap; -import java.util.Map; - -/** - * 用户管理类,负责用户验证和账户管理 - */ -public class UserManager { - private Map users; - - public UserManager() { - initializeUsers(); - } - - /** - * 初始化预设用户账户 - */ - private void initializeUsers() { - users = new HashMap<>(); - - // 小学账户 - users.put("张三1", new User("张三1", "123", "小学")); - users.put("张三2", new User("张三2", "123", "小学")); - users.put("张三3", new User("张三3", "123", "小学")); - - // 初中账户 - users.put("李四1", new User("李四1", "123", "初中")); - users.put("李四2", new User("李四2", "123", "初中")); - users.put("李四3", new User("李四3", "123", "初中")); - - // 高中账户 - users.put("王五1", new User("王五1", "123", "高中")); - users.put("王五2", new User("王五2", "123", "高中")); - users.put("王五3", new User("王五3", "123", "高中")); - } - - /** - * 验证用户登录 - * @param username 用户名 - * @param password 密码 - * @return 验证成功返回用户对象,失败返回null - */ - public User authenticate(String username, String password) { - User user = users.get(username); - if (user != null && user.getPassword().equals(password)) { - return user; - } - return null; - } - - /** - * 检查用户类型是否有效 - * @param userType 用户类型 - * @return 是否有效 - */ - public boolean isValidUserType(String userType) { - return "小学".equals(userType) || "初中".equals(userType) || "高中".equals(userType); - } -} \ No newline at end of file -- 2.34.1 From ed794948f26a00f4372a8e4c6ffb8139c7492483 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:52:05 +0800 Subject: [PATCH 12/42] Delete 'AbstractProblemGenerator.java' --- AbstractProblemGenerator.java | 124 ---------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 AbstractProblemGenerator.java diff --git a/AbstractProblemGenerator.java b/AbstractProblemGenerator.java deleted file mode 100644 index 82b61a2..0000000 --- a/AbstractProblemGenerator.java +++ /dev/null @@ -1,124 +0,0 @@ -import java.text.DecimalFormat; -import java.util.Random; - -/** - * 抽象题目生成器:封装公共工具方法与共享状态 - */ -public abstract class AbstractProblemGenerator { - protected final Random random; - protected final DecimalFormat df; - - protected AbstractProblemGenerator(Random random, DecimalFormat df) { - this.random = random; - this.df = df; - } - - /** - * 子类实现具体题目生成逻辑 - */ - public abstract MathProblem generate(); - - // 构建带括号的表达式(只包两个操作数) - protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - StringBuilder expression = new StringBuilder(); - for (int i = 0; i < operands.length; i++) { - if (i == startPos) { - expression.append("("); - } - expression.append(operands[i]); - if (i == startPos + 1) { - expression.append(")"); - } - if (i < operands.length - 1) { - expression.append(" ").append(operators[i]).append(" "); - } - } - return expression.toString(); - } - - // 计算带括号的表达式结果(只合并两个操作数) - protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); - int newOperandCount = operands.length - 1; - int[] newOperands = new int[newOperandCount]; - String[] newOperators = new String[newOperandCount - 1]; - for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; - newOperands[startPos] = (int) bracketResult; - for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; - for (int i = 0; i < newOperandCount - 1; i++) { - if (i < startPos) newOperators[i] = operators[i]; - else newOperators[i] = operators[i + 1]; - } - double result = newOperands[0]; - for (int i = 0; i < newOperandCount - 1; i++) { - result = applyOperator(result, newOperands[i + 1], newOperators[i]); - } - return result; - } - - /** 应用运算符(整数右操作数) */ - protected double applyOperator(double left, int right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 计算三角函数值 */ - protected double calculateTrigFunction(String function, int angle) { - double radians = Math.toRadians(angle); - switch (function) { - case "sin": return Math.sin(radians); - case "cos": return Math.cos(radians); - case "tan": - if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 - return Math.tan(radians); - default: return 0; - } - } - - /** Double 版本的运算符应用(用于包含三角函数的计算) */ - protected double applyOperatorDouble(double left, double right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0.0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 将 int 数组转 double 数组 */ - protected double[] toDoubleArray(int[] arr) { - double[] out = new double[arr.length]; - for (int i = 0; i < arr.length; i++) out[i] = arr[i]; - return out; - } - - /** - * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 - */ - protected int findBracketStart(double[] values, String[] operators, double probability) { - if (values == null || operators == null) return -1; - if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 - if (random.nextDouble() >= probability) return -1; - int maxStart = values.length - 2; // 仅包两个操作数 - int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; - int candidateCount = 0; - for (int s = 0; s <= maxStart; s++) { - boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); - boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); - boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); - if (insideLow && (leftHigh || rightHigh)) { - candidateStarts[candidateCount++] = s; - } - } - if (candidateCount == 0) return -1; - int candidate = candidateStarts[random.nextInt(candidateCount)]; - double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]); - return (bracketResult != 0.0) ? candidate : -1; - } -} \ No newline at end of file -- 2.34.1 From 59651fa15108f4fcf4f6e458601e32c423ff1ae3 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:07 +0800 Subject: [PATCH 13/42] ADD file via upload --- develope/src | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 develope/src diff --git a/develope/src b/develope/src new file mode 100644 index 0000000..afb83fd --- /dev/null +++ b/develope/src @@ -0,0 +1,125 @@ +import java.text.DecimalFormat; +import java.util.Random; + +/** + * 抽象题目生成器:封装公共工具方法与共享状态 + */ +public abstract class AbstractProblemGenerator { + protected final Random random; + protected final DecimalFormat df; + + protected AbstractProblemGenerator(Random random, DecimalFormat df) { + this.random = random; + this.df = df; + } + + /** + * 子类实现具体题目生成逻辑 + */ + public abstract MathProblem generate(); + + // 构建带括号的表达式(只包两个操作数) + protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + StringBuilder expression = new StringBuilder(); + for (int i = 0; i < operands.length; i++) { + if (i == startPos) { + expression.append("("); + } + expression.append(operands[i]); + if (i == startPos + 1) { + expression.append(")"); + } + if (i < operands.length - 1) { + expression.append(" ").append(operators[i]).append(" "); + } + } + return expression.toString(); + } + + // 计算带括号的表达式结果(只合并两个操作数) + protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); + int newOperandCount = operands.length - 1; + int[] newOperands = new int[newOperandCount]; + String[] newOperators = new String[newOperandCount - 1]; + for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; + newOperands[startPos] = (int) bracketResult; + for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; + for (int i = 0; i < newOperandCount - 1; i++) { + if (i < startPos) newOperators[i] = operators[i]; + else newOperators[i] = operators[i + 1]; + } + double result = newOperands[0]; + for (int i = 0; i < newOperandCount - 1; i++) { + result = applyOperator(result, newOperands[i + 1], newOperators[i]); + } + return result; + } + + /** 应用运算符(整数右操作数) */ + protected double applyOperator(double left, int right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 计算三角函数值 */ + protected double calculateTrigFunction(String function, int angle) { + double radians = Math.toRadians(angle); + switch (function) { + case "sin": return Math.sin(radians); + case "cos": return Math.cos(radians); + case "tan": + if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 + return Math.tan(radians); + default: return 0; + } + } + + /** Double 版本的运算符应用(用于包含三角函数的计算) */ + protected double applyOperatorDouble(double left, double right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0.0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 将 int 数组转 double 数组 */ + protected double[] toDoubleArray(int[] arr) { + double[] out = new double[arr.length]; + for (int i = 0; i < arr.length; i++) out[i] = arr[i]; + return out; + } + + /** + * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 + */ + protected int findBracketStart(double[] values, String[] operators, double probability) { + if (values == null || operators == null) return -1; + if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 + if (random.nextDouble() >= probability) return -1;//有括号的情况为人为设置,现在概率为0.3 + int maxStart = values.length - 2; // 仅包两个操作数 + int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; + int candidateCount = 0; + //只有改变运算顺序的括号才有意义 + for (int s = 0; s <= maxStart; s++) { + boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); + boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); + boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); + if (insideLow && (leftHigh || rightHigh)) { + candidateStarts[candidateCount++] = s; + } + } + if (candidateCount == 0) return -1; + int candidate = candidateStarts[random.nextInt(candidateCount)]; + double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);//避免括号内结果为0 + return (bracketResult != 0.0) ? candidate : -1; + } +} \ No newline at end of file -- 2.34.1 From bfc8860a75a268f550ca51c157f44c407713d43f Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:19 +0800 Subject: [PATCH 14/42] Delete 'develope/src' --- develope/src | 125 --------------------------------------------------- 1 file changed, 125 deletions(-) delete mode 100644 develope/src diff --git a/develope/src b/develope/src deleted file mode 100644 index afb83fd..0000000 --- a/develope/src +++ /dev/null @@ -1,125 +0,0 @@ -import java.text.DecimalFormat; -import java.util.Random; - -/** - * 抽象题目生成器:封装公共工具方法与共享状态 - */ -public abstract class AbstractProblemGenerator { - protected final Random random; - protected final DecimalFormat df; - - protected AbstractProblemGenerator(Random random, DecimalFormat df) { - this.random = random; - this.df = df; - } - - /** - * 子类实现具体题目生成逻辑 - */ - public abstract MathProblem generate(); - - // 构建带括号的表达式(只包两个操作数) - protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - StringBuilder expression = new StringBuilder(); - for (int i = 0; i < operands.length; i++) { - if (i == startPos) { - expression.append("("); - } - expression.append(operands[i]); - if (i == startPos + 1) { - expression.append(")"); - } - if (i < operands.length - 1) { - expression.append(" ").append(operators[i]).append(" "); - } - } - return expression.toString(); - } - - // 计算带括号的表达式结果(只合并两个操作数) - protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); - int newOperandCount = operands.length - 1; - int[] newOperands = new int[newOperandCount]; - String[] newOperators = new String[newOperandCount - 1]; - for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; - newOperands[startPos] = (int) bracketResult; - for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; - for (int i = 0; i < newOperandCount - 1; i++) { - if (i < startPos) newOperators[i] = operators[i]; - else newOperators[i] = operators[i + 1]; - } - double result = newOperands[0]; - for (int i = 0; i < newOperandCount - 1; i++) { - result = applyOperator(result, newOperands[i + 1], newOperators[i]); - } - return result; - } - - /** 应用运算符(整数右操作数) */ - protected double applyOperator(double left, int right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 计算三角函数值 */ - protected double calculateTrigFunction(String function, int angle) { - double radians = Math.toRadians(angle); - switch (function) { - case "sin": return Math.sin(radians); - case "cos": return Math.cos(radians); - case "tan": - if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 - return Math.tan(radians); - default: return 0; - } - } - - /** Double 版本的运算符应用(用于包含三角函数的计算) */ - protected double applyOperatorDouble(double left, double right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0.0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 将 int 数组转 double 数组 */ - protected double[] toDoubleArray(int[] arr) { - double[] out = new double[arr.length]; - for (int i = 0; i < arr.length; i++) out[i] = arr[i]; - return out; - } - - /** - * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 - */ - protected int findBracketStart(double[] values, String[] operators, double probability) { - if (values == null || operators == null) return -1; - if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 - if (random.nextDouble() >= probability) return -1;//有括号的情况为人为设置,现在概率为0.3 - int maxStart = values.length - 2; // 仅包两个操作数 - int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; - int candidateCount = 0; - //只有改变运算顺序的括号才有意义 - for (int s = 0; s <= maxStart; s++) { - boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); - boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); - boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); - if (insideLow && (leftHigh || rightHigh)) { - candidateStarts[candidateCount++] = s; - } - } - if (candidateCount == 0) return -1; - int candidate = candidateStarts[random.nextInt(candidateCount)]; - double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);//避免括号内结果为0 - return (bracketResult != 0.0) ? candidate : -1; - } -} \ No newline at end of file -- 2.34.1 From e3e75647d2d2e15676f649c2e002b34b97ebea4c Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:27 +0800 Subject: [PATCH 15/42] Delete 'ElementaryProblemGenerator.java' --- ElementaryProblemGenerator.java | 67 --------------------------------- 1 file changed, 67 deletions(-) delete mode 100644 ElementaryProblemGenerator.java diff --git a/ElementaryProblemGenerator.java b/ElementaryProblemGenerator.java deleted file mode 100644 index 612612d..0000000 --- a/ElementaryProblemGenerator.java +++ /dev/null @@ -1,67 +0,0 @@ -import java.text.DecimalFormat; -import java.util.Random; - -public class ElementaryProblemGenerator extends AbstractProblemGenerator { - public ElementaryProblemGenerator(Random random, DecimalFormat df) { - super(random, df); - } - - @Override - public MathProblem generate() { - // 小学题目要求:答案不得为负数。最多尝试若干次生成,若仍为负则回退到简单加法题。 - int maxAttempts = 50; - for (int attempt = 0; attempt < maxAttempts; attempt++) { - int operandCount = random.nextInt(4) + 2; // 2-5个操作数 - String[] operators = {"+", "-", "*", "/"}; - int[] operands = new int[operandCount]; - String[] selectedOperators = new String[operandCount - 1]; - for (int i = 0; i < operandCount; i++) operands[i] = random.nextInt(100) + 1; - // 运算符选择(避免连乘/连除,调整概率) - String previousOperator = null; - double pPlus = 0.45, pMinus = 0.35, pTimes = 0.15, pDivide = 0.05; - for (int i = 0; i < operandCount - 1; i++) { - String operator; - if ("*".equals(previousOperator) || "/".equals(previousOperator)) { - double randValue = random.nextDouble(); - double total = pPlus + pMinus; - operator = randValue < (pPlus / total) ? "+" : "-"; - } else { - double randValue = random.nextDouble(); - if (randValue < pPlus) operator = "+"; - else if (randValue < pPlus + pMinus) operator = "-"; - else if (randValue < pPlus + pMinus + pTimes) operator = "*"; - else operator = "/"; - } - selectedOperators[i] = operator; - previousOperator = operator; - } - // 括号选择 - int startPos = findBracketStart(toDoubleArray(operands), selectedOperators, 0.3); - String expression; - double result; - if (startPos != -1) { - expression = buildExpressionWithBrackets(operands, selectedOperators, startPos); - result = evaluateExpressionWithBrackets(operands, selectedOperators, startPos); - } else { - StringBuilder expBuilder = new StringBuilder(); - expBuilder.append(operands[0]); - result = operands[0]; - for (int i = 0; i < operandCount - 1; i++) { - expBuilder.append(" ").append(selectedOperators[i]).append(" ").append(operands[i + 1]); - result = applyOperator(result, operands[i + 1], selectedOperators[i]); - } - expression = expBuilder.toString(); - } - if (result >= 0) { - return new MathProblem(expression, df.format(result), "小学"); - } - // 如果为负数,继续下一次尝试 - } - // 回退:生成一个保证非负的简单加法题 - int a = random.nextInt(100) + 1; - int b = random.nextInt(100) + 1; - String expression = a + " + " + b; - double result = a + b; - return new MathProblem(expression, df.format(result), "小学"); - } -} \ No newline at end of file -- 2.34.1 From e7bcd493327226ec50791760fac93b6324fe568a Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:33 +0800 Subject: [PATCH 16/42] Delete 'FileManager.java' --- FileManager.java | 137 ----------------------------------------------- 1 file changed, 137 deletions(-) delete mode 100644 FileManager.java diff --git a/FileManager.java b/FileManager.java deleted file mode 100644 index e132798..0000000 --- a/FileManager.java +++ /dev/null @@ -1,137 +0,0 @@ -import java.io.*; -import java.nio.file.*; -import java.nio.charset.StandardCharsets; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.*; - -/** - * 文件管理类,负责题目的保存和历史题目的管理 - */ -public class FileManager { - private static final String BASE_DIR = "math_papers"; - private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"); - - /** - * 保存题目到文件 - * @param user 用户信息 - * @param problems 题目列表 - * @param difficulty 难度级别(当前选择) - * @return 保存的文件路径 - */ - public String savePaperToFile(User user, List problems, String difficulty) throws IOException { - // 创建用户文件夹 - String userDir = BASE_DIR + File.separator + user.getUsername(); - Files.createDirectories(Paths.get(userDir)); - - // 生成文件名 - String timestamp = LocalDateTime.now().format(formatter); - String fileName = timestamp + ".txt"; - String filePath = userDir + File.separator + fileName; - - // 写入题目到文件 - try (PrintWriter writer = new PrintWriter(new FileWriter(filePath, StandardCharsets.UTF_8))) { - writer.println("数学题目卷子"); - writer.println("用户: " + user.getUsername()); - writer.println("类型: " + difficulty); - writer.println("生成时间: " + timestamp.replace("-", "/").replace("-", ":")); - writer.println("题目数量: " + problems.size()); - writer.println("=" + "=".repeat(50)); - writer.println(); - - for (int i = 0; i < problems.size(); i++) { - writer.println((i + 1) + ". " + problems.get(i).toString()); - writer.println(); // 每题之间空一行 - } - } - - return filePath; - } - - /** - * 获取用户历史题目,用于重复检测 - * @param username 用户名 - * @return 历史题目集合 - */ - public Set getUserHistoryProblems(String username) { - Set historyProblems = new HashSet<>(); - String userDir = BASE_DIR + File.separator + username; - - try { - Path userPath = Paths.get(userDir); - if (!Files.exists(userPath)) { - return historyProblems; - } - - // 遍历用户文件夹中的所有txt文件 - Files.walk(userPath) - .filter(path -> path.toString().endsWith(".txt")) - .forEach(path -> { - try { - List lines = Files.readAllLines(path, StandardCharsets.UTF_8); - for (String line : lines) { - // 提取题目表达式(格式:数字. 表达式 = ?) - if (line.matches("^\\d+\\. .+ = \\?$")) { - String expression = line.substring(line.indexOf(". ") + 2, line.lastIndexOf(" = ?")); - historyProblems.add(expression); - } - } - } catch (IOException e) { - System.err.println("读取文件失败: " + path); - } - }); - } catch (IOException e) { - System.err.println("访问用户目录失败: " + userDir); - } - - return historyProblems; - } - - /** - * 检查题目是否重复 - * @param username 用户名 - * @param problem 要检查的题目 - * @return 是否重复 - */ - public boolean isDuplicateProblem(String username, MathProblem problem) { - Set historyProblems = getUserHistoryProblems(username); - return historyProblems.contains(problem.getExpression()); - } - - /** - * 生成不重复的题目列表 - * @param user 用户信息 - * @param generator 题目生成器 - * @param count 题目数量 - * @param difficulty 难度级别 - * @return 不重复的题目列表 - */ - public List generateUniqueProblems(User user, MathProblemGenerator generator, - int count, String difficulty) { - List problems = new ArrayList<>(); - Set historyProblems = getUserHistoryProblems(user.getUsername()); - Set currentProblems = new HashSet<>(); - - int attempts = 0; - int maxAttempts = count * 10; // 最多尝试次数,避免无限循环 - - while (problems.size() < count && attempts < maxAttempts) { - MathProblem problem = generator.generateProblem(difficulty); - String expression = problem.getExpression(); - - // 检查是否与历史题目或当前题目重复 - if (!historyProblems.contains(expression) && !currentProblems.contains(expression)) { - problems.add(problem); - currentProblems.add(expression); - } - - attempts++; - } - - if (problems.size() < count) { - System.out.println("警告: 只生成了 " + problems.size() + " 道题目,可能存在重复限制。"); - } - - return problems; - } -} \ No newline at end of file -- 2.34.1 From ea8aff1802faa098b99ff10f45aeab50bc9d8894 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:37 +0800 Subject: [PATCH 17/42] Delete 'HighSchoolProblemGenerator.java' --- HighSchoolProblemGenerator.java | 85 --------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 HighSchoolProblemGenerator.java diff --git a/HighSchoolProblemGenerator.java b/HighSchoolProblemGenerator.java deleted file mode 100644 index 12c7570..0000000 --- a/HighSchoolProblemGenerator.java +++ /dev/null @@ -1,85 +0,0 @@ - import java.text.DecimalFormat; -import java.util.Random; - -public class HighSchoolProblemGenerator extends AbstractProblemGenerator { - public HighSchoolProblemGenerator(Random random, DecimalFormat df) { - super(random, df); - } - - @Override - public MathProblem generate() { - int operandCount = random.nextInt(3) + 3; // 3-5 个操作数 - double[] operandsVal = new double[operandCount]; - String[] displayOperands = new String[operandCount]; - String[] selectedOperators = new String[operandCount - 1]; - - // 生成基本操作数 - for (int i = 0; i < operandCount; i++) { - int v = random.nextInt(100) + 1; - operandsVal[i] = v; - displayOperands[i] = String.valueOf(v); - } - // 运算符选择(更均衡,避免连乘/连除) - String previousOperator = null; - double pPlus = 0.35, pMinus = 0.25, pTimes = 0.25, pDivide = 0.15; - for (int i = 0; i < operandCount - 1; i++) { - String operator; - if ("*".equals(previousOperator) || "/".equals(previousOperator)) { - double randValue = random.nextDouble(); - double total = pPlus + pMinus; - operator = randValue < (pPlus / total) ? "+" : "-"; - } else { - double randValue = random.nextDouble(); - if (randValue < pPlus) operator = "+"; - else if (randValue < pPlus + pMinus) operator = "-"; - else if (randValue < pPlus + pMinus + pTimes) operator = "*"; - else operator = "/"; - } - selectedOperators[i] = operator; - previousOperator = operator; - } - - // 三角函数 - int trigIndex = random.nextInt(operandCount); - String[] functions = {"sin", "cos", "tan"}; - String function = functions[random.nextInt(functions.length)]; - int[] angles = {0, 30, 45, 60, 90}; - int angle = angles[random.nextInt(angles.length)]; - if ("tan".equals(function) && angle == 90) angle = 60; // 避免 tan(90°) - double trigVal = calculateTrigFunction(function, angle); - operandsVal[trigIndex] = trigVal; - displayOperands[trigIndex] = function + angle; - - // 括号选择(显示用 displayOperands,计算用 operandsVal) - boolean addedBracket = false; - int startPos = findBracketStart(operandsVal, selectedOperators, 0.3); - StringBuilder expBuilder = new StringBuilder(); - for (int i = 0; i < operandCount; i++) { - if (startPos != -1 && i == startPos) expBuilder.append("("); - expBuilder.append(displayOperands[i]); - if (startPos != -1 && i == startPos + 1) expBuilder.append(")"); - if (i < operandCount - 1) expBuilder.append(" ").append(selectedOperators[i]).append(" "); - } - String expression = expBuilder.toString(); - - // 计算结果(double) - double result; - if (startPos != -1) { - double bracketResult = applyOperatorDouble(operandsVal[startPos], operandsVal[startPos + 1], selectedOperators[startPos]); - int newCount = operandCount - 1; - double[] newVals = new double[newCount]; - String[] newOps = new String[newCount - 1]; - for (int i = 0; i < startPos; i++) newVals[i] = operandsVal[i]; - newVals[startPos] = bracketResult; - for (int i = startPos + 1; i < newCount; i++) newVals[i] = operandsVal[i + 1]; - for (int i = 0; i < newCount - 1; i++) newOps[i] = (i < startPos) ? selectedOperators[i] : selectedOperators[i + 1]; - result = newVals[0]; - for (int i = 0; i < newCount - 1; i++) result = applyOperatorDouble(result, newVals[i + 1], newOps[i]); - } else { - result = operandsVal[0]; - for (int i = 0; i < operandCount - 1; i++) result = applyOperatorDouble(result, operandsVal[i + 1], selectedOperators[i]); - } - - return new MathProblem(expression, df.format(result), "高中"); - } -} \ No newline at end of file -- 2.34.1 From 38ad4939f3f2a839100a18f230760350b3d59a38 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:41 +0800 Subject: [PATCH 18/42] Delete 'MathPaperGenerator.java' --- MathPaperGenerator.java | 161 ---------------------------------------- 1 file changed, 161 deletions(-) delete mode 100644 MathPaperGenerator.java diff --git a/MathPaperGenerator.java b/MathPaperGenerator.java deleted file mode 100644 index 6782cb5..0000000 --- a/MathPaperGenerator.java +++ /dev/null @@ -1,161 +0,0 @@ -import java.io.IOException; -import java.util.List; -import java.util.Scanner; - -/** - * 数学卷子自动生成程序主类 - */ -public class MathPaperGenerator { - private UserManager userManager; - private MathProblemGenerator problemGenerator; - private FileManager fileManager; - private Scanner scanner; - - public MathPaperGenerator() { - this.userManager = new UserManager(); - this.problemGenerator = new MathProblemGenerator(); - this.fileManager = new FileManager(); - this.scanner = new Scanner(System.in); - } - - /** - * 程序主入口 - */ - public static void main(String[] args) { - MathPaperGenerator generator = new MathPaperGenerator(); - generator.run(); - } - - /** - * 运行主程序 - */ - public void run() { - System.out.println("欢迎使用中小学数学卷子自动生成程序!"); - System.out.println("=" + "=".repeat(40)); - - while (true) { - User currentUser = login(); - if (currentUser != null) { - handleUserSession(currentUser); - } - } - } - - /*用户登录*/ - private User login() { - while (true) { - System.out.print("请输入用户名和密码(用空格隔开): "); - String input = scanner.nextLine().trim(); - - if (input.isEmpty()) { - System.out.println("输入不能为空,请重新输入。"); - continue; - } - - String[] parts = input.split("\\s+"); - String username = parts[0]; - String password = parts[1]; - - User user = userManager.authenticate(username, password); - if (user != null) { - System.out.println("登录成功!当前选择为 " + user.getUserType() + " 出题"); - return user; - } else { - System.out.println("请输入正确的用户名、密码"); - } - } - } - - /** - * 处理用户会话 - * @param user 当前登录用户 - */ - private void handleUserSession(User user) { - String currentDifficulty = user.getUserType(); - - while (true) { - System.out.println("准备生成 " + currentDifficulty + " 数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):"); - String input = scanner.nextLine().trim(); - - // 检查是否要切换类型 - if (input.startsWith("切换为")) { - String newType = input.substring(3).trim(); - if (userManager.isValidUserType(newType)) { - currentDifficulty = newType; - System.out.println("已切换为 " + newType + " 出题模式"); - continue; - } else { - System.out.println("请输入小学、初中和高中三个选项中的一个"); - continue; - } - } - - try { - int count = Integer.parseInt(input); - - if (count == -1) { - System.out.println("退出当前用户,重新登录..."); - System.out.println(); - return; - } - - if (count < 10 || count > 30) { - System.out.println("题目数量必须在10-30之间,请重新输入。"); - continue; - } - - // 生成题目 - generateAndSavePaper(user, currentDifficulty, count); - - } catch (NumberFormatException e) { - System.out.println("请输入有效的数字。"); - } - } - } - - /** - * 生成并保存题目 - * @param user 用户 - * @param difficulty 难度 - * @param count 题目数量 - */ - private void generateAndSavePaper(User user, String difficulty, int count) { - try { - System.out.println("正在生成 " + count + " 道 " + difficulty + " 数学题目..."); - - // 生成不重复的题目 - List problems = fileManager.generateUniqueProblems( - user, problemGenerator, count, difficulty); - - if (problems.size() < count) { - System.out.println("注意:由于重复限制,实际生成了 " + problems.size() + " 道题目。"); - } - - // 保存到文件 - String filePath = fileManager.savePaperToFile(user, problems, difficulty); - - System.out.println("题目生成完成!"); - System.out.println("文件已保存至: " + filePath); - System.out.println("题目预览:"); - System.out.println("-" + "-".repeat(30)); - - // 显示前5道题目作为预览 - int previewCount = Math.min(5, problems.size()); - for (int i = 0; i < previewCount; i++) { - System.out.println((i + 1) + ". " + problems.get(i).toString()); - } - - if (problems.size() > 5) { - System.out.println("... 还有 " + (problems.size() - 5) + " 道题目"); - } - - System.out.println("-" + "-".repeat(30)); - System.out.println(); - - } catch (IOException e) { - System.err.println("保存文件时出错: " + e.getMessage()); - } catch (Exception e) { - System.err.println("生成题目时出错: " + e.getMessage()); - } - } -} \ No newline at end of file -- 2.34.1 From c2d8db3d2bed497cc001f921a96d24d0df4e188c Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:46 +0800 Subject: [PATCH 19/42] Delete 'MathProblem.java' --- MathProblem.java | 44 -------------------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 MathProblem.java diff --git a/MathProblem.java b/MathProblem.java deleted file mode 100644 index 29019f9..0000000 --- a/MathProblem.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * 数学题目类,表示一道数学题 - */ -public class MathProblem { - private String expression; // 题目表达式 - private String answer; // 答案 - private String difficulty; // 难度级别 - - public MathProblem(String expression, String answer, String difficulty) { - this.expression = expression; - this.answer = answer; - this.difficulty = difficulty; - } - - public String getExpression() { - return expression; - } - - public String getAnswer() { - return answer; - } - - public String getDifficulty() { - return difficulty; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - MathProblem that = (MathProblem) obj; - return expression.equals(that.expression); - } - - @Override - public int hashCode() { - return expression.hashCode(); - } - - @Override - public String toString() { - return expression + " = ?"; - } -} \ No newline at end of file -- 2.34.1 From 962812e130886cc63ed023f108576cf0f7fe6d48 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:51 +0800 Subject: [PATCH 20/42] Delete 'MathProblemGenerator.java' --- MathProblemGenerator.java | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 MathProblemGenerator.java diff --git a/MathProblemGenerator.java b/MathProblemGenerator.java deleted file mode 100644 index 3a65350..0000000 --- a/MathProblemGenerator.java +++ /dev/null @@ -1,34 +0,0 @@ -import java.text.DecimalFormat; -import java.util.Random; - -/** - * 数学题目生成器,根据不同难度生成相应的数学题目(外观类) - * 将具体生成逻辑委托给对应子类,保持对外 API 不变。 - */ -public class MathProblemGenerator { - private final Random random; - private final DecimalFormat df; - - public MathProblemGenerator() { - this.random = new Random(); - this.df = new DecimalFormat("#.##"); - } - - /** - * 根据难度生成数学题目 - * @param difficulty 难度级别(小学、初中、高中) - * @return 生成的数学题目 - */ - public MathProblem generateProblem(String difficulty) { - switch (difficulty) { - case "小学": - return new ElementaryProblemGenerator(random, df).generate(); - case "初中": - return new MiddleSchoolProblemGenerator(random, df).generate(); - case "高中": - return new HighSchoolProblemGenerator(random, df).generate(); - default: - throw new IllegalArgumentException("不支持的难度级别: " + difficulty); - } - } -} \ No newline at end of file -- 2.34.1 From 03aadcbe0013976338fef3cf7351375dc14ab3fb Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:55 +0800 Subject: [PATCH 21/42] Delete 'MiddleSchoolProblemGenerator.java' --- MiddleSchoolProblemGenerator.java | 69 ------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 MiddleSchoolProblemGenerator.java diff --git a/MiddleSchoolProblemGenerator.java b/MiddleSchoolProblemGenerator.java deleted file mode 100644 index 4035743..0000000 --- a/MiddleSchoolProblemGenerator.java +++ /dev/null @@ -1,69 +0,0 @@ -import java.text.DecimalFormat; -import java.util.Random; - -public class MiddleSchoolProblemGenerator extends AbstractProblemGenerator { - public MiddleSchoolProblemGenerator(Random random, DecimalFormat df) { - super(random, df); - } - - @Override - public MathProblem generate() { - int operandCount = random.nextInt(3) + 3; // 3-5 个操作数 - int[] operands = new int[operandCount]; - String[] selectedOperators = new String[operandCount - 1]; - String[] displayOperands = new String[operandCount]; - String[] operatorPool = {"+", "-", "*", "/"}; - - for (int i = 0; i < operandCount; i++) { - operands[i] = random.nextInt(100) + 1; - displayOperands[i] = String.valueOf(operands[i]); - } - for (int i = 0; i < operandCount - 1; i++) { - selectedOperators[i] = operatorPool[random.nextInt(operatorPool.length)]; - } - - // 平方或根号 - int specialOperandIndex = random.nextInt(operandCount); - boolean useSquareRoot = random.nextBoolean(); - if (useSquareRoot) { - int base = random.nextInt(24) + 2; //2-25 - int perfectSquare = base * base; - operands[specialOperandIndex] = base; // √(base^2) = base - displayOperands[specialOperandIndex] = "√" + perfectSquare; - } else { - int base = random.nextInt(9) + 2; // 2-10 - int square = base * base; - operands[specialOperandIndex] = square; - displayOperands[specialOperandIndex] = base + "²"; - } - - // 括号选择 - boolean addedBracket = false; - int bracketStartIndex = findBracketStart(toDoubleArray(operands), selectedOperators, 0.3); - String expression; - double result; - if (bracketStartIndex != -1) { - // 构建带括号(显示用 displayOperands) - StringBuilder expressionBuilder = new StringBuilder(); - for (int i = 0; i < operandCount; i++) { - if (i == bracketStartIndex) expressionBuilder.append("("); - expressionBuilder.append(displayOperands[i]); - if (i == bracketStartIndex + 1) expressionBuilder.append(")"); - if (i < operandCount - 1) expressionBuilder.append(" ").append(selectedOperators[i]).append(" "); - } - expression = expressionBuilder.toString(); - result = evaluateExpressionWithBrackets(operands, selectedOperators, bracketStartIndex); - } else { - StringBuilder expressionBuilder = new StringBuilder(); - expressionBuilder.append(displayOperands[0]); - result = operands[0]; - for (int i = 0; i < operandCount - 1; i++) { - expressionBuilder.append(" ").append(selectedOperators[i]).append(" ").append(displayOperands[i + 1]); - result = applyOperator(result, operands[i + 1], selectedOperators[i]); - } - expression = expressionBuilder.toString(); - } - - return new MathProblem(expression, df.format(result), "初中"); - } -} \ No newline at end of file -- 2.34.1 From d9c7ce6248f978da99dcf9a4f8ff977eb8bec417 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:53:59 +0800 Subject: [PATCH 22/42] Delete 'README.md' --- README.md | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index 0f0a60f..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# projectone - -- 2.34.1 From 1919ae04270ab165d5fe1d7f0c894b3533976c66 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:54:03 +0800 Subject: [PATCH 23/42] Delete 'User.java' --- User.java | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 User.java diff --git a/User.java b/User.java deleted file mode 100644 index 6cc1bbf..0000000 --- a/User.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * 用户类,用于管理账户信息 - */ -public class User { - private String username; - private String password; - private String userType; // 小学、初中、高中 - - public User(String username, String password, String userType) { - this.username = username; - this.password = password; - this.userType = userType; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public String getUserType() { - return userType; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - User user = (User) obj; - return username.equals(user.username) && password.equals(user.password); - } - - @Override - public String toString() { - return "User{" + - "username='" + username + '\'' + - ", userType='" + userType + '\'' + - '}'; - } -} \ No newline at end of file -- 2.34.1 From cc1f60228908f5c2d92e1fe2facabad3f4938d9c Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:54:44 +0800 Subject: [PATCH 24/42] ADD file via upload --- develop/src | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 develop/src diff --git a/develop/src b/develop/src new file mode 100644 index 0000000..afb83fd --- /dev/null +++ b/develop/src @@ -0,0 +1,125 @@ +import java.text.DecimalFormat; +import java.util.Random; + +/** + * 抽象题目生成器:封装公共工具方法与共享状态 + */ +public abstract class AbstractProblemGenerator { + protected final Random random; + protected final DecimalFormat df; + + protected AbstractProblemGenerator(Random random, DecimalFormat df) { + this.random = random; + this.df = df; + } + + /** + * 子类实现具体题目生成逻辑 + */ + public abstract MathProblem generate(); + + // 构建带括号的表达式(只包两个操作数) + protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + StringBuilder expression = new StringBuilder(); + for (int i = 0; i < operands.length; i++) { + if (i == startPos) { + expression.append("("); + } + expression.append(operands[i]); + if (i == startPos + 1) { + expression.append(")"); + } + if (i < operands.length - 1) { + expression.append(" ").append(operators[i]).append(" "); + } + } + return expression.toString(); + } + + // 计算带括号的表达式结果(只合并两个操作数) + protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); + int newOperandCount = operands.length - 1; + int[] newOperands = new int[newOperandCount]; + String[] newOperators = new String[newOperandCount - 1]; + for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; + newOperands[startPos] = (int) bracketResult; + for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; + for (int i = 0; i < newOperandCount - 1; i++) { + if (i < startPos) newOperators[i] = operators[i]; + else newOperators[i] = operators[i + 1]; + } + double result = newOperands[0]; + for (int i = 0; i < newOperandCount - 1; i++) { + result = applyOperator(result, newOperands[i + 1], newOperators[i]); + } + return result; + } + + /** 应用运算符(整数右操作数) */ + protected double applyOperator(double left, int right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 计算三角函数值 */ + protected double calculateTrigFunction(String function, int angle) { + double radians = Math.toRadians(angle); + switch (function) { + case "sin": return Math.sin(radians); + case "cos": return Math.cos(radians); + case "tan": + if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 + return Math.tan(radians); + default: return 0; + } + } + + /** Double 版本的运算符应用(用于包含三角函数的计算) */ + protected double applyOperatorDouble(double left, double right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0.0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 将 int 数组转 double 数组 */ + protected double[] toDoubleArray(int[] arr) { + double[] out = new double[arr.length]; + for (int i = 0; i < arr.length; i++) out[i] = arr[i]; + return out; + } + + /** + * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 + */ + protected int findBracketStart(double[] values, String[] operators, double probability) { + if (values == null || operators == null) return -1; + if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 + if (random.nextDouble() >= probability) return -1;//有括号的情况为人为设置,现在概率为0.3 + int maxStart = values.length - 2; // 仅包两个操作数 + int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; + int candidateCount = 0; + //只有改变运算顺序的括号才有意义 + for (int s = 0; s <= maxStart; s++) { + boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); + boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); + boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); + if (insideLow && (leftHigh || rightHigh)) { + candidateStarts[candidateCount++] = s; + } + } + if (candidateCount == 0) return -1; + int candidate = candidateStarts[random.nextInt(candidateCount)]; + double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);//避免括号内结果为0 + return (bracketResult != 0.0) ? candidate : -1; + } +} \ No newline at end of file -- 2.34.1 From 1cbe1fcf509fb924781cd1004e63f44593573ea5 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:55:35 +0800 Subject: [PATCH 25/42] Delete 'develop/src' --- develop/src | 125 ---------------------------------------------------- 1 file changed, 125 deletions(-) delete mode 100644 develop/src diff --git a/develop/src b/develop/src deleted file mode 100644 index afb83fd..0000000 --- a/develop/src +++ /dev/null @@ -1,125 +0,0 @@ -import java.text.DecimalFormat; -import java.util.Random; - -/** - * 抽象题目生成器:封装公共工具方法与共享状态 - */ -public abstract class AbstractProblemGenerator { - protected final Random random; - protected final DecimalFormat df; - - protected AbstractProblemGenerator(Random random, DecimalFormat df) { - this.random = random; - this.df = df; - } - - /** - * 子类实现具体题目生成逻辑 - */ - public abstract MathProblem generate(); - - // 构建带括号的表达式(只包两个操作数) - protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - StringBuilder expression = new StringBuilder(); - for (int i = 0; i < operands.length; i++) { - if (i == startPos) { - expression.append("("); - } - expression.append(operands[i]); - if (i == startPos + 1) { - expression.append(")"); - } - if (i < operands.length - 1) { - expression.append(" ").append(operators[i]).append(" "); - } - } - return expression.toString(); - } - - // 计算带括号的表达式结果(只合并两个操作数) - protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); - int newOperandCount = operands.length - 1; - int[] newOperands = new int[newOperandCount]; - String[] newOperators = new String[newOperandCount - 1]; - for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; - newOperands[startPos] = (int) bracketResult; - for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; - for (int i = 0; i < newOperandCount - 1; i++) { - if (i < startPos) newOperators[i] = operators[i]; - else newOperators[i] = operators[i + 1]; - } - double result = newOperands[0]; - for (int i = 0; i < newOperandCount - 1; i++) { - result = applyOperator(result, newOperands[i + 1], newOperators[i]); - } - return result; - } - - /** 应用运算符(整数右操作数) */ - protected double applyOperator(double left, int right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 计算三角函数值 */ - protected double calculateTrigFunction(String function, int angle) { - double radians = Math.toRadians(angle); - switch (function) { - case "sin": return Math.sin(radians); - case "cos": return Math.cos(radians); - case "tan": - if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 - return Math.tan(radians); - default: return 0; - } - } - - /** Double 版本的运算符应用(用于包含三角函数的计算) */ - protected double applyOperatorDouble(double left, double right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0.0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 将 int 数组转 double 数组 */ - protected double[] toDoubleArray(int[] arr) { - double[] out = new double[arr.length]; - for (int i = 0; i < arr.length; i++) out[i] = arr[i]; - return out; - } - - /** - * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 - */ - protected int findBracketStart(double[] values, String[] operators, double probability) { - if (values == null || operators == null) return -1; - if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 - if (random.nextDouble() >= probability) return -1;//有括号的情况为人为设置,现在概率为0.3 - int maxStart = values.length - 2; // 仅包两个操作数 - int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; - int candidateCount = 0; - //只有改变运算顺序的括号才有意义 - for (int s = 0; s <= maxStart; s++) { - boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); - boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); - boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); - if (insideLow && (leftHigh || rightHigh)) { - candidateStarts[candidateCount++] = s; - } - } - if (candidateCount == 0) return -1; - int candidate = candidateStarts[random.nextInt(candidateCount)]; - double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);//避免括号内结果为0 - return (bracketResult != 0.0) ? candidate : -1; - } -} \ No newline at end of file -- 2.34.1 From 7987dae6124dd9cb1772377d50aa3f33bd7f523c Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:56:03 +0800 Subject: [PATCH 26/42] ADD file via upload --- src | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src diff --git a/src b/src new file mode 100644 index 0000000..afb83fd --- /dev/null +++ b/src @@ -0,0 +1,125 @@ +import java.text.DecimalFormat; +import java.util.Random; + +/** + * 抽象题目生成器:封装公共工具方法与共享状态 + */ +public abstract class AbstractProblemGenerator { + protected final Random random; + protected final DecimalFormat df; + + protected AbstractProblemGenerator(Random random, DecimalFormat df) { + this.random = random; + this.df = df; + } + + /** + * 子类实现具体题目生成逻辑 + */ + public abstract MathProblem generate(); + + // 构建带括号的表达式(只包两个操作数) + protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + StringBuilder expression = new StringBuilder(); + for (int i = 0; i < operands.length; i++) { + if (i == startPos) { + expression.append("("); + } + expression.append(operands[i]); + if (i == startPos + 1) { + expression.append(")"); + } + if (i < operands.length - 1) { + expression.append(" ").append(operators[i]).append(" "); + } + } + return expression.toString(); + } + + // 计算带括号的表达式结果(只合并两个操作数) + protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); + int newOperandCount = operands.length - 1; + int[] newOperands = new int[newOperandCount]; + String[] newOperators = new String[newOperandCount - 1]; + for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; + newOperands[startPos] = (int) bracketResult; + for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; + for (int i = 0; i < newOperandCount - 1; i++) { + if (i < startPos) newOperators[i] = operators[i]; + else newOperators[i] = operators[i + 1]; + } + double result = newOperands[0]; + for (int i = 0; i < newOperandCount - 1; i++) { + result = applyOperator(result, newOperands[i + 1], newOperators[i]); + } + return result; + } + + /** 应用运算符(整数右操作数) */ + protected double applyOperator(double left, int right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 计算三角函数值 */ + protected double calculateTrigFunction(String function, int angle) { + double radians = Math.toRadians(angle); + switch (function) { + case "sin": return Math.sin(radians); + case "cos": return Math.cos(radians); + case "tan": + if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 + return Math.tan(radians); + default: return 0; + } + } + + /** Double 版本的运算符应用(用于包含三角函数的计算) */ + protected double applyOperatorDouble(double left, double right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0.0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 将 int 数组转 double 数组 */ + protected double[] toDoubleArray(int[] arr) { + double[] out = new double[arr.length]; + for (int i = 0; i < arr.length; i++) out[i] = arr[i]; + return out; + } + + /** + * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 + */ + protected int findBracketStart(double[] values, String[] operators, double probability) { + if (values == null || operators == null) return -1; + if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 + if (random.nextDouble() >= probability) return -1;//有括号的情况为人为设置,现在概率为0.3 + int maxStart = values.length - 2; // 仅包两个操作数 + int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; + int candidateCount = 0; + //只有改变运算顺序的括号才有意义 + for (int s = 0; s <= maxStart; s++) { + boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); + boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); + boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); + if (insideLow && (leftHigh || rightHigh)) { + candidateStarts[candidateCount++] = s; + } + } + if (candidateCount == 0) return -1; + int candidate = candidateStarts[random.nextInt(candidateCount)]; + double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);//避免括号内结果为0 + return (bracketResult != 0.0) ? candidate : -1; + } +} \ No newline at end of file -- 2.34.1 From 61720de11ce9d6bc7b40274b6b9a6d153af6850e Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Sun, 28 Sep 2025 21:56:31 +0800 Subject: [PATCH 27/42] Delete 'src' --- src | 125 ------------------------------------------------------------ 1 file changed, 125 deletions(-) delete mode 100644 src diff --git a/src b/src deleted file mode 100644 index afb83fd..0000000 --- a/src +++ /dev/null @@ -1,125 +0,0 @@ -import java.text.DecimalFormat; -import java.util.Random; - -/** - * 抽象题目生成器:封装公共工具方法与共享状态 - */ -public abstract class AbstractProblemGenerator { - protected final Random random; - protected final DecimalFormat df; - - protected AbstractProblemGenerator(Random random, DecimalFormat df) { - this.random = random; - this.df = df; - } - - /** - * 子类实现具体题目生成逻辑 - */ - public abstract MathProblem generate(); - - // 构建带括号的表达式(只包两个操作数) - protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - StringBuilder expression = new StringBuilder(); - for (int i = 0; i < operands.length; i++) { - if (i == startPos) { - expression.append("("); - } - expression.append(operands[i]); - if (i == startPos + 1) { - expression.append(")"); - } - if (i < operands.length - 1) { - expression.append(" ").append(operators[i]).append(" "); - } - } - return expression.toString(); - } - - // 计算带括号的表达式结果(只合并两个操作数) - protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); - int newOperandCount = operands.length - 1; - int[] newOperands = new int[newOperandCount]; - String[] newOperators = new String[newOperandCount - 1]; - for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; - newOperands[startPos] = (int) bracketResult; - for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; - for (int i = 0; i < newOperandCount - 1; i++) { - if (i < startPos) newOperators[i] = operators[i]; - else newOperators[i] = operators[i + 1]; - } - double result = newOperands[0]; - for (int i = 0; i < newOperandCount - 1; i++) { - result = applyOperator(result, newOperands[i + 1], newOperators[i]); - } - return result; - } - - /** 应用运算符(整数右操作数) */ - protected double applyOperator(double left, int right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 计算三角函数值 */ - protected double calculateTrigFunction(String function, int angle) { - double radians = Math.toRadians(angle); - switch (function) { - case "sin": return Math.sin(radians); - case "cos": return Math.cos(radians); - case "tan": - if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 - return Math.tan(radians); - default: return 0; - } - } - - /** Double 版本的运算符应用(用于包含三角函数的计算) */ - protected double applyOperatorDouble(double left, double right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0.0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 将 int 数组转 double 数组 */ - protected double[] toDoubleArray(int[] arr) { - double[] out = new double[arr.length]; - for (int i = 0; i < arr.length; i++) out[i] = arr[i]; - return out; - } - - /** - * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 - */ - protected int findBracketStart(double[] values, String[] operators, double probability) { - if (values == null || operators == null) return -1; - if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 - if (random.nextDouble() >= probability) return -1;//有括号的情况为人为设置,现在概率为0.3 - int maxStart = values.length - 2; // 仅包两个操作数 - int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; - int candidateCount = 0; - //只有改变运算顺序的括号才有意义 - for (int s = 0; s <= maxStart; s++) { - boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); - boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); - boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); - if (insideLow && (leftHigh || rightHigh)) { - candidateStarts[candidateCount++] = s; - } - } - if (candidateCount == 0) return -1; - int candidate = candidateStarts[random.nextInt(candidateCount)]; - double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);//避免括号内结果为0 - return (bracketResult != 0.0) ? candidate : -1; - } -} \ No newline at end of file -- 2.34.1 From bd0549ea0554606b80742a16a5b09a02187f35e5 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:41:40 +0800 Subject: [PATCH 28/42] ADD file via upload --- src | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src diff --git a/src b/src new file mode 100644 index 0000000..afb83fd --- /dev/null +++ b/src @@ -0,0 +1,125 @@ +import java.text.DecimalFormat; +import java.util.Random; + +/** + * 抽象题目生成器:封装公共工具方法与共享状态 + */ +public abstract class AbstractProblemGenerator { + protected final Random random; + protected final DecimalFormat df; + + protected AbstractProblemGenerator(Random random, DecimalFormat df) { + this.random = random; + this.df = df; + } + + /** + * 子类实现具体题目生成逻辑 + */ + public abstract MathProblem generate(); + + // 构建带括号的表达式(只包两个操作数) + protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + StringBuilder expression = new StringBuilder(); + for (int i = 0; i < operands.length; i++) { + if (i == startPos) { + expression.append("("); + } + expression.append(operands[i]); + if (i == startPos + 1) { + expression.append(")"); + } + if (i < operands.length - 1) { + expression.append(" ").append(operators[i]).append(" "); + } + } + return expression.toString(); + } + + // 计算带括号的表达式结果(只合并两个操作数) + protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); + int newOperandCount = operands.length - 1; + int[] newOperands = new int[newOperandCount]; + String[] newOperators = new String[newOperandCount - 1]; + for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; + newOperands[startPos] = (int) bracketResult; + for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; + for (int i = 0; i < newOperandCount - 1; i++) { + if (i < startPos) newOperators[i] = operators[i]; + else newOperators[i] = operators[i + 1]; + } + double result = newOperands[0]; + for (int i = 0; i < newOperandCount - 1; i++) { + result = applyOperator(result, newOperands[i + 1], newOperators[i]); + } + return result; + } + + /** 应用运算符(整数右操作数) */ + protected double applyOperator(double left, int right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 计算三角函数值 */ + protected double calculateTrigFunction(String function, int angle) { + double radians = Math.toRadians(angle); + switch (function) { + case "sin": return Math.sin(radians); + case "cos": return Math.cos(radians); + case "tan": + if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 + return Math.tan(radians); + default: return 0; + } + } + + /** Double 版本的运算符应用(用于包含三角函数的计算) */ + protected double applyOperatorDouble(double left, double right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0.0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 将 int 数组转 double 数组 */ + protected double[] toDoubleArray(int[] arr) { + double[] out = new double[arr.length]; + for (int i = 0; i < arr.length; i++) out[i] = arr[i]; + return out; + } + + /** + * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 + */ + protected int findBracketStart(double[] values, String[] operators, double probability) { + if (values == null || operators == null) return -1; + if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 + if (random.nextDouble() >= probability) return -1;//有括号的情况为人为设置,现在概率为0.3 + int maxStart = values.length - 2; // 仅包两个操作数 + int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; + int candidateCount = 0; + //只有改变运算顺序的括号才有意义 + for (int s = 0; s <= maxStart; s++) { + boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); + boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); + boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); + if (insideLow && (leftHigh || rightHigh)) { + candidateStarts[candidateCount++] = s; + } + } + if (candidateCount == 0) return -1; + int candidate = candidateStarts[random.nextInt(candidateCount)]; + double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);//避免括号内结果为0 + return (bracketResult != 0.0) ? candidate : -1; + } +} \ No newline at end of file -- 2.34.1 From 01eec96480e3d4bdbccdad949a98c6717cae6421 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:45:55 +0800 Subject: [PATCH 29/42] Delete 'src' --- src | 125 ------------------------------------------------------------ 1 file changed, 125 deletions(-) delete mode 100644 src diff --git a/src b/src deleted file mode 100644 index afb83fd..0000000 --- a/src +++ /dev/null @@ -1,125 +0,0 @@ -import java.text.DecimalFormat; -import java.util.Random; - -/** - * 抽象题目生成器:封装公共工具方法与共享状态 - */ -public abstract class AbstractProblemGenerator { - protected final Random random; - protected final DecimalFormat df; - - protected AbstractProblemGenerator(Random random, DecimalFormat df) { - this.random = random; - this.df = df; - } - - /** - * 子类实现具体题目生成逻辑 - */ - public abstract MathProblem generate(); - - // 构建带括号的表达式(只包两个操作数) - protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - StringBuilder expression = new StringBuilder(); - for (int i = 0; i < operands.length; i++) { - if (i == startPos) { - expression.append("("); - } - expression.append(operands[i]); - if (i == startPos + 1) { - expression.append(")"); - } - if (i < operands.length - 1) { - expression.append(" ").append(operators[i]).append(" "); - } - } - return expression.toString(); - } - - // 计算带括号的表达式结果(只合并两个操作数) - protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { - double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); - int newOperandCount = operands.length - 1; - int[] newOperands = new int[newOperandCount]; - String[] newOperators = new String[newOperandCount - 1]; - for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; - newOperands[startPos] = (int) bracketResult; - for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; - for (int i = 0; i < newOperandCount - 1; i++) { - if (i < startPos) newOperators[i] = operators[i]; - else newOperators[i] = operators[i + 1]; - } - double result = newOperands[0]; - for (int i = 0; i < newOperandCount - 1; i++) { - result = applyOperator(result, newOperands[i + 1], newOperators[i]); - } - return result; - } - - /** 应用运算符(整数右操作数) */ - protected double applyOperator(double left, int right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 计算三角函数值 */ - protected double calculateTrigFunction(String function, int angle) { - double radians = Math.toRadians(angle); - switch (function) { - case "sin": return Math.sin(radians); - case "cos": return Math.cos(radians); - case "tan": - if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 - return Math.tan(radians); - default: return 0; - } - } - - /** Double 版本的运算符应用(用于包含三角函数的计算) */ - protected double applyOperatorDouble(double left, double right, String operator) { - switch (operator) { - case "+": return left + right; - case "-": return left - right; - case "*": return left * right; - case "/": return right != 0.0 ? left / right : left; // 避免除以零 - default: return left; - } - } - - /** 将 int 数组转 double 数组 */ - protected double[] toDoubleArray(int[] arr) { - double[] out = new double[arr.length]; - for (int i = 0; i < arr.length; i++) out[i] = arr[i]; - return out; - } - - /** - * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 - */ - protected int findBracketStart(double[] values, String[] operators, double probability) { - if (values == null || operators == null) return -1; - if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 - if (random.nextDouble() >= probability) return -1;//有括号的情况为人为设置,现在概率为0.3 - int maxStart = values.length - 2; // 仅包两个操作数 - int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; - int candidateCount = 0; - //只有改变运算顺序的括号才有意义 - for (int s = 0; s <= maxStart; s++) { - boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); - boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); - boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); - if (insideLow && (leftHigh || rightHigh)) { - candidateStarts[candidateCount++] = s; - } - } - if (candidateCount == 0) return -1; - int candidate = candidateStarts[random.nextInt(candidateCount)]; - double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);//避免括号内结果为0 - return (bracketResult != 0.0) ? candidate : -1; - } -} \ No newline at end of file -- 2.34.1 From e39d6331746ade517bd29166c3c4a0d6bad0730a Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:46:23 +0800 Subject: [PATCH 30/42] ADD file via upload --- src/AbstractProblemGenerator.java | 125 ++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/AbstractProblemGenerator.java diff --git a/src/AbstractProblemGenerator.java b/src/AbstractProblemGenerator.java new file mode 100644 index 0000000..afb83fd --- /dev/null +++ b/src/AbstractProblemGenerator.java @@ -0,0 +1,125 @@ +import java.text.DecimalFormat; +import java.util.Random; + +/** + * 抽象题目生成器:封装公共工具方法与共享状态 + */ +public abstract class AbstractProblemGenerator { + protected final Random random; + protected final DecimalFormat df; + + protected AbstractProblemGenerator(Random random, DecimalFormat df) { + this.random = random; + this.df = df; + } + + /** + * 子类实现具体题目生成逻辑 + */ + public abstract MathProblem generate(); + + // 构建带括号的表达式(只包两个操作数) + protected String buildExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + StringBuilder expression = new StringBuilder(); + for (int i = 0; i < operands.length; i++) { + if (i == startPos) { + expression.append("("); + } + expression.append(operands[i]); + if (i == startPos + 1) { + expression.append(")"); + } + if (i < operands.length - 1) { + expression.append(" ").append(operators[i]).append(" "); + } + } + return expression.toString(); + } + + // 计算带括号的表达式结果(只合并两个操作数) + protected double evaluateExpressionWithBrackets(int[] operands, String[] operators, int startPos) { + double bracketResult = applyOperator(operands[startPos], operands[startPos + 1], operators[startPos]); + int newOperandCount = operands.length - 1; + int[] newOperands = new int[newOperandCount]; + String[] newOperators = new String[newOperandCount - 1]; + for (int i = 0; i < startPos; i++) newOperands[i] = operands[i]; + newOperands[startPos] = (int) bracketResult; + for (int i = startPos + 1; i < newOperandCount; i++) newOperands[i] = operands[i + 1]; + for (int i = 0; i < newOperandCount - 1; i++) { + if (i < startPos) newOperators[i] = operators[i]; + else newOperators[i] = operators[i + 1]; + } + double result = newOperands[0]; + for (int i = 0; i < newOperandCount - 1; i++) { + result = applyOperator(result, newOperands[i + 1], newOperators[i]); + } + return result; + } + + /** 应用运算符(整数右操作数) */ + protected double applyOperator(double left, int right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 计算三角函数值 */ + protected double calculateTrigFunction(String function, int angle) { + double radians = Math.toRadians(angle); + switch (function) { + case "sin": return Math.sin(radians); + case "cos": return Math.cos(radians); + case "tan": + if (angle == 90) return Double.POSITIVE_INFINITY; // tan(90°)未定义 + return Math.tan(radians); + default: return 0; + } + } + + /** Double 版本的运算符应用(用于包含三角函数的计算) */ + protected double applyOperatorDouble(double left, double right, String operator) { + switch (operator) { + case "+": return left + right; + case "-": return left - right; + case "*": return left * right; + case "/": return right != 0.0 ? left / right : left; // 避免除以零 + default: return left; + } + } + + /** 将 int 数组转 double 数组 */ + protected double[] toDoubleArray(int[] arr) { + double[] out = new double[arr.length]; + for (int i = 0; i < arr.length; i++) out[i] = arr[i]; + return out; + } + + /** + * 选择括号起始位置:仅当能改变优先级,并且括号内结果不为 0 时返回有效下标,否则返回 -1 + */ + protected int findBracketStart(double[] values, String[] operators, double probability) { + if (values == null || operators == null) return -1; + if (values.length <= 3) return -1; // 至少 4 个操作数才有加括号的意义 + if (random.nextDouble() >= probability) return -1;//有括号的情况为人为设置,现在概率为0.3 + int maxStart = values.length - 2; // 仅包两个操作数 + int[] candidateStarts = new int[Math.max(0, maxStart + 1)]; + int candidateCount = 0; + //只有改变运算顺序的括号才有意义 + for (int s = 0; s <= maxStart; s++) { + boolean insideLow = "+".equals(operators[s]) || "-".equals(operators[s]); + boolean leftHigh = (s - 1) >= 0 && ("*".equals(operators[s - 1]) || "/".equals(operators[s - 1])); + boolean rightHigh = (s + 1) < operators.length && ("*".equals(operators[s + 1]) || "/".equals(operators[s + 1])); + if (insideLow && (leftHigh || rightHigh)) { + candidateStarts[candidateCount++] = s; + } + } + if (candidateCount == 0) return -1; + int candidate = candidateStarts[random.nextInt(candidateCount)]; + double bracketResult = applyOperatorDouble(values[candidate], values[candidate + 1], operators[candidate]);//避免括号内结果为0 + return (bracketResult != 0.0) ? candidate : -1; + } +} \ No newline at end of file -- 2.34.1 From bbb6924db462d83c568dc2ca8e04f249f4fba1ea Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:47:22 +0800 Subject: [PATCH 31/42] ADD file via upload --- src/ElementaryProblemGenerator.java | 67 +++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/ElementaryProblemGenerator.java diff --git a/src/ElementaryProblemGenerator.java b/src/ElementaryProblemGenerator.java new file mode 100644 index 0000000..612612d --- /dev/null +++ b/src/ElementaryProblemGenerator.java @@ -0,0 +1,67 @@ +import java.text.DecimalFormat; +import java.util.Random; + +public class ElementaryProblemGenerator extends AbstractProblemGenerator { + public ElementaryProblemGenerator(Random random, DecimalFormat df) { + super(random, df); + } + + @Override + public MathProblem generate() { + // 小学题目要求:答案不得为负数。最多尝试若干次生成,若仍为负则回退到简单加法题。 + int maxAttempts = 50; + for (int attempt = 0; attempt < maxAttempts; attempt++) { + int operandCount = random.nextInt(4) + 2; // 2-5个操作数 + String[] operators = {"+", "-", "*", "/"}; + int[] operands = new int[operandCount]; + String[] selectedOperators = new String[operandCount - 1]; + for (int i = 0; i < operandCount; i++) operands[i] = random.nextInt(100) + 1; + // 运算符选择(避免连乘/连除,调整概率) + String previousOperator = null; + double pPlus = 0.45, pMinus = 0.35, pTimes = 0.15, pDivide = 0.05; + for (int i = 0; i < operandCount - 1; i++) { + String operator; + if ("*".equals(previousOperator) || "/".equals(previousOperator)) { + double randValue = random.nextDouble(); + double total = pPlus + pMinus; + operator = randValue < (pPlus / total) ? "+" : "-"; + } else { + double randValue = random.nextDouble(); + if (randValue < pPlus) operator = "+"; + else if (randValue < pPlus + pMinus) operator = "-"; + else if (randValue < pPlus + pMinus + pTimes) operator = "*"; + else operator = "/"; + } + selectedOperators[i] = operator; + previousOperator = operator; + } + // 括号选择 + int startPos = findBracketStart(toDoubleArray(operands), selectedOperators, 0.3); + String expression; + double result; + if (startPos != -1) { + expression = buildExpressionWithBrackets(operands, selectedOperators, startPos); + result = evaluateExpressionWithBrackets(operands, selectedOperators, startPos); + } else { + StringBuilder expBuilder = new StringBuilder(); + expBuilder.append(operands[0]); + result = operands[0]; + for (int i = 0; i < operandCount - 1; i++) { + expBuilder.append(" ").append(selectedOperators[i]).append(" ").append(operands[i + 1]); + result = applyOperator(result, operands[i + 1], selectedOperators[i]); + } + expression = expBuilder.toString(); + } + if (result >= 0) { + return new MathProblem(expression, df.format(result), "小学"); + } + // 如果为负数,继续下一次尝试 + } + // 回退:生成一个保证非负的简单加法题 + int a = random.nextInt(100) + 1; + int b = random.nextInt(100) + 1; + String expression = a + " + " + b; + double result = a + b; + return new MathProblem(expression, df.format(result), "小学"); + } +} \ No newline at end of file -- 2.34.1 From 1132cb1dd7dde28c552775fe4055d15cc837ed3a Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:47:33 +0800 Subject: [PATCH 32/42] ADD file via upload --- src/FileManager.java | 137 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 src/FileManager.java diff --git a/src/FileManager.java b/src/FileManager.java new file mode 100644 index 0000000..e132798 --- /dev/null +++ b/src/FileManager.java @@ -0,0 +1,137 @@ +import java.io.*; +import java.nio.file.*; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +/** + * 文件管理类,负责题目的保存和历史题目的管理 + */ +public class FileManager { + private static final String BASE_DIR = "math_papers"; + private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"); + + /** + * 保存题目到文件 + * @param user 用户信息 + * @param problems 题目列表 + * @param difficulty 难度级别(当前选择) + * @return 保存的文件路径 + */ + public String savePaperToFile(User user, List problems, String difficulty) throws IOException { + // 创建用户文件夹 + String userDir = BASE_DIR + File.separator + user.getUsername(); + Files.createDirectories(Paths.get(userDir)); + + // 生成文件名 + String timestamp = LocalDateTime.now().format(formatter); + String fileName = timestamp + ".txt"; + String filePath = userDir + File.separator + fileName; + + // 写入题目到文件 + try (PrintWriter writer = new PrintWriter(new FileWriter(filePath, StandardCharsets.UTF_8))) { + writer.println("数学题目卷子"); + writer.println("用户: " + user.getUsername()); + writer.println("类型: " + difficulty); + writer.println("生成时间: " + timestamp.replace("-", "/").replace("-", ":")); + writer.println("题目数量: " + problems.size()); + writer.println("=" + "=".repeat(50)); + writer.println(); + + for (int i = 0; i < problems.size(); i++) { + writer.println((i + 1) + ". " + problems.get(i).toString()); + writer.println(); // 每题之间空一行 + } + } + + return filePath; + } + + /** + * 获取用户历史题目,用于重复检测 + * @param username 用户名 + * @return 历史题目集合 + */ + public Set getUserHistoryProblems(String username) { + Set historyProblems = new HashSet<>(); + String userDir = BASE_DIR + File.separator + username; + + try { + Path userPath = Paths.get(userDir); + if (!Files.exists(userPath)) { + return historyProblems; + } + + // 遍历用户文件夹中的所有txt文件 + Files.walk(userPath) + .filter(path -> path.toString().endsWith(".txt")) + .forEach(path -> { + try { + List lines = Files.readAllLines(path, StandardCharsets.UTF_8); + for (String line : lines) { + // 提取题目表达式(格式:数字. 表达式 = ?) + if (line.matches("^\\d+\\. .+ = \\?$")) { + String expression = line.substring(line.indexOf(". ") + 2, line.lastIndexOf(" = ?")); + historyProblems.add(expression); + } + } + } catch (IOException e) { + System.err.println("读取文件失败: " + path); + } + }); + } catch (IOException e) { + System.err.println("访问用户目录失败: " + userDir); + } + + return historyProblems; + } + + /** + * 检查题目是否重复 + * @param username 用户名 + * @param problem 要检查的题目 + * @return 是否重复 + */ + public boolean isDuplicateProblem(String username, MathProblem problem) { + Set historyProblems = getUserHistoryProblems(username); + return historyProblems.contains(problem.getExpression()); + } + + /** + * 生成不重复的题目列表 + * @param user 用户信息 + * @param generator 题目生成器 + * @param count 题目数量 + * @param difficulty 难度级别 + * @return 不重复的题目列表 + */ + public List generateUniqueProblems(User user, MathProblemGenerator generator, + int count, String difficulty) { + List problems = new ArrayList<>(); + Set historyProblems = getUserHistoryProblems(user.getUsername()); + Set currentProblems = new HashSet<>(); + + int attempts = 0; + int maxAttempts = count * 10; // 最多尝试次数,避免无限循环 + + while (problems.size() < count && attempts < maxAttempts) { + MathProblem problem = generator.generateProblem(difficulty); + String expression = problem.getExpression(); + + // 检查是否与历史题目或当前题目重复 + if (!historyProblems.contains(expression) && !currentProblems.contains(expression)) { + problems.add(problem); + currentProblems.add(expression); + } + + attempts++; + } + + if (problems.size() < count) { + System.out.println("警告: 只生成了 " + problems.size() + " 道题目,可能存在重复限制。"); + } + + return problems; + } +} \ No newline at end of file -- 2.34.1 From 249f034a6e33702d052cfe647ae0ee647e04dcb7 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:47:46 +0800 Subject: [PATCH 33/42] ADD file via upload --- src/HighSchoolProblemGenerator.java | 85 +++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/HighSchoolProblemGenerator.java diff --git a/src/HighSchoolProblemGenerator.java b/src/HighSchoolProblemGenerator.java new file mode 100644 index 0000000..12c7570 --- /dev/null +++ b/src/HighSchoolProblemGenerator.java @@ -0,0 +1,85 @@ + import java.text.DecimalFormat; +import java.util.Random; + +public class HighSchoolProblemGenerator extends AbstractProblemGenerator { + public HighSchoolProblemGenerator(Random random, DecimalFormat df) { + super(random, df); + } + + @Override + public MathProblem generate() { + int operandCount = random.nextInt(3) + 3; // 3-5 个操作数 + double[] operandsVal = new double[operandCount]; + String[] displayOperands = new String[operandCount]; + String[] selectedOperators = new String[operandCount - 1]; + + // 生成基本操作数 + for (int i = 0; i < operandCount; i++) { + int v = random.nextInt(100) + 1; + operandsVal[i] = v; + displayOperands[i] = String.valueOf(v); + } + // 运算符选择(更均衡,避免连乘/连除) + String previousOperator = null; + double pPlus = 0.35, pMinus = 0.25, pTimes = 0.25, pDivide = 0.15; + for (int i = 0; i < operandCount - 1; i++) { + String operator; + if ("*".equals(previousOperator) || "/".equals(previousOperator)) { + double randValue = random.nextDouble(); + double total = pPlus + pMinus; + operator = randValue < (pPlus / total) ? "+" : "-"; + } else { + double randValue = random.nextDouble(); + if (randValue < pPlus) operator = "+"; + else if (randValue < pPlus + pMinus) operator = "-"; + else if (randValue < pPlus + pMinus + pTimes) operator = "*"; + else operator = "/"; + } + selectedOperators[i] = operator; + previousOperator = operator; + } + + // 三角函数 + int trigIndex = random.nextInt(operandCount); + String[] functions = {"sin", "cos", "tan"}; + String function = functions[random.nextInt(functions.length)]; + int[] angles = {0, 30, 45, 60, 90}; + int angle = angles[random.nextInt(angles.length)]; + if ("tan".equals(function) && angle == 90) angle = 60; // 避免 tan(90°) + double trigVal = calculateTrigFunction(function, angle); + operandsVal[trigIndex] = trigVal; + displayOperands[trigIndex] = function + angle; + + // 括号选择(显示用 displayOperands,计算用 operandsVal) + boolean addedBracket = false; + int startPos = findBracketStart(operandsVal, selectedOperators, 0.3); + StringBuilder expBuilder = new StringBuilder(); + for (int i = 0; i < operandCount; i++) { + if (startPos != -1 && i == startPos) expBuilder.append("("); + expBuilder.append(displayOperands[i]); + if (startPos != -1 && i == startPos + 1) expBuilder.append(")"); + if (i < operandCount - 1) expBuilder.append(" ").append(selectedOperators[i]).append(" "); + } + String expression = expBuilder.toString(); + + // 计算结果(double) + double result; + if (startPos != -1) { + double bracketResult = applyOperatorDouble(operandsVal[startPos], operandsVal[startPos + 1], selectedOperators[startPos]); + int newCount = operandCount - 1; + double[] newVals = new double[newCount]; + String[] newOps = new String[newCount - 1]; + for (int i = 0; i < startPos; i++) newVals[i] = operandsVal[i]; + newVals[startPos] = bracketResult; + for (int i = startPos + 1; i < newCount; i++) newVals[i] = operandsVal[i + 1]; + for (int i = 0; i < newCount - 1; i++) newOps[i] = (i < startPos) ? selectedOperators[i] : selectedOperators[i + 1]; + result = newVals[0]; + for (int i = 0; i < newCount - 1; i++) result = applyOperatorDouble(result, newVals[i + 1], newOps[i]); + } else { + result = operandsVal[0]; + for (int i = 0; i < operandCount - 1; i++) result = applyOperatorDouble(result, operandsVal[i + 1], selectedOperators[i]); + } + + return new MathProblem(expression, df.format(result), "高中"); + } +} \ No newline at end of file -- 2.34.1 From b7f54e098f4195b5c686e22e05d236488a967746 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:54:33 +0800 Subject: [PATCH 34/42] ADD file via upload --- src/MathPaperGenerator.java | 174 ++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 src/MathPaperGenerator.java diff --git a/src/MathPaperGenerator.java b/src/MathPaperGenerator.java new file mode 100644 index 0000000..8eb9fea --- /dev/null +++ b/src/MathPaperGenerator.java @@ -0,0 +1,174 @@ +import java.io.IOException; +import java.util.List; +import java.util.Scanner; + +/** + * 数学卷子自动生成程序主类 + */ +public class MathPaperGenerator { + private UserManager userManager; + private MathProblemGenerator problemGenerator; + private FileManager fileManager; + private Scanner scanner; + + public MathPaperGenerator() { + this.userManager = new UserManager(); + this.problemGenerator = new MathProblemGenerator(); + this.fileManager = new FileManager(); + this.scanner = new Scanner(System.in); + } + + /** + * 程序主入口 + */ + public static void main(String[] args) { + MathPaperGenerator generator = new MathPaperGenerator(); + generator.run(); + } + + /** + * 运行主程序 + */ + public void run() { + System.out.println("欢迎使用中小学数学卷子自动生成程序!"); + System.out.println("=" + "=".repeat(40)); + // 使用说明(菜单提示) + System.out.println("使用说明:"); + System.out.println(" - 输入题目数量(10-30)生成试卷"); + System.out.println(" - 输入 切换为 小学/初中/高中 来切换难度,例如:切换为 初中"); + System.out.println(" - 输入 -1 退出当前用户,重新登录"); + System.out.println(); + + while (true) { + User currentUser = login(); + if (currentUser != null) { + handleUserSession(currentUser); + } + } + } + + /*用户登录*/ + private User login() { + while (true) { + System.out.print("请输入用户名和密码(用空格隔开): "); + String input = scanner.nextLine().trim(); + + if (input.isEmpty()) { + System.out.println("输入不能为空,请重新输入。"); + continue; + } + + String[] parts = input.split("\\s+"); + String username = parts[0]; + String password = parts[1]; + + User user = userManager.authenticate(username, password); + if (user != null) { + System.out.println("登录成功!当前选择为 " + user.getUserType() + " 出题"); + // 登录后提示如何切换难度 + System.out.println("提示:您可以在数量输入处键入 切换为 小学/初中/高中 来切换难度,例如:切换为 初中"); + return user; + } else { + System.out.println("请输入正确的用户名、密码"); + } + } + } + + /** + * 处理用户会话 + * @param user 当前登录用户 + */ + private void handleUserSession(User user) { + String currentDifficulty = user.getUserType(); + + while (true) { + // 原提示替换为更详细的说明 + System.out.println("准备生成 " + currentDifficulty + " 数学题目,请输入题目数量(10-30)。"); + System.out.println("提示:输入 切换为 小学/初中/高中 可切换难度(例如:切换为 初中);输入 -1 将退出当前用户并重新登录。"); + String input = scanner.nextLine().trim(); + + // 检查是否要切换类型 + if (input.startsWith("切换为")) { + String newType = input.substring(3).trim(); + if (userManager.isValidUserType(newType)) { + currentDifficulty = newType; + System.out.println("已切换为 " + newType + " 出题模式"); + continue; + } else { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + continue; + } + } + + try { + int count = Integer.parseInt(input); + + if (count == -1) { + System.out.println("退出当前用户,重新登录..."); + System.out.println(); + return; + } + + if (count < 10 || count > 30) { + System.out.println("题目数量必须在10-30之间,请重新输入。"); + continue; + } + + // 生成题目 + generateAndSavePaper(user, currentDifficulty, count); + + } catch (NumberFormatException e) { + System.out.println("请输入有效的数字。"); + } + } + } + + /** + * 生成并保存题目 + * @param user 用户 + * @param difficulty 难度 + * @param count 题目数量 + */ + private void generateAndSavePaper(User user, String difficulty, int count) { + try { + System.out.println("正在生成 " + count + " 道 " + difficulty + " 数学题目..."); + + // 生成不重复的题目 + List problems = fileManager.generateUniqueProblems( + user, problemGenerator, count, difficulty); + + if (problems.size() < count) { + System.out.println("注意:由于重复限制,实际生成了 " + problems.size() + " 道题目。"); + } + + // 保存到文件 + String filePath = fileManager.savePaperToFile(user, problems, difficulty); + + System.out.println("题目生成完成!"); + System.out.println("文件已保存至: " + filePath); + System.out.println("题目预览:"); + System.out.println("-" + "-".repeat(30)); + + // 显示前5道题目作为预览 + int previewCount = Math.min(5, problems.size()); + for (int i = 0; i < previewCount; i++) { + System.out.println((i + 1) + ". " + problems.get(i).toString()); + } + + if (problems.size() > 5) { + System.out.println("... 还有 " + (problems.size() - 5) + " 道题目"); + } + + System.out.println("-" + "-".repeat(30)); + System.out.println(); + // 生成完成后的操作提示 + System.out.println("提示:如需切换难度,请在下一次输入中键入 切换为 小学/初中/高中,例如:切换为 高中。"); + System.out.println("直接输入新的题目数量(10-30)将继续使用当前难度;输入 -1 退出当前用户。"); + + } catch (IOException e) { + System.err.println("保存文件时出错: " + e.getMessage()); + } catch (Exception e) { + System.err.println("生成题目时出错: " + e.getMessage()); + } + } +} \ No newline at end of file -- 2.34.1 From 3fa1d52ee97611a9b47a7b87293a0ad25f8738a7 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:58:07 +0800 Subject: [PATCH 35/42] ADD file via upload --- src/MathProblem.java | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/MathProblem.java diff --git a/src/MathProblem.java b/src/MathProblem.java new file mode 100644 index 0000000..29019f9 --- /dev/null +++ b/src/MathProblem.java @@ -0,0 +1,44 @@ +/** + * 数学题目类,表示一道数学题 + */ +public class MathProblem { + private String expression; // 题目表达式 + private String answer; // 答案 + private String difficulty; // 难度级别 + + public MathProblem(String expression, String answer, String difficulty) { + this.expression = expression; + this.answer = answer; + this.difficulty = difficulty; + } + + public String getExpression() { + return expression; + } + + public String getAnswer() { + return answer; + } + + public String getDifficulty() { + return difficulty; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + MathProblem that = (MathProblem) obj; + return expression.equals(that.expression); + } + + @Override + public int hashCode() { + return expression.hashCode(); + } + + @Override + public String toString() { + return expression + " = ?"; + } +} \ No newline at end of file -- 2.34.1 From f9f50451d7d36c486843df943ccf547c14a2befc Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:58:30 +0800 Subject: [PATCH 36/42] ADD file via upload --- src/MathProblemGenerator.java | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/MathProblemGenerator.java diff --git a/src/MathProblemGenerator.java b/src/MathProblemGenerator.java new file mode 100644 index 0000000..3a65350 --- /dev/null +++ b/src/MathProblemGenerator.java @@ -0,0 +1,34 @@ +import java.text.DecimalFormat; +import java.util.Random; + +/** + * 数学题目生成器,根据不同难度生成相应的数学题目(外观类) + * 将具体生成逻辑委托给对应子类,保持对外 API 不变。 + */ +public class MathProblemGenerator { + private final Random random; + private final DecimalFormat df; + + public MathProblemGenerator() { + this.random = new Random(); + this.df = new DecimalFormat("#.##"); + } + + /** + * 根据难度生成数学题目 + * @param difficulty 难度级别(小学、初中、高中) + * @return 生成的数学题目 + */ + public MathProblem generateProblem(String difficulty) { + switch (difficulty) { + case "小学": + return new ElementaryProblemGenerator(random, df).generate(); + case "初中": + return new MiddleSchoolProblemGenerator(random, df).generate(); + case "高中": + return new HighSchoolProblemGenerator(random, df).generate(); + default: + throw new IllegalArgumentException("不支持的难度级别: " + difficulty); + } + } +} \ No newline at end of file -- 2.34.1 From 291bb7194aa79378d4f7032563d648dd1f746731 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:58:41 +0800 Subject: [PATCH 37/42] ADD file via upload --- src/MiddleSchoolProblemGenerator.java | 69 +++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/MiddleSchoolProblemGenerator.java diff --git a/src/MiddleSchoolProblemGenerator.java b/src/MiddleSchoolProblemGenerator.java new file mode 100644 index 0000000..4035743 --- /dev/null +++ b/src/MiddleSchoolProblemGenerator.java @@ -0,0 +1,69 @@ +import java.text.DecimalFormat; +import java.util.Random; + +public class MiddleSchoolProblemGenerator extends AbstractProblemGenerator { + public MiddleSchoolProblemGenerator(Random random, DecimalFormat df) { + super(random, df); + } + + @Override + public MathProblem generate() { + int operandCount = random.nextInt(3) + 3; // 3-5 个操作数 + int[] operands = new int[operandCount]; + String[] selectedOperators = new String[operandCount - 1]; + String[] displayOperands = new String[operandCount]; + String[] operatorPool = {"+", "-", "*", "/"}; + + for (int i = 0; i < operandCount; i++) { + operands[i] = random.nextInt(100) + 1; + displayOperands[i] = String.valueOf(operands[i]); + } + for (int i = 0; i < operandCount - 1; i++) { + selectedOperators[i] = operatorPool[random.nextInt(operatorPool.length)]; + } + + // 平方或根号 + int specialOperandIndex = random.nextInt(operandCount); + boolean useSquareRoot = random.nextBoolean(); + if (useSquareRoot) { + int base = random.nextInt(24) + 2; //2-25 + int perfectSquare = base * base; + operands[specialOperandIndex] = base; // √(base^2) = base + displayOperands[specialOperandIndex] = "√" + perfectSquare; + } else { + int base = random.nextInt(9) + 2; // 2-10 + int square = base * base; + operands[specialOperandIndex] = square; + displayOperands[specialOperandIndex] = base + "²"; + } + + // 括号选择 + boolean addedBracket = false; + int bracketStartIndex = findBracketStart(toDoubleArray(operands), selectedOperators, 0.3); + String expression; + double result; + if (bracketStartIndex != -1) { + // 构建带括号(显示用 displayOperands) + StringBuilder expressionBuilder = new StringBuilder(); + for (int i = 0; i < operandCount; i++) { + if (i == bracketStartIndex) expressionBuilder.append("("); + expressionBuilder.append(displayOperands[i]); + if (i == bracketStartIndex + 1) expressionBuilder.append(")"); + if (i < operandCount - 1) expressionBuilder.append(" ").append(selectedOperators[i]).append(" "); + } + expression = expressionBuilder.toString(); + result = evaluateExpressionWithBrackets(operands, selectedOperators, bracketStartIndex); + } else { + StringBuilder expressionBuilder = new StringBuilder(); + expressionBuilder.append(displayOperands[0]); + result = operands[0]; + for (int i = 0; i < operandCount - 1; i++) { + expressionBuilder.append(" ").append(selectedOperators[i]).append(" ").append(displayOperands[i + 1]); + result = applyOperator(result, operands[i + 1], selectedOperators[i]); + } + expression = expressionBuilder.toString(); + } + + return new MathProblem(expression, df.format(result), "初中"); + } +} \ No newline at end of file -- 2.34.1 From 2a3dc33789ff5723d678802164946e5393f9a2bc Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:58:53 +0800 Subject: [PATCH 38/42] ADD file via upload --- src/User.java | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/User.java diff --git a/src/User.java b/src/User.java new file mode 100644 index 0000000..6cc1bbf --- /dev/null +++ b/src/User.java @@ -0,0 +1,42 @@ +/** + * 用户类,用于管理账户信息 + */ +public class User { + private String username; + private String password; + private String userType; // 小学、初中、高中 + + public User(String username, String password, String userType) { + this.username = username; + this.password = password; + this.userType = userType; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getUserType() { + return userType; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + User user = (User) obj; + return username.equals(user.username) && password.equals(user.password); + } + + @Override + public String toString() { + return "User{" + + "username='" + username + '\'' + + ", userType='" + userType + '\'' + + '}'; + } +} \ No newline at end of file -- 2.34.1 From 97e3b15fb5a506e6ecfc4dd6da2d0c2db664cd27 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 10:59:04 +0800 Subject: [PATCH 39/42] ADD file via upload --- src/UserManager.java | 58 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/UserManager.java diff --git a/src/UserManager.java b/src/UserManager.java new file mode 100644 index 0000000..6458b12 --- /dev/null +++ b/src/UserManager.java @@ -0,0 +1,58 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * 用户管理类,负责用户验证和账户管理 + */ +public class UserManager { + private Map users; + + public UserManager() { + initializeUsers(); + } + + /** + * 初始化预设用户账户 + */ + private void initializeUsers() { + users = new HashMap<>(); + + // 小学账户 + users.put("张三1", new User("张三1", "123", "小学")); + users.put("张三2", new User("张三2", "123", "小学")); + users.put("张三3", new User("张三3", "123", "小学")); + + // 初中账户 + users.put("李四1", new User("李四1", "123", "初中")); + users.put("李四2", new User("李四2", "123", "初中")); + users.put("李四3", new User("李四3", "123", "初中")); + + // 高中账户 + users.put("王五1", new User("王五1", "123", "高中")); + users.put("王五2", new User("王五2", "123", "高中")); + users.put("王五3", new User("王五3", "123", "高中")); + } + + /** + * 验证用户登录 + * @param username 用户名 + * @param password 密码 + * @return 验证成功返回用户对象,失败返回null + */ + public User authenticate(String username, String password) { + User user = users.get(username); + if (user != null && user.getPassword().equals(password)) { + return user; + } + return null; + } + + /** + * 检查用户类型是否有效 + * @param userType 用户类型 + * @return 是否有效 + */ + public boolean isValidUserType(String userType) { + return "小学".equals(userType) || "初中".equals(userType) || "高中".equals(userType); + } +} \ No newline at end of file -- 2.34.1 From f8b59f91466422b953e4602b4fe8aa4c94d50c67 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 17:14:56 +0800 Subject: [PATCH 40/42] ADD file via upload --- doc | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 doc diff --git a/doc b/doc new file mode 100644 index 0000000..ed69649 --- /dev/null +++ b/doc @@ -0,0 +1,125 @@ +# 数学试卷自动生成程序 + +一个在命令行运行的数学试卷生成器,支持小学/初中/高中三种难度,按用户维度避免题目重复。 + +## 目录 +- [功能特点](#功能特点) +- [运行环境要求](#运行环境要求) +- [快速开始(推荐分发)](#快速开始推荐分发) +- [使用说明](#使用说明) +- [账户信息](#账户信息) +- [题目难度说明](#题目难度说明) + - [小学](#小学) + - [初中](#初中) + - [高中](#高中) +- [文件保存](#文件保存) +- [项目结构](#项目结构) +- [开发与构建(IntelliJ IDEA)](#开发与构建intellij-idea) +- [常见问题与排查](#常见问题与排查) +- [注意事项](#注意事项) + +## 功能特点 +- 支持三个教学阶段:小学、初中、高中 +- 预设 9 个教师账户(每个阶段 3 个账户) +- 自动生成不重复的数学题目(以用户为维度) +- 按用户分类保存题目文件 +- 支持类型切换功能(无需重新登录即可切换难度) + +## 运行环境要求 +- 已安装 Java(推荐 JDK 18;JDK 17 也可)。 +- Windows 命令行环境(PowerShell 或 CMD)。 + +## 快速开始(推荐分发) +将以下文件打包并发送给使用者: +- projecttest.jar(已构建的可运行 JAR) +- 运行数学试卷生成器.bat(中文名启动脚本) + +使用方式: +1. 解压后保证 .bat 与 projecttest.jar 在同一文件夹。 +2. 双击任意一个 .bat 即可启动;脚本会自动寻找 JAVA_HOME 或 PATH 中的 java.exe,并以 UTF-8 输出。 +3. 如未安装 Java,脚本会给出提示,请先安装 JDK 17/18 并配置环境变量。 + +## 使用说明 +程序启动后将显示提示: +- 输入题目数量(10–30)生成试卷; +- 输入“切换为 小学/初中/高中”来切换难度;例如:切换为 初中; +- 输入 -1 退出当前用户并重新登录; +- 同一用户生成的题目不会重复。 + +## 账户信息 +### 小学账户 +- 用户名:张三1,密码:123 +- 用户名:张三2,密码:123 +- 用户名:张三3,密码:123 + +### 初中账户 +- 用户名:李四1,密码:123 +- 用户名:李四2,密码:123 +- 用户名:李四3,密码:123 + +### 高中账户 +- 用户名:王五1,密码:123 +- 用户名:王五2,密码:123 +- 用户名:王五3,密码:123 + +## 题目难度说明 +- 不同阶段的题目难度与运算比例不同:小学加减比例高,高中乘除比例高。 +- 括号会根据是否改变运算顺序而决定是否出现。 + +### 小学 +- 运算符:+、-、*、/ +- 操作数:1–5 个 +- 数值范围:1–100 +- 运算结果不会出现负数 + +### 初中 +- 包含小学所有运算 +- 新增:平方运算、开根号运算 +- 题目中至少包含一个平方或开根号运算 +- 题目中的开根号运算都是可以计算出来的 + +### 高中 +- 包含初中所有运算 +- 新增:sin、cos、tan 三角函数 +- 题目中至少包含一个三角函数运算 +- 题目中的三角函数都是可以运算出来的 + +## 文件保存 +- 生成的题目会保存在 `math_papers` 文件夹下 +- 每个用户有独立的文件夹 +- 文件名格式:`年-月-日-时-分-秒.txt` +- 每道题目有题号,题目之间空一行 + +## 项目结构 +- META-INF/MANIFEST.MF:清单文件(Main-Class: MathPaperGenerator)。 +- out/production/projecttest:模块编译输出(.class)。 +- out/artifacts/projecttest_jar/projecttest.jar:构建产物(JAR)。 +- run_math_paper_english.bat、运行数学试卷生成器.bat:启动脚本。 +- math_papers/:生成的试卷与历史记录(按用户分文件夹)。 + +## 开发与构建(IntelliJ IDEA) +1. 项目结构(Ctrl+Alt+Shift+S): + - Project SDK 设为 JDK 18(或 17);Project language level 与 Bytecode version 保持一致。 + - Modules > Sources:将 d:\projecttest 标记为 Sources Root;.idea 与 math_papers 标记为 Excluded。 + - Modules > Paths:选择“继承项目编译输出路径”,输出到 d:\projecttest\out。 +2. 构建项目:Build > Build/Rebuild Project,确认 out/production/projecttest 下生成 .class。 +3. 构件(Artifacts):projecttest:jar + - 输出布局包含“模块输出(projecttest)”与 META-INF(MANIFEST.MF)。 + - Build > Build Artifacts > Build projecttest:jar,生成 JAR 于 out/artifacts/projecttest_jar/。 +4. 运行: + - 命令行:`java -jar d:\projecttest\out\artifacts\projecttest_jar\projecttest.jar` + - 或双击两个 .bat 启动脚本。 + +## 常见问题与排查 +- 不支持的标志: 21:JDK 与语言级别不匹配。将 Project SDK/Language level/Bytecode 统一到 18(或 17)。 +- 没有为模块指定输出路径:在 Modules > Paths 中启用“继承项目编译输出路径”。 +- 没有主清单属性:确认 META-INF/MANIFEST.MF 存在并包含 `Main-Class: MathPaperGenerator`;构件输出布局包含清单与模块输出。 +- 找不到主类:主类名必须与清单一致,且 .class 已编译到 out/production/projecttest。 + +## 注意事项 +- 题目数量必须在 10–30 之间 +- 同一用户生成的题目不会重复 +- 程序会自动创建必要的文件夹 +- 支持中文界面,操作简单直观 + +如需重新打包分发版,直接使用 zip:`MathPaperGenerator_release.zip`,包含 JAR 与两个启动脚本,解压即用。 \ No newline at end of file -- 2.34.1 From 5dda64e29c89587eeacbcde606a17e7ba45d5e59 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 17:15:09 +0800 Subject: [PATCH 41/42] Delete 'doc' --- doc | 125 ------------------------------------------------------------ 1 file changed, 125 deletions(-) delete mode 100644 doc diff --git a/doc b/doc deleted file mode 100644 index ed69649..0000000 --- a/doc +++ /dev/null @@ -1,125 +0,0 @@ -# 数学试卷自动生成程序 - -一个在命令行运行的数学试卷生成器,支持小学/初中/高中三种难度,按用户维度避免题目重复。 - -## 目录 -- [功能特点](#功能特点) -- [运行环境要求](#运行环境要求) -- [快速开始(推荐分发)](#快速开始推荐分发) -- [使用说明](#使用说明) -- [账户信息](#账户信息) -- [题目难度说明](#题目难度说明) - - [小学](#小学) - - [初中](#初中) - - [高中](#高中) -- [文件保存](#文件保存) -- [项目结构](#项目结构) -- [开发与构建(IntelliJ IDEA)](#开发与构建intellij-idea) -- [常见问题与排查](#常见问题与排查) -- [注意事项](#注意事项) - -## 功能特点 -- 支持三个教学阶段:小学、初中、高中 -- 预设 9 个教师账户(每个阶段 3 个账户) -- 自动生成不重复的数学题目(以用户为维度) -- 按用户分类保存题目文件 -- 支持类型切换功能(无需重新登录即可切换难度) - -## 运行环境要求 -- 已安装 Java(推荐 JDK 18;JDK 17 也可)。 -- Windows 命令行环境(PowerShell 或 CMD)。 - -## 快速开始(推荐分发) -将以下文件打包并发送给使用者: -- projecttest.jar(已构建的可运行 JAR) -- 运行数学试卷生成器.bat(中文名启动脚本) - -使用方式: -1. 解压后保证 .bat 与 projecttest.jar 在同一文件夹。 -2. 双击任意一个 .bat 即可启动;脚本会自动寻找 JAVA_HOME 或 PATH 中的 java.exe,并以 UTF-8 输出。 -3. 如未安装 Java,脚本会给出提示,请先安装 JDK 17/18 并配置环境变量。 - -## 使用说明 -程序启动后将显示提示: -- 输入题目数量(10–30)生成试卷; -- 输入“切换为 小学/初中/高中”来切换难度;例如:切换为 初中; -- 输入 -1 退出当前用户并重新登录; -- 同一用户生成的题目不会重复。 - -## 账户信息 -### 小学账户 -- 用户名:张三1,密码:123 -- 用户名:张三2,密码:123 -- 用户名:张三3,密码:123 - -### 初中账户 -- 用户名:李四1,密码:123 -- 用户名:李四2,密码:123 -- 用户名:李四3,密码:123 - -### 高中账户 -- 用户名:王五1,密码:123 -- 用户名:王五2,密码:123 -- 用户名:王五3,密码:123 - -## 题目难度说明 -- 不同阶段的题目难度与运算比例不同:小学加减比例高,高中乘除比例高。 -- 括号会根据是否改变运算顺序而决定是否出现。 - -### 小学 -- 运算符:+、-、*、/ -- 操作数:1–5 个 -- 数值范围:1–100 -- 运算结果不会出现负数 - -### 初中 -- 包含小学所有运算 -- 新增:平方运算、开根号运算 -- 题目中至少包含一个平方或开根号运算 -- 题目中的开根号运算都是可以计算出来的 - -### 高中 -- 包含初中所有运算 -- 新增:sin、cos、tan 三角函数 -- 题目中至少包含一个三角函数运算 -- 题目中的三角函数都是可以运算出来的 - -## 文件保存 -- 生成的题目会保存在 `math_papers` 文件夹下 -- 每个用户有独立的文件夹 -- 文件名格式:`年-月-日-时-分-秒.txt` -- 每道题目有题号,题目之间空一行 - -## 项目结构 -- META-INF/MANIFEST.MF:清单文件(Main-Class: MathPaperGenerator)。 -- out/production/projecttest:模块编译输出(.class)。 -- out/artifacts/projecttest_jar/projecttest.jar:构建产物(JAR)。 -- run_math_paper_english.bat、运行数学试卷生成器.bat:启动脚本。 -- math_papers/:生成的试卷与历史记录(按用户分文件夹)。 - -## 开发与构建(IntelliJ IDEA) -1. 项目结构(Ctrl+Alt+Shift+S): - - Project SDK 设为 JDK 18(或 17);Project language level 与 Bytecode version 保持一致。 - - Modules > Sources:将 d:\projecttest 标记为 Sources Root;.idea 与 math_papers 标记为 Excluded。 - - Modules > Paths:选择“继承项目编译输出路径”,输出到 d:\projecttest\out。 -2. 构建项目:Build > Build/Rebuild Project,确认 out/production/projecttest 下生成 .class。 -3. 构件(Artifacts):projecttest:jar - - 输出布局包含“模块输出(projecttest)”与 META-INF(MANIFEST.MF)。 - - Build > Build Artifacts > Build projecttest:jar,生成 JAR 于 out/artifacts/projecttest_jar/。 -4. 运行: - - 命令行:`java -jar d:\projecttest\out\artifacts\projecttest_jar\projecttest.jar` - - 或双击两个 .bat 启动脚本。 - -## 常见问题与排查 -- 不支持的标志: 21:JDK 与语言级别不匹配。将 Project SDK/Language level/Bytecode 统一到 18(或 17)。 -- 没有为模块指定输出路径:在 Modules > Paths 中启用“继承项目编译输出路径”。 -- 没有主清单属性:确认 META-INF/MANIFEST.MF 存在并包含 `Main-Class: MathPaperGenerator`;构件输出布局包含清单与模块输出。 -- 找不到主类:主类名必须与清单一致,且 .class 已编译到 out/production/projecttest。 - -## 注意事项 -- 题目数量必须在 10–30 之间 -- 同一用户生成的题目不会重复 -- 程序会自动创建必要的文件夹 -- 支持中文界面,操作简单直观 - -如需重新打包分发版,直接使用 zip:`MathPaperGenerator_release.zip`,包含 JAR 与两个启动脚本,解压即用。 \ No newline at end of file -- 2.34.1 From 98ec2fb3cf7e6be8a3068cb9a057b9f6186dc656 Mon Sep 17 00:00:00 2001 From: hnu202326010320 <2482315830@qq.com> Date: Mon, 29 Sep 2025 17:15:37 +0800 Subject: [PATCH 42/42] ADD file via upload --- doc/README.md | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 doc/README.md diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..ed69649 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,125 @@ +# 数学试卷自动生成程序 + +一个在命令行运行的数学试卷生成器,支持小学/初中/高中三种难度,按用户维度避免题目重复。 + +## 目录 +- [功能特点](#功能特点) +- [运行环境要求](#运行环境要求) +- [快速开始(推荐分发)](#快速开始推荐分发) +- [使用说明](#使用说明) +- [账户信息](#账户信息) +- [题目难度说明](#题目难度说明) + - [小学](#小学) + - [初中](#初中) + - [高中](#高中) +- [文件保存](#文件保存) +- [项目结构](#项目结构) +- [开发与构建(IntelliJ IDEA)](#开发与构建intellij-idea) +- [常见问题与排查](#常见问题与排查) +- [注意事项](#注意事项) + +## 功能特点 +- 支持三个教学阶段:小学、初中、高中 +- 预设 9 个教师账户(每个阶段 3 个账户) +- 自动生成不重复的数学题目(以用户为维度) +- 按用户分类保存题目文件 +- 支持类型切换功能(无需重新登录即可切换难度) + +## 运行环境要求 +- 已安装 Java(推荐 JDK 18;JDK 17 也可)。 +- Windows 命令行环境(PowerShell 或 CMD)。 + +## 快速开始(推荐分发) +将以下文件打包并发送给使用者: +- projecttest.jar(已构建的可运行 JAR) +- 运行数学试卷生成器.bat(中文名启动脚本) + +使用方式: +1. 解压后保证 .bat 与 projecttest.jar 在同一文件夹。 +2. 双击任意一个 .bat 即可启动;脚本会自动寻找 JAVA_HOME 或 PATH 中的 java.exe,并以 UTF-8 输出。 +3. 如未安装 Java,脚本会给出提示,请先安装 JDK 17/18 并配置环境变量。 + +## 使用说明 +程序启动后将显示提示: +- 输入题目数量(10–30)生成试卷; +- 输入“切换为 小学/初中/高中”来切换难度;例如:切换为 初中; +- 输入 -1 退出当前用户并重新登录; +- 同一用户生成的题目不会重复。 + +## 账户信息 +### 小学账户 +- 用户名:张三1,密码:123 +- 用户名:张三2,密码:123 +- 用户名:张三3,密码:123 + +### 初中账户 +- 用户名:李四1,密码:123 +- 用户名:李四2,密码:123 +- 用户名:李四3,密码:123 + +### 高中账户 +- 用户名:王五1,密码:123 +- 用户名:王五2,密码:123 +- 用户名:王五3,密码:123 + +## 题目难度说明 +- 不同阶段的题目难度与运算比例不同:小学加减比例高,高中乘除比例高。 +- 括号会根据是否改变运算顺序而决定是否出现。 + +### 小学 +- 运算符:+、-、*、/ +- 操作数:1–5 个 +- 数值范围:1–100 +- 运算结果不会出现负数 + +### 初中 +- 包含小学所有运算 +- 新增:平方运算、开根号运算 +- 题目中至少包含一个平方或开根号运算 +- 题目中的开根号运算都是可以计算出来的 + +### 高中 +- 包含初中所有运算 +- 新增:sin、cos、tan 三角函数 +- 题目中至少包含一个三角函数运算 +- 题目中的三角函数都是可以运算出来的 + +## 文件保存 +- 生成的题目会保存在 `math_papers` 文件夹下 +- 每个用户有独立的文件夹 +- 文件名格式:`年-月-日-时-分-秒.txt` +- 每道题目有题号,题目之间空一行 + +## 项目结构 +- META-INF/MANIFEST.MF:清单文件(Main-Class: MathPaperGenerator)。 +- out/production/projecttest:模块编译输出(.class)。 +- out/artifacts/projecttest_jar/projecttest.jar:构建产物(JAR)。 +- run_math_paper_english.bat、运行数学试卷生成器.bat:启动脚本。 +- math_papers/:生成的试卷与历史记录(按用户分文件夹)。 + +## 开发与构建(IntelliJ IDEA) +1. 项目结构(Ctrl+Alt+Shift+S): + - Project SDK 设为 JDK 18(或 17);Project language level 与 Bytecode version 保持一致。 + - Modules > Sources:将 d:\projecttest 标记为 Sources Root;.idea 与 math_papers 标记为 Excluded。 + - Modules > Paths:选择“继承项目编译输出路径”,输出到 d:\projecttest\out。 +2. 构建项目:Build > Build/Rebuild Project,确认 out/production/projecttest 下生成 .class。 +3. 构件(Artifacts):projecttest:jar + - 输出布局包含“模块输出(projecttest)”与 META-INF(MANIFEST.MF)。 + - Build > Build Artifacts > Build projecttest:jar,生成 JAR 于 out/artifacts/projecttest_jar/。 +4. 运行: + - 命令行:`java -jar d:\projecttest\out\artifacts\projecttest_jar\projecttest.jar` + - 或双击两个 .bat 启动脚本。 + +## 常见问题与排查 +- 不支持的标志: 21:JDK 与语言级别不匹配。将 Project SDK/Language level/Bytecode 统一到 18(或 17)。 +- 没有为模块指定输出路径:在 Modules > Paths 中启用“继承项目编译输出路径”。 +- 没有主清单属性:确认 META-INF/MANIFEST.MF 存在并包含 `Main-Class: MathPaperGenerator`;构件输出布局包含清单与模块输出。 +- 找不到主类:主类名必须与清单一致,且 .class 已编译到 out/production/projecttest。 + +## 注意事项 +- 题目数量必须在 10–30 之间 +- 同一用户生成的题目不会重复 +- 程序会自动创建必要的文件夹 +- 支持中文界面,操作简单直观 + +如需重新打包分发版,直接使用 zip:`MathPaperGenerator_release.zip`,包含 JAR 与两个启动脚本,解压即用。 \ No newline at end of file -- 2.34.1