|
|
|
|
@ -1,30 +1,30 @@
|
|
|
|
|
import java.io.*;
|
|
|
|
|
import java.nio.file.*;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
public class questionGenerator {
|
|
|
|
|
public class Generator {
|
|
|
|
|
private static final Random rand = new Random();
|
|
|
|
|
|
|
|
|
|
static class QuestionGenerator {
|
|
|
|
|
private final login.Level level;
|
|
|
|
|
private final Login.Level level;
|
|
|
|
|
private final Set<String> existing;
|
|
|
|
|
|
|
|
|
|
QuestionGenerator(login.Level level, List<String> existingQuestions) {
|
|
|
|
|
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;
|
|
|
|
|
// 防止死循环
|
|
|
|
|
int attempts = 0;
|
|
|
|
|
int maxAttempts = 2000;
|
|
|
|
|
|
|
|
|
|
while (generated.size() < n && attempts < maxAttempts) {
|
|
|
|
|
attempts++;
|
|
|
|
|
String q = generateOneQuestion();
|
|
|
|
|
// 统一去掉题号与多余空白来比对
|
|
|
|
|
String key = normalize(q);
|
|
|
|
|
//与文件内+本次前面生成的查重
|
|
|
|
|
if (!existing.contains(key) && !generated.contains(key)) {
|
|
|
|
|
generated.add(q);
|
|
|
|
|
}
|
|
|
|
|
@ -34,14 +34,14 @@ public class questionGenerator {
|
|
|
|
|
}
|
|
|
|
|
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 个操作数
|
|
|
|
|
int operands = rand.nextInt(5) + 1; // 保证 2..5 个操作数
|
|
|
|
|
return switch (level) {
|
|
|
|
|
case PRIMARY -> genPrimary(operands);
|
|
|
|
|
case MIDDLE -> genMiddle(operands);
|
|
|
|
|
@ -79,9 +79,8 @@ public class questionGenerator {
|
|
|
|
|
private String genMiddle(int operands) {
|
|
|
|
|
// 基本表达式生成,后插入平方或开根号
|
|
|
|
|
String expr = genPrimary(operands); // 基本算术
|
|
|
|
|
// decide to apply square or sqrt to random operand or subexpression
|
|
|
|
|
// 2选1
|
|
|
|
|
if (rand.nextBoolean()) {
|
|
|
|
|
// apply ^2 somewhere
|
|
|
|
|
// 找一个数字位置并替换为 (x)^2
|
|
|
|
|
expr = applySquare(expr);
|
|
|
|
|
} else {
|
|
|
|
|
@ -93,7 +92,7 @@ public class questionGenerator {
|
|
|
|
|
// 生成高中题:至少包含 sin/cos/tan
|
|
|
|
|
private String genHigh(int operands) {
|
|
|
|
|
String expr = genPrimary(operands);
|
|
|
|
|
expr = applyTrig(expr); // 把某个数或子表达式包成 trig(...)
|
|
|
|
|
expr = applyTrig(expr);
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -115,7 +114,6 @@ public class questionGenerator {
|
|
|
|
|
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()));
|
|
|
|
|
@ -139,7 +137,7 @@ public class questionGenerator {
|
|
|
|
|
return before + func + "(" + num + ")" + after;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 找到表达式中纯数字的起止索引
|
|
|
|
|
// 找出数字位置
|
|
|
|
|
private List<int[]> findNumberSpans(String expr) {
|
|
|
|
|
List<int[]> spans = new ArrayList<>();
|
|
|
|
|
char[] chs = expr.toCharArray();
|
|
|
|
|
@ -156,11 +154,11 @@ public class questionGenerator {
|
|
|
|
|
}
|
|
|
|
|
return spans;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//a..b随机数
|
|
|
|
|
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()));
|
|
|
|
|
}
|