From 05fb0e052116dec4e007aac27779889bc34d79c5 Mon Sep 17 00:00:00 2001 From: peterpan Date: Sun, 28 Sep 2025 11:05:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 - doc/README.md | 303 +++++++++++++++++++++++++ src/generator/SeniorHighGenerator.java | 4 +- 3 files changed, 305 insertions(+), 4 deletions(-) delete mode 100644 README.md create mode 100644 doc/README.md diff --git a/README.md b/README.md deleted file mode 100644 index aa4a855..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# math-paper-cli - diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..74719b2 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,303 @@ +# 数学题目生成器 + +这是潘俊晖在《软件工程导论》课程中的个人项目。 +该项目是一个基于 Java 的命令行应用程序,支持用户登录并生成小学、初中、高中的数学题目。 +项目采用**策略模式**设计,便于扩展新的题目生成器。 + +--- + +## 环境要求 +- **JDK 版本**:JDK 17+(兼容 JDK 11) +- **依赖库**:纯 Java 项目,无需额外依赖 +- **推荐 IDE**:IntelliJ IDEA(也可通过命令行运行) + +--- + +## 运行 + +### 1. 通过 JRE 运行 jar 包 + +执行: +```aiignore +java -jar new-math-cli.jar +``` +### 2. 克隆仓库并通过 IDEA 运行 + +## 代码说明 + +### 登陆检查 +```java +private static void handleLogin(Scanner scanner) { + System.out.println("**********欢迎使用数学题目生成 Client **********"); + System.out.println("请输入用户名和密码,用空格隔开 (输入 'exit' 退出程序):"); + String line = scanner.nextLine(); + + if ("exit".equalsIgnoreCase(line)) { + System.out.println("感谢使用,程序已退出。"); + System.exit(0); + } + + String[] input = line.split(" "); + if (input.length == 2) { + authService.login(input[0], input[1]).ifPresentOrElse( + user -> { + currentUser = user; + currentLevel = user.getLevel(); + System.out.printf("当前选择为%s出题%n", currentLevel.getName());}, + () -> System.out.println("请输入正确的用户名、密码") + ); + } else { + System.out.println("输入格式不正确,请重新输入。"); + } +} +``` + +### 生成题目时检查输入 +```java +private static void handleQuestionGeneration(Scanner scanner) { + System.out.printf("准备生成%s数学题目, 请输入生成题目数量(输入-1将退出当前用户, 重新登录):%n", currentLevel.getName()); // 生成提示 + System.out.println("可输入“切换为(小学/初中/高中)”"); + String input = scanner.nextLine(); + + if (input.startsWith("切换为")) { + handleLevelSwitch(input); + return; + } + + try { + int count = Integer.parseInt(input); + if (count == -1) { + currentUser = null; + currentLevel = null; + System.out.println("已退出,请重新登录。"); + } else if (count >= 10 && count <= 30) { + testPaperService.generateAndSave(currentUser, currentLevel, count); + } else { + System.out.println("输入无效,请输入10-30之间的数字或-1。"); + } + } catch (NumberFormatException e) { + System.out.println("输入无效,请输入一个数字。"); + } +} +``` +### 题目查重和生成部分 +```java +public void generateAndSave(User user, Level level, int count) { + Set existingQuestions = loadExistingQuestions(user.getUsername()); + System.out.println("检测到历史题目 " + existingQuestions.size() + " 道。"); + + IQuestionGenerator generator = createGenerator(level); + Set newQuestions = new HashSet<>(); + + // 生成新的、与历史和本次不重复的题目 + for (int i = 0; i < count; i++) { + Set used = new HashSet<>(existingQuestions); + used.addAll(newQuestions); + + String question = generator.generate(used); + newQuestions.add(question); + } + + saveToFile(user.getUsername(), newQuestions); +} + +private Set loadExistingQuestions(String username) { + Set existingQuestions = new HashSet<>(); + File userDir = new File(username); + if (!userDir.exists() || !userDir.isDirectory()) { + return existingQuestions; + } + + File[] files = userDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".txt")); + if (files == null) { + return existingQuestions; + } + + for (File file : files) { + try { + Files.lines(file.toPath()).forEach(line -> { + if (line.matches("^\\d+\\.\\s.*")) { + String question = line.substring(line.indexOf(' ') + 1).trim(); + existingQuestions.add(question); + } + }); + } catch (IOException e) { + System.err.println("错误:读取历史文件失败: " + file.getName()); + } + } + return existingQuestions; +} +``` + +### 题目生成接口和抽象类 +```java +// generator/IQuestionGenerator.java +package generator; + +import java.util.Set; + +public interface IQuestionGenerator { + String generate(Set existingQuestions); +} + +``` +和 +```java +// generator/BaseGenerator.java +package generator; + +import java.util.Random; +import java.util.Set; + +public abstract class BaseGenerator implements IQuestionGenerator { + protected final Random random = new Random(); + + protected int getRandomOperand() { + return random.nextInt(100) + 1; + } + + protected int getNumberOfOperands() { + return random.nextInt(5) + 1; + } + + @Override + public String generate(Set existingQuestions) { + String question; + do { + question = createUniqueQuestion(); + } while (existingQuestions.contains(question)); + return question; + } + + protected abstract String createUniqueQuestion(); +} + +``` +### 小学题目生成器 +```java +public class ElementarySchoolGenerator extends BaseGenerator { + private final String[] OPERATORS = {"+", "-", "*", "/"}; + + @Override + protected String createUniqueQuestion() { + int numOperands = random.nextInt(4) + 2; + StringBuilder sb = new StringBuilder(); + + int runningTotal = getRandomOperand(); + sb.append(runningTotal); + + for (int i = 0; i < numOperands - 1; i++) { + String operator = pickOperator(); + int operand = getRandomOperand(); + + operator = adjustOperator(operator, operand, runningTotal); + runningTotal = applyOperation(runningTotal, operator, operand); + + sb.append(" ").append(operator).append(" ").append(operand); + } + + return sb.append(" = ?").toString(); + } + + private String pickOperator() { + return OPERATORS[random.nextInt(OPERATORS.length)]; + } + + private String adjustOperator(String op, int operand, int current) { + if (op.equals("-") && operand > current) return "+"; + if (op.equals("/") && (operand == 0 || current % operand != 0)) return "*"; + return op; + } + + private int applyOperation(int current, String op, int operand) { + switch (op) { + case "+": return current + operand; + case "-": return current - operand; + case "*": return current * operand; + case "/": return current / operand; + default: throw new IllegalArgumentException("Unknown operator: " + op); + } + } +} +``` +### 初中题目生成器 +```java +public class JuniorHighGenerator extends BaseGenerator { + @Override + protected String createUniqueQuestion() { + int numOperands = random.nextInt(4) + 2; + + List operands = new ArrayList<>(); + for (int i = 0; i < numOperands; i++) { + operands.add(String.valueOf(getRandomOperand())); + } + + int specialIndex = random.nextInt(numOperands); + int originalValue = Integer.parseInt(operands.get(specialIndex)); + + if (random.nextBoolean()) { + operands.set(specialIndex, "sqrt(" + (originalValue * originalValue) + ")"); + } else { + operands.set(specialIndex, originalValue + "^2"); + } + + StringBuilder questionBuilder = new StringBuilder(); + String[] basicOperators = {"+", "-", "*"}; + + questionBuilder.append(operands.get(0)); + for (int i = 1; i < numOperands; i++) { + String operator = basicOperators[random.nextInt(basicOperators.length)]; + questionBuilder.append(" ").append(operator).append(" ").append(operands.get(i)); + } + questionBuilder.append(" = ?"); + + return questionBuilder.toString(); + } +} +``` +### 高中题目生成器 +```java +public class SeniorHighGenerator extends BaseGenerator { + @Override + protected String createUniqueQuestion() { + int numOperands = random.nextInt(4) + 2; + + List operands = new ArrayList<>(); + for (int i = 0; i < numOperands; i++) { + operands.add(String.valueOf(getRandomOperand())); + } + + int specialIndex = random.nextInt(numOperands); + String[] trigFunctions = {"sin", "cos", "tan"}; + String func = trigFunctions[random.nextInt(trigFunctions.length)]; + int angle = random.nextInt(91); + operands.set(specialIndex, String.format("%s(%d)", func, angle)); + + StringBuilder questionBuilder = new StringBuilder(); + String[] basicOperators = {"+", "-", "*"}; + + questionBuilder.append(operands.get(0)); + + for (int i = 1; i < numOperands; i++) { + String operator = basicOperators[random.nextInt(basicOperators.length)]; + questionBuilder.append(" ").append(operator).append(" ").append(operands.get(i)); + } + questionBuilder.append(" = ?"); + + return questionBuilder.toString(); + } +} +``` +--- + +## 后续改进方向 + +- 增加题目难度参数(如:数字范围、运算符种类)。 + +- 增加 GUI 界面,提升交互体验。 + +- 增加单元测试和持续集成,确保题目生成正确性。 + +- 题目结果可导出为 PDF/Word 试卷格式。 + +--- diff --git a/src/generator/SeniorHighGenerator.java b/src/generator/SeniorHighGenerator.java index d8a8e27..b73b192 100644 --- a/src/generator/SeniorHighGenerator.java +++ b/src/generator/SeniorHighGenerator.java @@ -14,8 +14,8 @@ public class SeniorHighGenerator extends BaseGenerator { } int specialIndex = random.nextInt(numOperands); - String[] trigFuncs = {"sin", "cos", "tan"}; - String func = trigFuncs[random.nextInt(trigFuncs.length)]; + String[] trigFunctions = {"sin", "cos", "tan"}; + String func = trigFunctions[random.nextInt(trigFunctions.length)]; int angle = random.nextInt(91); operands.set(specialIndex, String.format("%s(%d)", func, angle));