|
|
|
@ -0,0 +1,626 @@
|
|
|
|
|
import java.io.*;
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
import java.util.regex.Matcher;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 中小学数学卷子自动生成程序主类
|
|
|
|
|
*/
|
|
|
|
|
public class MathExamGenerator {
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
try {
|
|
|
|
|
ApplicationController controller = new ApplicationController();
|
|
|
|
|
controller.run();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.out.println("程序启动失败: " + e.getMessage());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 应用程序控制器 - 负责协调各个模块
|
|
|
|
|
*/
|
|
|
|
|
class ApplicationController {
|
|
|
|
|
private AccountManager accountManager;
|
|
|
|
|
private String currentUser;
|
|
|
|
|
private String currentType;
|
|
|
|
|
private DuplicateChecker duplicateChecker;
|
|
|
|
|
private FileSaver fileSaver;
|
|
|
|
|
private Map<String, QuestionGenerator> generatorMap;
|
|
|
|
|
|
|
|
|
|
public ApplicationController() {
|
|
|
|
|
this.accountManager = new AccountManager();
|
|
|
|
|
this.generatorMap = new HashMap<>();
|
|
|
|
|
generatorMap.put("小学", new PrimarySchoolGenerator());
|
|
|
|
|
generatorMap.put("初中", new JuniorHighGenerator());
|
|
|
|
|
generatorMap.put("高中", new SeniorHighGenerator());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
|
System.out.println("=== 中小学数学卷子自动生成程序 ===");
|
|
|
|
|
Scanner scanner = new Scanner(System.in);
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
// 登录
|
|
|
|
|
if (!login(scanner)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 登录后直接进入出题流程
|
|
|
|
|
boolean stayLoggedIn = true;
|
|
|
|
|
while (stayLoggedIn) {
|
|
|
|
|
System.out.print("准备生成" + currentType + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录): ");
|
|
|
|
|
String input = scanner.nextLine().trim();
|
|
|
|
|
|
|
|
|
|
// 处理切换类型命令
|
|
|
|
|
if (input.startsWith("切换为")) {
|
|
|
|
|
String newType = input.substring(3).trim();
|
|
|
|
|
if (switchType(newType)) {
|
|
|
|
|
// 切换成功后继续循环,会显示新的提示
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
// 切换失败,继续当前循环
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理退出命令
|
|
|
|
|
if ("-1".equals(input)) {
|
|
|
|
|
stayLoggedIn = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理题目数量输入
|
|
|
|
|
try {
|
|
|
|
|
int numQuestions = Integer.parseInt(input);
|
|
|
|
|
if (numQuestions < 10 || numQuestions > 30) {
|
|
|
|
|
System.out.println("题目数量范围应为10-30");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成题目
|
|
|
|
|
QuestionGenerator generator = generatorMap.get(currentType);
|
|
|
|
|
List<String> questions = new ArrayList<>();
|
|
|
|
|
int attempts = 0;
|
|
|
|
|
int maxAttempts = numQuestions * 10; // 防止无限循环
|
|
|
|
|
|
|
|
|
|
while (questions.size() < numQuestions && attempts < maxAttempts) {
|
|
|
|
|
String newQuestion = generator.generateQuestion();
|
|
|
|
|
if (!duplicateChecker.isDuplicate(newQuestion)) {
|
|
|
|
|
questions.add(newQuestion);
|
|
|
|
|
duplicateChecker.addQuestion(newQuestion);
|
|
|
|
|
}
|
|
|
|
|
attempts++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (questions.size() < numQuestions) {
|
|
|
|
|
System.out.println("警告:只生成了" + questions.size() + "道不重复的题目(历史题目过多)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保存文件
|
|
|
|
|
String filename = fileSaver.saveExam(questions, currentType);
|
|
|
|
|
System.out.println("试卷已生成并保存为: " + filename);
|
|
|
|
|
System.out.println("题目生成完成,可以继续生成新试卷或输入-1退出当前用户");
|
|
|
|
|
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
System.out.println("请输入有效的数字或'切换为小学/初中/高中'");
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.out.println("生成题目出错: " + e.getMessage());
|
|
|
|
|
e.printStackTrace(); // 添加详细错误信息
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 退出当前用户,准备重新登录
|
|
|
|
|
logout();
|
|
|
|
|
System.out.println("已退出当前用户");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scanner.close();
|
|
|
|
|
System.out.println("程序结束");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean login(Scanner scanner) {
|
|
|
|
|
while (true) {
|
|
|
|
|
System.out.print("请输入用户名和密码(用空格隔开): ");
|
|
|
|
|
String input = scanner.nextLine().trim();
|
|
|
|
|
|
|
|
|
|
if (input.isEmpty()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String[] parts = input.split("\\s+");
|
|
|
|
|
if (parts.length != 2) {
|
|
|
|
|
System.out.println("请输入正确的用户名、密码格式");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String username = parts[0];
|
|
|
|
|
String password = parts[1];
|
|
|
|
|
|
|
|
|
|
LoginResult result = accountManager.validateAccount(username, password);
|
|
|
|
|
if (result.isSuccess()) {
|
|
|
|
|
currentUser = username;
|
|
|
|
|
currentType = result.getUserType();
|
|
|
|
|
duplicateChecker = new DuplicateChecker(username);
|
|
|
|
|
fileSaver = new FileSaver(username);
|
|
|
|
|
System.out.println("当前选择为" + currentType + "出题");
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
System.out.println("请输入正确的用户名、密码");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean switchType(String newType) {
|
|
|
|
|
if ("小学".equals(newType) || "初中".equals(newType) || "高中".equals(newType)) {
|
|
|
|
|
currentType = newType;
|
|
|
|
|
System.out.println("已切换为" + newType + "出题");
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
System.out.println("请输入小学、初中和高中三个选项中的一个");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void logout() {
|
|
|
|
|
currentUser = null;
|
|
|
|
|
currentType = null;
|
|
|
|
|
duplicateChecker = null;
|
|
|
|
|
fileSaver = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 登录结果封装类
|
|
|
|
|
*/
|
|
|
|
|
class LoginResult {
|
|
|
|
|
private boolean success;
|
|
|
|
|
private String userType;
|
|
|
|
|
|
|
|
|
|
public LoginResult(boolean success, String userType) {
|
|
|
|
|
this.success = success;
|
|
|
|
|
this.userType = userType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isSuccess() {
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getUserType() {
|
|
|
|
|
return userType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 账户管理类
|
|
|
|
|
*/
|
|
|
|
|
class AccountManager {
|
|
|
|
|
private Map<String, List<Account>> accounts;
|
|
|
|
|
|
|
|
|
|
public AccountManager() {
|
|
|
|
|
accounts = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
// 小学账户
|
|
|
|
|
List<Account> primaryAccounts = Arrays.asList(
|
|
|
|
|
new Account("张三1", "123"),
|
|
|
|
|
new Account("张三2", "123"),
|
|
|
|
|
new Account("张三3", "123")
|
|
|
|
|
);
|
|
|
|
|
accounts.put("小学", primaryAccounts);
|
|
|
|
|
|
|
|
|
|
// 初中账户
|
|
|
|
|
List<Account> juniorAccounts = Arrays.asList(
|
|
|
|
|
new Account("李四1", "123"),
|
|
|
|
|
new Account("李四2", "123"),
|
|
|
|
|
new Account("李四3", "123")
|
|
|
|
|
);
|
|
|
|
|
accounts.put("初中", juniorAccounts);
|
|
|
|
|
|
|
|
|
|
// 高中账户
|
|
|
|
|
List<Account> seniorAccounts = Arrays.asList(
|
|
|
|
|
new Account("王五1", "123"),
|
|
|
|
|
new Account("王五2", "123"),
|
|
|
|
|
new Account("王五3", "123")
|
|
|
|
|
);
|
|
|
|
|
accounts.put("高中", seniorAccounts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public LoginResult validateAccount(String username, String password) {
|
|
|
|
|
for (Map.Entry<String, List<Account>> entry : accounts.entrySet()) {
|
|
|
|
|
for (Account account : entry.getValue()) {
|
|
|
|
|
if (account.getUsername().equals(username) && account.getPassword().equals(password)) {
|
|
|
|
|
return new LoginResult(true, entry.getKey());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return new LoginResult(false, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 账户信息封装类
|
|
|
|
|
*/
|
|
|
|
|
private static class Account {
|
|
|
|
|
private String username;
|
|
|
|
|
private String password;
|
|
|
|
|
|
|
|
|
|
public Account(String username, String password) {
|
|
|
|
|
this.username = username;
|
|
|
|
|
this.password = password;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getUsername() {
|
|
|
|
|
return username;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getPassword() {
|
|
|
|
|
return password;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 题目生成器接口
|
|
|
|
|
*/
|
|
|
|
|
interface QuestionGenerator {
|
|
|
|
|
String generateQuestion();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 小学题目生成器
|
|
|
|
|
*/
|
|
|
|
|
class PrimarySchoolGenerator implements QuestionGenerator {
|
|
|
|
|
private Random random = new Random();
|
|
|
|
|
private List<String> operators = Arrays.asList("+", "-", "*", "/");
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String generateQuestion() {
|
|
|
|
|
try {
|
|
|
|
|
// 确保每道题目最少有两个操作数(2-5个)
|
|
|
|
|
int numOperands = random.nextInt(4) + 2; // 2-5个操作数
|
|
|
|
|
|
|
|
|
|
// 生成操作数
|
|
|
|
|
int[] operands = new int[numOperands];
|
|
|
|
|
for (int i = 0; i < numOperands; i++) {
|
|
|
|
|
operands[i] = random.nextInt(100) + 1; // 1-100
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成运算符
|
|
|
|
|
String[] operatorArray = new String[numOperands - 1];
|
|
|
|
|
for (int i = 0; i < numOperands - 1; i++) {
|
|
|
|
|
operatorArray[i] = operators.get(random.nextInt(operators.size()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 构建表达式并确保结果非负
|
|
|
|
|
String expression;
|
|
|
|
|
do {
|
|
|
|
|
// 重新生成操作数和运算符(如果之前的结果为负)
|
|
|
|
|
for (int i = 0; i < numOperands; i++) {
|
|
|
|
|
operands[i] = random.nextInt(100) + 1;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < numOperands - 1; i++) {
|
|
|
|
|
operatorArray[i] = operators.get(random.nextInt(operators.size()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 构建表达式
|
|
|
|
|
StringBuilder exprBuilder = new StringBuilder();
|
|
|
|
|
exprBuilder.append(operands[0]);
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i < numOperands; i++) {
|
|
|
|
|
// 如果是减法,确保不会产生负数
|
|
|
|
|
if ("-".equals(operatorArray[i-1])) {
|
|
|
|
|
// 计算当前部分表达式的值
|
|
|
|
|
int currentValue = calculatePartialExpression(exprBuilder.toString());
|
|
|
|
|
if (currentValue < operands[i]) {
|
|
|
|
|
// 如果减法会产生负数,改为加法
|
|
|
|
|
operatorArray[i-1] = "+";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exprBuilder.append(" ").append(operatorArray[i-1]).append(" ").append(operands[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expression = exprBuilder.toString();
|
|
|
|
|
|
|
|
|
|
// 计算整个表达式的结果
|
|
|
|
|
double result = evaluateExpression(expression);
|
|
|
|
|
|
|
|
|
|
// 如果结果为负,重新生成
|
|
|
|
|
if (result < 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 随机添加括号(只在有3个及以上操作数时)
|
|
|
|
|
if (numOperands >= 3 && random.nextDouble() < 0.3) {
|
|
|
|
|
// 只在表达式开头和结尾添加括号,避免复杂计算
|
|
|
|
|
expression = "(" + expression + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
|
|
// 在表达式末尾添加等号
|
|
|
|
|
return expression + " =";
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 如果生成题目出错,返回一个简单的默认题目
|
|
|
|
|
return "10 + 20 =";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 计算部分表达式的值(简化版,只处理简单的加减乘除)
|
|
|
|
|
*/
|
|
|
|
|
private int calculatePartialExpression(String expression) {
|
|
|
|
|
try {
|
|
|
|
|
// 简单的表达式计算,只处理没有括号的情况
|
|
|
|
|
String[] tokens = expression.split(" ");
|
|
|
|
|
int result = Integer.parseInt(tokens[0]);
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i < tokens.length; i += 2) {
|
|
|
|
|
String operator = tokens[i];
|
|
|
|
|
int operand = Integer.parseInt(tokens[i+1]);
|
|
|
|
|
|
|
|
|
|
switch (operator) {
|
|
|
|
|
case "+":
|
|
|
|
|
result += operand;
|
|
|
|
|
break;
|
|
|
|
|
case "-":
|
|
|
|
|
result -= operand;
|
|
|
|
|
break;
|
|
|
|
|
case "*":
|
|
|
|
|
result *= operand;
|
|
|
|
|
break;
|
|
|
|
|
case "/":
|
|
|
|
|
if (operand != 0) result /= operand;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
return 0; // 如果计算出错,返回0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 评估表达式的结果(简化版)
|
|
|
|
|
*/
|
|
|
|
|
private double evaluateExpression(String expression) {
|
|
|
|
|
try {
|
|
|
|
|
// 移除括号(简化处理)
|
|
|
|
|
String cleanExpression = expression.replace("(", "").replace(")", "");
|
|
|
|
|
|
|
|
|
|
// 简单的表达式计算
|
|
|
|
|
String[] tokens = cleanExpression.split(" ");
|
|
|
|
|
double result = Double.parseDouble(tokens[0]);
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i < tokens.length; i += 2) {
|
|
|
|
|
String operator = tokens[i];
|
|
|
|
|
double operand = Double.parseDouble(tokens[i+1]);
|
|
|
|
|
|
|
|
|
|
switch (operator) {
|
|
|
|
|
case "+":
|
|
|
|
|
result += operand;
|
|
|
|
|
break;
|
|
|
|
|
case "-":
|
|
|
|
|
result -= operand;
|
|
|
|
|
break;
|
|
|
|
|
case "*":
|
|
|
|
|
result *= operand;
|
|
|
|
|
break;
|
|
|
|
|
case "/":
|
|
|
|
|
if (operand != 0) result /= operand;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
return 0; // 如果计算出错,返回0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 初中题目生成器
|
|
|
|
|
*/
|
|
|
|
|
class JuniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
private Random random = new Random();
|
|
|
|
|
private List<String> baseOperators = Arrays.asList("+", "-", "*", "/");
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String generateQuestion() {
|
|
|
|
|
try {
|
|
|
|
|
// 确保每道题目最少有两个操作数(2-5个)
|
|
|
|
|
int numOperands = random.nextInt(4) + 2; // 2-5个操作数
|
|
|
|
|
StringBuilder expression = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
boolean hasSpecialOperator = false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numOperands; i++) {
|
|
|
|
|
// 确保至少有一个特殊运算符
|
|
|
|
|
if (!hasSpecialOperator && (i == numOperands - 1 || random.nextDouble() < 0.3)) {
|
|
|
|
|
if (random.nextBoolean()) {
|
|
|
|
|
// 平方
|
|
|
|
|
int num = random.nextInt(10) + 1; // 平方的数不宜太大
|
|
|
|
|
expression.append(num).append("²");
|
|
|
|
|
} else {
|
|
|
|
|
// 开根号
|
|
|
|
|
int num = random.nextInt(100) + 1;
|
|
|
|
|
expression.append("√").append(num);
|
|
|
|
|
}
|
|
|
|
|
hasSpecialOperator = true;
|
|
|
|
|
} else {
|
|
|
|
|
expression.append(random.nextInt(100) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i < numOperands - 1) {
|
|
|
|
|
String operator = baseOperators.get(random.nextInt(baseOperators.size()));
|
|
|
|
|
expression.append(" ").append(operator).append(" ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果还没有特殊运算符,强制添加一个
|
|
|
|
|
if (!hasSpecialOperator) {
|
|
|
|
|
if (random.nextBoolean()) {
|
|
|
|
|
expression.insert(0, random.nextInt(10) + 1 + "² + ");
|
|
|
|
|
} else {
|
|
|
|
|
expression.insert(0, "√" + (random.nextInt(100) + 1) + " + ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在表达式末尾添加等号
|
|
|
|
|
return expression.toString() + " =";
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 如果生成题目出错,返回一个简单的默认题目
|
|
|
|
|
return "√25 + 10 =";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 高中题目生成器
|
|
|
|
|
*/
|
|
|
|
|
class SeniorHighGenerator implements QuestionGenerator {
|
|
|
|
|
private Random random = new Random();
|
|
|
|
|
private List<String> baseOperators = Arrays.asList("+", "-", "*", "/");
|
|
|
|
|
private List<String> trigFunctions = Arrays.asList("sin", "cos", "tan");
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String generateQuestion() {
|
|
|
|
|
try {
|
|
|
|
|
// 确保每道题目最少有两个操作数(2-5个)
|
|
|
|
|
int numOperands = random.nextInt(4) + 2; // 2-5个操作数
|
|
|
|
|
StringBuilder expression = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
boolean hasTrigFunction = false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numOperands; i++) {
|
|
|
|
|
// 确保至少有一个三角函数
|
|
|
|
|
if (!hasTrigFunction && (i == numOperands - 1 || random.nextDouble() < 0.3)) {
|
|
|
|
|
String trigFunc = trigFunctions.get(random.nextInt(trigFunctions.size()));
|
|
|
|
|
int angle = random.nextInt(360); // 角度0-359
|
|
|
|
|
expression.append(trigFunc).append("(").append(angle).append("°)");
|
|
|
|
|
hasTrigFunction = true;
|
|
|
|
|
} else {
|
|
|
|
|
expression.append(random.nextInt(100) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i < numOperands - 1) {
|
|
|
|
|
String operator = baseOperators.get(random.nextInt(baseOperators.size()));
|
|
|
|
|
expression.append(" ").append(operator).append(" ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果还没有三角函数,强制添加一个
|
|
|
|
|
if (!hasTrigFunction) {
|
|
|
|
|
String trigFunc = trigFunctions.get(random.nextInt(trigFunctions.size()));
|
|
|
|
|
int angle = random.nextInt(360);
|
|
|
|
|
expression.insert(0, trigFunc + "(" + angle + "°) + ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在表达式末尾添加等号
|
|
|
|
|
return expression.toString() + " =";
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 如果生成题目出错,返回一个简单的默认题目
|
|
|
|
|
return "sin(30°) + 10 =";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 查重管理器
|
|
|
|
|
*/
|
|
|
|
|
class DuplicateChecker {
|
|
|
|
|
private String username;
|
|
|
|
|
private Set<String> historyQuestions;
|
|
|
|
|
|
|
|
|
|
public DuplicateChecker(String username) {
|
|
|
|
|
this.username = username;
|
|
|
|
|
this.historyQuestions = new HashSet<>();
|
|
|
|
|
loadHistoryQuestions();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void loadHistoryQuestions() {
|
|
|
|
|
File userFolder = new File("exams/" + username);
|
|
|
|
|
if (!userFolder.exists() || !userFolder.isDirectory()) {
|
|
|
|
|
userFolder.mkdirs();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
File[] files = userFolder.listFiles((dir, name) -> name.endsWith(".txt"));
|
|
|
|
|
if (files == null) return;
|
|
|
|
|
|
|
|
|
|
Pattern questionPattern = Pattern.compile("\\d+\\.\\s*(.+)");
|
|
|
|
|
|
|
|
|
|
for (File file : files) {
|
|
|
|
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
|
|
|
|
String line;
|
|
|
|
|
while ((line = reader.readLine()) != null) {
|
|
|
|
|
Matcher matcher = questionPattern.matcher(line);
|
|
|
|
|
if (matcher.find()) {
|
|
|
|
|
String question = matcher.group(1).trim();
|
|
|
|
|
historyQuestions.add(normalizeQuestion(question));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
System.out.println("读取历史文件出错: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String normalizeQuestion(String question) {
|
|
|
|
|
// 移除多余空格和等号
|
|
|
|
|
return question.replaceAll("\\s+", " ").replace(" =", "").trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isDuplicate(String question) {
|
|
|
|
|
// 移除等号后再进行比较
|
|
|
|
|
String normalized = normalizeQuestion(question.replace(" =", ""));
|
|
|
|
|
return historyQuestions.contains(normalized);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void addQuestion(String question) {
|
|
|
|
|
// 移除等号后再保存
|
|
|
|
|
String normalized = normalizeQuestion(question.replace(" =", ""));
|
|
|
|
|
historyQuestions.add(normalized);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 文件保存器
|
|
|
|
|
*/
|
|
|
|
|
class FileSaver {
|
|
|
|
|
private String username;
|
|
|
|
|
private File userFolder;
|
|
|
|
|
|
|
|
|
|
public FileSaver(String username) {
|
|
|
|
|
this.username = username;
|
|
|
|
|
this.userFolder = new File("exams/" + username);
|
|
|
|
|
this.userFolder.mkdirs();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String saveExam(List<String> questions, String questionType) {
|
|
|
|
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
|
|
|
|
String timestamp = dateFormat.format(new Date());
|
|
|
|
|
String filename = timestamp + ".txt";
|
|
|
|
|
File file = new File(userFolder, filename);
|
|
|
|
|
|
|
|
|
|
try (PrintWriter writer = new PrintWriter(new FileWriter(file))) {
|
|
|
|
|
writer.println(questionType + "数学试卷");
|
|
|
|
|
writer.println("==============================");
|
|
|
|
|
writer.println();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < questions.size(); i++) {
|
|
|
|
|
writer.println((i + 1) + ". " + questions.get(i));
|
|
|
|
|
writer.println();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return file.getAbsolutePath();
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
System.out.println("保存文件出错: " + e.getMessage());
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|