Merge pull request 'commit' (#9) from develop into main

main
plks47r9b 4 months ago
commit 7d6d4a878a

Binary file not shown.

@ -27,6 +27,7 @@
├── Assign.java # 调度核心逻辑,负责用户登录和功能调用
├── Function.java # 用户交互与出题数量输入处理
├── Create.java # 调用生成器并保存试卷
├── QuestionGenerator.java # Generator的父类
├── Generator.java # 随机数学题生成器(小学/初中/高中)
├── LoadFile.java # 读取用户已有题目,避免重复
├── Save.java # 保存生成的试卷到本地

@ -4,7 +4,7 @@ public class Create {
public static void create(int n,Login.Level currentLevel,Login.Account user) {
List<String> existing = LoadFile.loadExistingQuestions(user.username);
Generator.QuestionGenerator qg = new Generator.QuestionGenerator(currentLevel, existing);
Generator qg = new Generator(currentLevel, existing);
List<String> paper = qg.generatePaper(n);
if (paper.isEmpty()) {
System.out.println("未能生成题目(可能因去重约束导致)。");

@ -1,196 +1,190 @@
import java.util.Random;
import java.util.Set;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
/**
*
*/
public class Generator {
private static final Random RAND = new Random();
private static final int MAX_ATTEMPTS = 2000;
/**
*
*/
static class QuestionGenerator {
public class Generator extends QuestionGenerator {
private final Login.Level level;
private final Set<String> existing;
public static final Random RAND = new Random();
public static final int MAX_ATTEMPTS = 2000;
QuestionGenerator(Login.Level level, List<String> existingQuestions) {
this.level = level;
this.existing = existingQuestions.stream().map(String::trim).collect(Collectors.toSet());
}
public final Login.Level level;
public final Set<String> existing;
/**
*
*
* @param n
* @return
*/
List<String> generatePaper(int n) {
Set<String> generated = new LinkedHashSet<>();
// 防止死循环
int attempts = 0;
while (generated.size() < n && attempts < MAX_ATTEMPTS) {
attempts++;
String q = generateOneQuestion();
// 统一去掉题号与多余空白来比对
String key = normalize(q);
//与文件内+本次前面生成的查重
if (!existing.contains(key) && !generated.contains(key)) {
generated.add(q);
}
}
Generator(Login.Level level, List<String> existingQuestions) {
this.level = level;
this.existing = existingQuestions.stream().map(String::trim).collect(Collectors.toSet());
}
if (generated.size() < n) {
System.out.println(
"注意:无法生成足够的不重复题目,已生成 "
+ generated.size() + " 道题(请求 " + n + " 道)");
/**
*
*
* @param n
* @return
*/
public List<String> generatePaper(int n) {
Set<String> generated = new LinkedHashSet<>();
// 防止死循环
int attempts = 0;
while (generated.size() < n && attempts < MAX_ATTEMPTS) {
attempts++;
String q = generateOneQuestion();
// 统一去掉题号与多余空白来比对
String key = normalize(q);
//与文件内+本次前面生成的查重
if (!existing.contains(key) && !generated.contains(key)) {
generated.add(q);
}
return new ArrayList<>(generated);
}
//去空格
private String normalize(String s) {
return s.replaceAll("\\s+", "").toLowerCase();
if (generated.size() < n) {
System.out.println(
"注意:无法生成足够的不重复题目,已生成 "
+ generated.size() + " 道题(请求 " + n + " 道)");
}
return new ArrayList<>(generated);
}
// 生成单题主逻辑
private String generateOneQuestion() {
int operands = RAND.nextInt(5) + 1; // 保证 1..5 个操作数
int operands_p = RAND.nextInt(4) + 2; // 保证 2..5 个操作数
return switch (level) {
case PRIMARY -> genPrimary(operands_p);
case MIDDLE -> genMiddle(operands);
case HIGH -> genHigh(operands);
};
}
//去空格
public String normalize(String s) {
return s.replaceAll("\\s+", "").toLowerCase();
}
// 生成单题主逻辑
public String generateOneQuestion() {
int operands = RAND.nextInt(5) + 1; // 保证 1..5 个操作数
int operands_p = RAND.nextInt(4) + 2; // 保证 2..5 个操作数
return switch (level) {
case PRIMARY -> genPrimary(operands_p);
case MIDDLE -> genMiddle(operands);
case HIGH -> genHigh(operands);
};
}
// 生成小学题(只有 + - * / 和括号)
private String genPrimary(int operands) {
if (operands == 1) {
return String.valueOf(randInt(1, 100));
// 生成小学题(只有 + - * / 和括号)
public 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));
}
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));
}
} 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();
}
return sb.toString();
}
// 生成初中题:至少包含一个 ^2 或 sqrt()
private String genMiddle(int operands) {
// 基本表达式生成,后插入平方或开根号
String expr = genPrimary(operands); // 基本算术
// 2选1
if (RAND.nextBoolean()) {
// 找一个数字位置并替换为 (x)^2
expr = applySquare(expr);
} else {
expr = applySqrt(expr);
}
return expr;
// 生成初中题:至少包含一个 ^2 或 sqrt()
public String genMiddle(int operands) {
// 基本表达式生成,后插入平方或开根号
String expr = genPrimary(operands); // 基本算术
// 2选1
if (RAND.nextBoolean()) {
// 找一个数字位置并替换为 (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);
return expr;
}
// 生成高中题:至少包含 sin/cos/tan
public String genHigh(int operands) {
String expr = genPrimary(operands);
expr = applyTrig(expr);
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;
// 把表达式中某个数字替换为 (x)^2
public 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()) {
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;
// 把表达式中某个数字替换为 sqrt(x)
public String applySqrt(String expr) {
List<int[]> spans = findNumberSpans(expr);
if (spans.isEmpty()) {
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;
// 把某个数字或子表达式替换为 sin(x)/cos(x)/tan(x)
public 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++;
// 找出数字位置
public 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;
}
return spans;
}
//a..b随机数
private int randInt(int a, int b) {
return RAND.nextInt(b - a + 1) + a;
}
//a..b随机数
public 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()));
}
//抽签功能
public <T> T randomChoice(List<T> list) {
return list.get(RAND.nextInt(list.size()));
}
}

@ -0,0 +1,46 @@
import java.util.List;
public abstract class QuestionGenerator {
protected QuestionGenerator() {
}
public abstract List<String> generatePaper(int n);
//去空格
public abstract String normalize(String s);
// 生成单题主逻辑
public abstract String generateOneQuestion();
// 生成小学题(只有 + - * / 和括号)
public abstract String genPrimary(int operands);
// 生成初中题:至少包含一个 ^2 或 sqrt()
public abstract String genMiddle(int operands);
// 生成高中题:至少包含 sin/cos/tan
public abstract String genHigh(int operands);
// 把表达式中某个数字替换为 (x)^2
public abstract String applySquare(String expr);
// 把表达式中某个数字替换为 sqrt(x)
public abstract String applySqrt(String expr);
// 把某个数字或子表达式替换为 sin(x)/cos(x)/tan(x)
public abstract String applyTrig(String expr);
// 找出数字位置
public abstract List<int[]> findNumberSpans(String expr);
//a..b随机数
public abstract int randInt(int a, int b);
//抽签功能
public abstract <T> T randomChoice(List<T> list);
}
Loading…
Cancel
Save