初始提交: 添加项目源代码

develop
杨捷 6 days ago
commit d36668c75d

@ -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;
}
}
}
Loading…
Cancel
Save