From d36668c75d3083c09849d0d31b8abcb06358b819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=8D=B7?= <2747764757@qq.com> Date: Mon, 29 Sep 2025 00:27:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E6=8F=90=E4=BA=A4:=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=E6=BA=90=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MathExamGenerator.java | 626 +++++++++++++++++++++++++++++++++++++ 1 file changed, 626 insertions(+) create mode 100644 src/MathExamGenerator.java diff --git a/src/MathExamGenerator.java b/src/MathExamGenerator.java new file mode 100644 index 0000000..201f6cd --- /dev/null +++ b/src/MathExamGenerator.java @@ -0,0 +1,626 @@ +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * 中小学数学卷子自动生成程序主类 + */ +public class MathExamGenerator { + public static void main(String[] args) { + try { + ApplicationController controller = new ApplicationController(); + controller.run(); + } catch (Exception e) { + System.out.println("程序启动失败: " + e.getMessage()); + e.printStackTrace(); + } + } +} + +/** + * 应用程序控制器 - 负责协调各个模块 + */ +class ApplicationController { + private AccountManager accountManager; + private String currentUser; + private String currentType; + private DuplicateChecker duplicateChecker; + private FileSaver fileSaver; + private Map generatorMap; + + public ApplicationController() { + this.accountManager = new AccountManager(); + this.generatorMap = new HashMap<>(); + generatorMap.put("小学", new PrimarySchoolGenerator()); + generatorMap.put("初中", new JuniorHighGenerator()); + generatorMap.put("高中", new SeniorHighGenerator()); + } + + public void run() { + System.out.println("=== 中小学数学卷子自动生成程序 ==="); + Scanner scanner = new Scanner(System.in); + + while (true) { + // 登录 + if (!login(scanner)) { + break; + } + + // 登录后直接进入出题流程 + boolean stayLoggedIn = true; + while (stayLoggedIn) { + System.out.print("准备生成" + currentType + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录): "); + String input = scanner.nextLine().trim(); + + // 处理切换类型命令 + if (input.startsWith("切换为")) { + String newType = input.substring(3).trim(); + if (switchType(newType)) { + // 切换成功后继续循环,会显示新的提示 + continue; + } else { + // 切换失败,继续当前循环 + continue; + } + } + + // 处理退出命令 + if ("-1".equals(input)) { + stayLoggedIn = false; + continue; + } + + // 处理题目数量输入 + try { + int numQuestions = Integer.parseInt(input); + if (numQuestions < 10 || numQuestions > 30) { + System.out.println("题目数量范围应为10-30"); + continue; + } + + // 生成题目 + QuestionGenerator generator = generatorMap.get(currentType); + List questions = new ArrayList<>(); + int attempts = 0; + int maxAttempts = numQuestions * 10; // 防止无限循环 + + while (questions.size() < numQuestions && attempts < maxAttempts) { + String newQuestion = generator.generateQuestion(); + if (!duplicateChecker.isDuplicate(newQuestion)) { + questions.add(newQuestion); + duplicateChecker.addQuestion(newQuestion); + } + attempts++; + } + + if (questions.size() < numQuestions) { + System.out.println("警告:只生成了" + questions.size() + "道不重复的题目(历史题目过多)"); + } + + // 保存文件 + String filename = fileSaver.saveExam(questions, currentType); + System.out.println("试卷已生成并保存为: " + filename); + System.out.println("题目生成完成,可以继续生成新试卷或输入-1退出当前用户"); + + } catch (NumberFormatException e) { + System.out.println("请输入有效的数字或'切换为小学/初中/高中'"); + } catch (Exception e) { + System.out.println("生成题目出错: " + e.getMessage()); + e.printStackTrace(); // 添加详细错误信息 + } + } + + // 退出当前用户,准备重新登录 + logout(); + System.out.println("已退出当前用户"); + } + + scanner.close(); + System.out.println("程序结束"); + } + + private boolean login(Scanner scanner) { + while (true) { + System.out.print("请输入用户名和密码(用空格隔开): "); + String input = scanner.nextLine().trim(); + + if (input.isEmpty()) { + continue; + } + + String[] parts = input.split("\\s+"); + if (parts.length != 2) { + System.out.println("请输入正确的用户名、密码格式"); + continue; + } + + String username = parts[0]; + String password = parts[1]; + + LoginResult result = accountManager.validateAccount(username, password); + if (result.isSuccess()) { + currentUser = username; + currentType = result.getUserType(); + duplicateChecker = new DuplicateChecker(username); + fileSaver = new FileSaver(username); + System.out.println("当前选择为" + currentType + "出题"); + return true; + } else { + System.out.println("请输入正确的用户名、密码"); + } + } + } + + private boolean switchType(String newType) { + if ("小学".equals(newType) || "初中".equals(newType) || "高中".equals(newType)) { + currentType = newType; + System.out.println("已切换为" + newType + "出题"); + return true; + } else { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + return false; + } + } + + private void logout() { + currentUser = null; + currentType = null; + duplicateChecker = null; + fileSaver = null; + } +} + +/** + * 登录结果封装类 + */ +class LoginResult { + private boolean success; + private String userType; + + public LoginResult(boolean success, String userType) { + this.success = success; + this.userType = userType; + } + + public boolean isSuccess() { + return success; + } + + public String getUserType() { + return userType; + } +} + +/** + * 账户管理类 + */ +class AccountManager { + private Map> accounts; + + public AccountManager() { + accounts = new HashMap<>(); + + // 小学账户 + List primaryAccounts = Arrays.asList( + new Account("张三1", "123"), + new Account("张三2", "123"), + new Account("张三3", "123") + ); + accounts.put("小学", primaryAccounts); + + // 初中账户 + List juniorAccounts = Arrays.asList( + new Account("李四1", "123"), + new Account("李四2", "123"), + new Account("李四3", "123") + ); + accounts.put("初中", juniorAccounts); + + // 高中账户 + List seniorAccounts = Arrays.asList( + new Account("王五1", "123"), + new Account("王五2", "123"), + new Account("王五3", "123") + ); + accounts.put("高中", seniorAccounts); + } + + public LoginResult validateAccount(String username, String password) { + for (Map.Entry> entry : accounts.entrySet()) { + for (Account account : entry.getValue()) { + if (account.getUsername().equals(username) && account.getPassword().equals(password)) { + return new LoginResult(true, entry.getKey()); + } + } + } + return new LoginResult(false, null); + } + + /** + * 账户信息封装类 + */ + private static class Account { + private String username; + private String password; + + public Account(String username, String password) { + this.username = username; + this.password = password; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + } +} + +/** + * 题目生成器接口 + */ +interface QuestionGenerator { + String generateQuestion(); +} + +/** + * 小学题目生成器 + */ +class PrimarySchoolGenerator implements QuestionGenerator { + private Random random = new Random(); + private List operators = Arrays.asList("+", "-", "*", "/"); + + @Override + public String generateQuestion() { + try { + // 确保每道题目最少有两个操作数(2-5个) + int numOperands = random.nextInt(4) + 2; // 2-5个操作数 + + // 生成操作数 + int[] operands = new int[numOperands]; + for (int i = 0; i < numOperands; i++) { + operands[i] = random.nextInt(100) + 1; // 1-100 + } + + // 生成运算符 + String[] operatorArray = new String[numOperands - 1]; + for (int i = 0; i < numOperands - 1; i++) { + operatorArray[i] = operators.get(random.nextInt(operators.size())); + } + + // 构建表达式并确保结果非负 + String expression; + do { + // 重新生成操作数和运算符(如果之前的结果为负) + for (int i = 0; i < numOperands; i++) { + operands[i] = random.nextInt(100) + 1; + } + for (int i = 0; i < numOperands - 1; i++) { + operatorArray[i] = operators.get(random.nextInt(operators.size())); + } + + // 构建表达式 + StringBuilder exprBuilder = new StringBuilder(); + exprBuilder.append(operands[0]); + + for (int i = 1; i < numOperands; i++) { + // 如果是减法,确保不会产生负数 + if ("-".equals(operatorArray[i-1])) { + // 计算当前部分表达式的值 + int currentValue = calculatePartialExpression(exprBuilder.toString()); + if (currentValue < operands[i]) { + // 如果减法会产生负数,改为加法 + operatorArray[i-1] = "+"; + } + } + + exprBuilder.append(" ").append(operatorArray[i-1]).append(" ").append(operands[i]); + } + + expression = exprBuilder.toString(); + + // 计算整个表达式的结果 + double result = evaluateExpression(expression); + + // 如果结果为负,重新生成 + if (result < 0) { + continue; + } + + // 随机添加括号(只在有3个及以上操作数时) + if (numOperands >= 3 && random.nextDouble() < 0.3) { + // 只在表达式开头和结尾添加括号,避免复杂计算 + expression = "(" + expression + ")"; + } + + break; + } while (true); + + // 在表达式末尾添加等号 + return expression + " ="; + } catch (Exception e) { + // 如果生成题目出错,返回一个简单的默认题目 + return "10 + 20 ="; + } + } + + /** + * 计算部分表达式的值(简化版,只处理简单的加减乘除) + */ + private int calculatePartialExpression(String expression) { + try { + // 简单的表达式计算,只处理没有括号的情况 + String[] tokens = expression.split(" "); + int result = Integer.parseInt(tokens[0]); + + for (int i = 1; i < tokens.length; i += 2) { + String operator = tokens[i]; + int operand = Integer.parseInt(tokens[i+1]); + + switch (operator) { + case "+": + result += operand; + break; + case "-": + result -= operand; + break; + case "*": + result *= operand; + break; + case "/": + if (operand != 0) result /= operand; + break; + } + } + + return result; + } catch (Exception e) { + return 0; // 如果计算出错,返回0 + } + } + + /** + * 评估表达式的结果(简化版) + */ + private double evaluateExpression(String expression) { + try { + // 移除括号(简化处理) + String cleanExpression = expression.replace("(", "").replace(")", ""); + + // 简单的表达式计算 + String[] tokens = cleanExpression.split(" "); + double result = Double.parseDouble(tokens[0]); + + for (int i = 1; i < tokens.length; i += 2) { + String operator = tokens[i]; + double operand = Double.parseDouble(tokens[i+1]); + + switch (operator) { + case "+": + result += operand; + break; + case "-": + result -= operand; + break; + case "*": + result *= operand; + break; + case "/": + if (operand != 0) result /= operand; + break; + } + } + + return result; + } catch (Exception e) { + return 0; // 如果计算出错,返回0 + } + } +} + +/** + * 初中题目生成器 + */ +class JuniorHighGenerator implements QuestionGenerator { + private Random random = new Random(); + private List baseOperators = Arrays.asList("+", "-", "*", "/"); + + @Override + public String generateQuestion() { + try { + // 确保每道题目最少有两个操作数(2-5个) + int numOperands = random.nextInt(4) + 2; // 2-5个操作数 + StringBuilder expression = new StringBuilder(); + + boolean hasSpecialOperator = false; + + for (int i = 0; i < numOperands; i++) { + // 确保至少有一个特殊运算符 + if (!hasSpecialOperator && (i == numOperands - 1 || random.nextDouble() < 0.3)) { + if (random.nextBoolean()) { + // 平方 + int num = random.nextInt(10) + 1; // 平方的数不宜太大 + expression.append(num).append("²"); + } else { + // 开根号 + int num = random.nextInt(100) + 1; + expression.append("√").append(num); + } + hasSpecialOperator = true; + } else { + expression.append(random.nextInt(100) + 1); + } + + if (i < numOperands - 1) { + String operator = baseOperators.get(random.nextInt(baseOperators.size())); + expression.append(" ").append(operator).append(" "); + } + } + + // 如果还没有特殊运算符,强制添加一个 + if (!hasSpecialOperator) { + if (random.nextBoolean()) { + expression.insert(0, random.nextInt(10) + 1 + "² + "); + } else { + expression.insert(0, "√" + (random.nextInt(100) + 1) + " + "); + } + } + + // 在表达式末尾添加等号 + return expression.toString() + " ="; + } catch (Exception e) { + // 如果生成题目出错,返回一个简单的默认题目 + return "√25 + 10 ="; + } + } +} + +/** + * 高中题目生成器 + */ +class SeniorHighGenerator implements QuestionGenerator { + private Random random = new Random(); + private List baseOperators = Arrays.asList("+", "-", "*", "/"); + private List trigFunctions = Arrays.asList("sin", "cos", "tan"); + + @Override + public String generateQuestion() { + try { + // 确保每道题目最少有两个操作数(2-5个) + int numOperands = random.nextInt(4) + 2; // 2-5个操作数 + StringBuilder expression = new StringBuilder(); + + boolean hasTrigFunction = false; + + for (int i = 0; i < numOperands; i++) { + // 确保至少有一个三角函数 + if (!hasTrigFunction && (i == numOperands - 1 || random.nextDouble() < 0.3)) { + String trigFunc = trigFunctions.get(random.nextInt(trigFunctions.size())); + int angle = random.nextInt(360); // 角度0-359 + expression.append(trigFunc).append("(").append(angle).append("°)"); + hasTrigFunction = true; + } else { + expression.append(random.nextInt(100) + 1); + } + + if (i < numOperands - 1) { + String operator = baseOperators.get(random.nextInt(baseOperators.size())); + expression.append(" ").append(operator).append(" "); + } + } + + // 如果还没有三角函数,强制添加一个 + if (!hasTrigFunction) { + String trigFunc = trigFunctions.get(random.nextInt(trigFunctions.size())); + int angle = random.nextInt(360); + expression.insert(0, trigFunc + "(" + angle + "°) + "); + } + + // 在表达式末尾添加等号 + return expression.toString() + " ="; + } catch (Exception e) { + // 如果生成题目出错,返回一个简单的默认题目 + return "sin(30°) + 10 ="; + } + } +} + +/** + * 查重管理器 + */ +class DuplicateChecker { + private String username; + private Set historyQuestions; + + public DuplicateChecker(String username) { + this.username = username; + this.historyQuestions = new HashSet<>(); + loadHistoryQuestions(); + } + + private void loadHistoryQuestions() { + File userFolder = new File("exams/" + username); + if (!userFolder.exists() || !userFolder.isDirectory()) { + userFolder.mkdirs(); + return; + } + + File[] files = userFolder.listFiles((dir, name) -> name.endsWith(".txt")); + if (files == null) return; + + Pattern questionPattern = Pattern.compile("\\d+\\.\\s*(.+)"); + + for (File file : files) { + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + Matcher matcher = questionPattern.matcher(line); + if (matcher.find()) { + String question = matcher.group(1).trim(); + historyQuestions.add(normalizeQuestion(question)); + } + } + } catch (IOException e) { + System.out.println("读取历史文件出错: " + e.getMessage()); + } + } + } + + private String normalizeQuestion(String question) { + // 移除多余空格和等号 + return question.replaceAll("\\s+", " ").replace(" =", "").trim(); + } + + public boolean isDuplicate(String question) { + // 移除等号后再进行比较 + String normalized = normalizeQuestion(question.replace(" =", "")); + return historyQuestions.contains(normalized); + } + + public void addQuestion(String question) { + // 移除等号后再保存 + String normalized = normalizeQuestion(question.replace(" =", "")); + historyQuestions.add(normalized); + } +} + +/** + * 文件保存器 + */ +class FileSaver { + private String username; + private File userFolder; + + public FileSaver(String username) { + this.username = username; + this.userFolder = new File("exams/" + username); + this.userFolder.mkdirs(); + } + + public String saveExam(List questions, String questionType) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + String timestamp = dateFormat.format(new Date()); + String filename = timestamp + ".txt"; + File file = new File(userFolder, filename); + + try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { + writer.println(questionType + "数学试卷"); + writer.println("=============================="); + writer.println(); + + for (int i = 0; i < questions.size(); i++) { + writer.println((i + 1) + ". " + questions.get(i)); + writer.println(); + } + + return file.getAbsolutePath(); + } catch (IOException e) { + System.out.println("保存文件出错: " + e.getMessage()); + return null; + } + } +} \ No newline at end of file