Merge branch 'refs/heads/develop'

main
Teptao 5 months ago
commit 48cbfc78ee

@ -1,13 +1,15 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
*
* IProblemGenerator
*
*
*/
public abstract class AbstractProblemGenerator implements IProblemGenerator {
@ -17,51 +19,153 @@ public abstract class AbstractProblemGenerator implements IProblemGenerator {
protected static final int MIN_OPERANDS_COUNT = 2;
protected static final int MAX_OPERANDS_COUNT = 5;
private static final Operator[] AVAILABLE_OPERATORS = {
Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE
};
@Override
public List<Equation> generate(int count, Set<String> existingProblems) {
public final List<Equation> generate(int count, Set<String> existingProblems) {
List<Equation> newProblems = new ArrayList<>(count);
// 使用一个临时的Set来防止在同一次生成任务中产生重复
Set<String> currentBatchSet = new HashSet<>();
while (newProblems.size() < count) {
Equation candidate = createProblem();
int maxTries = count * 100;
int tries = 0;
String canonicalForm = candidate.toCanonicalString();
while (newProblems.size() < count && tries < maxTries) {
Equation candidate = createProblem();
String canonicalForm = candidate.toString();
// 执行唯一性检查:既不能与历史重复,也不能与本次生成的其他题目重复
if (!existingProblems.contains(canonicalForm) && !currentBatchSet.contains(canonicalForm)) {
if (!existingProblems.contains(canonicalForm) && currentBatchSet.add(canonicalForm)) {
newProblems.add(candidate);
currentBatchSet.add(canonicalForm);
}
tries++;
}
return newProblems;
}
/**
*
*
*
* @return Equation
*
*/
protected abstract Equation createProblem();
/**
*
*
*
*
* @param min
* @param max
* @return
* @param nonNegativeOnly true
* @return Equation
*/
protected int getRandomNumber(int min, int max) {
return random.nextInt(max - min + 1) + min;
protected Equation createBaseArithmeticProblem(boolean nonNegativeOnly) {
int numOperands = getRandomNumber(MIN_OPERANDS_COUNT, MAX_OPERANDS_COUNT);
List<String> operands = new ArrayList<>();
List<Operator> operators = new ArrayList<>();
int currentResult = getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE);
operands.add(String.valueOf(currentResult));
for (int i = 0; i < numOperands - 1; i++) {
if (nonNegativeOnly) {
currentResult = appendNonNegativeOperation(operands, operators, currentResult);
} else {
appendStandardOperation(operands, operators);
}
}
addParentheses(operands, operators);
return new Equation(operands, operators);
}
/**
* (Refactored Helper)
*
* @param operands
* @param operators
* @param currentResult
* @return
*/
private int appendNonNegativeOperation(List<String> operands, List<Operator> operators, int currentResult) {
Operator operator = AVAILABLE_OPERATORS[random.nextInt(AVAILABLE_OPERATORS.length)];
int nextOperand;
int newResult = currentResult;
switch (operator) {
case ADD:
nextOperand = getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE);
newResult += nextOperand;
break;
case SUBTRACT:
nextOperand = getRandomNumber(MIN_OPERAND_VALUE, currentResult);
newResult -= nextOperand;
break;
case MULTIPLY:
nextOperand = getRandomNumber(MIN_OPERAND_VALUE, 10);
newResult *= nextOperand;
break;
case DIVIDE:
List<Integer> divisors = findDivisors(currentResult);
nextOperand = divisors.get(random.nextInt(divisors.size()));
newResult /= nextOperand;
break;
default:
// 为了编译安全,实际上不会执行到这里
throw new IllegalStateException("Unexpected value: " + operator);
}
operands.add(String.valueOf(nextOperand));
operators.add(operator);
return newResult;
}
/**
*
* @param availableOperators
* @return
* (Refactored Helper)
*
* @param operands
* @param operators
*/
protected Operator getRandomOperator(Operator[] availableOperators) {
return availableOperators[random.nextInt(availableOperators.length)];
private void appendStandardOperation(List<String> operands, List<Operator> operators) {
Operator operator = AVAILABLE_OPERATORS[random.nextInt(AVAILABLE_OPERATORS.length)];
int nextOperand;
if (operator == Operator.DIVIDE) {
// 为确保整除,反向构造
int divisor = getRandomNumber(1, 10);
int quotient = getRandomNumber(1, 20);
// 替换前一个操作数以确保可整除
operands.set(operands.size() - 1, String.valueOf(divisor * quotient));
nextOperand = divisor;
} else {
nextOperand = getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE);
}
operands.add(String.valueOf(nextOperand));
operators.add(operator);
}
private void addParentheses(List<String> operands, List<Operator> operators) {
if (operators.size() > 1 && random.nextBoolean()) {
int pos = random.nextInt(operators.size());
Operator op = operators.get(pos);
// 仅在优先级较低的运算符旁边添加括号才有视觉意义
if (op == Operator.ADD || op == Operator.SUBTRACT) {
operands.set(pos, "(" + operands.get(pos));
operands.set(pos + 1, operands.get(pos + 1) + ")");
}
}
}
private List<Integer> findDivisors(int number) {
if (number == 0) {
return Collections.singletonList(1); // 避免除以0
}
return IntStream.rangeClosed(1, Math.abs(number))
.filter(i -> number % i == 0)
.boxed()
.collect(Collectors.toList());
}
protected int getRandomNumber(int min, int max) {
if (min > max) {
return max; // 安全处理例如当currentResult变为1时
}
return random.nextInt(max - min + 1) + min;
}
}

@ -0,0 +1,66 @@
/**
*
*
*
*/
public abstract class AbstractSessionManager {
protected User currentUser;
protected IProblemGenerator currentGenerator;
protected String currentLevel;
/**
*
*
* @param user
*/
public abstract void startSession(User user);
/**
* 退
*/
public abstract void endSession();
/**
*
*
* @param level
*/
public abstract void setCurrentGenerator(String level);
/**
*
*
* @return true false
*/
public boolean isUserLoggedIn() {
return currentUser != null;
}
/**
*
*
* @return
*/
public User getCurrentUser() {
return currentUser;
}
/**
*
*
* @return
*/
public IProblemGenerator getCurrentGenerator() {
return currentGenerator;
}
/**
*
*
* @return "小学"
*/
public String getCurrentLevelName() {
return currentLevel;
}
}

@ -0,0 +1,61 @@
import java.util.Objects;
/**
*
*
*/
public abstract class AbstractUser {
protected final String username;
protected final String password;
/**
*
*
* @param username
* @param password
*/
public AbstractUser(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
/**
*
*
*
* @param o
* @return true false
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
// 使用 getClass() != o.getClass() 来确保子类之间不会错误地相等
if (o == null || getClass() != o.getClass()) {
return false;
}
AbstractUser that = (AbstractUser) o;
return username.equals(that.username);
}
/**
*
*
*
* @return
*/
@Override
public int hashCode() {
return Objects.hash(username);
}
}

@ -20,16 +20,13 @@ public class Application {
// 用于解析“切换为XX”命令的正则表达式
private static final Pattern SWITCH_COMMAND_PATTERN = Pattern.compile("^切换为(小学|初中|高中)$");
private static final int MIN_GENERATE_COUNT = 10;
private static final int MAX_GENERATE_COUNT = 30;
public Application() {
this.scanner = new Scanner(System.in, "UTF-8");
// --- 依赖注入与组件装配 ---
// 创建数据访问层的实例
UserRepository userRepository = new InMemoryUserRepository();
this.fileService = new TextFilePersistence();
IUserRepository userRepository = new UserRepository();
this.fileService = new FileService();
// 创建应用服务层的实例,并注入依赖
this.authService = new AuthService(userRepository);
// 获取会话管理器的单例实例
@ -39,7 +36,7 @@ public class Application {
/**
*
*/
public void run() {
public void run() throws IOException {
System.out.println("欢迎使用中小学数学卷子自动生成程序!");
while (true) {
if (!sessionManager.isUserLoggedIn()) {
@ -62,7 +59,7 @@ public class Application {
System.exit(0);
}
String[] credentials = input.split("\\s+");
String[] credentials = input.split(" ");
if (credentials.length != 2) {
System.out.println("输入格式错误,请输入正确的用户名、密码。");
return;
@ -71,7 +68,7 @@ public class Application {
Optional<User> userOptional = authService.login(credentials[0], credentials[1]);
if (userOptional.isPresent()) {
sessionManager.startSession(userOptional.get());
System.out.println("登录成功!欢迎您," + userOptional.get().getUsername() + "。");
System.out.println("登录成功!欢迎您," + credentials[0] + "。");
} else {
System.out.println("用户名或密码错误,请重试。");
}
@ -80,30 +77,23 @@ public class Application {
/**
*
*/
private void handleLoggedInState() {
String currentLevelName = sessionManager.getCurrentLevelName();
private void handleLoggedInState() throws IOException {
String currentLevel = sessionManager.getCurrentLevel();
System.out.printf(
"当前选择为%s出题。请输入生成题目数量%d-%d),或输入 '切换为XX',或输入 '-1' 退出登录:%n",
currentLevelName, MIN_GENERATE_COUNT, MAX_GENERATE_COUNT);
"当前选择为%s出题。请输入生成题目数量10-30),或输入 '切换为XX',或输入 '-1' 退出登录:%n",
currentLevel);
String input = scanner.nextLine().trim();
try {
if ("-1".equals(input)) {
handleLogout();
} else if (isSwitchCommand(input)) {
handleSwitchLevel(input);
} else if (isNumeric(input)) {
int count = Integer.parseInt(input);
validateGenerateCount(count);
handleGenerateProblems(count);
handleGenerateProblems(input);
} else {
throw new InvalidInputException(
String.format("请输入小学、初中和高中三个选项中的一个",
MIN_GENERATE_COUNT, MAX_GENERATE_COUNT));
System.out.println("无效的选项,请重新输入");
}
} catch (InvalidInputException | IOException | NumberFormatException e) {
System.err.println("错误: " + e.getMessage());
}
}
private void handleLogout() {
@ -111,22 +101,25 @@ public class Application {
sessionManager.endSession();
}
private void handleSwitchLevel(String input) throws InvalidInputException {
private void handleSwitchLevel(String input) {
Matcher matcher = SWITCH_COMMAND_PATTERN.matcher(input);
if (matcher.matches()) {
String levelName = matcher.group(1);
EducationLevel level = EducationLevel.fromLevelName(levelName);
String level = matcher.group(1);
if (level != null) {
sessionManager.setCurrentGenerator(level);
System.out.println("成功切换到 " + levelName + " 出题模式。");
} else {
// 这部分代码理论上不会执行,因为正则表达式已经限制了级别名称
throw new InvalidInputException("无效的切换目标级别。");
System.out.println("成功切换到 " + level + " 出题模式。");
}
}
}
private void handleGenerateProblems(int count) throws IOException {
private void handleGenerateProblems(String input) throws IOException {
int count = Integer.parseInt(input);
if (count < 10 || count > 30) {
System.out.println("生成数量必须在10到30之间。");
return;
}
User currentUser = sessionManager.getCurrentUser();
System.out.println("正在加载历史题目,请稍候...");
Set<String> history = fileService.loadAllProblemHistory(currentUser);
@ -135,11 +128,11 @@ public class Application {
System.out.println("正在生成 " + count + " 道不重复的新题目...");
IProblemGenerator generator = sessionManager.getCurrentGenerator();
List<Equation> newProblems = generator.generate(count, history);
//命令行显示生成题目
// 命令行显示生成题目
for (int i = 0; i < newProblems.size(); i++) {
String problemLine = (i + 1) + ". " + newProblems.get(i).toString();
System.out.println(problemLine);
// 满足题目之间空一行的格式要求
System.out.println();
}
@ -153,17 +146,10 @@ public class Application {
}
private boolean isNumeric(String str) {
return str != null && str.matches("-?\\d+");
}
private void validateGenerateCount(int count) throws InvalidInputException {
if (count < MIN_GENERATE_COUNT || count > MAX_GENERATE_COUNT) {
throw new InvalidInputException(
String.format("生成数量必须在 %d 到 %d 之间。", MIN_GENERATE_COUNT, MAX_GENERATE_COUNT));
}
return str != null && str.matches("\\d+");
}
public static void main(String[] args) {
public static void main(String[] args) throws IOException {
Application app = new Application();
app.run();
}

@ -4,11 +4,11 @@ import java.util.Optional;
*
*
*/
public class AuthService {
public class AuthService implements IAuthService {
private final UserRepository userRepository;
private final IUserRepository userRepository;
public AuthService(UserRepository userRepository) {
public AuthService(IUserRepository userRepository) {
this.userRepository = userRepository;
}
@ -17,7 +17,7 @@ public class AuthService {
*
* @param username
* @param password
* @return User Optional
* @return ture,false
*/
public Optional<User> login(String username, String password) {
Optional<User> userOptional = userRepository.findByUsername(username);

@ -1,39 +0,0 @@
/**
*
*
*/
public enum EducationLevel {
PRIMARY("小学"),
MIDDLE("初中"),
HIGH("高中");
private final String levelName;
EducationLevel(String levelName) {
this.levelName = levelName;
}
/**
*
*
* @return
*/
public String getLevelName() {
return levelName;
}
/**
*
*
* @param levelName "初中"
* @return EducationLevel null
*/
public static EducationLevel fromLevelName(String levelName) {
for (EducationLevel level : values()) {
if (level.getLevelName().equals(levelName)) {
return level;
}
}
return null;
}
}

@ -1,45 +1,12 @@
import java.util.ArrayList;
import java.util.List;
/**
*
* 2-5
*
*/
public class ElementaryProblemGenerator extends AbstractProblemGenerator {
private static final Operator[] AVAILABLE_OPERATORS = {
Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE
};
@Override
protected Equation createProblem() {
int numOperands = getRandomNumber(MIN_OPERANDS_COUNT, MAX_OPERANDS_COUNT);
List<Integer> operands = new ArrayList<>();
List<Operator> operators = new ArrayList<>();
// 生成第一个操作数
operands.add(getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE));
for (int i = 0; i < numOperands - 1; i++) {
Operator operator = getRandomOperator(AVAILABLE_OPERATORS);
int nextOperand;
// 特殊处理除法确保除数不为0且能整除避免产生小数
if (operator == Operator.DIVIDE) {
// 为了简化,我们让被除数是新生成的随机数的倍数
int divisor = getRandomNumber(1, 10); // 将除数范围缩小以增加整除概率
int quotient = getRandomNumber(1, 10);
int dividend = operands.get(operands.size() - 1); // 获取前一个结果或操作数
operands.set(operands.size() - 1, divisor * quotient); // 替换前一个操作数确保能整除
nextOperand = divisor;
} else {
nextOperand = getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE);
}
operands.add(nextOperand);
operators.add(operator);
}
return new Equation(operands, operators, true);
// 调用父类的核心方法,并传入 true要求启用“无负数”约束。
return createBaseArithmeticProblem(true);
}
}

@ -1,77 +1,65 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
*
*
*
* 使 String
*/
public class Equation {
private final List<String> operands; // 使用String以支持如 "sqrt(16)" 的形式
private final List<String> operands;
private final List<Operator> operators;
/**
*
*
* @param operands
* @param operators
*/
public Equation(List<String> operands, List<Operator> operators) {
this.operands = new ArrayList<>(operands);
this.operators = new ArrayList<>(operators);
}
// 为了方便,提供一个只接受整数操作数的构造函数
public Equation(List<Integer> intOperands, List<Operator> operators, boolean isSimple) {
this.operands = intOperands.stream().map(String::valueOf).collect(Collectors.toList());
this.operators = new ArrayList<>(operators);
this.operands = Collections.unmodifiableList(operands);
this.operators = Collections.unmodifiableList(operators);
}
/**
*
*
* @return
*/
public List<String> getOperands() {
return Collections.unmodifiableList(operands);
return operands;
}
/**
*
*
* @return
*/
public List<Operator> getOperators() {
return Collections.unmodifiableList(operators);
return operators;
}
/**
*
* : "操作数1 运算符1 操作数2 = 结果"
*
* : "操作数1 运算符1 操作数2 = ?"
*
* @return
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(operands.get(0));
for (int i = 0; i < operators.size(); i++) {
sb.append(" ").append(operators.get(i).getSymbol()).append(" ");
sb.append(operands.get(i + 1));
}
sb.append(" = ").append("?");
// 使用 IntStream 处理操作数和操作符的交替拼接
IntStream.range(0, operators.size())
.forEach(i -> sb.append(operands.get(i))
.append(" ")
.append(operators.get(i).getSymbol())
.append(" "));
sb.append(operands.get(operands.size() - 1)); // 追加最后一个操作数
sb.append(" = ?");
return sb.toString();
}
/**
*
* "3 + 5" "5 + 3"
*
*
* @return
*/
public String toCanonicalString() {
if (operators.size() == 1 && operators.get(0).isCommutative()) {
// 仅处理最简单的二元运算场景
String[] sortedOperands = operands.toArray(new String[0]);
Arrays.sort(sortedOperands);
return sortedOperands[0] + " " + operators.get(0).getSymbol() + " " + sortedOperands[1];
}
// 对于更复杂的或不可交换的运算,直接按顺序拼接
StringBuilder sb = new StringBuilder();
sb.append(operands.get(0));
for (int i = 0; i < operators.size(); i++) {
sb.append(" ").append(operators.get(i).getSymbol()).append(" ");
sb.append(operands.get(i + 1));
}
return sb.toString();
}
}

@ -12,21 +12,16 @@ import java.time.format.DateTimeFormatter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
*
*/
public class TextFilePersistence implements IFileService {
public class FileService implements IFileService {
private static final DateTimeFormatter FILE_NAME_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
// 正则表达式用于从文件中解析出题目表达式部分(忽略题号和答案)
private static final Pattern PROBLEM_PATTERN = Pattern.compile("^\\d+\\.\\s*(.+?)\\s*=");
@Override
public void saveProblems(User user, List<Equation> problems) throws IOException {
Path userDirectory = Paths.get(user.getStoragePath());
@ -71,39 +66,15 @@ public class TextFilePersistence implements IFileService {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
Matcher matcher = PROBLEM_PATTERN.matcher(line.trim());
if (matcher.find()) {
String expression = matcher.group(1).trim();
// 将解析出的表达式转换为规范化形式
// 这是一个简化的转换,假设表达式格式固定
// 更健壮的实现会构建一个临时的 Equation 对象来获取其规范化字符串
String canonicalForm = normalizeExpression(expression);
historySet.add(canonicalForm);
if (!line.trim().isEmpty()) {
String cleanedLine = line.replaceFirst("^\\d+\\.\\s*", "");
historySet.add(cleanedLine);
}
}
}
}
return historySet;
}
/**
*
* Equation.toCanonicalString()
*
* @param expression "5 + 3" "12 * 4"
* @return
*/
private String normalizeExpression(String expression) {
String[] parts = expression.split(" ");
if (parts.length == 3) {
String op = parts[1];
if (op.equals("+") || op.equals("*")) {
// 如果是可交换运算符,对操作数进行排序
if (parts[0].compareTo(parts[2]) > 0) {
return parts[2] + " " + op + " " + parts[0];
}
}
}
return expression; // 其他情况直接返回
}
}

@ -3,52 +3,34 @@ import java.util.List;
/**
*
* /
* /
* 使
*/
public class HighSchoolProblemGenerator extends MiddleSchoolProblemGenerator {
// 预定义一些常见的三角函数角度
private static final int[] PREDEFINED_ANGLES = {0, 30, 45, 60, 90};
private static final String[] TRIG_FUNCTIONS = {"sin", "cos", "tan"};
@Override
protected Equation createProblem() {
// 首先调用父类MiddleSchoolProblemGenerator的方法
// 生成一个已经包含平方或开方运算的题目结构。
// 1. 调用父类(已修正的 MiddleSchoolProblemGenerator的方法
Equation middleSchoolEquation = super.createProblem();
// 直接获取父类生成的可变列表进行再次修改
List<String> operands = new ArrayList<>(middleSchoolEquation.getOperands());
List<Operator> operators = new ArrayList<>(middleSchoolEquation.getOperators());
// 随机选择一个操作数,用三角函数表达式替换。
// 这可能替换一个普通数字,也可能替换掉父类生成的 sqrt(x) 或 (x^2) 表达式,增加了多样性。
// 2. 随机替换一个操作数为三角函数
int modifyIndex = random.nextInt(operands.size());
int angle = PREDEFINED_ANGLES[random.nextInt(PREDEFINED_ANGLES.length)];
String funcType = TRIG_FUNCTIONS[random.nextInt(TRIG_FUNCTIONS.length)];
// 随机选择一个三角函数
int funcType = random.nextInt(3);
String trigExpression;
switch (funcType) {
case 0: // sin
trigExpression = "sin(" + angle + ")";
break;
case 1: // cos
trigExpression = "cos(" + angle + ")";
break;
default: // tan
if (angle == 90) {
angle = 45; // 避免tan(90)无定义的情况
}
trigExpression = "tan(" + angle + ")";
break;
if ("tan".equals(funcType) && angle == 90) {
angle = 45; // 避免 tan(90)
}
// 用三角函数的表达式字符串替换随机选择的操作数
String trigExpression = String.format("%s(%d)", funcType, angle);
operands.set(modifyIndex, trigExpression);
// 用修改后的操作数和原有的操作符列表创建最终的高中题目
return new Equation(operands, operators);
}
}

@ -0,0 +1,17 @@
import java.util.Optional;
/**
*
*
*/
public interface IAuthService {
/**
*
*
* @param username
* @param password
* @return UserOptionalOptional
*/
Optional<User> login(String username, String password);
}

@ -21,7 +21,7 @@ public interface IFileService {
*
*
* @param user
* @return
* @return
* @throws IOException
*/
Set<String> loadAllProblemHistory(User user) throws IOException;

@ -0,0 +1,16 @@
import java.util.Optional;
/**
*
* 访
*/
public interface IUserRepository {
/**
*
*
* @param username
* @return Optional
*/
Optional<User> findByUsername(String username);
}

@ -1,33 +0,0 @@
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
*
*
*/
public class InMemoryUserRepository implements UserRepository {
private final Map<String, User> userDatabase = new ConcurrentHashMap<>();
public InMemoryUserRepository() {
// 初始化预定义的9个用户账户
// 小学老师
userDatabase.put("张三1", new User("张三1", "123", EducationLevel.PRIMARY));
userDatabase.put("张三2", new User("张三2", "123", EducationLevel.PRIMARY));
userDatabase.put("张三3", new User("张三3", "123", EducationLevel.PRIMARY));
// 初中老师
userDatabase.put("李四1", new User("李四1", "123", EducationLevel.MIDDLE));
userDatabase.put("李四2", new User("李四2", "123", EducationLevel.MIDDLE));
userDatabase.put("李四3", new User("李四3", "123", EducationLevel.MIDDLE));
// 高中老师
userDatabase.put("王五1", new User("王五1", "123", EducationLevel.HIGH));
userDatabase.put("王五2", new User("王五2", "123", EducationLevel.HIGH));
userDatabase.put("王五3", new User("王五3", "123", EducationLevel.HIGH));
}
@Override
public Optional<User> findByUsername(String username) {
return Optional.ofNullable(userDatabase.get(username));
}
}

@ -1,8 +0,0 @@
/**
*
*/
public class InvalidInputException extends Exception {
public InvalidInputException(String message) {
super(message);
}
}

@ -1,37 +1,34 @@
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
*
*
*
*/
public class MiddleSchoolProblemGenerator extends ElementaryProblemGenerator {
public class MiddleSchoolProblemGenerator extends AbstractProblemGenerator {
@Override
protected Equation createProblem() {
// 首先,借用父类方法生成一个基础的四则运算结构
Equation basicEquation = super.createProblem();
// 1. 调用父类的核心方法,并传入 false允许生成包含负数的标准表达式。
Equation basicEquation = createBaseArithmeticProblem(false);
// 将父类生成的操作数Integer转换为本类需要的 String 列表
List<String> operands = basicEquation.getOperands().stream()
.map(String::valueOf)
.collect(Collectors.toList());
// 2. 将基础表达式元素转为可修改的列表
List<String> operands = new ArrayList<>(basicEquation.getOperands());
List<Operator> operators = new ArrayList<>(basicEquation.getOperators());
// 随机选择一个操作数进行变形
// 3. 随机选择一个操作数进行变形
int modifyIndex = random.nextInt(operands.size());
int originalValue = Integer.parseInt(operands.get(modifyIndex));
String targetOperand = operands.get(modifyIndex).replace("(", "").replace(")", "");
// 随机决定是进行平方还是开方运算
// 4. 随机决定是进行平方还是开方运算
if (random.nextBoolean()) {
// 平方运算:生成 "(originalValue^2)" 格式的字符串
String squaredExpression = String.format("(%d^2)", originalValue);
// 平方运算
String squaredExpression = String.format("(%s^2)", targetOperand);
operands.set(modifyIndex, squaredExpression);
} else {
// 开方运算:生成 "sqrt(value)" 格式的字符串
// 开方运算
int base = getRandomNumber(2, 10);
int valueToRoot = base * base; // 确保可以完美开方
int valueToRoot = base * base;
String sqrtExpression = String.format("sqrt(%d)", valueToRoot);
operands.set(modifyIndex, sqrtExpression);
}

@ -1,54 +1,29 @@
import java.util.function.BinaryOperator;
/**
*
*
*
*
*/
public enum Operator {
ADD('+', (a, b) -> a + b, true),
SUBTRACT('-', (a, b) -> a - b, false),
MULTIPLY('*', (a, b) -> a * b, true),
DIVIDE('/', (a, b) -> a / b, false);
ADD('+'),
SUBTRACT('-'),
MULTIPLY('*'),
DIVIDE('/');
private final char symbol;
private final BinaryOperator<Integer> operation;
private final boolean isCommutative; // 标记是否为可交换运算符(如加法、乘法)
/**
*
*
* @param symbol
* @param operation
* @param isCommutative
*/
Operator(char symbol, BinaryOperator<Integer> operation, boolean isCommutative) {
Operator(char symbol) {
this.symbol = symbol;
this.operation = operation;
this.isCommutative = isCommutative;
}
/**
*
* @return
*/
public char getSymbol() {
return symbol;
}
public boolean isCommutative() {
return isCommutative;
}
/**
*
*
* @param a
* @param b
* @return
*/
public int apply(int a, int b) {
// 为除法增加安全检查,防止除以零
if (this == DIVIDE && b == 0) {
// 在实际生成中应避免生成除数为0的题目这里作为最后防线
throw new ArithmeticException("Division by zero.");
}
return operation.apply(a, b);
}
}

@ -2,13 +2,14 @@
*
*
*/
public final class SessionManager {
public final class SessionManager extends AbstractSessionManager {
// 懒汉式单例模式,确保线程安全
private static volatile SessionManager instance;
private User currentUser;
private IProblemGenerator currentGenerator;
private String currentLevel;
private SessionManager() {
// 私有构造函数,防止外部实例化
@ -38,7 +39,7 @@ public final class SessionManager {
public void startSession(User user) {
this.currentUser = user;
// 根据用户的默认级别,初始化对应的题目生成策略
setGeneratorByDefaultLevel(user.getDefaultLevel());
setGeneratorByLevel(user.getDefaultLevel());
}
/**
@ -66,43 +67,37 @@ public final class SessionManager {
*
* @param level
*/
public void setCurrentGenerator(EducationLevel level) {
public void setCurrentGenerator(String level) {
if (level == null) {
throw new IllegalArgumentException("难度等级不可为空。");
}
setGeneratorByDefaultLevel(level);
setGeneratorByLevel(level);
}
private void setGeneratorByDefaultLevel(EducationLevel level) {
private void setGeneratorByLevel(String level) {
String tempLevel = this.currentLevel;
this.currentLevel = level;
switch (level) {
case PRIMARY:
case "小学":
this.currentGenerator = new ElementaryProblemGenerator();
break;
case MIDDLE:
case "初中":
this.currentGenerator = new MiddleSchoolProblemGenerator();
break;
case HIGH:
case "高中":
this.currentGenerator = new HighSchoolProblemGenerator();
break;
default:
// 理论上不会发生,因为枚举是固定的
throw new IllegalStateException("错误的难度等级: " + level);
System.out.println("错误的难度等级: " + level);
this.currentLevel = tempLevel;
}
}
/**
*
*
* @return "小学"
*/
public String getCurrentLevelName() {
if (currentGenerator instanceof HighSchoolProblemGenerator) {
return "高中";
} else if (currentGenerator instanceof MiddleSchoolProblemGenerator) {
return "初中";
}else if (currentGenerator instanceof ElementaryProblemGenerator) {
return "小学";
}
return "未知";
public String getCurrentLevel() {
return currentLevel;
}
}

@ -1,33 +1,18 @@
import java.util.Objects;
// 修改后的 User.java
public class User extends AbstractUser {
/**
*
* POJO
*/
public class User {
private final String username;
private final String password; // 注意:在生产系统中应存储哈希值
private final EducationLevel defaultLevel;
private final String defaultLevel;
private final String storagePath;
public User(String username, String password, EducationLevel defaultLevel) {
this.username = username;
this.password = password;
public User(String username, String password, String defaultLevel) {
// 调用父类的构造函数来初始化 username 和 password
super(username, password);
this.defaultLevel = defaultLevel;
// 根据用户名生成唯一的存储路径
this.storagePath = "./data/" + username + "/";
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
this.storagePath = "./data/" + this.username + "/";
}
public EducationLevel getDefaultLevel() {
public String getDefaultLevel() {
return defaultLevel;
}
@ -35,20 +20,5 @@ public class User {
return storagePath;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
return username.equals(user.username);
}
@Override
public int hashCode() {
return Objects.hash(username);
}
// equals() 和 hashCode() 方法已由父类 AbstractUser 提供
}

@ -1,16 +1,33 @@
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
*
* 访
*
*
*/
public interface UserRepository {
public class UserRepository implements IUserRepository {
/**
*
*
* @param username
* @return Optional
*/
Optional<User> findByUsername(String username);
private final Map<String, User> userDatabase = new ConcurrentHashMap<>();
public UserRepository() {
// 初始化预定义的9个用户账户
// 小学老师
userDatabase.put("张三1", new User("张三1", "123", "小学"));
userDatabase.put("张三2", new User("张三2", "123", "小学"));
userDatabase.put("张三3", new User("张三3", "123", "小学"));
// 初中老师
userDatabase.put("李四1", new User("李四1", "123", "初中"));
userDatabase.put("李四2", new User("李四2", "123", "初中"));
userDatabase.put("李四3", new User("李四3", "123", "初中"));
// 高中老师
userDatabase.put("王五1", new User("王五1", "123", "高中"));
userDatabase.put("王五2", new User("王五2", "123", "高中"));
userDatabase.put("王五3", new User("王五3", "123", "高中"));
}
@Override
public Optional<User> findByUsername(String username) {
return Optional.ofNullable(userDatabase.get(username));
}
}
Loading…
Cancel
Save