1 #1

Closed
hnu202326010114 wants to merge 0 commits from main into master

29
.gitignore vendored

@ -1,29 +0,0 @@
### 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

3
.idea/.gitignore vendored

@ -1,3 +0,0 @@
# 默认忽略的文件
/shelf/
/workspace.xml

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" native2AsciiForPropertiesFiles="true" defaultCharsetForPropertiesFiles="GBK" addBOMForNewFiles="with BOM">
<file url="file://$PROJECT_DIR$/src/Main.java" charset="UTF-8" />
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/MathSystem.iml" filepath="$PROJECT_DIR$/MathSystem.iml" />
</modules>
</component>
</project>

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings" defaultProject="true" />
</project>

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,2 @@
# wgll926MathSystem

@ -1,393 +0,0 @@
//TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或
// 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。
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<String, Account> 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<String> history = loadHistoryQuestions(login.username);
List<String> 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<String> generateUniquePaper(Level level, int count, Set<String> history) {
Set<String> 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<String> 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<String> 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<String> 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<Integer> 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<Integer> numbers, List<Character> ops) {
// 已不再使用该构造器于主流程,保留供兼容
List<String> 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<String> 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<String> 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<String> tokens) {
boolean hasSquareOrSqrt = false;
for (String tk : tokens) {
if (tk.contains("^2") || tk.contains("√")) { hasSquareOrSqrt = true; break; }
}
if (!hasSquareOrSqrt) {
// 选择一个操作数位置50% 概率平方50% 概率开根号
List<Integer> 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<String> tokens) {
boolean hasTrig = false;
for (String tk : tokens) {
if (tk.contains("sin") || tk.contains("cos") || tk.contains("tan")) { hasTrig = true; break; }
}
if (!hasTrig) {
List<Integer> 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<String> loadHistoryQuestions(String username) {
Set<String> 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<String> 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;
}
}
Loading…
Cancel
Save