parent
f9b760420d
commit
313decf7da
@ -0,0 +1,21 @@
|
||||
public class languageSwitch {
|
||||
//等级转中文输出
|
||||
public static String levelToChinese(login.Level l) {
|
||||
return switch (l) {
|
||||
case PRIMARY -> "小学";
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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<String> loadExistingQuestions(String username) {
|
||||
List<String> all = new ArrayList<>();
|
||||
Path userDir = Paths.get("data", username);
|
||||
if (!Files.exists(userDir)) return all;
|
||||
try {
|
||||
DirectoryStream<Path> ds = Files.newDirectoryStream(userDir, "*.txt");
|
||||
for (Path p : ds) {
|
||||
List<String> 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());
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String> existing;
|
||||
private final int maxAttempts = 2000; // 防止死循环
|
||||
|
||||
QuestionGenerator(login.Level level, List<String> existingQuestions) {
|
||||
this.level = level;
|
||||
this.existing = existingQuestions.stream().map(String::trim).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
List<String> generatePaper(int n) {
|
||||
Set<String> 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<String> 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<operands;i++) {
|
||||
sb.append(" ").append(randomChoice(ops)).append(" ").append(randInt(1,100));
|
||||
}
|
||||
} else {
|
||||
// 直连
|
||||
sb.append(randInt(1,100));
|
||||
for (int i=1;i<operands;i++) {
|
||||
sb.append(" ").append(randomChoice(ops)).append(" ").append(randInt(1,100));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// 生成初中题:至少包含一个 ^2 或 sqrt()
|
||||
private String genMiddle(int operands) {
|
||||
// 基本表达式生成,后插入平方或开根号
|
||||
String expr = genPrimary(operands); // 基本算术
|
||||
// decide to apply square or sqrt to random operand or subexpression
|
||||
if (rand.nextBoolean()) {
|
||||
// apply ^2 somewhere
|
||||
// 找一个数字位置并替换为 (x)^2
|
||||
expr = applySquare(expr);
|
||||
} else {
|
||||
expr = applySqrt(expr);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
// 生成高中题:至少包含 sin/cos/tan
|
||||
private String genHigh(int operands) {
|
||||
String expr = genPrimary(operands);
|
||||
expr = applyTrig(expr); // 把某个数或子表达式包成 trig(...)
|
||||
return expr;
|
||||
}
|
||||
|
||||
// 把表达式中某个数字替换为 (x)^2
|
||||
private String applySquare(String expr) {
|
||||
// 寻找所有数字的片段
|
||||
List<int[]> 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<int[]> 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<int[]> 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<int[]> findNumberSpans(String expr) {
|
||||
List<int[]> 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> T randomChoice(List<T> list) {
|
||||
return list.get(rand.nextInt(list.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<String> 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();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in new issue