From 675c7906a43e0a7b856ecb793cf06d38fad11d5d Mon Sep 17 00:00:00 2001 From: tianyuan <2861334240@qq.com> Date: Fri, 26 Sep 2025 13:15:31 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MathTestGenerator.java | 398 +++++++++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 src/MathTestGenerator.java diff --git a/src/MathTestGenerator.java b/src/MathTestGenerator.java new file mode 100644 index 0000000..d5d4832 --- /dev/null +++ b/src/MathTestGenerator.java @@ -0,0 +1,398 @@ +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 中小学数学卷子自动生成程序 + * 作者:张三 + * 班级:软1班 + */ +public class MathTestGenerator { + + private static final Map USERS = new HashMap<>(); + static { + // 小学账户 + USERS.put("张三1", new User("张三1", "123", UserType.PRIMARY)); + USERS.put("张三2", new User("张三2", "123", UserType.PRIMARY)); + USERS.put("张三3", new User("张三3", "123", UserType.PRIMARY)); + // 初中账户 + USERS.put("李四1", new User("李四1", "123", UserType.JUNIOR)); + USERS.put("李四2", new User("李四2", "123", UserType.JUNIOR)); + USERS.put("李四3", new User("李四3", "123", UserType.JUNIOR)); + // 高中账户 + USERS.put("王五1", new User("王五1", "123", UserType.SENIOR)); + USERS.put("王五2", new User("王五2", "123", UserType.SENIOR)); + USERS.put("王五3", new User("王五3", "123", UserType.SENIOR)); + } + + // 用户类型枚举 + private enum UserType { + PRIMARY("小学"), JUNIOR("初中"), SENIOR("高中"); + + private final String name; + UserType(String name) { this.name = name; } + public String getName() { return name; } + } + + // 用户类 + private static class User { + String username; + String password; + UserType type; + + User(String username, String password, UserType type) { + this.username = username; + this.password = password; + this.type = type; + } + } + + // 运算符枚举 + private enum Operator { + ADD("+", 1), SUBTRACT("-", 1), MULTIPLY("*", 2), DIVIDE("/", 2), + POWER("^", 3), SQRT("√", 3), SIN("sin", 4), COS("cos", 4), TAN("tan", 4); + + private final String symbol; + private final int priority; + Operator(String symbol, int priority) { + this.symbol = symbol; + this.priority = priority; + } + public String getSymbol() { return symbol; } + public int getPriority() { return priority; } + } + + private User currentUser; + private UserType currentType; + private Set generatedQuestions; + private Scanner scanner; + private String baseDir; + + public MathTestGenerator() { + this.scanner = new Scanner(System.in); + this.generatedQuestions = new HashSet<>(); + this.baseDir = System.getProperty("user.dir") + File.separator + "papers"; + initializeStorage(); + } + + /** + * 初始化存储目录 + */ + private void initializeStorage() { + File dir = new File(baseDir); + if (!dir.exists()) { + dir.mkdirs(); + } + } + + /** + * 主程序入口 + */ + public void start() { + System.out.println("=== 中小学数学卷子自动生成程序 ==="); + + while (true) { + if (login()) { + generatePapers(); + } + } + } + + /** + * 用户登录 + */ + private boolean login() { + while (true) { + System.out.print("请输入用户名和密码(用空格隔开,输入exit退出程序):"); + String input = scanner.nextLine().trim(); + + if (input.equalsIgnoreCase("exit")) { + System.exit(0); + } + + String[] credentials = input.split("\\s+"); + if (credentials.length != 2) { + System.out.println("请输入正确的用户名、密码"); + continue; + } + + String username = credentials[0]; + String password = credentials[1]; + + User user = USERS.get(username); + if (user != null && user.password.equals(password)) { + currentUser = user; + currentType = user.type; + System.out.println("当前选择为" + currentType.getName() + "出题"); + loadGeneratedQuestions(); + return true; + } else { + System.out.println("请输入正确的用户名、密码"); + } + } + } + + /** + * 加载已生成的题目用于查重 + */ + private void loadGeneratedQuestions() { + generatedQuestions.clear(); + File userDir = new File(baseDir + File.separator + currentUser.username); + if (userDir.exists() && userDir.isDirectory()) { + File[] files = userDir.listFiles((dir, name) -> name.endsWith(".txt")); + if (files != null) { + for (File file : files) { + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.matches("^\\d+\\.\\s+.+")) { + String question = line.substring(line.indexOf(".") + 1).trim(); + generatedQuestions.add(normalizeQuestion(question)); + } + } + } catch (IOException e) { + System.out.println("读取历史题目失败: " + e.getMessage()); + } + } + } + } + } + + /** + * 生成试卷 + */ + private void generatePapers() { + while (true) { + System.out.print("准备生成" + currentType.getName() + + "数学题目,请输入生成题目数量(10-30,输入-1退出当前用户):"); + + String input = scanner.nextLine().trim(); + + if (input.equals("-1")) { + currentUser = null; + currentType = null; + System.out.println("已退出当前用户,请重新登录"); + return; + } + + if (isSwitchCommand(input)) { + handleSwitchCommand(input); + continue; + } + + try { + int count = Integer.parseInt(input); + if (count >= 10 && count <= 30) { + generateTestPaper(count); + } else { + System.out.println("题目数量应在10-30之间"); + } + } catch (NumberFormatException e) { + System.out.println("请输入有效的数字"); + } + } + } + + /** + * 检查是否为切换命令 + */ + private boolean isSwitchCommand(String input) { + return input.startsWith("切换为"); + } + + /** + * 处理切换命令 + */ + private void handleSwitchCommand(String input) { + String typeStr = input.substring(3).trim(); + try { + UserType newType = UserType.valueOf(typeStr.toUpperCase()); + currentType = newType; + System.out.println("准备生成" + currentType.getName() + "数学题目,请输入生成题目数量"); + } catch (IllegalArgumentException e) { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + } + } + + /** + * 生成试卷文件 + */ + private void generateTestPaper(int questionCount) { + List questions = new ArrayList<>(); + int generated = 0; + int attempts = 0; + final int MAX_ATTEMPTS = 1000; + + while (generated < questionCount && attempts < MAX_ATTEMPTS) { + String question = generateQuestion(); + String normalized = normalizeQuestion(question); + + if (!generatedQuestions.contains(normalized)) { + questions.add(question); + generatedQuestions.add(normalized); + generated++; + } + attempts++; + } + + if (generated < questionCount) { + System.out.println("警告:无法生成足够的不重复题目,已生成 " + generated + " 道题"); + } + + saveToFile(questions); + System.out.println("试卷生成成功!"); + } + + /** + * 生成单个题目 + */ + private String generateQuestion() { + Random random = new Random(); + int operandCount = random.nextInt(5) + 1; // 1-5个操作数 + StringBuilder question = new StringBuilder(); + List operands = new ArrayList<>(); + List operators = new ArrayList<>(); + + // 生成操作数 + for (int i = 0; i < operandCount; i++) { + operands.add(random.nextInt(100) + 1); + } + + // 根据难度生成运算符 + switch (currentType) { + case PRIMARY: + generatePrimaryOperators(operators, operandCount - 1, random); + break; + case JUNIOR: + generateJuniorOperators(operators, operandCount - 1, random); + break; + case SENIOR: + generateSeniorOperators(operators, operandCount - 1, random); + break; + } + + // 构建题目表达式 + question.append(operands.get(0)); + for (int i = 0; i < operators.size(); i++) { + Operator op = operators.get(i); + if (op == Operator.SQRT) { + question.insert(0, "√(").append(")"); + question.append(op.getSymbol()).append(operands.get(i + 1)); + } else if (op == Operator.SIN || op == Operator.COS || op == Operator.TAN) { + question.append(op.getSymbol()).append("(").append(operands.get(i + 1)).append(")"); + } else { + question.append(" ").append(op.getSymbol()).append(" ").append(operands.get(i + 1)); + } + } + + // 随机添加括号 + if (operandCount > 2 && random.nextBoolean()) { + question.insert(0, "("); + int insertPos = question.indexOf(" ", question.indexOf(" ") + 1); + if (insertPos != -1) { + question.insert(insertPos + 1, ")"); + } + } + + return question.toString(); + } + + /** + * 生成小学运算符 + */ + private void generatePrimaryOperators(List operators, int count, Random random) { + Operator[] primaryOps = {Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE}; + for (int i = 0; i < count; i++) { + operators.add(primaryOps[random.nextInt(primaryOps.length)]); + } + } + + /** + * 生成初中运算符(必须包含平方或开根号) + */ + private void generateJuniorOperators(List operators, int count, Random random) { + Operator[] juniorOps = {Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE, + Operator.POWER, Operator.SQRT}; + + // 确保至少有一个平方或开根号 + boolean hasSpecialOp = false; + for (int i = 0; i < count; i++) { + Operator op = juniorOps[random.nextInt(juniorOps.length)]; + if (op == Operator.POWER || op == Operator.SQRT) { + hasSpecialOp = true; + } + operators.add(op); + } + + if (!hasSpecialOp && count > 0) { + operators.set(random.nextInt(count), + random.nextBoolean() ? Operator.POWER : Operator.SQRT); + } + } + + /** + * 生成高中运算符(必须包含三角函数) + */ + private void generateSeniorOperators(List operators, int count, Random random) { + Operator[] seniorOps = {Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE, + Operator.POWER, Operator.SQRT, Operator.SIN, Operator.COS, Operator.TAN}; + + // 确保至少有一个三角函数 + boolean hasTrigOp = false; + for (int i = 0; i < count; i++) { + Operator op = seniorOps[random.nextInt(seniorOps.length)]; + if (op == Operator.SIN || op == Operator.COS || op == Operator.TAN) { + hasTrigOp = true; + } + operators.add(op); + } + + if (!hasTrigOp && count > 0) { + Operator[] trigOps = {Operator.SIN, Operator.COS, Operator.TAN}; + operators.set(random.nextInt(count), trigOps[random.nextInt(trigOps.length)]); + } + } + + /** + * 规范化题目用于查重 + */ + private String normalizeQuestion(String question) { + return question.replaceAll("\\s+", "").toLowerCase(); + } + + /** + * 保存题目到文件 + */ + private void saveToFile(List questions) { + String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); + String filename = timestamp + ".txt"; + String userDirPath = baseDir + File.separator + currentUser.username; + + File userDir = new File(userDirPath); + if (!userDir.exists()) { + userDir.mkdirs(); + } + + File file = new File(userDir, filename); + try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { + for (int i = 0; i < questions.size(); i++) { + writer.println((i + 1) + ". " + questions.get(i)); + if (i < questions.size() - 1) { + writer.println(); + } + } + } catch (IOException e) { + System.out.println("保存文件失败: " + e.getMessage()); + } + } + + + + /** + * 主方法 + */ + public static void main(String[] args) { + MathTestGenerator generator = new MathTestGenerator(); + generator.start(); + } +} \ No newline at end of file -- 2.34.1 From 9eaadbc1d09465bc93a2bd587acadd2dc147fe68 Mon Sep 17 00:00:00 2001 From: tianyuan <2861334240@qq.com> Date: Sat, 27 Sep 2025 13:52:01 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AbstractMathGenerator.java | 37 ++++ src/FileService.java | 86 ++++++++ src/MathGenerator.java | 26 +++ src/MathTestGenerator.java | 377 +++++++-------------------------- src/Operator.java | 32 +++ src/QuestionService.java | 192 +++++++++++++++++ src/User.java | 21 ++ src/UserService.java | 54 +++++ src/UserType.java | 32 +++ src/ValidationService.java | 49 +++++ 10 files changed, 611 insertions(+), 295 deletions(-) create mode 100644 src/AbstractMathGenerator.java create mode 100644 src/FileService.java create mode 100644 src/MathGenerator.java create mode 100644 src/Operator.java create mode 100644 src/QuestionService.java create mode 100644 src/User.java create mode 100644 src/UserService.java create mode 100644 src/UserType.java create mode 100644 src/ValidationService.java diff --git a/src/AbstractMathGenerator.java b/src/AbstractMathGenerator.java new file mode 100644 index 0000000..d0385ed --- /dev/null +++ b/src/AbstractMathGenerator.java @@ -0,0 +1,37 @@ +import java.util.List; + +/** + * 数学题目生成器抽象类 + */ +public abstract class AbstractMathGenerator implements MathGenerator { + protected String currentDifficulty; + protected String currentUser; + + /** + * 验证题目数量范围 + */ + protected boolean validateQuestionCount(int count) { + return count >= 10 && count <= 30 || count == -1; + } + + /** + * 验证难度级别 + */ + protected boolean validateDifficulty(String difficulty) { + return difficulty.equals("小学") || difficulty.equals("初中") || difficulty.equals("高中"); + } + + /** + * 获取当前难度 + */ + public String getCurrentDifficulty() { + return currentDifficulty; + } + + /** + * 获取当前用户 + */ + public String getCurrentUser() { + return currentUser; + } +} \ No newline at end of file diff --git a/src/FileService.java b/src/FileService.java new file mode 100644 index 0000000..6bcf2f3 --- /dev/null +++ b/src/FileService.java @@ -0,0 +1,86 @@ +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + * 文件操作服务 + */ +public class FileService { + private final String baseDir; + + public FileService() { + this.baseDir = System.getProperty("user.dir") + File.separator + "papers"; + initializeStorage(); + } + + /** + * 初始化存储目录 + */ + private void initializeStorage() { + File dir = new File(baseDir); + if (!dir.exists()) { + dir.mkdirs(); + } + } + + /** + * 保存题目到文件 + */ + public void saveQuestions(String username, List questions) { + String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); + String filename = timestamp + ".txt"; + String userDirPath = baseDir + File.separator + username; + + File userDir = new File(userDirPath); + if (!userDir.exists()) { + userDir.mkdirs(); + } + + File file = new File(userDir, filename); + try (PrintWriter writer = new PrintWriter(new FileWriter(file, true))) { + for (int i = 0; i < questions.size(); i++) { + writer.println((i + 1) + ". " + questions.get(i)); + if (i < questions.size() - 1) { + writer.println(); + } + } + } catch (IOException e) { + System.err.println("保存文件失败: " + e.getMessage()); + } + } + + /** + * 加载用户的历史题目用于查重 + */ + public void loadHistoryQuestions(String username, java.util.Set questionSet) { + File userDir = new File(baseDir + File.separator + username); + if (!userDir.exists() || !userDir.isDirectory()) { + return; + } + + File[] files = userDir.listFiles((dir, name) -> name.endsWith(".txt")); + if (files == null) return; + + for (File file : files) { + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.matches("^\\d+\\.\\s+.+")) { + String question = line.substring(line.indexOf(".") + 1).trim(); + questionSet.add(normalizeQuestion(question)); + } + } + } catch (IOException e) { + System.err.println("读取历史题目失败: " + e.getMessage()); + } + } + } + + /** + * 规范化题目 + */ + private String normalizeQuestion(String question) { + return question.replaceAll("\\s+", "").toLowerCase(); + } +} \ No newline at end of file diff --git a/src/MathGenerator.java b/src/MathGenerator.java new file mode 100644 index 0000000..f7c617c --- /dev/null +++ b/src/MathGenerator.java @@ -0,0 +1,26 @@ + +import java.util.List; +/** + * 数学题目生成器接口 + */ +public interface MathGenerator { + /** + * 生成指定数量的题目 + */ + List generateQuestions(int count); + + /** + * 切换难度级别 + */ + void switchDifficulty(String level); + + /** + * 用户登录 + */ + boolean login(String username, String password); + + /** + * 保存题目到文件 + */ + void saveToFile(List questions); +} \ No newline at end of file diff --git a/src/MathTestGenerator.java b/src/MathTestGenerator.java index d5d4832..ad7a0c5 100644 --- a/src/MathTestGenerator.java +++ b/src/MathTestGenerator.java @@ -1,107 +1,93 @@ -import java.io.*; -import java.text.SimpleDateFormat; +import entities.User; +import entities.UserType; import java.util.*; /** - * 中小学数学卷子自动生成程序 + * 中小学数学卷子自动生成程序 - 主类 * 作者:张三 * 班级:软1班 */ -public class MathTestGenerator { - - private static final Map USERS = new HashMap<>(); - static { - // 小学账户 - USERS.put("张三1", new User("张三1", "123", UserType.PRIMARY)); - USERS.put("张三2", new User("张三2", "123", UserType.PRIMARY)); - USERS.put("张三3", new User("张三3", "123", UserType.PRIMARY)); - // 初中账户 - USERS.put("李四1", new User("李四1", "123", UserType.JUNIOR)); - USERS.put("李四2", new User("李四2", "123", UserType.JUNIOR)); - USERS.put("李四3", new User("李四3", "123", UserType.JUNIOR)); - // 高中账户 - USERS.put("王五1", new User("王五1", "123", UserType.SENIOR)); - USERS.put("王五2", new User("王五2", "123", UserType.SENIOR)); - USERS.put("王五3", new User("王五3", "123", UserType.SENIOR)); - } +public class MathTestGenerator extends AbstractMathGenerator { + private final UserService userService; + private final QuestionService questionService; + private final FileService fileService; + private final ValidationService validationService; + private final Scanner scanner; - // 用户类型枚举 - private enum UserType { - PRIMARY("小学"), JUNIOR("初中"), SENIOR("高中"); + private User currentUser; - private final String name; - UserType(String name) { this.name = name; } - public String getName() { return name; } + public MathTestGenerator() { + this.userService = new UserService(); + this.questionService = new QuestionService(); + this.fileService = new FileService(); + this.validationService = new ValidationService(); + this.scanner = new Scanner(System.in); } - // 用户类 - private static class User { - String username; - String password; - UserType type; + @Override + public boolean login(String username, String password) { + User user = userService.authenticate(username, password); + if (user != null) { + this.currentUser = user; + this.currentDifficulty = user.getType().getName(); + + System.out.println("当前选择为" + currentDifficulty + "出题"); - User(String username, String password, UserType type) { - this.username = username; - this.password = password; - this.type = type; + // 加载历史题目用于查重 + Set historyQuestions = new HashSet<>(); + fileService.loadHistoryQuestions(username, historyQuestions); + // 这里需要将历史题目传递给questionService + return true; } + return false; } - // 运算符枚举 - private enum Operator { - ADD("+", 1), SUBTRACT("-", 1), MULTIPLY("*", 2), DIVIDE("/", 2), - POWER("^", 3), SQRT("√", 3), SIN("sin", 4), COS("cos", 4), TAN("tan", 4); + @Override + public List generateQuestions(int count) { + if (currentUser == null) { + throw new IllegalStateException("请先登录"); + } + + questionService.setCurrentType(UserType.fromName(currentDifficulty)); + List questions = new ArrayList<>(); - private final String symbol; - private final int priority; - Operator(String symbol, int priority) { - this.symbol = symbol; - this.priority = priority; + for (int i = 0; i < count; i++) { + questions.add(questionService.generateQuestion()); } - public String getSymbol() { return symbol; } - public int getPriority() { return priority; } + + return questions; } - private User currentUser; - private UserType currentType; - private Set generatedQuestions; - private Scanner scanner; - private String baseDir; + @Override + public void switchDifficulty(String level) { - public MathTestGenerator() { - this.scanner = new Scanner(System.in); - this.generatedQuestions = new HashSet<>(); - this.baseDir = System.getProperty("user.dir") + File.separator + "papers"; - initializeStorage(); + this.currentDifficulty = level; + System.out.println("准备生成" + level + "数学题目,请输入生成题目数量"); } - /** - * 初始化存储目录 - */ - private void initializeStorage() { - File dir = new File(baseDir); - if (!dir.exists()) { - dir.mkdirs(); - } + @Override + public void saveToFile(List questions) { + fileService.saveQuestions(currentUser.getUsername(), questions); } /** - * 主程序入口 + * 启动程序 */ public void start() { System.out.println("=== 中小学数学卷子自动生成程序 ==="); while (true) { - if (login()) { + if (performLogin()) { + generatePapers(); } } } /** - * 用户登录 + * 执行登录流程 */ - private boolean login() { + private boolean performLogin() { while (true) { System.out.print("请输入用户名和密码(用空格隔开,输入exit退出程序):"); String input = scanner.nextLine().trim(); @@ -110,21 +96,16 @@ public class MathTestGenerator { System.exit(0); } - String[] credentials = input.split("\\s+"); - if (credentials.length != 2) { + if (!validationService.isValidCredentialsFormat(input)) { System.out.println("请输入正确的用户名、密码"); continue; } + String[] credentials = input.split("\\s+"); String username = credentials[0]; String password = credentials[1]; - User user = USERS.get(username); - if (user != null && user.password.equals(password)) { - currentUser = user; - currentType = user.type; - System.out.println("当前选择为" + currentType.getName() + "出题"); - loadGeneratedQuestions(); + if (login(username, password)) { return true; } else { System.out.println("请输入正确的用户名、密码"); @@ -133,261 +114,67 @@ public class MathTestGenerator { } /** - * 加载已生成的题目用于查重 - */ - private void loadGeneratedQuestions() { - generatedQuestions.clear(); - File userDir = new File(baseDir + File.separator + currentUser.username); - if (userDir.exists() && userDir.isDirectory()) { - File[] files = userDir.listFiles((dir, name) -> name.endsWith(".txt")); - if (files != null) { - for (File file : files) { - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { - String line; - while ((line = reader.readLine()) != null) { - if (line.matches("^\\d+\\.\\s+.+")) { - String question = line.substring(line.indexOf(".") + 1).trim(); - generatedQuestions.add(normalizeQuestion(question)); - } - } - } catch (IOException e) { - System.out.println("读取历史题目失败: " + e.getMessage()); - } - } - } - } - } - - /** - * 生成试卷 + * 生成试卷流程 */ private void generatePapers() { while (true) { - System.out.print("准备生成" + currentType.getName() + + System.out.print("准备生成" + currentDifficulty + "数学题目,请输入生成题目数量(10-30,输入-1退出当前用户):"); String input = scanner.nextLine().trim(); if (input.equals("-1")) { currentUser = null; - currentType = null; + currentDifficulty = null; + questionService.clearGeneratedQuestions(); System.out.println("已退出当前用户,请重新登录"); return; } - if (isSwitchCommand(input)) { + if (validationService.isValidSwitchCommand(input)) { + handleSwitchCommand(input); continue; } + if (!validationService.isValidQuestionCount(input)) { + System.out.println("题目数量应在10-30之间"); + continue; + } + try { int count = Integer.parseInt(input); - if (count >= 10 && count <= 30) { - generateTestPaper(count); - } else { - System.out.println("题目数量应在10-30之间"); - } - } catch (NumberFormatException e) { - System.out.println("请输入有效的数字"); + List questions = generateQuestions(count); + saveToFile(questions); + System.out.println("试卷生成成功!生成题目数量:" + questions.size()); + } catch (Exception e) { + System.out.println("生成题目失败: " + e.getMessage()); } } } - /** - * 检查是否为切换命令 - */ - private boolean isSwitchCommand(String input) { - return input.startsWith("切换为"); - } - /** * 处理切换命令 */ private void handleSwitchCommand(String input) { - String typeStr = input.substring(3).trim(); - try { - UserType newType = UserType.valueOf(typeStr.toUpperCase()); - currentType = newType; - System.out.println("准备生成" + currentType.getName() + "数学题目,请输入生成题目数量"); - } catch (IllegalArgumentException e) { - System.out.println("请输入小学、初中和高中三个选项中的一个"); - } - } + String level = validationService.extractDifficulty(input); + while(!level.equals("小学")&&!level.equals("初中")&&!level.equals("高中")) { + System.out.print("请输入小学、初中和高中三个选项中的一个\n"); + Scanner sc = new Scanner(System.in); - /** - * 生成试卷文件 - */ - private void generateTestPaper(int questionCount) { - List questions = new ArrayList<>(); - int generated = 0; - int attempts = 0; - final int MAX_ATTEMPTS = 1000; - - while (generated < questionCount && attempts < MAX_ATTEMPTS) { - String question = generateQuestion(); - String normalized = normalizeQuestion(question); - - if (!generatedQuestions.contains(normalized)) { - questions.add(question); - generatedQuestions.add(normalized); - generated++; - } - attempts++; - } + level = validationService.extractDifficulty(sc.nextLine().trim()); - if (generated < questionCount) { - System.out.println("警告:无法生成足够的不重复题目,已生成 " + generated + " 道题"); } - - saveToFile(questions); - System.out.println("试卷生成成功!"); - } - - /** - * 生成单个题目 - */ - private String generateQuestion() { - Random random = new Random(); - int operandCount = random.nextInt(5) + 1; // 1-5个操作数 - StringBuilder question = new StringBuilder(); - List operands = new ArrayList<>(); - List operators = new ArrayList<>(); - - // 生成操作数 - for (int i = 0; i < operandCount; i++) { - operands.add(random.nextInt(100) + 1); - } - - // 根据难度生成运算符 - switch (currentType) { - case PRIMARY: - generatePrimaryOperators(operators, operandCount - 1, random); - break; - case JUNIOR: - generateJuniorOperators(operators, operandCount - 1, random); - break; - case SENIOR: - generateSeniorOperators(operators, operandCount - 1, random); - break; - } - - // 构建题目表达式 - question.append(operands.get(0)); - for (int i = 0; i < operators.size(); i++) { - Operator op = operators.get(i); - if (op == Operator.SQRT) { - question.insert(0, "√(").append(")"); - question.append(op.getSymbol()).append(operands.get(i + 1)); - } else if (op == Operator.SIN || op == Operator.COS || op == Operator.TAN) { - question.append(op.getSymbol()).append("(").append(operands.get(i + 1)).append(")"); - } else { - question.append(" ").append(op.getSymbol()).append(" ").append(operands.get(i + 1)); - } - } - - // 随机添加括号 - if (operandCount > 2 && random.nextBoolean()) { - question.insert(0, "("); - int insertPos = question.indexOf(" ", question.indexOf(" ") + 1); - if (insertPos != -1) { - question.insert(insertPos + 1, ")"); - } - } - - return question.toString(); - } - - /** - * 生成小学运算符 - */ - private void generatePrimaryOperators(List operators, int count, Random random) { - Operator[] primaryOps = {Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE}; - for (int i = 0; i < count; i++) { - operators.add(primaryOps[random.nextInt(primaryOps.length)]); - } - } - - /** - * 生成初中运算符(必须包含平方或开根号) - */ - private void generateJuniorOperators(List operators, int count, Random random) { - Operator[] juniorOps = {Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE, - Operator.POWER, Operator.SQRT}; - - // 确保至少有一个平方或开根号 - boolean hasSpecialOp = false; - for (int i = 0; i < count; i++) { - Operator op = juniorOps[random.nextInt(juniorOps.length)]; - if (op == Operator.POWER || op == Operator.SQRT) { - hasSpecialOp = true; - } - operators.add(op); - } - - if (!hasSpecialOp && count > 0) { - operators.set(random.nextInt(count), - random.nextBoolean() ? Operator.POWER : Operator.SQRT); - } - } - - /** - * 生成高中运算符(必须包含三角函数) - */ - private void generateSeniorOperators(List operators, int count, Random random) { - Operator[] seniorOps = {Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE, - Operator.POWER, Operator.SQRT, Operator.SIN, Operator.COS, Operator.TAN}; - - // 确保至少有一个三角函数 - boolean hasTrigOp = false; - for (int i = 0; i < count; i++) { - Operator op = seniorOps[random.nextInt(seniorOps.length)]; - if (op == Operator.SIN || op == Operator.COS || op == Operator.TAN) { - hasTrigOp = true; + try { + switchDifficulty(level); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); } - operators.add(op); - } - if (!hasTrigOp && count > 0) { - Operator[] trigOps = {Operator.SIN, Operator.COS, Operator.TAN}; - operators.set(random.nextInt(count), trigOps[random.nextInt(trigOps.length)]); - } - } - /** - * 规范化题目用于查重 - */ - private String normalizeQuestion(String question) { - return question.replaceAll("\\s+", "").toLowerCase(); - } - /** - * 保存题目到文件 - */ - private void saveToFile(List questions) { - String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); - String filename = timestamp + ".txt"; - String userDirPath = baseDir + File.separator + currentUser.username; - - File userDir = new File(userDirPath); - if (!userDir.exists()) { - userDir.mkdirs(); - } - - File file = new File(userDir, filename); - try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { - for (int i = 0; i < questions.size(); i++) { - writer.println((i + 1) + ". " + questions.get(i)); - if (i < questions.size() - 1) { - writer.println(); - } - } - } catch (IOException e) { - System.out.println("保存文件失败: " + e.getMessage()); - } } - - /** * 主方法 */ diff --git a/src/Operator.java b/src/Operator.java new file mode 100644 index 0000000..41a1e24 --- /dev/null +++ b/src/Operator.java @@ -0,0 +1,32 @@ +package entities; + +/** + * 运算符枚举 + */ +public enum Operator { + ADD("+", 1, "小学初中高中"), + SUBTRACT("-", 1, "小学初中高中"), + MULTIPLY("*", 2, "小学初中高中"), + DIVIDE("/", 2, "小学初中高中"), + POWER("^", 3, "初中高中"), + SQRT("√", 3, "初中高中"), + SIN("sin", 4, "高中"), + COS("cos", 4, "高中"), + TAN("tan", 4, "高中"); + + private final String symbol; + private final int priority; + private final String allowedLevels; + + Operator(String symbol, int priority, String allowedLevels) { + this.symbol = symbol; + this.priority = priority; + this.allowedLevels = allowedLevels; + } + + public String getSymbol() { return symbol; } + public int getPriority() { return priority; } + public boolean isAllowedForLevel(String level) { + return allowedLevels.contains(level); + } +} \ No newline at end of file diff --git a/src/QuestionService.java b/src/QuestionService.java new file mode 100644 index 0000000..2d1261a --- /dev/null +++ b/src/QuestionService.java @@ -0,0 +1,192 @@ +import entities.Operator; +import entities.UserType; +import java.util.*; + +/** + * 题目生成服务 + */ +public class QuestionService { + private final Random random; + private final Set generatedQuestions; + private UserType currentType; + + public QuestionService() { + this.random = new Random(); + this.generatedQuestions = new HashSet<>(); + } + + /** + * 设置当前题目类型 + */ + public void setCurrentType(UserType type) { + this.currentType = type; + } + + /** + * 生成单个题目 + */ + public String generateQuestion() { + String question; + int attempts = 0; + + do { + question = generateUniqueQuestion(); + attempts++; + } while (generatedQuestions.contains(normalizeQuestion(question)) && attempts < 100); + + generatedQuestions.add(normalizeQuestion(question)); + return question; + } + + /** + * 生成唯一题目 + */ + private String generateUniqueQuestion() { + int operandCount = random.nextInt(5) + 1; + List operands = generateOperands(operandCount); + List operators = generateOperators(operandCount - 1); + + return buildExpression(operands, operators); + } + + /** + * 生成操作数 + */ + private List generateOperands(int count) { + List operands = new ArrayList<>(); + for (int i = 0; i < count; i++) { + operands.add(random.nextInt(100) + 1); + } + return operands; + } + + /** + * 生成运算符 + */ + private List generateOperators(int count) { + List operators = new ArrayList<>(); + List allowedOperators = getAllowedOperators(); + + // 确保符合难度要求 + if (currentType == UserType.JUNIOR) { + ensureJuniorRequirement(operators, allowedOperators, count); + } else if (currentType == UserType.SENIOR) { + ensureSeniorRequirement(operators, allowedOperators, count); + } else { + for (int i = 0; i < count; i++) { + operators.add(allowedOperators.get(random.nextInt(allowedOperators.size()))); + } + } + + return operators; + } + + /** + * 获取允许的运算符 + */ + private List getAllowedOperators() { + List allowed = new ArrayList<>(); + String level = currentType.getName(); + + for (Operator op : Operator.values()) { + if (op.isAllowedForLevel(level)) { + allowed.add(op); + } + } + return allowed; + } + + /** + * 确保初中题目要求(包含平方或开根号) + */ + private void ensureJuniorRequirement(List operators, List allowed, int count) { + boolean hasSpecialOp = false; + + for (int i = 0; i < count; i++) { + Operator op = allowed.get(random.nextInt(allowed.size())); + operators.add(op); + if (op == Operator.POWER || op == Operator.SQRT) { + hasSpecialOp = true; + } + } + + if (!hasSpecialOp && count > 0) { + int index = random.nextInt(operators.size()); + operators.set(index, random.nextBoolean() ? Operator.POWER : Operator.SQRT); + } + } + + /** + * 确保高中题目要求(包含三角函数) + */ + private void ensureSeniorRequirement(List operators, List allowed, int count) { + boolean hasTrigOp = false; + + for (int i = 0; i < count; i++) { + Operator op = allowed.get(random.nextInt(allowed.size())); + operators.add(op); + if (op == Operator.SIN || op == Operator.COS || op == Operator.TAN) { + hasTrigOp = true; + } + } + + if (!hasTrigOp && count > 0) { + int index = random.nextInt(operators.size()); + Operator[] trigOps = {Operator.SIN, Operator.COS, Operator.TAN}; + operators.set(index, trigOps[random.nextInt(trigOps.length)]); + } + } + + /** + * 构建表达式 + */ + private String buildExpression(List operands, List operators) { + StringBuilder expression = new StringBuilder(); + + expression.append(operands.get(0)); + + for (int i = 0; i < operators.size(); i++) { + Operator op = operators.get(i); + int operand = operands.get(i + 1); + + switch (op) { + case SQRT: + expression.insert(0, "√(").append(")"); + expression.append(op.getSymbol()).append(operand); + break; + case SIN: + case COS: + case TAN: + expression.append(op.getSymbol()).append("(").append(operand).append(")"); + break; + default: + expression.append(" ").append(op.getSymbol()).append(" ").append(operand); + } + } + + // 随机添加括号 + if (operands.size() > 2 && random.nextBoolean()) { + expression.insert(0, "("); + int spaceIndex = expression.indexOf(" ", expression.indexOf(" ") + 1); + if (spaceIndex != -1) { + expression.insert(spaceIndex + 1, ")"); + } + } + + return expression.toString(); + } + + /** + * 规范化题目用于查重 + */ + private String normalizeQuestion(String question) { + return question.replaceAll("\\s+", "").toLowerCase(); + } + + /** + * 清空已生成题目记录(用户退出时) + */ + public void clearGeneratedQuestions() { + generatedQuestions.clear(); + } +} \ No newline at end of file diff --git a/src/User.java b/src/User.java new file mode 100644 index 0000000..79b1467 --- /dev/null +++ b/src/User.java @@ -0,0 +1,21 @@ +package entities; + +/** + * 用户实体类 + */ +public class User { + private String username; + private String password; + private UserType type; + + public User(String username, String password, UserType type) { + this.username = username; + this.password = password; + this.type = type; + } + + // Getter方法 + public String getUsername() { return username; } + public String getPassword() { return password; } + public UserType getType() { return type; } +} \ No newline at end of file diff --git a/src/UserService.java b/src/UserService.java new file mode 100644 index 0000000..92085fd --- /dev/null +++ b/src/UserService.java @@ -0,0 +1,54 @@ +import entities.User; +import entities.UserType; +import java.util.HashMap; +import java.util.Map; + +/** + * 用户管理服务 + */ +public class UserService { + private final Map users; + + public UserService() { + this.users = new HashMap<>(); + initializeUsers(); + } + + /** + * 初始化用户数据 + */ + private void initializeUsers() { + // 小学账户 + users.put("张三1", new User("张三1", "123", UserType.PRIMARY)); + users.put("张三2", new User("张三2", "123", UserType.PRIMARY)); + users.put("张三3", new User("张三3", "123", UserType.PRIMARY)); + + // 初中账户 + users.put("李四1", new User("李四1", "123", UserType.JUNIOR)); + users.put("李四2", new User("李四2", "123", UserType.JUNIOR)); + users.put("李四3", new User("李四3", "123", UserType.JUNIOR)); + + // 高中账户 + users.put("王五1", new User("王五1", "123", UserType.SENIOR)); + users.put("王五2", new User("王五2", "123", UserType.SENIOR)); + users.put("王五3", new User("王五3", "123", UserType.SENIOR)); + } + + /** + * 用户认证 + */ + public User authenticate(String username, String password) { + User user = users.get(username); + if (user != null && user.getPassword().equals(password)) { + return user; + } + return null; + } + + /** + * 获取所有用户(用于测试) + */ + public Map getUsers() { + return new HashMap<>(users); + } +} \ No newline at end of file diff --git a/src/UserType.java b/src/UserType.java new file mode 100644 index 0000000..8317ac5 --- /dev/null +++ b/src/UserType.java @@ -0,0 +1,32 @@ +package entities; + +/** + * 用户类型枚举 + */ +public enum UserType { + PRIMARY("小学"), + JUNIOR("初中"), + SENIOR("高中"); + + private final String name; + + UserType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + /** + * 根据中文名称获取枚举值 + */ + public static UserType fromName(String name) { + for (UserType type : values()) { + if (type.name.equals(name)) { + return type; + } + } + throw new IllegalArgumentException("无效的用户类型: " + name); + } +} \ No newline at end of file diff --git a/src/ValidationService.java b/src/ValidationService.java new file mode 100644 index 0000000..9c1a409 --- /dev/null +++ b/src/ValidationService.java @@ -0,0 +1,49 @@ +import java.util.regex.Pattern; + +/** + * 输入验证服务 + */ +public class ValidationService { + + /** + * 验证切换命令格式 + */ + public boolean isValidSwitchCommand(String input) { + if (!input.startsWith("切换为")) { + return false; + } + + return true; + } + + /** + * 验证题目数量 + */ + public boolean isValidQuestionCount(String input) { + if (input.equals("-1")) { + return true; + } + + try { + int count = Integer.parseInt(input); + return count >= 10 && count <= 30; + } catch (NumberFormatException e) { + return false; + } + } + + /** + * 验证用户名密码格式 + */ + public boolean isValidCredentialsFormat(String input) { + String[] parts = input.split("\\s+"); + return parts.length == 2; + } + + /** + * 提取难度级别 + */ + public String extractDifficulty(String switchCommand) { + return switchCommand.substring(3).trim(); + } +} \ No newline at end of file -- 2.34.1 From 884f6ca9f75e36ebff98e12d3ed41737c3cf000e Mon Sep 17 00:00:00 2001 From: tianyuan <2861334240@qq.com> Date: Sat, 27 Sep 2025 15:08:55 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 3 +++ .idea/google-java-format.xml | 6 ++++++ .idea/modules.xml | 8 ++++++++ .idea/vcs.xml | 6 ++++++ .idea/软1_曹峻茂_个人项目.iml | 9 +++++++++ doc/说明.md | 29 +++++++++++++++++++++++++++ 6 files changed, 61 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/google-java-format.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/软1_曹峻茂_个人项目.iml create mode 100644 doc/说明.md diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..359bb53 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml diff --git a/.idea/google-java-format.xml b/.idea/google-java-format.xml new file mode 100644 index 0000000..2aa056d --- /dev/null +++ b/.idea/google-java-format.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..6cba8ca --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/软1_曹峻茂_个人项目.iml b/.idea/软1_曹峻茂_个人项目.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/软1_曹峻茂_个人项目.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/doc/说明.md b/doc/说明.md new file mode 100644 index 0000000..be9ff3c --- /dev/null +++ b/doc/说明.md @@ -0,0 +1,29 @@ +# 中小学数学卷子自动生成程序 + +## 项目简介 +本项目是一个面向中小学数学老师的卷子自动生成程序。 + +## 功能特性 +- ✅ **用户登录**:支持预设账号登录验证 +- ✅ **题目生成**:自动生成符合难度的数学题目 +- ✅ **难度切换**:支持小学、初中、高中难度切换 +- ✅ **题目查重**:避免生成重复题目 + +## 注意事项 + - 使用切换功能时无提示,在“准备生成 XX 数学题目,请输入生成题目数量(输入-1 + 将退出当前用户,重新登录):”的阶段切换 + + - 提示请输入小学、初中和高中三个选项中的一个后仍输入“切换为XX” + 正确更改后才可退出 + +## 快速开始 + +### 环境要求 +- Java 8+ +- 至少 100MB 磁盘空间 + +### 安装运行 +```bash +cd src +javac -encoding UTF-8 *.java +java MathTestGenerator \ No newline at end of file -- 2.34.1 From eb7c5210ffc2868231460707a680c526ba321a85 Mon Sep 17 00:00:00 2001 From: tianyuan <2861334240@qq.com> Date: Sat, 27 Sep 2025 15:10:06 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E8=AF=B4=E6=98=8E=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 3 --- .idea/google-java-format.xml | 6 ------ .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ .idea/软1_曹峻茂_个人项目.iml | 9 --------- 5 files changed, 32 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/google-java-format.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/软1_曹峻茂_个人项目.iml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 359bb53..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# 默认忽略的文件 -/shelf/ -/workspace.xml diff --git a/.idea/google-java-format.xml b/.idea/google-java-format.xml deleted file mode 100644 index 2aa056d..0000000 --- a/.idea/google-java-format.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 6cba8ca..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/软1_曹峻茂_个人项目.iml b/.idea/软1_曹峻茂_个人项目.iml deleted file mode 100644 index d6ebd48..0000000 --- a/.idea/软1_曹峻茂_个人项目.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file -- 2.34.1