From 6cc655468a9c4bbec47fccac0094877b67c61d93 Mon Sep 17 00:00:00 2001 From: imok <2386255140@qq.com> Date: Sun, 28 Sep 2025 23:14:07 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=A1=B9=E7=9B=AE=E7=BB=93?= =?UTF-8?q?=E6=9E=84=EF=BC=9A=E7=AC=A6=E5=90=88=E6=8E=A5=E5=8F=A3=E4=BC=98?= =?UTF-8?q?=E5=85=88=E8=AE=BE=E8=AE=A1=E5=8E=9F=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增interfaces包,定义QuestionInterface、LoginSystemInterface、FileManagerInterface - 新增services包,实现具体业务逻辑类 - 新增models包,存放数据模型 - 新增factories包,实现服务工厂 - 修改Main.java使用接口编程 - 完善.gitignore文件 - 符合'先定义接口类'的评分标准 --- .idea/vcs.xml | 6 + exams/张三1/2025-09-28-20-12-09.txt | 29 +++ exams/张三1/2025-09-28-23-06-51.txt | 31 +++ src/Main.java | 40 ++-- src/Question.java | 4 - src/factories/ServiceFactory.java | 16 ++ src/interfaces/FileManagerInterface.java | 9 + src/interfaces/LoginSystemInterface.java | 9 + src/interfaces/QuestionInterface.java | 10 + src/{ => models}/DifficultyLevel.java | 48 ++--- src/{ => models}/User.java | 33 ++-- src/{ => services}/FileManager.java | 132 ++++++------- src/{ => services}/LoginSystem.java | 108 +++++------ .../MathQuestion.java} | 180 +++++++++--------- src/services/QuestionGenerator.java | 42 ++++ ...工程导论-个人项目需求-2025.pdf | Bin 0 -> 272160 bytes 16 files changed, 418 insertions(+), 279 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 exams/张三1/2025-09-28-20-12-09.txt create mode 100644 exams/张三1/2025-09-28-23-06-51.txt delete mode 100644 src/Question.java create mode 100644 src/factories/ServiceFactory.java create mode 100644 src/interfaces/FileManagerInterface.java create mode 100644 src/interfaces/LoginSystemInterface.java create mode 100644 src/interfaces/QuestionInterface.java rename src/{ => models}/DifficultyLevel.java (95%) rename src/{ => models}/User.java (91%) rename src/{ => services}/FileManager.java (86%) rename src/{ => services}/LoginSystem.java (58%) rename src/{QuestionGenerator.java => services/MathQuestion.java} (53%) create mode 100644 src/services/QuestionGenerator.java create mode 100644 软件工程导论-个人项目需求-2025.pdf 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/exams/张三1/2025-09-28-20-12-09.txt b/exams/张三1/2025-09-28-20-12-09.txt new file mode 100644 index 0000000..ec3ee1e --- /dev/null +++ b/exams/张三1/2025-09-28-20-12-09.txt @@ -0,0 +1,29 @@ +1. 58 = + +2. 19 / 81 = + +3. 77 - 20 = + +4. (66 + 65 + 35 / 57) = + +5. 29 / 37 = + +6. (64 / 31) - 27 * 64 - 69 = + +7. ((97) * 83 * 39 + 23) = + +8. 72 - 85 = + +9. 30 - 79 + 63 + 82 = + +10. 95 - 26 = + +11. 13 - 98 = + +12. 36 - 55 = + +13. (((94 + 72) * 1) * 13) / 90 = + +14. 36 * 69 = + +15. (68 + 60) * 65 / 33 = diff --git a/exams/张三1/2025-09-28-23-06-51.txt b/exams/张三1/2025-09-28-23-06-51.txt new file mode 100644 index 0000000..5d84912 --- /dev/null +++ b/exams/张三1/2025-09-28-23-06-51.txt @@ -0,0 +1,31 @@ +1. 69 = + +2. (4 + 49 - 36 + 79) = + +3. 17 = + +4. ((83 + 61 - 26) + 24 * 93) = + +5. 65 = + +6. 16 / 66 = + +7. 5 / 93 = + +8. 33 / 11 = + +9. 91 = + +10. (22 - 13) + 70 + 40 / 59 = + +11. 88 = + +12. ((87) + 89) - 55 * 76 = + +13. 63 + 18 + 6 - 25 = + +14. 44 / 37 - 45 - 87 = + +15. ((74) + 53) / 31 / 54 = + +16. 91 / 9 + 55 * 38 = diff --git a/src/Main.java b/src/Main.java index 9f9933b..d986921 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,31 +1,45 @@ +import interfaces.LoginSystemInterface; +import interfaces.FileManagerInterface; +import models.User; +import models.DifficultyLevel; +import factories.ServiceFactory; +import services.QuestionGenerator; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); - LoginSystem loginSystem = new LoginSystem(); + + LoginSystemInterface loginSystem = ServiceFactory.createLoginSystem(); QuestionGenerator generator = new QuestionGenerator(); - FileManager fileManager = new FileManager(); + FileManagerInterface fileManager = ServiceFactory.createFileManager(); while (true) { - // 登录阶段 - User currentUser = loginSystem.login(scanner); + System.out.print("请输入用户名和密码(用空格隔开):"); + String input = scanner.nextLine().trim(); + String[] parts = input.split("\\s+"); + + if (parts.length != 2) { + System.out.println("请输入正确的用户名、密码"); + continue; + } + + User currentUser = loginSystem.login(parts[0], parts[1]); if (currentUser == null) { + System.out.println("请输入正确的用户名、密码"); continue; } System.out.println("当前选择为" + currentUser.getLevel().getDisplayName() + "出题"); - // 主循环 while (true) { System.out.println("准备生成" + currentUser.getLevel().getDisplayName() + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录)"); - String input = scanner.nextLine().trim(); + String command = scanner.nextLine().trim(); - // 检查切换命令 - if (input.startsWith("切换为")) { - String levelName = input.substring(3).trim(); + if (command.startsWith("切换为")) { + String levelName = command.substring(3).trim(); DifficultyLevel newLevel = loginSystem.switchLevel(levelName); if (newLevel != null) { currentUser.setLevel(newLevel); @@ -35,21 +49,18 @@ public class Main { } } - // 检查退出命令 - if (input.equals("-1")) { + if (command.equals("-1")) { System.out.println("退出当前用户,重新登录..."); break; } - // 生成题目 try { - int count = Integer.parseInt(input); + int count = Integer.parseInt(command); if (count < 10 || count > 30) { System.out.println("题目数量应在10-30之间"); continue; } - // 生成题目并检查重复 String[] questions = generator.generateQuestions(currentUser.getLevel(), count, currentUser.getUsername()); if (questions == null) { @@ -57,7 +68,6 @@ public class Main { continue; } - // 保存文件 boolean success = fileManager.saveQuestions(currentUser, questions); if (success) { System.out.println("题目生成成功!"); diff --git a/src/Question.java b/src/Question.java deleted file mode 100644 index ae414c9..0000000 --- a/src/Question.java +++ /dev/null @@ -1,4 +0,0 @@ -public interface Question { - String generateQuestion(); - boolean isValid(); -} \ No newline at end of file diff --git a/src/factories/ServiceFactory.java b/src/factories/ServiceFactory.java new file mode 100644 index 0000000..b1b5a6a --- /dev/null +++ b/src/factories/ServiceFactory.java @@ -0,0 +1,16 @@ +package factories; + +import interfaces.LoginSystemInterface; +import interfaces.FileManagerInterface; +import services.LoginSystem; +import services.FileManager; + +public class ServiceFactory { + public static LoginSystemInterface createLoginSystem() { + return new LoginSystem(); + } + + public static FileManagerInterface createFileManager() { + return new FileManager(); + } +} \ No newline at end of file diff --git a/src/interfaces/FileManagerInterface.java b/src/interfaces/FileManagerInterface.java new file mode 100644 index 0000000..1820ced --- /dev/null +++ b/src/interfaces/FileManagerInterface.java @@ -0,0 +1,9 @@ +package interfaces; + +import models.User; +import java.util.Set; + +public interface FileManagerInterface { + boolean saveQuestions(User user, String[] questions); + Set loadExistingQuestions(String username); +} \ No newline at end of file diff --git a/src/interfaces/LoginSystemInterface.java b/src/interfaces/LoginSystemInterface.java new file mode 100644 index 0000000..8c740f0 --- /dev/null +++ b/src/interfaces/LoginSystemInterface.java @@ -0,0 +1,9 @@ +package interfaces; + +import models.User; +import models.DifficultyLevel; + +public interface LoginSystemInterface { + User login(String username, String password); + DifficultyLevel switchLevel(String levelName); +} \ No newline at end of file diff --git a/src/interfaces/QuestionInterface.java b/src/interfaces/QuestionInterface.java new file mode 100644 index 0000000..a258625 --- /dev/null +++ b/src/interfaces/QuestionInterface.java @@ -0,0 +1,10 @@ +package interfaces; + +import models.DifficultyLevel; + +public interface QuestionInterface { + String generateQuestion(); + boolean isValid(); + String getQuestionText(); + DifficultyLevel getDifficulty(); +} \ No newline at end of file diff --git a/src/DifficultyLevel.java b/src/models/DifficultyLevel.java similarity index 95% rename from src/DifficultyLevel.java rename to src/models/DifficultyLevel.java index b549d7f..7fb255d 100644 --- a/src/DifficultyLevel.java +++ b/src/models/DifficultyLevel.java @@ -1,24 +1,26 @@ -public enum DifficultyLevel { - PRIMARY("小学"), - JUNIOR("初中"), - SENIOR("高中"); - - private final String displayName; - - DifficultyLevel(String displayName) { - this.displayName = displayName; - } - - public String getDisplayName() { - return displayName; - } - - public static DifficultyLevel fromString(String text) { - for (DifficultyLevel level : DifficultyLevel.values()) { - if (level.displayName.equals(text)) { - return level; - } - } - return null; - } +package models; + +public enum DifficultyLevel { + PRIMARY("小学"), + JUNIOR("初中"), + SENIOR("高中"); + + private final String displayName; + + DifficultyLevel(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return displayName; + } + + public static DifficultyLevel fromString(String text) { + for (DifficultyLevel level : DifficultyLevel.values()) { + if (level.displayName.equals(text)) { + return level; + } + } + return null; + } } \ No newline at end of file diff --git a/src/User.java b/src/models/User.java similarity index 91% rename from src/User.java rename to src/models/User.java index fa199e4..de9eee8 100644 --- a/src/User.java +++ b/src/models/User.java @@ -1,17 +1,18 @@ -public class User { - private String username; - private String password; - private DifficultyLevel level; - - public User(String username, String password, DifficultyLevel level) { - this.username = username; - this.password = password; - this.level = level; - } - - // Getter 和 Setter 方法 - public String getUsername() { return username; } - public String getPassword() { return password; } - public DifficultyLevel getLevel() { return level; } - public void setLevel(DifficultyLevel level) { this.level = level; } +package models; + +public class User { + private String username; + private String password; + private DifficultyLevel level; + + public User(String username, String password, DifficultyLevel level) { + this.username = username; + this.password = password; + this.level = level; + } + + public String getUsername() { return username; } + public String getPassword() { return password; } + public DifficultyLevel getLevel() { return level; } + public void setLevel(DifficultyLevel level) { this.level = level; } } \ No newline at end of file diff --git a/src/FileManager.java b/src/services/FileManager.java similarity index 86% rename from src/FileManager.java rename to src/services/FileManager.java index 9900915..ca8cfba 100644 --- a/src/FileManager.java +++ b/src/services/FileManager.java @@ -1,66 +1,68 @@ -import java.io.*; -import java.nio.file.*; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; - -public class FileManager { - private static final String BASE_DIR = "exams"; - - public boolean saveQuestions(User user, String[] questions) { - try { - // 创建用户目录 - Path userDir = Paths.get(BASE_DIR, user.getUsername()); - Files.createDirectories(userDir); - - // 生成文件名 - String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); - Path filePath = userDir.resolve(timestamp + ".txt"); - - // 写入文件 - try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(filePath))) { - for (int i = 0; i < questions.length; i++) { - writer.println(questions[i]); - if (i < questions.length - 1) { - writer.println(); // 题目之间空一行 - } - } - } - - return true; - } catch (IOException e) { - e.printStackTrace(); - return false; - } - } - - public Set loadExistingQuestions(String username) { - Set questions = new HashSet<>(); - Path userDir = Paths.get(BASE_DIR, username); - - if (!Files.exists(userDir)) { - return questions; - } - - try (DirectoryStream stream = Files.newDirectoryStream(userDir, "*.txt")) { - for (Path filePath : stream) { - try (BufferedReader reader = Files.newBufferedReader(filePath)) { - String line; - while ((line = reader.readLine()) != null) { - if (line.trim().isEmpty() || !line.contains(".")) { - continue; - } - // 提取题目内容(去掉题号) - String question = line.substring(line.indexOf(".") + 1).trim(); - questions.add(question); - } - } - } - } catch (IOException e) { - e.printStackTrace(); - } - - return questions; - } +package services; + +import interfaces.FileManagerInterface; +import models.User; +import java.io.*; +import java.nio.file.*; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +public class FileManager implements FileManagerInterface { + private static final String BASE_DIR = "exams"; + + @Override + public boolean saveQuestions(User user, String[] questions) { + try { + Path userDir = Paths.get(BASE_DIR, user.getUsername()); + Files.createDirectories(userDir); + + String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); + Path filePath = userDir.resolve(timestamp + ".txt"); + + try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(filePath))) { + for (int i = 0; i < questions.length; i++) { + writer.println(questions[i]); + if (i < questions.length - 1) { + writer.println(); + } + } + } + + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public Set loadExistingQuestions(String username) { + Set questions = new HashSet<>(); + Path userDir = Paths.get(BASE_DIR, username); + + if (!Files.exists(userDir)) { + return questions; + } + + try (DirectoryStream stream = Files.newDirectoryStream(userDir, "*.txt")) { + for (Path filePath : stream) { + try (BufferedReader reader = Files.newBufferedReader(filePath)) { + String line; + while ((line = reader.readLine()) != null) { + if (line.trim().isEmpty() || !line.contains(".")) { + continue; + } + String question = line.substring(line.indexOf(".") + 1).trim(); + questions.add(question); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + + return questions; + } } \ No newline at end of file diff --git a/src/LoginSystem.java b/src/services/LoginSystem.java similarity index 58% rename from src/LoginSystem.java rename to src/services/LoginSystem.java index ae93435..8084fa4 100644 --- a/src/LoginSystem.java +++ b/src/services/LoginSystem.java @@ -1,62 +1,48 @@ -import java.util.HashMap; -import java.util.Map; -import java.util.Scanner; - -public class LoginSystem { - private Map users; - - public LoginSystem() { - initializeUsers(); - } - - private void initializeUsers() { - users = new HashMap<>(); - - // 小学账户 - users.put("张三1", new User("张三1", "123", DifficultyLevel.PRIMARY)); - users.put("张三2", new User("张三2", "123", DifficultyLevel.PRIMARY)); - users.put("张三3", new User("张三3", "123", DifficultyLevel.PRIMARY)); - - // 初中账户 - users.put("李四1", new User("李四1", "123", DifficultyLevel.JUNIOR)); - users.put("李四2", new User("李四2", "123", DifficultyLevel.JUNIOR)); - users.put("李四3", new User("李四3", "123", DifficultyLevel.JUNIOR)); - - // 高中账户 - users.put("王五1", new User("王五1", "123", DifficultyLevel.SENIOR)); - users.put("王五2", new User("王五2", "123", DifficultyLevel.SENIOR)); - users.put("王五3", new User("王五3", "123", DifficultyLevel.SENIOR)); - } - - public User login(Scanner scanner) { - while (true) { - System.out.print("请输入用户名和密码(用空格隔开):"); - String input = scanner.nextLine().trim(); - String[] parts = input.split("\\s+"); - - if (parts.length != 2) { - System.out.println("请输入正确的用户名、密码"); - continue; - } - - String username = parts[0]; - String password = parts[1]; - - User user = users.get(username); - if (user != null && user.getPassword().equals(password)) { - return user; - } else { - System.out.println("请输入正确的用户名、密码"); - } - } - } - - public DifficultyLevel switchLevel(String levelName) { - DifficultyLevel newLevel = DifficultyLevel.fromString(levelName); - if (newLevel == null) { - System.out.println("请输入小学、初中和高中三个选项中的一个"); - return null; - } - return newLevel; - } +package services; + +import interfaces.LoginSystemInterface; +import models.User; +import models.DifficultyLevel; +import java.util.HashMap; +import java.util.Map; + +public class LoginSystem implements LoginSystemInterface { + private Map users; + + public LoginSystem() { + initializeUsers(); + } + + private void initializeUsers() { + users = new HashMap<>(); + + users.put("张三1", new User("张三1", "123", DifficultyLevel.PRIMARY)); + users.put("张三2", new User("张三2", "123", DifficultyLevel.PRIMARY)); + users.put("张三3", new User("张三3", "123", DifficultyLevel.PRIMARY)); + users.put("李四1", new User("李四1", "123", DifficultyLevel.JUNIOR)); + users.put("李四2", new User("李四2", "123", DifficultyLevel.JUNIOR)); + users.put("李四3", new User("李四3", "123", DifficultyLevel.JUNIOR)); + users.put("王五1", new User("王五1", "123", DifficultyLevel.SENIOR)); + users.put("王五2", new User("王五2", "123", DifficultyLevel.SENIOR)); + users.put("王五3", new User("王五3", "123", DifficultyLevel.SENIOR)); + } + + @Override + public User login(String username, String password) { + User user = users.get(username); + if (user != null && user.getPassword().equals(password)) { + return user; + } + return null; + } + + @Override + public DifficultyLevel switchLevel(String levelName) { + DifficultyLevel newLevel = DifficultyLevel.fromString(levelName); + if (newLevel == null) { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + return null; + } + return newLevel; + } } \ No newline at end of file diff --git a/src/QuestionGenerator.java b/src/services/MathQuestion.java similarity index 53% rename from src/QuestionGenerator.java rename to src/services/MathQuestion.java index 46d690f..4324b32 100644 --- a/src/QuestionGenerator.java +++ b/src/services/MathQuestion.java @@ -1,96 +1,86 @@ -import java.util.HashSet; -import java.util.Random; -import java.util.Set; - -public class QuestionGenerator { - private Random random; - private FileManager fileManager; - - public QuestionGenerator() { - random = new Random(); - fileManager = new FileManager(); - } - - public String[] generateQuestions(DifficultyLevel level, int count, String username) { - Set existingQuestions = fileManager.loadExistingQuestions(username); - Set newQuestions = new HashSet<>(); - String[] questions = new String[count]; - - for (int i = 0; i < count; i++) { - String question; - int attempts = 0; - - do { - question = generateSingleQuestion(level, i + 1); - attempts++; - if (attempts > 100) { - return null; // 避免无限循环 - } - } while (existingQuestions.contains(question) || newQuestions.contains(question)); - - newQuestions.add(question); - questions[i] = question; - } - - return questions; - } - - private String generateSingleQuestion(DifficultyLevel level, int questionNumber) { - int operandCount = random.nextInt(5) + 1; // 1-5个操作数 - StringBuilder question = new StringBuilder(questionNumber + ". "); - - switch (level) { - case PRIMARY: - question.append(generatePrimaryQuestion(operandCount)); - break; - case JUNIOR: - question.append(generateJuniorQuestion(operandCount)); - break; - case SENIOR: - question.append(generateSeniorQuestion(operandCount)); - break; - } - - question.append(" = "); - return question.toString(); - } - - private String generatePrimaryQuestion(int operandCount) { - String[] operators = {"+", "-", "*", "/"}; - StringBuilder question = new StringBuilder(); - - for (int i = 0; i < operandCount; i++) { - if (i > 0) { - question.append(" ").append(operators[random.nextInt(operators.length)]).append(" "); - } - question.append(random.nextInt(100) + 1); - - // 随机添加括号(小学难度) - if (operandCount > 2 && random.nextDouble() < 0.3) { - question.insert(0, "(").append(")"); - } - } - - return question.toString(); - } - - private String generateJuniorQuestion(int operandCount) { - String question = generatePrimaryQuestion(operandCount); - - // 确保至少有一个平方或开根号 - if (random.nextBoolean()) { - return "√" + (random.nextInt(100) + 1) + " + " + question; - } else { - return "(" + (random.nextInt(10) + 1) + ")² + " + question; - } - } - - private String generateSeniorQuestion(int operandCount) { - String question = generatePrimaryQuestion(operandCount); - String[] trigFunctions = {"sin", "cos", "tan"}; - - // 确保至少有一个三角函数 - return trigFunctions[random.nextInt(trigFunctions.length)] + - "(" + (random.nextInt(90) + 1) + "°) + " + question; - } +package services; + +import interfaces.QuestionInterface; +import models.DifficultyLevel; +import java.util.Random; + +public class MathQuestion implements QuestionInterface { + private String questionText; + private DifficultyLevel difficulty; + private Random random; + + public MathQuestion(DifficultyLevel difficulty) { + this.difficulty = difficulty; + this.random = new Random(); + this.questionText = generateQuestion(); + } + + @Override + public String generateQuestion() { + int operandCount = random.nextInt(5) + 1; + StringBuilder question = new StringBuilder(); + + switch (difficulty) { + case PRIMARY: + question.append(generatePrimaryQuestion(operandCount)); + break; + case JUNIOR: + question.append(generateJuniorQuestion(operandCount)); + break; + case SENIOR: + question.append(generateSeniorQuestion(operandCount)); + break; + } + + question.append(" = "); + return question.toString(); + } + + @Override + public boolean isValid() { + return questionText != null && !questionText.trim().isEmpty(); + } + + @Override + public String getQuestionText() { + return questionText; + } + + @Override + public DifficultyLevel getDifficulty() { + return difficulty; + } + + private String generatePrimaryQuestion(int operandCount) { + String[] operators = {"+", "-", "*", "/"}; + StringBuilder question = new StringBuilder(); + + for (int i = 0; i < operandCount; i++) { + if (i > 0) { + question.append(" ").append(operators[random.nextInt(operators.length)]).append(" "); + } + question.append(random.nextInt(100) + 1); + + if (operandCount > 2 && random.nextDouble() < 0.3) { + question.insert(0, "(").append(")"); + } + } + return question.toString(); + } + + private String generateJuniorQuestion(int operandCount) { + String question = generatePrimaryQuestion(operandCount); + if (random.nextBoolean()) { + return "√" + (random.nextInt(100) + 1) + " + " + question; + } else { + return "(" + (random.nextInt(10) + 1) + ")² + " + question; + } + } + + private String generateSeniorQuestion(int operandCount) { + String question = generatePrimaryQuestion(operandCount); + String[] trigFunctions = {"sin", "cos", "tan"}; + return trigFunctions[random.nextInt(trigFunctions.length)] + + "(" + (random.nextInt(90) + 1) + "°) + " + question; + } } \ No newline at end of file diff --git a/src/services/QuestionGenerator.java b/src/services/QuestionGenerator.java new file mode 100644 index 0000000..08ebb15 --- /dev/null +++ b/src/services/QuestionGenerator.java @@ -0,0 +1,42 @@ +package services; + +import interfaces.QuestionInterface; +import models.DifficultyLevel; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +public class QuestionGenerator { + private Random random; + private FileManager fileManager; + + public QuestionGenerator() { + random = new Random(); + fileManager = new FileManager(); + } + + public String[] generateQuestions(DifficultyLevel level, int count, String username) { + Set existingQuestions = fileManager.loadExistingQuestions(username); + Set newQuestions = new HashSet<>(); + String[] questions = new String[count]; + + for (int i = 0; i < count; i++) { + QuestionInterface question; + int attempts = 0; + + do { + question = new MathQuestion(level); + attempts++; + if (attempts > 100) { + return null; + } + } while (existingQuestions.contains(question.getQuestionText()) || + newQuestions.contains(question.getQuestionText())); + + newQuestions.add(question.getQuestionText()); + questions[i] = (i + 1) + ". " + question.getQuestionText(); + } + + return questions; + } +} \ No newline at end of file diff --git a/软件工程导论-个人项目需求-2025.pdf b/软件工程导论-个人项目需求-2025.pdf new file mode 100644 index 0000000000000000000000000000000000000000..27e68f0c348ea8b616a50bc00445710915fe0b44 GIT binary patch literal 272160 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