From f201473d99437e487826a790901cee1984d776c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E9=BB=98=E6=B6=B5?= <15530826+wgll926@user.noreply.gitee.com> Date: Thu, 25 Sep 2025 17:01:08 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E7=A8=B3=E5=AE=9A=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 29 ++++ .idea/.gitignore | 3 + .idea/encodings.xml | 7 + .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 4 + MathSystem.iml | 11 ++ src/Main.java | 393 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 461 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/encodings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 MathSystem.iml create mode 100644 src/Main.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..359bb53 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..ec4453f --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..6f29fee --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d26ca7f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/MathSystem.iml b/MathSystem.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/MathSystem.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Main.java b/src/Main.java new file mode 100644 index 0000000..3b77df8 --- /dev/null +++ b/src/Main.java @@ -0,0 +1,393 @@ +//TIP 要运行代码,请按 或 +// 点击装订区域中的 图标。 +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +public class Main { + enum Level { + 小学, 初中, 高中 + } + + static class Account { + final String username; + final String password; + final Level level; + + Account(String username, String password, Level level) { + this.username = username; + this.password = password; + this.level = level; + } + } + + private static final Map USER_MAP = new HashMap<>(); + private static final String OUTPUT_ROOT = "papers"; // 每个账号一个子文件夹 + private static final Random RANDOM = new Random(); + + public static void main(String[] args) { + initAccounts(); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); + while (true) { + Account login = loginLoop(reader); + if (login == null) { + break; + } + Level currentLevel = login.level; + System.out.println("当前选择为" + currentLevel + "出题"); + // 登录后的工作循环 + while (true) { + System.out.println("准备生成" + currentLevel + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录)"); + String line = readLineTrim(reader); + if (line == null) return; // EOF + // 支持命令:切换为XX + if (line.startsWith("切换为")) { + String target = line.substring("切换为".length()).trim(); + Level targetLevel = parseLevel(target); + if (targetLevel == null) { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + continue; + } + currentLevel = targetLevel; + continue; + } + int count; + try { + count = Integer.parseInt(line); + } catch (NumberFormatException e) { + System.out.println("请输入10-30之间的整数,或-1退出登录,或输入‘切换为XX’"); + continue; + } + if (count == -1) { + break; // 退出当前账号,重新登录 + } + if (count < 10 || count > 30) { + System.out.println("题目数量应为10-30之间(含),或-1退出登录"); + continue; + } + + // 生成题目并去重 + Set history = loadHistoryQuestions(login.username); + List paper = generateUniquePaper(currentLevel, count, history); + // 保存 + try { + File saved = savePaper(login.username, paper); + System.out.println("已生成并保存:" + saved.getAbsolutePath()); + } catch (IOException e) { + System.out.println("保存失败:" + e.getMessage()); + } + } + } + } + + private static void initAccounts() { + // 小学三个账号 + USER_MAP.put("张三1", new Account("张三1", "123", Level.小学)); + USER_MAP.put("张三2", new Account("张三2", "123", Level.小学)); + USER_MAP.put("张三3", new Account("张三3", "123", Level.小学)); + // 初中三个账号 + USER_MAP.put("李四1", new Account("李四1", "123", Level.初中)); + USER_MAP.put("李四2", new Account("李四2", "123", Level.初中)); + USER_MAP.put("李四3", new Account("李四3", "123", Level.初中)); + // 高中三个账号 + USER_MAP.put("王五1", new Account("王五1", "123", Level.高中)); + USER_MAP.put("王五2", new Account("王五2", "123", Level.高中)); + USER_MAP.put("王五3", new Account("王五3", "123", Level.高中)); + } + + private static Account loginLoop(BufferedReader reader) { + while (true) { + System.out.println("请输入用户名和密码(用空格分隔),或按Ctrl+D退出:"); + String line = readLineTrim(reader); + if (line == null) return null; // EOF 退出 + String[] parts = line.split("\\s+"); + if (parts.length != 2) { + System.out.println("请按格式输入"); + continue; + } + String username = parts[0]; + String password = parts[1]; + Account acc = USER_MAP.get(username); + if (acc != null && Objects.equals(acc.password, password)) { + return acc; + } + System.out.println("请输入正确的用户名、密码"); + } + } + + private static String readLineTrim(BufferedReader reader) { + try { + String s = reader.readLine(); + if (s == null) return null; + return s.trim(); + } catch (IOException e) { + return null; + } + } + + private static Level parseLevel(String s) { + for (Level lv : Level.values()) { + if (lv.name().equals(s)) return lv; + } + return null; + } + + private static List generateUniquePaper(Level level, int count, Set history) { + Set set = new LinkedHashSet<>(); + int attempts = 0; + int maxAttempts = count * 200; // 足够多的尝试次数以避免死循环 + while (set.size() < count && attempts < maxAttempts) { + String q = generateQuestion(level); + attempts++; + if (!history.contains(q) && !set.contains(q)) { + set.add(q); + } + } + if (set.size() < count) { + System.out.println("注意:因去重限制,仅生成" + set.size() + "题"); + } + return new ArrayList<>(set); + } + + private static String generateQuestion(Level level) { + // 统一表达式末尾不加等号,以字符串完全相等进行去重 + return switch (level) { + case 小学 -> generatePrimary(); + case 初中 -> generateJunior(); + case 高中 -> generateSenior(); + default -> generatePrimary(); + }; + } + + private static String generatePrimary() { + // 仅使用 +, *, / 和括号,运算数 1-5 个,范围 1-100 + int operands = 2 + RANDOM.nextInt(4); // 2-5 + List tokens = new ArrayList<>(); + int first = 1 + RANDOM.nextInt(100); + tokens.add(String.valueOf(first)); + for (int i = 1; i < operands; i++) { + char op = pickOperator("+*/"); + int n = 1 + RANDOM.nextInt(100); + if (op == '/') { + // 让被除数尽可能能整除,依据上一个纯数字令除数为其因子 + int prevNumber = extractLastPureNumber(tokens); + if (prevNumber > 0) { + n = pickDivisor(prevNumber); + } + } + tokens.add(" " + op + " "); + tokens.add(String.valueOf(n)); + } + maybeInsertParentheses(tokens); + StringBuilder sb = new StringBuilder(); + for (String tk : tokens) sb.append(tk); + return sb.toString(); + } + + private static String generateJunior() { + // 至少包含一个 平方 或 开根号;允许 + - * / 和括号 + int operands = 2 + RANDOM.nextInt(4); // 2-5 + List tokens = new ArrayList<>(); + String first = String.valueOf(1 + RANDOM.nextInt(100)); + tokens.add(first); + for (int i = 1; i < operands; i++) { + char op = pickOperator("+-*/"); + String n = String.valueOf(1 + RANDOM.nextInt(100)); + tokens.add(" " + op + " "); + tokens.add(n); + } + // 强制至少包含一个 平方 或 根号 + ensureJuniorFeature(tokens); + maybeInsertParentheses(tokens); + StringBuilder sb = new StringBuilder(); + for (String tk : tokens) sb.append(tk); + return sb.toString(); + } + + private static String generateSenior() { + // 至少包含一个 sin/cos/tan;允许 + - * / 和括号 + int operands = 3 + RANDOM.nextInt(3); // 3-5 + List tokens = new ArrayList<>(); + tokens.add(String.valueOf(1 + RANDOM.nextInt(100))); + for (int i = 1; i < operands; i++) { + char op = pickOperator("+-*/"); + String n = String.valueOf(1 + RANDOM.nextInt(100)); + tokens.add(" " + op + " "); + tokens.add(n); + } + ensureSeniorFeature(tokens); + maybeInsertParentheses(tokens); + StringBuilder sb = new StringBuilder(); + for (String tk : tokens) sb.append(tk); + return sb.toString(); + } + + private static char pickOperator(String candidates) { + int idx = RANDOM.nextInt(candidates.length()); + return candidates.charAt(idx); + } + + private static int lastNumberForDivision(CharSequence currentExpr) { + // 粗略解析,找到最后一个数字(用于生成可整除的除法) + int i = currentExpr.length() - 1; + while (i >= 0 && !Character.isDigit(currentExpr.charAt(i))) i--; + int end = i; + while (i >= 0 && Character.isDigit(currentExpr.charAt(i))) i--; + int start = i + 1; + if (start <= end) { + return Integer.parseInt(currentExpr.subSequence(start, end + 1).toString()); + } + return 1 + RANDOM.nextInt(100); + } + + private static int pickDivisor(int dividend) { + dividend = Math.abs(dividend); + if (dividend == 0) return 1; + List divisors = new ArrayList<>(); + for (int d = 1; d <= Math.min(dividend, 100); d++) { + if (dividend % d == 0) { + divisors.add(d); + } + } + return divisors.get(RANDOM.nextInt(divisors.size())); + } + + private static String buildExpressionWithParentheses(List numbers, List ops) { + // 已不再使用该构造器于主流程,保留供兼容 + List tokens = new ArrayList<>(); + tokens.add(String.valueOf(numbers.get(0))); + for (int i = 0; i < ops.size(); i++) { + char op = ops.get(i); + int n = numbers.get(i + 1); + tokens.add(" " + op + " "); + tokens.add(String.valueOf(n)); + } + maybeInsertParentheses(tokens); + StringBuilder sb = new StringBuilder(); + for (String tk : tokens) sb.append(tk); + return sb.toString(); + } + + private static void maybeInsertParentheses(List tokens) { + int parenCount = RANDOM.nextInt(3); // 0,1,2 对 + for (int k = 0; k < parenCount; k++) { + int terms = (tokens.size() + 1) / 2; // 操作数个数 + if (terms < 3) break; + int leftIndex = 0; + int rightIndex = 0; + for (int t = 0; t < 10; t++) { + int li = RANDOM.nextInt(terms - 1); + int ri = li + 1 + RANDOM.nextInt(terms - li - 1); + leftIndex = li * 2; + rightIndex = ri * 2; + if (rightIndex - leftIndex >= 4) break; // 至少一个运算符 + } + tokens.add(leftIndex, "("); + tokens.add(rightIndex + 2, ")"); + } + } + + private static int extractLastPureNumber(List tokens) { + for (int i = tokens.size() - 1; i >= 0; i--) { + String tk = tokens.get(i).trim(); + if (tk.matches("\\d+")) { + return Integer.parseInt(tk); + } + } + return -1; + } + + private static void ensureJuniorFeature(List tokens) { + boolean hasSquareOrSqrt = false; + for (String tk : tokens) { + if (tk.contains("^2") || tk.contains("√")) { hasSquareOrSqrt = true; break; } + } + if (!hasSquareOrSqrt) { + // 选择一个操作数位置,50% 概率平方,50% 概率开根号 + List operandIndexes = new ArrayList<>(); + for (int i = 0; i < tokens.size(); i += 2) operandIndexes.add(i); + if (operandIndexes.isEmpty()) return; + int idxToken = operandIndexes.get(RANDOM.nextInt(operandIndexes.size())); + String val = tokens.get(idxToken).trim(); + if (RANDOM.nextBoolean()) { + // 平方 + tokens.set(idxToken, val + "^2"); + } else { + // 开根号 + tokens.set(idxToken, "√(" + val + ")"); + } + } + } + + private static void ensureSeniorFeature(List tokens) { + boolean hasTrig = false; + for (String tk : tokens) { + if (tk.contains("sin") || tk.contains("cos") || tk.contains("tan")) { hasTrig = true; break; } + } + if (!hasTrig) { + List operandIndexes = new ArrayList<>(); + for (int i = 0; i < tokens.size(); i += 2) operandIndexes.add(i); + if (operandIndexes.isEmpty()) return; + int idxToken = operandIndexes.get(RANDOM.nextInt(operandIndexes.size())); + String val = tokens.get(idxToken).trim(); + String func; + switch (RANDOM.nextInt(3)) { + case 0: func = "sin"; break; + case 1: func = "cos"; break; + default: func = "tan"; break; + } + tokens.set(idxToken, func + "(" + val + ")"); + } + } + + private static Set loadHistoryQuestions(String username) { + Set set = new HashSet<>(); + File folder = new File(OUTPUT_ROOT, username); + if (!folder.exists() || !folder.isDirectory()) return set; + File[] files = folder.listFiles((dir, name) -> name.endsWith(".txt")); + if (files == null) return set; + for (File f : files) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8))) { + String line; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.isEmpty()) continue; + int dot = line.indexOf('.') ; + if (dot > 0) { + String maybe = line.substring(dot + 1).trim(); + if (!maybe.isEmpty()) set.add(maybe); + } + } + } catch (IOException ignored) { + } + } + return set; + } + + private static File savePaper(String username, List questions) throws IOException { + File folder = new File(OUTPUT_ROOT, username); + if (!folder.exists()) { + if (!folder.mkdirs()) throw new IOException("无法创建目录:" + folder.getAbsolutePath()); + } + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-M-d-H-m-s"); + String filename = now.format(formatter) + ".txt"; + File out = new File(folder, filename); + try (BufferedWriter bw = new BufferedWriter(new FileWriter(out, StandardCharsets.UTF_8))) { + for (int i = 0; i < questions.size(); i++) { + bw.write((i + 1) + ". " + questions.get(i)); + bw.newLine(); + bw.newLine(); + } + } + return out; + } +} \ No newline at end of file -- 2.34.1 From 454ba2d656aaba96e4a53730d2d26a678ee158bc Mon Sep 17 00:00:00 2001 From: hnu202326010114 <1961004835@qq.com> Date: Thu, 25 Sep 2025 17:08:34 +0800 Subject: [PATCH 2/2] Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..58a19f0 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# wgll926MathSystem + -- 2.34.1