From 313decf7da5bcb807b2c885c2350ea63a1ed0172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E5=A5=87=E5=B3=B0?= Date: Wed, 24 Sep 2025 12:40:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 10244 -> 10244 bytes src/languageSwitch.java | 21 +++++ src/loadFile.java | 49 +++++++++++ src/login.java | 61 ++++++++++++++ src/mpg_main.java | 69 +++++++++++++++ src/questionGenerator.java | 168 +++++++++++++++++++++++++++++++++++++ src/savepaper.java | 31 +++++++ 7 files changed, 399 insertions(+) create mode 100644 src/languageSwitch.java create mode 100644 src/loadFile.java create mode 100644 src/login.java create mode 100644 src/mpg_main.java create mode 100644 src/questionGenerator.java create mode 100644 src/savepaper.java diff --git a/.DS_Store b/.DS_Store index 6cbe5f6f3d3b9aab020178147e1990eabd67b281..b1de7be016416f38c31c59505b7a5dec241d6a89 100644 GIT binary patch delta 135 zcmZn(XbISGR*Z4SWIN$Pb&2X~BQpaX1!E(VS{;RIOCuoL#MrF1mXkwNS>HM+K07Bj qFTZQ@bzynN?#=Du4IG=<6ppizuA94?fq{XUp_rkFA$hW(U "小学"; + case MIDDLE -> "初中"; + case HIGH -> "高中"; + default -> "未知"; + }; + } + //等级中文输入转level + public static login.Level chineseToLevel(String s) { + s = s.trim();//去除前后空格 + return switch (s) { + case "小学" -> login.Level.PRIMARY; + case "初中" -> login.Level.MIDDLE; + case "高中" -> login.Level.HIGH; + default -> null; + }; + } +} diff --git a/src/loadFile.java b/src/loadFile.java new file mode 100644 index 0000000..9bd5842 --- /dev/null +++ b/src/loadFile.java @@ -0,0 +1,49 @@ +import java.nio.charset.StandardCharsets; +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.util.stream.Collectors; +public class loadFile { + // 读取该用户文件夹下已有题目的所有题目文本(每行一个题目或跨行拼接) + public static List loadExistingQuestions(String username) { + List all = new ArrayList<>(); + Path userDir = Paths.get("data", username); + if (!Files.exists(userDir)) return all; + try { + DirectoryStream ds = Files.newDirectoryStream(userDir, "*.txt"); + for (Path p : ds) { + List lines = Files.readAllLines(p, StandardCharsets.UTF_8); + // 将文件中按题号拆分题目 —— 假设格式 "1. xxx" 开头。我们做简单处理:每个题号开头的新题。 + StringBuilder cur = new StringBuilder(); + for (String line : lines) { + if (line.matches("^\\s*\\d+\\..*")) { + // 新题开始 -> 保存旧题 + if (cur.length() > 0) { + all.add(cur.toString().trim()); + } + cur.setLength(0); + cur.append(line.replaceFirst("^\\s*\\d+\\.", "").trim()); + } else { + // 继续当前题(空行也可能出现) + if (line.trim().isEmpty()) { + // treat as separator; finish current if non-empty + if (cur.length() > 0) { + all.add(cur.toString().trim()); + cur.setLength(0); + } + } else { + if (cur.length() > 0) cur.append(" "); + cur.append(line.trim()); + } + } + } + if (cur.length() > 0) all.add(cur.toString().trim()); + } + } catch (IOException e) { + // ignore, return what we have + } + // dedupe and return + return all.stream().map(String::trim).filter(s->!s.isEmpty()).distinct().collect(Collectors.toList()); + } + +} diff --git a/src/login.java b/src/login.java new file mode 100644 index 0000000..f135ba1 --- /dev/null +++ b/src/login.java @@ -0,0 +1,61 @@ +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.Scanner; + +public class login { + public static class Account { + String username;//用户名 + String password;//密码 + Level level;//出题等级 + Account(String u, String p, Level l) { + username = u; + password = p; + level = l; + } + } + enum Level { PRIMARY, MIDDLE, HIGH } + + private static final Map accounts = new HashMap<>(); + private static final Scanner scanner = new Scanner(System.in, StandardCharsets.UTF_8); + //private static final Random rand = new Random(); + + // 初始化预设账号 + // 初始Map索引 + static { + // 小学 张三1..3 + accounts.put("张三1", new Account("张三1","123", Level.PRIMARY)); + accounts.put("张三2", new Account("张三2","123", Level.PRIMARY)); + accounts.put("张三3", new Account("张三3","123", Level.PRIMARY)); + // 初中 李四1..3 + accounts.put("李四1", new Account("李四1","123", Level.MIDDLE)); + accounts.put("李四2", new Account("李四2","123", Level.MIDDLE)); + accounts.put("李四3", new Account("李四3","123", Level.MIDDLE)); + // 高中 王五1..3 + accounts.put("王五1", new Account("王五1","123", Level.HIGH)); + accounts.put("王五2", new Account("王五2","123", Level.HIGH)); + accounts.put("王五3", new Account("王五3","123", Level.HIGH)); + } + public static Account loginLoop() { + while (true) { + System.out.print("请输入用户名和密码,两者之间用空格隔开:\n> "); + String line = scanner.nextLine().trim();//行输入; + String[] parts = line.split("\\s+");//拆分输入的账号密码,拆分标志为空格; + //正常情况下parts.length=2; + if (parts.length != 2) { + System.out.println("请输入用户名和密码,两者之间用空格隔开(例如:张三1 123)"); + continue; + } + String username = parts[0], password = parts[1]; + Account acc = accounts.get(username); + + if (acc != null && acc.password.equals(password)) { + System.out.println("登录成功。当前选择为 " + languageSwitch.levelToChinese(acc.level) + "出题"); + return acc; + } else { + System.out.println("请输入正确的用户名、密码"); + } + } + } +} diff --git a/src/mpg_main.java b/src/mpg_main.java new file mode 100644 index 0000000..b7f108a --- /dev/null +++ b/src/mpg_main.java @@ -0,0 +1,69 @@ +import java.nio.charset.StandardCharsets; +import java.io.*; +import java.nio.file.*; +import java.util.*; + +public class mpg_main { + private static final Scanner scanner = new Scanner(System.in, StandardCharsets.UTF_8); + public static void main(String[] args) { + System.out.println("=== 中小学数学卷子自动生成程序 ==="); + while (true) { + login.Account user = login.loginLoop(); + if (user == null) continue; + login.Level currentLevel = user.level; + System.out.println("当前选择为 " + languageSwitch.levelToChinese(currentLevel) + "出题"); + boolean loggedIn = true; + while (loggedIn) { + System.out.print("系统提示“准备生成 " + languageSwitch.levelToChinese(currentLevel) + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”\n> "); + String line = scanner.nextLine().trim(); + if (line.equals("-1")) { + System.out.println("退出当前用户,返回登录界面。"); + loggedIn = false; + break; + } + if (line.startsWith("切换为")) { + String target = line.substring("切换为".length()).trim(); + if (target.isEmpty()) { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + continue; + } + login.Level newLevel = languageSwitch.chineseToLevel(target); + if (newLevel == null) { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + } else { + currentLevel = newLevel; + System.out.println("切换成功。当前选择为 " + languageSwitch.levelToChinese(currentLevel) + "出题"); + } + continue; + } + int n; + try { + n = Integer.parseInt(line); + } catch (NumberFormatException e) { + System.out.println("请输入有效的整数(10-30,或-1退出)或 '切换为 XX'。"); + continue; + } + if (n == -1) { + System.out.println("退出当前用户,返回登录界面。"); + loggedIn = false; + break; + } + if (n < 10 || n > 30) { + System.out.println("题目数量的有效输入范围是“10-30”(含10,30,或-1退出登录)。"); + continue; + } + // 生成题目 + List existing = loadFile.loadExistingQuestions(user.username); + questionGenerator.QuestionGenerator qg = new questionGenerator.QuestionGenerator(currentLevel, existing); + List paper = qg.generatePaper(n); + if (paper.isEmpty()) { + System.out.println("未能生成题目(可能因去重约束导致)。"); + } else { + // 保存文件 + String savedPath = savepaper.savePaper(user.username, paper); + System.out.println("已生成 " + paper.size() + " 道题,保存为: " + savedPath); + } + } + } + } +} \ No newline at end of file diff --git a/src/questionGenerator.java b/src/questionGenerator.java new file mode 100644 index 0000000..b491c6c --- /dev/null +++ b/src/questionGenerator.java @@ -0,0 +1,168 @@ +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.util.stream.Collectors; + +public class questionGenerator { + private static final Random rand = new Random(); + static class QuestionGenerator { + private final login.Level level; + private final Set existing; + private final int maxAttempts = 2000; // 防止死循环 + + QuestionGenerator(login.Level level, List existingQuestions) { + this.level = level; + this.existing = existingQuestions.stream().map(String::trim).collect(Collectors.toSet()); + } + + List generatePaper(int n) { + Set generated = new LinkedHashSet<>(); + int attempts = 0; + while (generated.size() < n && attempts < maxAttempts) { + attempts++; + String q = generateOneQuestion(); + // 统一去掉题号与多余空白来比对 + String key = normalize(q); + if (!existing.contains(key) && !generated.contains(key)) { + generated.add(q); + } + } + if (generated.size() < n) { + System.out.println("注意:无法生成足够的不重复题目,已生成 " + generated.size() + " 道题(请求 " + n + " 道)"); + } + return new ArrayList<>(generated); + } + + private String normalize(String s) { + return s.replaceAll("\\s+","").toLowerCase(); + } + + // 生成单题主逻辑 + // 生成单题主逻辑 + private String generateOneQuestion() { + int operands = rand.nextInt(4) + 2; // 保证 2..5 个操作数 + switch (level) { + case PRIMARY: return genPrimary(operands); + case MIDDLE: return genMiddle(operands); + case HIGH: return genHigh(operands); + default: return genPrimary(operands); + } + } + // 生成小学题(只有 + - * / 和括号) + private String genPrimary(int operands) { + if (operands == 1) { + return String.valueOf(randInt(1,100)); + } + List ops = Arrays.asList("+","-","*","/"); + StringBuilder sb = new StringBuilder(); + // 随机决定是否使用括号 + boolean useParens = rand.nextBoolean(); + if (useParens && operands >= 3 && rand.nextBoolean()) { + // 构造 (a op b) op c ... + sb.append("("); + sb.append(randInt(1,100)).append(" ").append(randomChoice(ops)).append(" ").append(randInt(1,100)); + sb.append(")"); + for (int i=2;i spans = findNumberSpans(expr); + if (spans.isEmpty()) { + return expr + "^2"; + } + int[] s = spans.get(rand.nextInt(spans.size())); + String before = expr.substring(0, s[0]); + String num = expr.substring(s[0], s[1]); + String after = expr.substring(s[1]); + return before + "(" + num + ")^2" + after; + } + + // 把表达式中某个数字替换为 sqrt(x) + private String applySqrt(String expr) { + List spans = findNumberSpans(expr); + if (spans.isEmpty()) { + // fallback: wrap entire expr + return "sqrt(" + expr + ")"; + } + int[] s = spans.get(rand.nextInt(spans.size())); + String before = expr.substring(0, s[0]); + String num = expr.substring(s[0], s[1]); + String after = expr.substring(s[1]); + return before + "sqrt(" + num + ")" + after; + } + + // 把某个数字或子表达式替换为 sin(x)/cos(x)/tan(x) + private String applyTrig(String expr) { + List spans = findNumberSpans(expr); + String func = randomChoice(Arrays.asList("sin","cos","tan")); + if (spans.isEmpty()) { + return func + "(" + expr + ")"; + } + int[] s = spans.get(rand.nextInt(spans.size())); + String before = expr.substring(0, s[0]); + String num = expr.substring(s[0], s[1]); + String after = expr.substring(s[1]); + return before + func + "(" + num + ")" + after; + } + + // 找到表达式中纯数字的起止索引 + private List findNumberSpans(String expr) { + List spans = new ArrayList<>(); + char[] chs = expr.toCharArray(); + int i = 0, n = chs.length; + while (i < n) { + if (Character.isDigit(chs[i])) { + int j = i; + while (j < n && (Character.isDigit(chs[j]) )) j++; + spans.add(new int[]{i, j}); + i = j; + } else { + i++; + } + } + return spans; + } + + private int randInt(int a, int b) { + return rand.nextInt(b - a + 1) + a; + } + + private T randomChoice(List list) { + return list.get(rand.nextInt(list.size())); + } + } +} diff --git a/src/savepaper.java b/src/savepaper.java new file mode 100644 index 0000000..4bcb6d5 --- /dev/null +++ b/src/savepaper.java @@ -0,0 +1,31 @@ +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.text.SimpleDateFormat; +import java.nio.charset.StandardCharsets; +public class savepaper { + // 保存试卷,返回保存路径字符串 + public static String savePaper(String username, List paper) { + Path userDir = Paths.get("data", username); + try { + if (!Files.exists(userDir)) Files.createDirectories(userDir); + } catch (IOException e) { + System.out.println("无法创建用户文件夹:" + e.getMessage()); + return "保存失败"; + } + String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); + Path file = userDir.resolve(timestamp + ".txt"); + try (BufferedWriter bw = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) { + for (int i = 0; i < paper.size(); i++) { + bw.write((i+1) + ". " + paper.get(i)); + bw.newLine(); + bw.newLine(); + } + } catch (IOException e) { + System.out.println("保存文件失败:" + e.getMessage()); + return "保存失败"; + } + return file.toString(); + } + +}