@ -0,0 +1,51 @@
|
||||
package com.personalproject.auth;
|
||||
|
||||
import com.personalproject.model.DifficultyLevel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 存放预设教师账号并提供认证查询能力。
|
||||
*/
|
||||
public final class AccountRepository {
|
||||
private final Map<String, UserAccount> accounts = new HashMap<>();
|
||||
|
||||
public AccountRepository() {
|
||||
registerPrimaryAccounts();
|
||||
registerMiddleSchoolAccounts();
|
||||
registerHighSchoolAccounts();
|
||||
}
|
||||
|
||||
public Optional<UserAccount> authenticate(String username, String password) {
|
||||
if (username == null || password == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
UserAccount account = accounts.get(username.trim());
|
||||
if (account == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (!account.password().equals(password.trim())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(account);
|
||||
}
|
||||
|
||||
private void registerPrimaryAccounts() {
|
||||
accounts.put("张三1", new UserAccount("张三1", "123", DifficultyLevel.PRIMARY));
|
||||
accounts.put("张三2", new UserAccount("张三2", "123", DifficultyLevel.PRIMARY));
|
||||
accounts.put("张三3", new UserAccount("张三3", "123", DifficultyLevel.PRIMARY));
|
||||
}
|
||||
|
||||
private void registerMiddleSchoolAccounts() {
|
||||
accounts.put("李四1", new UserAccount("李四1", "123", DifficultyLevel.MIDDLE));
|
||||
accounts.put("李四2", new UserAccount("李四2", "123", DifficultyLevel.MIDDLE));
|
||||
accounts.put("李四3", new UserAccount("李四3", "123", DifficultyLevel.MIDDLE));
|
||||
}
|
||||
|
||||
private void registerHighSchoolAccounts() {
|
||||
accounts.put("王五1", new UserAccount("王五1", "123", DifficultyLevel.HIGH));
|
||||
accounts.put("王五2", new UserAccount("王五2", "123", DifficultyLevel.HIGH));
|
||||
accounts.put("王五3", new UserAccount("王五3", "123", DifficultyLevel.HIGH));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package com.personalproject.auth;
|
||||
|
||||
import com.personalproject.model.DifficultyLevel;
|
||||
|
||||
/**
|
||||
* 不可变的账号定义。
|
||||
*/
|
||||
public record UserAccount(String username, String password, DifficultyLevel difficultyLevel) {
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.personalproject.generator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 生成至少包含一种三角函数的高中难度题目表达式。
|
||||
*/
|
||||
public final class HighSchoolQuestionGenerator implements QuestionGenerator {
|
||||
private static final String[] OPERATORS = {"+", "-", "*", "/"};
|
||||
private static final String[] TRIG_FUNCTIONS = {"sin", "cos", "tan"};
|
||||
|
||||
@Override
|
||||
public String generateQuestion(Random random) {
|
||||
int operandCount = random.nextInt(5) + 1;
|
||||
String[] operands = new String[operandCount];
|
||||
for (int index = 0; index < operandCount; index++) {
|
||||
operands[index] = String.valueOf(random.nextInt(100) + 1);
|
||||
}
|
||||
int specialIndex = random.nextInt(operandCount);
|
||||
String function = TRIG_FUNCTIONS[random.nextInt(TRIG_FUNCTIONS.length)];
|
||||
operands[specialIndex] = function + '(' + operands[specialIndex] + ')';
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int index = 0; index < operandCount; index++) {
|
||||
if (index > 0) {
|
||||
String operator = OPERATORS[random.nextInt(OPERATORS.length)];
|
||||
builder.append(' ').append(operator).append(' ');
|
||||
}
|
||||
builder.append(operands[index]);
|
||||
}
|
||||
String expression = builder.toString();
|
||||
if (operandCount > 1 && random.nextBoolean()) {
|
||||
return '(' + expression + ')';
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.personalproject.generator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 生成包含平方或开根号运算的初中难度题目表达式。
|
||||
*/
|
||||
public final class MiddleSchoolQuestionGenerator implements QuestionGenerator {
|
||||
private static final String[] OPERATORS = {"+", "-", "*", "/"};
|
||||
|
||||
@Override
|
||||
public String generateQuestion(Random random) {
|
||||
int operandCount = random.nextInt(5) + 1;
|
||||
String[] operands = new String[operandCount];
|
||||
for (int index = 0; index < operandCount; index++) {
|
||||
operands[index] = String.valueOf(random.nextInt(100) + 1);
|
||||
}
|
||||
int specialIndex = random.nextInt(operandCount);
|
||||
if (random.nextBoolean()) {
|
||||
operands[specialIndex] = '(' + operands[specialIndex] + ")^2";
|
||||
} else {
|
||||
operands[specialIndex] = "sqrt(" + operands[specialIndex] + ')';
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int index = 0; index < operandCount; index++) {
|
||||
if (index > 0) {
|
||||
String operator = OPERATORS[random.nextInt(OPERATORS.length)];
|
||||
builder.append(' ').append(operator).append(' ');
|
||||
}
|
||||
builder.append(operands[index]);
|
||||
}
|
||||
String expression = builder.toString();
|
||||
if (operandCount > 1 && random.nextBoolean()) {
|
||||
return '(' + expression + ')';
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.personalproject.generator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 生成包含基础四则运算的小学难度题目表达式。
|
||||
*/
|
||||
public final class PrimaryQuestionGenerator implements QuestionGenerator {
|
||||
private static final String[] OPERATORS = {"+", "-", "*", "/"};
|
||||
|
||||
@Override
|
||||
public String generateQuestion(Random random) {
|
||||
int operandCount = random.nextInt(5) + 1;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int index = 0; index < operandCount; index++) {
|
||||
if (index > 0) {
|
||||
String operator = OPERATORS[random.nextInt(OPERATORS.length)];
|
||||
builder.append(' ').append(operator).append(' ');
|
||||
}
|
||||
int value = random.nextInt(100) + 1;
|
||||
builder.append(value);
|
||||
}
|
||||
String expression = builder.toString();
|
||||
if (operandCount > 1 && random.nextBoolean()) {
|
||||
return '(' + expression + ')';
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package com.personalproject.generator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 负责生成单条数学题目的表达式。
|
||||
*/
|
||||
public interface QuestionGenerator {
|
||||
String generateQuestion(Random random);
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.personalproject.model;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 系统支持的出题难度级别。
|
||||
*/
|
||||
public enum DifficultyLevel {
|
||||
PRIMARY("小学"),
|
||||
MIDDLE("初中"),
|
||||
HIGH("高中");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
DifficultyLevel(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public static Optional<DifficultyLevel> fromDisplayName(String name) {
|
||||
if (name == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
String trimmed = name.trim();
|
||||
if (trimmed.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
for (DifficultyLevel level : values()) {
|
||||
if (level.displayName.equals(trimmed)) {
|
||||
return Optional.of(level);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.personalproject.service;
|
||||
|
||||
import com.personalproject.generator.QuestionGenerator;
|
||||
import com.personalproject.model.DifficultyLevel;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 负责批量生成题目并避免与历史题库重复。
|
||||
*/
|
||||
public final class QuestionGenerationService {
|
||||
private static final int MAX_ATTEMPTS = 10_000;
|
||||
private final Map<DifficultyLevel, QuestionGenerator> generators;
|
||||
private final Random random = new SecureRandom();
|
||||
|
||||
public QuestionGenerationService(Map<DifficultyLevel, QuestionGenerator> generatorMap) {
|
||||
generators = new EnumMap<>(DifficultyLevel.class);
|
||||
generators.putAll(generatorMap);
|
||||
}
|
||||
|
||||
public List<String> generateUniqueQuestions(
|
||||
DifficultyLevel level, int count, Set<String> existingQuestions) {
|
||||
QuestionGenerator generator = generators.get(level);
|
||||
if (generator == null) {
|
||||
throw new IllegalArgumentException("Unsupported difficulty level: " + level);
|
||||
}
|
||||
Set<String> produced = new HashSet<>();
|
||||
List<String> results = new ArrayList<>();
|
||||
int attempts = 0;
|
||||
while (results.size() < count) {
|
||||
if (attempts >= MAX_ATTEMPTS) {
|
||||
throw new IllegalStateException("Unable to generate enough unique questions.");
|
||||
}
|
||||
attempts++;
|
||||
String question = generator.generateQuestion(random).trim();
|
||||
if (question.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (existingQuestions.contains(question)) {
|
||||
continue;
|
||||
}
|
||||
if (!produced.add(question)) {
|
||||
continue;
|
||||
}
|
||||
results.add(question);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package com.personalproject.storage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 负责保存生成的题目并维护查重信息。
|
||||
*/
|
||||
public final class QuestionStorageService {
|
||||
private static final String BASE_DIRECTORY = "generated_questions";
|
||||
private static final DateTimeFormatter FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
|
||||
|
||||
public Set<String> loadExistingQuestions(String username) throws IOException {
|
||||
Path accountDirectory = getAccountDirectory(username);
|
||||
Set<String> questions = new HashSet<>();
|
||||
if (!Files.exists(accountDirectory)) {
|
||||
return questions;
|
||||
}
|
||||
try (Stream<Path> paths = Files.list(accountDirectory)) {
|
||||
paths
|
||||
.filter(path -> path.getFileName().toString().endsWith(".txt"))
|
||||
.sorted()
|
||||
.forEach(path -> readQuestionsFromFile(path, questions));
|
||||
}
|
||||
return questions;
|
||||
}
|
||||
|
||||
public Path saveQuestions(String username, List<String> questions) throws IOException {
|
||||
Path accountDirectory = getAccountDirectory(username);
|
||||
Files.createDirectories(accountDirectory);
|
||||
String fileName = FORMATTER.format(LocalDateTime.now()) + ".txt";
|
||||
Path outputFile = accountDirectory.resolve(fileName);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int index = 0; index < questions.size(); index++) {
|
||||
String question = questions.get(index);
|
||||
builder
|
||||
.append(index + 1)
|
||||
.append(". ")
|
||||
.append(question)
|
||||
.append(System.lineSeparator())
|
||||
.append(System.lineSeparator());
|
||||
}
|
||||
Files.writeString(
|
||||
outputFile, builder.toString(), StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW);
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
private Path getAccountDirectory(String username) {
|
||||
return Paths.get(BASE_DIRECTORY, username);
|
||||
}
|
||||
|
||||
private void readQuestionsFromFile(Path path, Set<String> questions) {
|
||||
try {
|
||||
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
|
||||
for (String line : lines) {
|
||||
String trimmed = line.trim();
|
||||
if (trimmed.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
int dotIndex = trimmed.indexOf('.');
|
||||
if (dotIndex >= 0 && dotIndex + 1 < trimmed.length()) {
|
||||
String question = trimmed.substring(dotIndex + 1).trim();
|
||||
if (!question.isEmpty()) {
|
||||
questions.add(question);
|
||||
}
|
||||
} else {
|
||||
questions.add(trimmed);
|
||||
}
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
// 继续处理其他文件,如有需要可在此处添加日志。
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue