diff --git a/doc/README.md b/doc/README.md index 9e2e6b5..7a89b0c 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,2 +1,189 @@ -# math-test +# 中小学数学卷子自动生成程序 +## 项目简介 + +这是一个基于Java开发的智能数学试卷自动生成系统,专为中小学数学教师设计。系统能够根据不同学段(小学、初中、高中)自动生成符合教学大纲要求的数学题目,支持用户管理、题目查重、类型切换等功能。 + +## 功能特点 + +### 🔐 用户认证系统 +- **多用户支持**:预设小学、初中、高中各三个测试账户 +- **安全验证**:用户名密码双重验证机制 +- **权限管理**:不同学段用户只能生成对应难度的题目 + +### 📝 智能题目生成 +- **小学题目**:加减乘除四则运算,支持括号优先级 +- **初中题目**:包含平方、开根号等进阶运算 +- **高中题目**:支持三角函数等高等数学运算 +- **难度控制**:操作数范围1-100,操作符数量1-5个 +- **随机性保证**:基于Java Random类的真随机数生成 + +### 🔍 智能查重系统 +- **历史查重**:自动检查用户历史生成的题目 +- **实时去重**:避免在同一份试卷中出现重复题目 +- **文件级查重**:基于用户文件夹下的所有历史文件 + +### 🔄 灵活类型切换 +- **动态切换**:登录状态下可随时切换出题类型 +- **命令格式**:输入"切换为 XX"(XX为小学、初中、高中) +- **即时生效**:切换后立即应用新的题目生成规则 + +### 💾 智能文件管理 +- **用户隔离**:按用户名创建独立的文件夹 +- **时间戳命名**:文件名格式:年-月-日-时-分-秒.txt +- **规范格式**:题目有序号,每题之间空一行,便于阅读 + +## 预设账户 + +| 学段 | 用户名 | 密码 | 权限说明 | +|------|--------|------|----------| +| 小学 | 张三1 | 123 | 生成小学难度题目 | +| 小学 | 张三2 | 123 | 生成小学难度题目 | +| 小学 | 张三3 | 123 | 生成小学难度题目 | +| 初中 | 李四1 | 123 | 生成初中难度题目 | +| 初中 | 李四2 | 123 | 生成初中难度题目 | +| 初中 | 李四3 | 123 | 生成初中难度题目 | +| 高中 | 王五1 | 123 | 生成高中难度题目 | +| 高中 | 王五2 | 123 | 生成高中难度题目 | +| 高中 | 王五3 | 123 | 生成高中难度题目 | + +## 技术架构 + +### 项目结构 +``` +src/ +├── App.java # 主程序入口,控制程序流程 +├── User.java # 用户实体类,管理用户信息和认证 +├── QuestionGenerator.java # 题目生成器抽象类,定义公共接口 +├── PrimarySchoolGenerator.java # 小学题目生成器实现 +├── MiddleSchoolGenerator.java # 初中题目生成器实现 +├── HighSchoolGenerator.java # 高中题目生成器实现 +└── FileManager.java # 文件操作工具类 +``` + +### 核心类说明 + +- **App类**:程序主控制器,负责用户交互和流程调度 +- **User类**:用户数据模型,包含用户名、密码和权限信息 +- **QuestionGenerator**:抽象工厂模式,定义题目生成规范 +- **各学段生成器**:策略模式实现,不同难度采用不同生成策略 +- **FileManager**:单例模式,统一管理文件读写操作 + +## 快速开始 + +### 环境要求 +- Java 8 或更高版本 +- 至少100MB可用磁盘空间 +- 支持命令行操作的操作系统 + +### 编译项目 +```bash +# 进入项目目录 +cd 1 + +# 编译所有Java源文件 +javac -d bin src/*.java + +# 或者使用批处理方式(Windows) +javac -d bin src\*.java +``` + +### 运行程序 +```bash +# 运行主程序 +java -cp bin App + +# 或者指定类路径 +java -classpath bin App +``` + +## 使用指南 + +### 基本操作流程 + +1. **启动程序**:运行`java -cp bin App`命令 +2. **用户登录**:输入用户名和密码(用空格分隔) + ``` + 请输入用户名和密码(用空格隔开):张三1 123 + ``` +3. **查看权限**:登录成功后显示当前出题类型 + ``` + 登录成功!当前出题类型:小学 + ``` +4. **生成题目**:输入要生成的题目数量(10-30) + ``` + 请输入题目数量(10-30):15 + ``` +5. **切换类型**:或输入"切换为 XX"来改变出题类型 + ``` + 请输入题目数量或切换类型:切换为初中 + ``` +6. **退出登录**:输入"-1"退出当前用户 + +### 文件输出示例 + +生成的试卷文件示例: +``` +1. (3 + 5) × 2 - 4 ÷ 2 = + +2. 7 × (9 - 3) + 6 ÷ 2 = + +3. 12 + 8 ÷ 4 × 3 - 5 = +... +``` + +## 开发规范 + +### 代码质量 +- **面向对象设计**:采用清晰的类结构和职责分离 +- **方法简洁性**:单个方法代码行数控制在40行以内 +- **命名规范**:遵循Java驼峰命名法,见名知意 +- **注释完整**:关键方法和复杂逻辑有详细注释 + +### 错误处理 +- **输入验证**:对用户输入进行严格的格式和范围检查 +- **异常捕获**:使用try-catch处理可能的运行时异常 +- **友好提示**:提供清晰易懂的错误信息 + +## 扩展建议 + +### 功能扩展 +1. **题目难度分级**:在每个学段内设置不同难度级别 +2. **题目类型扩展**:增加几何、代数等更多题目类型 +3. **批量生成**:支持一次性生成多套试卷 +4. **模板定制**:允许教师自定义试卷模板格式 + +### 技术优化 +1. **数据库支持**:使用数据库存储用户和题目数据 +2. **Web界面**:开发Web版界面,提升用户体验 +3. **算法优化**:改进题目生成算法,提高题目质量 +4. **国际化**:支持多语言界面 + +## 注意事项 + +### 系统要求 +- 确保Java环境正确安装并配置PATH +- 程序运行目录需要有写权限 +- 建议在SSD硬盘上运行以获得更好的文件读写性能 + +### 数据安全 +- 用户密码以明文存储,生产环境建议加密 +- 定期备份papers文件夹中的重要数据 +- 避免在公共计算机上保存敏感的用户数据 + +### 性能考虑 +- 题目数量较多时,生成时间会相应增加 +- 历史文件较多时,查重操作可能影响性能 +- 建议定期清理不再需要的历史试卷文件 + +## 技术支持 + +如遇到问题,请检查: +1. Java环境是否安装正确 +2. 文件路径权限是否足够 +3. 输入格式是否符合要求 +4. 磁盘空间是否充足 + +--- + +*最后更新:2025年9月27日* diff --git a/src/App.java b/src/App.java index f996731..3e7d07d 100644 --- a/src/App.java +++ b/src/App.java @@ -5,248 +5,251 @@ import java.util.Scanner; import java.util.Set; public class App { - private static final Scanner scanner = new Scanner(System.in); - private static final Map users = User.getPresetUsers(); - private static final FileManager fileManager = new FileManager(); - private static QuestionGenerator currentGenerator; - private static String currentUsername; - - public static void main(String[] args) { - System.out.println("=== 中小学数学卷子自动生成程序 ==="); - - while (true) { - // 登录 - User loggedInUser = login(); - - currentUsername = loggedInUser.getUsername(); - String userType = loggedInUser.getUserType(); - - // 根据用户类型初始化题目生成器 - switch (userType) { - case "小学": - currentGenerator = new PrimarySchoolGenerator(); - break; - case "初中": - currentGenerator = new MiddleSchoolGenerator(); - break; - case "高中": - currentGenerator = new HighSchoolGenerator(); - break; - } - - System.out.println("当前选择为 " + userType + " 出题"); - - // 加载已存在的题目用于查重 - Set existingQuestions = fileManager.loadExistingQuestions(currentUsername); - for (String question : existingQuestions) { - currentGenerator.addToGenerated(question); - } - - // 主循环 - boolean stayLoggedIn = true; - while (stayLoggedIn) { - System.out.println("\n准备生成 " + currentGenerator.getCurrentType() + " 数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):"); - - String input = scanner.nextLine().trim(); - - if (input.equals("-1")) { - stayLoggedIn = false; - System.out.println("退出当前用户..."); - break; - } - - // 处理切换类型命令 - if (input.startsWith("切换为")) { - handleTypeSwitch(input); - continue; - } - - // 生成题目 - try { - int count = Integer.parseInt(input); - if (count >= 10 && count <= 30) { - generateAndSaveQuestions(count); - } else { - System.out.println("题目数量必须在10-30之间,请重新输入。"); - } - } catch (NumberFormatException e) { - System.out.println("请输入有效的数字(10-30)或'切换为XX'命令。"); - } - } - } - } - - private static User login() { - while (true) { - System.out.println("\n请输入用户名和密码(用空格隔开):"); - System.out.println("如果需要注册新用户,请输入'register'"); - System.out.println("如果需要退出程序,请输入'-1'"); - String input = scanner.nextLine(); - String[] credentials = input.split("\\s+"); - - if (credentials[0].equals("-1")) { - System.out.println("退出程序..."); - System.exit(0); - } - - // 处理注册请求 - if (credentials[0].equalsIgnoreCase("register")) { - handleRegistration(); - continue; - } - - if (credentials.length != 2) { - System.out.println("请输入正确的用户名、密码格式(用户名 密码)"); - continue; - } - - String username = credentials[0]; - String password = credentials[1]; - - User user = User.authenticate(username, password); - if (user != null) { - return user; - } else { - System.out.println("请输入正确的用户名、密码"); - } - } - } - - /** - * 处理用户注册 - */ - private static void handleRegistration() { - System.out.println("\n=== 用户注册 ==="); - - // 输入用户名 - String username; - while (true) { - System.out.print("请输入用户名: "); - username = scanner.nextLine().trim(); - - if (username.isEmpty()) { - System.out.println("用户名不能为空,请重新输入。"); - continue; - } - - if (User.userExists(username)) { - System.out.println("用户名已存在,请选择其他用户名。"); - continue; - } - - break; - } - - // 输入密码 - String password; - while (true) { - System.out.print("请输入密码: "); - password = scanner.nextLine().trim(); - - if (password.isEmpty()) { - System.out.println("密码不能为空,请重新输入。"); - continue; - } - - break; + + private static final Scanner scanner = new Scanner(System.in); + private static final Map users = User.getPresetUsers(); + private static final FileManager fileManager = new FileManager(); + private static QuestionGenerator currentGenerator; + private static String currentUsername; + + public static void main(String[] args) { + System.out.println("=== 中小学数学卷子自动生成程序 ==="); + + while (true) { + // 登录 + User loggedInUser = login(); + + currentUsername = loggedInUser.getUsername(); + String userType = loggedInUser.getUserType(); + + // 根据用户类型初始化题目生成器 + switch (userType) { + case "小学": + currentGenerator = new PrimarySchoolGenerator(); + break; + case "初中": + currentGenerator = new MiddleSchoolGenerator(); + break; + case "高中": + currentGenerator = new HighSchoolGenerator(); + break; + } + + System.out.println("当前选择为 " + userType + " 出题"); + + // 加载已存在的题目用于查重 + Set existingQuestions = fileManager.loadExistingQuestions(currentUsername); + for (String question : existingQuestions) { + currentGenerator.addToGenerated(question); + } + + // 主循环 + boolean stayLoggedIn = true; + while (stayLoggedIn) { + System.out.println("\n准备生成 " + currentGenerator.getCurrentType() + + " 数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):"); + + String input = scanner.nextLine().trim(); + + if (input.equals("-1")) { + stayLoggedIn = false; + System.out.println("退出当前用户..."); + break; } - - // 选择用户类型 - String userType; - while (true) { - System.out.println("请选择用户类型:"); - System.out.println("1. 小学"); - System.out.println("2. 初中"); - System.out.println("3. 高中"); - System.out.print("请输入选项(1-3): "); - - String choice = scanner.nextLine().trim(); - - switch (choice) { - case "1": - userType = "小学"; - break; - case "2": - userType = "初中"; - break; - case "3": - userType = "高中"; - break; - default: - System.out.println("无效选项,请重新选择。"); - continue; - } - break; + + // 处理切换类型命令 + if (input.startsWith("切换为")) { + handleTypeSwitch(input); + continue; } - - // 添加用户 - if (User.addUser(username, password, userType)) { - System.out.println("用户注册成功!"); - System.out.println("用户名: " + username); - System.out.println("用户类型: " + userType); - System.out.println("请使用新用户登录。"); - } else { - System.out.println("用户注册失败,请重试。"); + + // 生成题目 + try { + int count = Integer.parseInt(input); + if (count >= 10 && count <= 30) { + generateAndSaveQuestions(count); + } else { + System.out.println("题目数量必须在10-30之间,请重新输入。"); + } + } catch (NumberFormatException e) { + System.out.println("请输入有效的数字(10-30)或'切换为XX'命令。"); } + } } - - private static void handleTypeSwitch(String input) { - // 提取目标类型,支持"切换为小学"和"切换为 小学"两种格式 - String targetType; - if (input.contains(" ")) { - // 格式:"切换为 小学"(有空格) - String[] parts = input.split("\\s+"); - if (parts.length != 2) { - System.out.println("请输入小学、初中和高中三个选项中的一个"); - return; - } - targetType = parts[1]; - } else { - // 格式:"切换为小学"(无空格) - targetType = input.substring(3); // 去掉"切换为"三个字 - } - if (!targetType.equals("小学") && !targetType.equals("初中") && !targetType.equals("高中")) { - System.out.println("请输入小学、初中和高中三个选项中的一个"); - return; - } - - // 切换题目生成器 - switch (targetType) { - case "小学": - currentGenerator = new PrimarySchoolGenerator(); - break; - case "初中": - currentGenerator = new MiddleSchoolGenerator(); - break; - case "高中": - currentGenerator = new HighSchoolGenerator(); - break; - } - - // 重新加载已存在的题目用于查重 - Set existingQuestions = fileManager.loadExistingQuestions(currentUsername); - for (String question : existingQuestions) { - currentGenerator.addToGenerated(question); - } - - System.out.println("已切换为 " + targetType + " 出题模式"); + } + + private static User login() { + while (true) { + System.out.println("\n请输入用户名和密码(用空格隔开):"); + System.out.println("如果需要注册新用户,请输入'register'"); + System.out.println("如果需要退出程序,请输入'-1'"); + String input = scanner.nextLine(); + String[] credentials = input.split("\\s+"); + + if (credentials[0].equals("-1")) { + System.out.println("退出程序..."); + System.exit(0); + } + + // 处理注册请求 + if (credentials[0].equalsIgnoreCase("register")) { + handleRegistration(); + continue; + } + + if (credentials.length != 2) { + System.out.println("请输入正确的用户名、密码格式(用户名 密码)"); + continue; + } + + String username = credentials[0]; + String password = credentials[1]; + + User user = User.authenticate(username, password); + if (user != null) { + return user; + } else { + System.out.println("请输入正确的用户名、密码"); + } } - - private static void generateAndSaveQuestions(int count) { - String[] questions = new String[count]; - - System.out.println("正在生成 " + count + " 道 " + currentGenerator.getCurrentType() + " 题目..."); - - for (int i = 0; i < count; i++) { - questions[i] = currentGenerator.generateQuestion(); - System.out.println((i + 1) + ". " + questions[i]); - } - - try { - fileManager.saveQuestions(currentUsername, questions); - System.out.println("题目生成完成!"); - } catch (Exception e) { - System.out.println("保存文件时出错: " + e.getMessage()); - } + } + + /** + * 处理用户注册 + */ + private static void handleRegistration() { + System.out.println("\n=== 用户注册 ==="); + + // 输入用户名 + String username; + while (true) { + System.out.print("请输入用户名: "); + username = scanner.nextLine().trim(); + + if (username.isEmpty()) { + System.out.println("用户名不能为空,请重新输入。"); + continue; + } + + if (User.userExists(username)) { + System.out.println("用户名已存在,请选择其他用户名。"); + continue; + } + + break; + } + + // 输入密码 + String password; + while (true) { + System.out.print("请输入密码: "); + password = scanner.nextLine().trim(); + + if (password.isEmpty()) { + System.out.println("密码不能为空,请重新输入。"); + continue; + } + + break; + } + + // 选择用户类型 + String userType; + while (true) { + System.out.println("请选择用户类型:"); + System.out.println("1. 小学"); + System.out.println("2. 初中"); + System.out.println("3. 高中"); + System.out.print("请输入选项(1-3): "); + + String choice = scanner.nextLine().trim(); + + switch (choice) { + case "1": + userType = "小学"; + break; + case "2": + userType = "初中"; + break; + case "3": + userType = "高中"; + break; + default: + System.out.println("无效选项,请重新选择。"); + continue; + } + break; + } + + // 添加用户 + if (User.addUser(username, password, userType)) { + System.out.println("用户注册成功!"); + System.out.println("用户名: " + username); + System.out.println("用户类型: " + userType); + System.out.println("请使用新用户登录。"); + } else { + System.out.println("用户注册失败,请重试。"); + } + } + + private static void handleTypeSwitch(String input) { + // 提取目标类型,支持"切换为小学"和"切换为 小学"两种格式 + String targetType; + if (input.contains(" ")) { + // 格式:"切换为 小学"(有空格) + String[] parts = input.split("\\s+"); + if (parts.length != 2) { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + return; + } + targetType = parts[1]; + } else { + // 格式:"切换为小学"(无空格) + targetType = input.substring(3); // 去掉"切换为"三个字 + } + if (!targetType.equals("小学") && !targetType.equals("初中") && !targetType.equals("高中")) { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + return; + } + + // 切换题目生成器 + switch (targetType) { + case "小学": + currentGenerator = new PrimarySchoolGenerator(); + break; + case "初中": + currentGenerator = new MiddleSchoolGenerator(); + break; + case "高中": + currentGenerator = new HighSchoolGenerator(); + break; + } + + // 重新加载已存在的题目用于查重 + Set existingQuestions = fileManager.loadExistingQuestions(currentUsername); + for (String question : existingQuestions) { + currentGenerator.addToGenerated(question); + } + + System.out.println("已切换为 " + targetType + " 出题模式"); + } + + private static void generateAndSaveQuestions(int count) { + String[] questions = new String[count]; + + System.out.println( + "正在生成 " + count + " 道 " + currentGenerator.getCurrentType() + " 题目..."); + + for (int i = 0; i < count; i++) { + questions[i] = currentGenerator.generateQuestion(); + System.out.println((i + 1) + ". " + questions[i]); + } + + try { + fileManager.saveQuestions(currentUsername, questions); + System.out.println("题目生成完成!"); + } catch (Exception e) { + System.out.println("保存文件时出错: " + e.getMessage()); } + } } diff --git a/src/FileManager.java b/src/FileManager.java index fb3257e..504b04a 100644 --- a/src/FileManager.java +++ b/src/FileManager.java @@ -1,98 +1,104 @@ package src; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; import java.util.Set; public class FileManager { - private String baseDir; - - public FileManager() { - this.baseDir = System.getProperty("user.dir") + File.separator + "papers"; - createBaseDirectory(); + + private String baseDir; + + public FileManager() { + this.baseDir = System.getProperty("user.dir") + File.separator + "papers"; + createBaseDirectory(); + } + + // 创建基础目录 + private void createBaseDirectory() { + File dir = new File(baseDir); + if (!dir.exists()) { + dir.mkdirs(); } - - // 创建基础目录 - private void createBaseDirectory() { - File dir = new File(baseDir); - if (!dir.exists()) { - dir.mkdirs(); - } + } + + // 为用户创建目录 + private String createUserDirectory(String username) { + String userDir = baseDir + File.separator + username; + File dir = new File(userDir); + if (!dir.exists()) { + dir.mkdirs(); } - - // 为用户创建目录 - private String createUserDirectory(String username) { - String userDir = baseDir + File.separator + username; - File dir = new File(userDir); - if (!dir.exists()) { - dir.mkdirs(); + return userDir; + } + + // 生成文件名 + private String generateFileName() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + return sdf.format(new Date()) + ".txt"; + } + + // 保存题目到文件 + public void saveQuestions(String username, String[] questions) throws IOException { + String userDir = createUserDirectory(username); + String fileName = generateFileName(); + String filePath = userDir + File.separator + fileName; + + try (PrintWriter writer = new PrintWriter(new FileWriter(filePath))) { + for (int i = 0; i < questions.length; i++) { + writer.println((i + 1) + ". " + questions[i]); + if (i < questions.length - 1) { + writer.println(); // 题目之间空一行 } - return userDir; + } } - - // 生成文件名 - private String generateFileName() { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); - return sdf.format(new Date()) + ".txt"; - } - - // 保存题目到文件 - public void saveQuestions(String username, String[] questions) throws IOException { - String userDir = createUserDirectory(username); - String fileName = generateFileName(); - String filePath = userDir + File.separator + fileName; - - try (PrintWriter writer = new PrintWriter(new FileWriter(filePath))) { - for (int i = 0; i < questions.length; i++) { - writer.println((i + 1) + ". " + questions[i]); - if (i < questions.length - 1) { - writer.println(); // 题目之间空一行 + + System.out.println("题目已保存到: " + filePath); + } + + // 检查题目是否重复(读取用户目录下所有文件) + public Set loadExistingQuestions(String username) { + Set existingQuestions = new HashSet<>(); + String userDir = baseDir + File.separator + username; + File dir = new File(userDir); + + if (dir.exists() && dir.isDirectory()) { + File[] files = dir.listFiles((d, name) -> name.endsWith(".txt")); + if (files != null) { + for (File file : files) { + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + StringBuilder questionBuilder = new StringBuilder(); + while ((line = reader.readLine()) != null) { + if (line.trim().isEmpty()) { + if (questionBuilder.length() > 0) { + // 移除题号 + String question = questionBuilder.toString().replaceAll("^\\d+\\.\\s*", ""); + existingQuestions.add(question.trim()); + questionBuilder.setLength(0); } + } else { + questionBuilder.append(line).append(" "); + } } - } - - System.out.println("题目已保存到: " + filePath); - } - - // 检查题目是否重复(读取用户目录下所有文件) - public Set loadExistingQuestions(String username) { - Set existingQuestions = new HashSet<>(); - String userDir = baseDir + File.separator + username; - File dir = new File(userDir); - - if (dir.exists() && dir.isDirectory()) { - File[] files = dir.listFiles((d, name) -> name.endsWith(".txt")); - if (files != null) { - for (File file : files) { - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { - String line; - StringBuilder questionBuilder = new StringBuilder(); - while ((line = reader.readLine()) != null) { - if (line.trim().isEmpty()) { - if (questionBuilder.length() > 0) { - // 移除题号 - String question = questionBuilder.toString().replaceAll("^\\d+\\.\\s*", ""); - existingQuestions.add(question.trim()); - questionBuilder.setLength(0); - } - } else { - questionBuilder.append(line).append(" "); - } - } - // 处理最后一个题目 - if (questionBuilder.length() > 0) { - String question = questionBuilder.toString().replaceAll("^\\d+\\.\\s*", ""); - existingQuestions.add(question.trim()); - } - } catch (IOException e) { - System.out.println("读取文件失败: " + file.getName()); - } - } + // 处理最后一个题目 + if (questionBuilder.length() > 0) { + String question = questionBuilder.toString().replaceAll("^\\d+\\.\\s*", ""); + existingQuestions.add(question.trim()); } + } catch (IOException e) { + System.out.println("读取文件失败: " + file.getName()); + } } - - return existingQuestions; + } } + + return existingQuestions; + } } \ No newline at end of file diff --git a/src/HighSchoolGenerator.java b/src/HighSchoolGenerator.java index a07407c..728174e 100644 --- a/src/HighSchoolGenerator.java +++ b/src/HighSchoolGenerator.java @@ -1,85 +1,88 @@ package src; public class HighSchoolGenerator extends QuestionGenerator { - private static final String[] BASIC_OPERATORS = {"+", "-", "*", "/"}; - private static final String[] TRIG_FUNCTIONS = {"sin", "cos", "tan"}; - - public HighSchoolGenerator() { - super("高中"); - } - - @Override - public String generateQuestion() { - String question; - do { - question = generateSingleQuestion(); - } while (isDuplicate(question) || !question.matches(".*(sin|cos|tan)\\(.*\\).*")); // 确保包含三角函数 - - addToGenerated(question); - return question; - } - - private String generateSingleQuestion() { - int operatorCount = generateOperatorCount(); - StringBuilder questionBuilder = new StringBuilder(); - boolean hasTrigFunction = false; - - // 生成第一个操作数或三角函数 - hasTrigFunction = processFirstOperandOrTrig(questionBuilder); - - // 生成操作符和操作数 - processOperatorsAndOperands(questionBuilder, operatorCount, hasTrigFunction); - - return questionBuilder.toString(); - } - - private boolean processFirstOperandOrTrig(StringBuilder builder) { - if (random.nextBoolean()) { - // 使用三角函数 - String trigFunction = TRIG_FUNCTIONS[random.nextInt(TRIG_FUNCTIONS.length)]; - int angle = random.nextInt(360) + 1; // 1-360度 - builder.append(trigFunction).append("(").append(angle).append("°)"); - return true; - } else { - // 使用普通数字 - builder.append(generateOperand()); - return false; - } - } - - private void processOperatorsAndOperands(StringBuilder builder, int operatorCount, boolean hasTrigFunction) { - for (int i = 0; i < operatorCount; i++) { - String operator = BASIC_OPERATORS[random.nextInt(BASIC_OPERATORS.length)]; - - // 决定下一个操作数是普通数字还是三角函数 - if (!hasTrigFunction && i == operatorCount - 1) { - // 确保至少有一个三角函数 - appendTrigFunction(builder, operator); - hasTrigFunction = true; - } else if (random.nextBoolean()) { - // 使用三角函数 - appendTrigFunction(builder, operator); - hasTrigFunction = true; - } else { - // 使用普通数字 - appendBasicOperand(builder, operator, operatorCount); - } - } + + private static final String[] BASIC_OPERATORS = {"+", "-", "*", "/"}; + private static final String[] TRIG_FUNCTIONS = {"sin", "cos", "tan"}; + + public HighSchoolGenerator() { + super("高中"); + } + + @Override + public String generateQuestion() { + String question; + do { + question = generateSingleQuestion(); + } while (isDuplicate(question) || !question.matches(".*(sin|cos|tan)\\(.*\\).*")); // 确保包含三角函数 + + addToGenerated(question); + return question; + } + + private String generateSingleQuestion() { + int operatorCount = generateOperatorCount(); + StringBuilder questionBuilder = new StringBuilder(); + boolean hasTrigFunction = false; + + // 生成第一个操作数或三角函数 + hasTrigFunction = processFirstOperandOrTrig(questionBuilder); + + // 生成操作符和操作数 + processOperatorsAndOperands(questionBuilder, operatorCount, hasTrigFunction); + + return questionBuilder.toString(); + } + + private boolean processFirstOperandOrTrig(StringBuilder builder) { + if (random.nextBoolean()) { + // 使用三角函数 + String trigFunction = TRIG_FUNCTIONS[random.nextInt(TRIG_FUNCTIONS.length)]; + int angle = random.nextInt(360) + 1; // 1-360度 + builder.append(trigFunction).append("(").append(angle).append("°)"); + return true; + } else { + // 使用普通数字 + builder.append(generateOperand()); + return false; } - - private void appendTrigFunction(StringBuilder builder, String operator) { - String trigFunction = TRIG_FUNCTIONS[random.nextInt(TRIG_FUNCTIONS.length)]; - int angle = random.nextInt(360) + 1; - builder.append(" ").append(operator).append(" ").append(trigFunction).append("(").append(angle).append("°)"); + } + + private void processOperatorsAndOperands(StringBuilder builder, int operatorCount, + boolean hasTrigFunction) { + for (int i = 0; i < operatorCount; i++) { + String operator = BASIC_OPERATORS[random.nextInt(BASIC_OPERATORS.length)]; + + // 决定下一个操作数是普通数字还是三角函数 + if (!hasTrigFunction && i == operatorCount - 1) { + // 确保至少有一个三角函数 + appendTrigFunction(builder, operator); + hasTrigFunction = true; + } else if (random.nextBoolean()) { + // 使用三角函数 + appendTrigFunction(builder, operator); + hasTrigFunction = true; + } else { + // 使用普通数字 + appendBasicOperand(builder, operator, operatorCount); + } } - - private void appendBasicOperand(StringBuilder builder, String operator, int operatorCount) { - int operand = generateOperand(); - // 随机决定是否加括号 - if (random.nextBoolean() && operatorCount > 1) { - builder.insert(0, "(").append(" ").append(operator).append(" ").append(operand).append(")"); - } else { - builder.append(" ").append(operator).append(" ").append(operand); - } + } + + private void appendTrigFunction(StringBuilder builder, String operator) { + String trigFunction = TRIG_FUNCTIONS[random.nextInt(TRIG_FUNCTIONS.length)]; + int angle = random.nextInt(360) + 1; + builder.append(" ").append(operator).append(" ").append(trigFunction).append("(").append(angle) + .append("°)"); + } + + private void appendBasicOperand(StringBuilder builder, String operator, int operatorCount) { + int operand = generateOperand(); + // 随机决定是否加括号 + if (random.nextBoolean() && operatorCount > 1) { + builder.insert(0, "(").append(" ").append(operator).append(" ").append(operand).append(")"); + } else { + builder.append(" ").append(operator).append(" ").append(operand); } + } } \ No newline at end of file diff --git a/src/MiddleSchoolGenerator.java b/src/MiddleSchoolGenerator.java index a49ddc9..79c024a 100644 --- a/src/MiddleSchoolGenerator.java +++ b/src/MiddleSchoolGenerator.java @@ -1,95 +1,99 @@ package src; public class MiddleSchoolGenerator extends QuestionGenerator { - private static final String[] BASIC_OPERATORS = {"+", "-", "*", "/"}; - private static final String[] ADVANCED_OPERATORS = {"²", "√"}; - - public MiddleSchoolGenerator() { - super("初中"); - } - - @Override - public String generateQuestion() { - String question; - do { - question = generateSingleQuestion(); - } while (isDuplicate(question) || !question.matches(".*[²√].*")); // 确保包含高级运算符 - - addToGenerated(question); - return question; - } - - private String generateSingleQuestion() { - int operatorCount = generateOperatorCount(); - StringBuilder questionBuilder = new StringBuilder(); - boolean hasAdvancedOperator = false; - - // 生成第一个操作数 - int firstOperand = generateOperand(); - - // 处理第一个操作数(可能使用高级运算符) - hasAdvancedOperator = processFirstOperand(questionBuilder, firstOperand); - - // 生成操作符和操作数 - processOperatorsAndOperands(questionBuilder, operatorCount, hasAdvancedOperator); - - return questionBuilder.toString(); - } - - private boolean processFirstOperand(StringBuilder builder, int operand) { - // 随机决定第一个操作数是否使用高级运算符 - if (random.nextBoolean()) { - String advancedOp = ADVANCED_OPERATORS[random.nextInt(ADVANCED_OPERATORS.length)]; - if (advancedOp.equals("²")) { - builder.append(operand).append("²"); - } else { - builder.append("√").append(operand); - } - return true; - } else { - builder.append(operand); - return false; - } + + private static final String[] BASIC_OPERATORS = {"+", "-", "*", "/"}; + private static final String[] ADVANCED_OPERATORS = {"²", "√"}; + + public MiddleSchoolGenerator() { + super("初中"); + } + + @Override + public String generateQuestion() { + String question; + do { + question = generateSingleQuestion(); + } while (isDuplicate(question) || !question.matches(".*[²√].*")); // 确保包含高级运算符 + + addToGenerated(question); + return question; + } + + private String generateSingleQuestion() { + int operatorCount = generateOperatorCount(); + StringBuilder questionBuilder = new StringBuilder(); + boolean hasAdvancedOperator = false; + + // 生成第一个操作数 + int firstOperand = generateOperand(); + + // 处理第一个操作数(可能使用高级运算符) + hasAdvancedOperator = processFirstOperand(questionBuilder, firstOperand); + + // 生成操作符和操作数 + processOperatorsAndOperands(questionBuilder, operatorCount, hasAdvancedOperator); + + return questionBuilder.toString(); + } + + private boolean processFirstOperand(StringBuilder builder, int operand) { + // 随机决定第一个操作数是否使用高级运算符 + if (random.nextBoolean()) { + String advancedOp = ADVANCED_OPERATORS[random.nextInt(ADVANCED_OPERATORS.length)]; + if (advancedOp.equals("²")) { + builder.append(operand).append("²"); + } else { + builder.append("√").append(operand); + } + return true; + } else { + builder.append(operand); + return false; } - - private void processOperatorsAndOperands(StringBuilder builder, int operatorCount, boolean hasAdvancedOperator) { - for (int i = 0; i < operatorCount; i++) { - String operator = determineOperator(i, operatorCount, hasAdvancedOperator); - int operand = generateOperand(); - - if (operator.equals("²") || operator.equals("√")) { - processAdvancedOperator(builder, operator, operand); - hasAdvancedOperator = true; - } else { - processBasicOperator(builder, operator, operand, operatorCount); - } - } + } + + private void processOperatorsAndOperands(StringBuilder builder, int operatorCount, + boolean hasAdvancedOperator) { + for (int i = 0; i < operatorCount; i++) { + String operator = determineOperator(i, operatorCount, hasAdvancedOperator); + int operand = generateOperand(); + + if (operator.equals("²") || operator.equals("√")) { + processAdvancedOperator(builder, operator, operand); + hasAdvancedOperator = true; + } else { + processBasicOperator(builder, operator, operand, operatorCount); + } } - - private String determineOperator(int currentIndex, int totalOperators, boolean hasAdvancedOperator) { - if (!hasAdvancedOperator && currentIndex == totalOperators - 1) { - // 确保至少有一个高级运算符 - return ADVANCED_OPERATORS[random.nextInt(ADVANCED_OPERATORS.length)]; - } else { - return BASIC_OPERATORS[random.nextInt(BASIC_OPERATORS.length)]; - } + } + + private String determineOperator(int currentIndex, int totalOperators, + boolean hasAdvancedOperator) { + if (!hasAdvancedOperator && currentIndex == totalOperators - 1) { + // 确保至少有一个高级运算符 + return ADVANCED_OPERATORS[random.nextInt(ADVANCED_OPERATORS.length)]; + } else { + return BASIC_OPERATORS[random.nextInt(BASIC_OPERATORS.length)]; } - - private void processAdvancedOperator(StringBuilder builder, String operator, int operand) { - String basicOp = BASIC_OPERATORS[random.nextInt(BASIC_OPERATORS.length)]; - if (operator.equals("²")) { - builder.append(" ").append(basicOp).append(" ").append(operand).append("²"); - } else { - builder.append(" ").append(basicOp).append(" √").append(operand); - } + } + + private void processAdvancedOperator(StringBuilder builder, String operator, int operand) { + String basicOp = BASIC_OPERATORS[random.nextInt(BASIC_OPERATORS.length)]; + if (operator.equals("²")) { + builder.append(" ").append(basicOp).append(" ").append(operand).append("²"); + } else { + builder.append(" ").append(basicOp).append(" √").append(operand); } - - private void processBasicOperator(StringBuilder builder, String operator, int operand, int operatorCount) { - // 随机决定是否加括号 - if (random.nextBoolean() && operatorCount > 1) { - builder.insert(0, "(").append(" ").append(operator).append(" ").append(operand).append(")"); - } else { - builder.append(" ").append(operator).append(" ").append(operand); - } + } + + private void processBasicOperator(StringBuilder builder, String operator, int operand, + int operatorCount) { + // 随机决定是否加括号 + if (random.nextBoolean() && operatorCount > 1) { + builder.insert(0, "(").append(" ").append(operator).append(" ").append(operand).append(")"); + } else { + builder.append(" ").append(operator).append(" ").append(operand); } + } } \ No newline at end of file diff --git a/src/PrimarySchoolGenerator.java b/src/PrimarySchoolGenerator.java index db7e266..10172cb 100644 --- a/src/PrimarySchoolGenerator.java +++ b/src/PrimarySchoolGenerator.java @@ -1,40 +1,41 @@ package src; public class PrimarySchoolGenerator extends QuestionGenerator { - private static final String[] OPERATORS = {"+", "-", "*", "/"}; - - public PrimarySchoolGenerator() { - super("小学"); - } - - @Override - public String generateQuestion() { - String question; - do { - int operatorCount = generateOperatorCount(); - StringBuilder questionBuilder = new StringBuilder(); - - // 生成第一个操作数 - questionBuilder.append(generateOperand()); - - // 生成操作符和操作数 - for (int i = 0; i < operatorCount; i++) { - String operator = OPERATORS[random.nextInt(OPERATORS.length)]; - int operand = generateOperand(); - - // 随机决定是否加括号 - if (random.nextBoolean() && operatorCount > 1) { - questionBuilder.insert(0, "(").append(" " + operator + " " + operand + ")"); - } else { - questionBuilder.append(" " + operator + " " + operand); - } - } - - question = questionBuilder.toString(); - - } while (isDuplicate(question)); - - addToGenerated(question); - return question; - } + + private static final String[] OPERATORS = {"+", "-", "*", "/"}; + + public PrimarySchoolGenerator() { + super("小学"); + } + + @Override + public String generateQuestion() { + String question; + do { + int operatorCount = generateOperatorCount_one(); + StringBuilder questionBuilder = new StringBuilder(); + + // 生成第一个操作数 + questionBuilder.append(generateOperand()); + + // 生成操作符和操作数 + for (int i = 0; i < operatorCount; i++) { + String operator = OPERATORS[random.nextInt(OPERATORS.length)]; + int operand = generateOperand(); + + // 随机决定是否加括号 + if (random.nextBoolean() && operatorCount > 1) { + questionBuilder.insert(0, "(").append(" " + operator + " " + operand + ")"); + } else { + questionBuilder.append(" " + operator + " " + operand); + } + } + + question = questionBuilder.toString(); + + } while (isDuplicate(question)); + + addToGenerated(question); + return question; + } } \ No newline at end of file diff --git a/src/QuestionGenerator.java b/src/QuestionGenerator.java index 7d19598..fb75548 100644 --- a/src/QuestionGenerator.java +++ b/src/QuestionGenerator.java @@ -5,45 +5,50 @@ import java.util.Random; import java.util.Set; public abstract class QuestionGenerator { - protected Random random = new Random(); - protected Set generatedQuestions = new HashSet<>(); - protected String currentType; - - public QuestionGenerator(String type) { - this.currentType = type; - } - - // 生成操作数 - protected int generateOperand() { - return random.nextInt(100) + 1; // 1-100 - } - - // 生成操作符数量 - protected int generateOperatorCount() { - return random.nextInt(5) + 1; // 1-5个操作符 - } - - // 检查题目是否重复 - protected boolean isDuplicate(String question) { - return generatedQuestions.contains(question); - } - - // 添加题目到已生成集合 - protected void addToGenerated(String question) { - generatedQuestions.add(question); - } - - // 抽象方法:生成题目 - public abstract String generateQuestion(); - - // 获取当前类型 - public String getCurrentType() { - return currentType; - } - - // 设置当前类型 - public void setCurrentType(String type) { - this.currentType = type; - this.generatedQuestions.clear(); // 切换类型时清空已生成题目 - } + + protected Random random = new Random(); + protected Set generatedQuestions = new HashSet<>(); + protected String currentType; + + public QuestionGenerator(String type) { + this.currentType = type; + } + + // 生成操作数 + protected int generateOperand() { + return random.nextInt(100) + 1; // 1-100 + } + + // 生成操作符数量 + protected int generateOperatorCount() { + return random.nextInt(5) + 1; // 1-5个操作符 + } + + protected int generateOperatorCount_one() { + return random.nextInt(4) + 2; // 1-5个操作符 + } + + // 检查题目是否重复 + protected boolean isDuplicate(String question) { + return generatedQuestions.contains(question); + } + + // 添加题目到已生成集合 + protected void addToGenerated(String question) { + generatedQuestions.add(question); + } + + // 抽象方法:生成题目 + public abstract String generateQuestion(); + + // 获取当前类型 + public String getCurrentType() { + return currentType; + } + + // 设置当前类型 + public void setCurrentType(String type) { + this.currentType = type; + this.generatedQuestions.clear(); // 切换类型时清空已生成题目 + } } \ No newline at end of file diff --git a/src/User.java b/src/User.java index 6318cb3..a900fc6 100644 --- a/src/User.java +++ b/src/User.java @@ -4,135 +4,108 @@ import java.util.HashMap; import java.util.Map; public class User { - private String username; - private String password; - private String userType; // 小学、初中、高中 - - // 静态用户映射,用于存储所有用户 - private static Map userMap = getPresetUsers(); - - 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; - } - - // 用户管理接口 - - /** - * 添加新用户 - * @param username 用户名 - * @param password 密码 - * @param userType 用户类型(小学、初中、高中) - * @return 添加成功返回true,用户名已存在返回false - */ - public static boolean addUser(String username, String password, String userType) { - if (userMap.containsKey(username)) { - return false; // 用户名已存在 - } - userMap.put(username, new User(username, password, userType)); - return true; - } - - /** - * 删除用户 - * @param username 用户名 - * @return 删除成功返回true,用户不存在返回false - */ - public static boolean removeUser(String username) { - if (!userMap.containsKey(username)) { - return false; // 用户不存在 - } - userMap.remove(username); - return true; - } - - /** - * 检查用户是否存在 - * @param username 用户名 - * @return 存在返回true,否则返回false - */ - public static boolean userExists(String username) { - return userMap.containsKey(username); - } - - /** - * 验证用户登录 - * @param username 用户名 - * @param password 密码 - * @return 验证成功返回User对象,失败返回null - */ - public static User authenticate(String username, String password) { - User user = userMap.get(username); - if (user != null && user.getPassword().equals(password)) { - return user; - } - return null; - } - - /** - * 获取所有用户数量 - * @return 用户总数 - */ - public static int getUserCount() { - return userMap.size(); - } - - /** - * 根据用户类型获取用户数量 - * @param userType 用户类型 - * @return 该类型的用户数量 - */ - public static int getUserCountByType(String userType) { - int count = 0; - for (User user : userMap.values()) { - if (user.getUserType().equals(userType)) { - count++; - } - } - return count; + + private String username; + private String password; + private String userType; // 小学、初中、高中 + + // 静态用户映射,用于存储所有用户 + private static Map userMap = getPresetUsers(); + + 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; + } + + // 用户管理接口 + + /** + * 添加新用户 + * + * @param username 用户名 + * @param password 密码 + * @param userType 用户类型(小学、初中、高中) + * @return 添加成功返回true,用户名已存在返回false + */ + public static boolean addUser(String username, String password, String userType) { + if (userMap.containsKey(username)) { + return false; // 用户名已存在 } - - /** - * 获取用户信息 - * @param username 用户名 - * @return User对象,不存在返回null - */ - public static User getUser(String username) { - return userMap.get(username); + userMap.put(username, new User(username, password, userType)); + return true; + } + + /** + * 删除用户 + * + * @param username 用户名 + * @return 删除成功返回true,用户不存在返回false + */ + public static boolean removeUser(String username) { + if (!userMap.containsKey(username)) { + return false; // 用户不存在 } - - // 预设用户数据 - public static Map getPresetUsers() { - Map 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", "高中")); - - return users; + userMap.remove(username); + return true; + } + + /** + * 检查用户是否存在 + * + * @param username 用户名 + * @return 存在返回true,否则返回false + */ + public static boolean userExists(String username) { + return userMap.containsKey(username); + } + + /** + * 验证用户登录 + * + * @param username 用户名 + * @param password 密码 + * @return 验证成功返回User对象,失败返回null + */ + public static User authenticate(String username, String password) { + User user = userMap.get(username); + if (user != null && user.getPassword().equals(password)) { + return user; } + return null; + } + + // 预设用户数据 + public static Map getPresetUsers() { + Map 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", "高中")); + + return users; + } } \ No newline at end of file