|
|
|
@ -0,0 +1,398 @@
|
|
|
|
|
import java.io.*;
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 中小学数学卷子自动生成程序
|
|
|
|
|
* 作者:张三
|
|
|
|
|
* 班级:软1班
|
|
|
|
|
*/
|
|
|
|
|
public class MathTestGenerator {
|
|
|
|
|
|
|
|
|
|
private static final Map<String, User> USERS = new HashMap<>();
|
|
|
|
|
static {
|
|
|
|
|
// 小学账户
|
|
|
|
|
USERS.put("张三1", new User("张三1", "123", UserType.PRIMARY));
|
|
|
|
|
USERS.put("张三2", new User("张三2", "123", UserType.PRIMARY));
|
|
|
|
|
USERS.put("张三3", new User("张三3", "123", UserType.PRIMARY));
|
|
|
|
|
// 初中账户
|
|
|
|
|
USERS.put("李四1", new User("李四1", "123", UserType.JUNIOR));
|
|
|
|
|
USERS.put("李四2", new User("李四2", "123", UserType.JUNIOR));
|
|
|
|
|
USERS.put("李四3", new User("李四3", "123", UserType.JUNIOR));
|
|
|
|
|
// 高中账户
|
|
|
|
|
USERS.put("王五1", new User("王五1", "123", UserType.SENIOR));
|
|
|
|
|
USERS.put("王五2", new User("王五2", "123", UserType.SENIOR));
|
|
|
|
|
USERS.put("王五3", new User("王五3", "123", UserType.SENIOR));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 用户类型枚举
|
|
|
|
|
private enum UserType {
|
|
|
|
|
PRIMARY("小学"), JUNIOR("初中"), SENIOR("高中");
|
|
|
|
|
|
|
|
|
|
private final String name;
|
|
|
|
|
UserType(String name) { this.name = name; }
|
|
|
|
|
public String getName() { return name; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 用户类
|
|
|
|
|
private static class User {
|
|
|
|
|
String username;
|
|
|
|
|
String password;
|
|
|
|
|
UserType type;
|
|
|
|
|
|
|
|
|
|
User(String username, String password, UserType type) {
|
|
|
|
|
this.username = username;
|
|
|
|
|
this.password = password;
|
|
|
|
|
this.type = type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 运算符枚举
|
|
|
|
|
private enum Operator {
|
|
|
|
|
ADD("+", 1), SUBTRACT("-", 1), MULTIPLY("*", 2), DIVIDE("/", 2),
|
|
|
|
|
POWER("^", 3), SQRT("√", 3), SIN("sin", 4), COS("cos", 4), TAN("tan", 4);
|
|
|
|
|
|
|
|
|
|
private final String symbol;
|
|
|
|
|
private final int priority;
|
|
|
|
|
Operator(String symbol, int priority) {
|
|
|
|
|
this.symbol = symbol;
|
|
|
|
|
this.priority = priority;
|
|
|
|
|
}
|
|
|
|
|
public String getSymbol() { return symbol; }
|
|
|
|
|
public int getPriority() { return priority; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private User currentUser;
|
|
|
|
|
private UserType currentType;
|
|
|
|
|
private Set<String> generatedQuestions;
|
|
|
|
|
private Scanner scanner;
|
|
|
|
|
private String baseDir;
|
|
|
|
|
|
|
|
|
|
public MathTestGenerator() {
|
|
|
|
|
this.scanner = new Scanner(System.in);
|
|
|
|
|
this.generatedQuestions = new HashSet<>();
|
|
|
|
|
this.baseDir = System.getProperty("user.dir") + File.separator + "papers";
|
|
|
|
|
initializeStorage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 初始化存储目录
|
|
|
|
|
*/
|
|
|
|
|
private void initializeStorage() {
|
|
|
|
|
File dir = new File(baseDir);
|
|
|
|
|
if (!dir.exists()) {
|
|
|
|
|
dir.mkdirs();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 主程序入口
|
|
|
|
|
*/
|
|
|
|
|
public void start() {
|
|
|
|
|
System.out.println("=== 中小学数学卷子自动生成程序 ===");
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
if (login()) {
|
|
|
|
|
generatePapers();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 用户登录
|
|
|
|
|
*/
|
|
|
|
|
private boolean login() {
|
|
|
|
|
while (true) {
|
|
|
|
|
System.out.print("请输入用户名和密码(用空格隔开,输入exit退出程序):");
|
|
|
|
|
String input = scanner.nextLine().trim();
|
|
|
|
|
|
|
|
|
|
if (input.equalsIgnoreCase("exit")) {
|
|
|
|
|
System.exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String[] credentials = input.split("\\s+");
|
|
|
|
|
if (credentials.length != 2) {
|
|
|
|
|
System.out.println("请输入正确的用户名、密码");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String username = credentials[0];
|
|
|
|
|
String password = credentials[1];
|
|
|
|
|
|
|
|
|
|
User user = USERS.get(username);
|
|
|
|
|
if (user != null && user.password.equals(password)) {
|
|
|
|
|
currentUser = user;
|
|
|
|
|
currentType = user.type;
|
|
|
|
|
System.out.println("当前选择为" + currentType.getName() + "出题");
|
|
|
|
|
loadGeneratedQuestions();
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
System.out.println("请输入正确的用户名、密码");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 加载已生成的题目用于查重
|
|
|
|
|
*/
|
|
|
|
|
private void loadGeneratedQuestions() {
|
|
|
|
|
generatedQuestions.clear();
|
|
|
|
|
File userDir = new File(baseDir + File.separator + currentUser.username);
|
|
|
|
|
if (userDir.exists() && userDir.isDirectory()) {
|
|
|
|
|
File[] files = userDir.listFiles((dir, name) -> name.endsWith(".txt"));
|
|
|
|
|
if (files != null) {
|
|
|
|
|
for (File file : files) {
|
|
|
|
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
|
|
|
|
String line;
|
|
|
|
|
while ((line = reader.readLine()) != null) {
|
|
|
|
|
if (line.matches("^\\d+\\.\\s+.+")) {
|
|
|
|
|
String question = line.substring(line.indexOf(".") + 1).trim();
|
|
|
|
|
generatedQuestions.add(normalizeQuestion(question));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
System.out.println("读取历史题目失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成试卷
|
|
|
|
|
*/
|
|
|
|
|
private void generatePapers() {
|
|
|
|
|
while (true) {
|
|
|
|
|
System.out.print("准备生成" + currentType.getName() +
|
|
|
|
|
"数学题目,请输入生成题目数量(10-30,输入-1退出当前用户):");
|
|
|
|
|
|
|
|
|
|
String input = scanner.nextLine().trim();
|
|
|
|
|
|
|
|
|
|
if (input.equals("-1")) {
|
|
|
|
|
currentUser = null;
|
|
|
|
|
currentType = null;
|
|
|
|
|
System.out.println("已退出当前用户,请重新登录");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isSwitchCommand(input)) {
|
|
|
|
|
handleSwitchCommand(input);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
int count = Integer.parseInt(input);
|
|
|
|
|
if (count >= 10 && count <= 30) {
|
|
|
|
|
generateTestPaper(count);
|
|
|
|
|
} else {
|
|
|
|
|
System.out.println("题目数量应在10-30之间");
|
|
|
|
|
}
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
System.out.println("请输入有效的数字");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 检查是否为切换命令
|
|
|
|
|
*/
|
|
|
|
|
private boolean isSwitchCommand(String input) {
|
|
|
|
|
return input.startsWith("切换为");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理切换命令
|
|
|
|
|
*/
|
|
|
|
|
private void handleSwitchCommand(String input) {
|
|
|
|
|
String typeStr = input.substring(3).trim();
|
|
|
|
|
try {
|
|
|
|
|
UserType newType = UserType.valueOf(typeStr.toUpperCase());
|
|
|
|
|
currentType = newType;
|
|
|
|
|
System.out.println("准备生成" + currentType.getName() + "数学题目,请输入生成题目数量");
|
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
|
System.out.println("请输入小学、初中和高中三个选项中的一个");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成试卷文件
|
|
|
|
|
*/
|
|
|
|
|
private void generateTestPaper(int questionCount) {
|
|
|
|
|
List<String> questions = new ArrayList<>();
|
|
|
|
|
int generated = 0;
|
|
|
|
|
int attempts = 0;
|
|
|
|
|
final int MAX_ATTEMPTS = 1000;
|
|
|
|
|
|
|
|
|
|
while (generated < questionCount && attempts < MAX_ATTEMPTS) {
|
|
|
|
|
String question = generateQuestion();
|
|
|
|
|
String normalized = normalizeQuestion(question);
|
|
|
|
|
|
|
|
|
|
if (!generatedQuestions.contains(normalized)) {
|
|
|
|
|
questions.add(question);
|
|
|
|
|
generatedQuestions.add(normalized);
|
|
|
|
|
generated++;
|
|
|
|
|
}
|
|
|
|
|
attempts++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (generated < questionCount) {
|
|
|
|
|
System.out.println("警告:无法生成足够的不重复题目,已生成 " + generated + " 道题");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saveToFile(questions);
|
|
|
|
|
System.out.println("试卷生成成功!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成单个题目
|
|
|
|
|
*/
|
|
|
|
|
private String generateQuestion() {
|
|
|
|
|
Random random = new Random();
|
|
|
|
|
int operandCount = random.nextInt(5) + 1; // 1-5个操作数
|
|
|
|
|
StringBuilder question = new StringBuilder();
|
|
|
|
|
List<Integer> operands = new ArrayList<>();
|
|
|
|
|
List<Operator> operators = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
// 生成操作数
|
|
|
|
|
for (int i = 0; i < operandCount; i++) {
|
|
|
|
|
operands.add(random.nextInt(100) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据难度生成运算符
|
|
|
|
|
switch (currentType) {
|
|
|
|
|
case PRIMARY:
|
|
|
|
|
generatePrimaryOperators(operators, operandCount - 1, random);
|
|
|
|
|
break;
|
|
|
|
|
case JUNIOR:
|
|
|
|
|
generateJuniorOperators(operators, operandCount - 1, random);
|
|
|
|
|
break;
|
|
|
|
|
case SENIOR:
|
|
|
|
|
generateSeniorOperators(operators, operandCount - 1, random);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 构建题目表达式
|
|
|
|
|
question.append(operands.get(0));
|
|
|
|
|
for (int i = 0; i < operators.size(); i++) {
|
|
|
|
|
Operator op = operators.get(i);
|
|
|
|
|
if (op == Operator.SQRT) {
|
|
|
|
|
question.insert(0, "√(").append(")");
|
|
|
|
|
question.append(op.getSymbol()).append(operands.get(i + 1));
|
|
|
|
|
} else if (op == Operator.SIN || op == Operator.COS || op == Operator.TAN) {
|
|
|
|
|
question.append(op.getSymbol()).append("(").append(operands.get(i + 1)).append(")");
|
|
|
|
|
} else {
|
|
|
|
|
question.append(" ").append(op.getSymbol()).append(" ").append(operands.get(i + 1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 随机添加括号
|
|
|
|
|
if (operandCount > 2 && random.nextBoolean()) {
|
|
|
|
|
question.insert(0, "(");
|
|
|
|
|
int insertPos = question.indexOf(" ", question.indexOf(" ") + 1);
|
|
|
|
|
if (insertPos != -1) {
|
|
|
|
|
question.insert(insertPos + 1, ")");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return question.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成小学运算符
|
|
|
|
|
*/
|
|
|
|
|
private void generatePrimaryOperators(List<Operator> operators, int count, Random random) {
|
|
|
|
|
Operator[] primaryOps = {Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE};
|
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
|
operators.add(primaryOps[random.nextInt(primaryOps.length)]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成初中运算符(必须包含平方或开根号)
|
|
|
|
|
*/
|
|
|
|
|
private void generateJuniorOperators(List<Operator> operators, int count, Random random) {
|
|
|
|
|
Operator[] juniorOps = {Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE,
|
|
|
|
|
Operator.POWER, Operator.SQRT};
|
|
|
|
|
|
|
|
|
|
// 确保至少有一个平方或开根号
|
|
|
|
|
boolean hasSpecialOp = false;
|
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
|
Operator op = juniorOps[random.nextInt(juniorOps.length)];
|
|
|
|
|
if (op == Operator.POWER || op == Operator.SQRT) {
|
|
|
|
|
hasSpecialOp = true;
|
|
|
|
|
}
|
|
|
|
|
operators.add(op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!hasSpecialOp && count > 0) {
|
|
|
|
|
operators.set(random.nextInt(count),
|
|
|
|
|
random.nextBoolean() ? Operator.POWER : Operator.SQRT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成高中运算符(必须包含三角函数)
|
|
|
|
|
*/
|
|
|
|
|
private void generateSeniorOperators(List<Operator> operators, int count, Random random) {
|
|
|
|
|
Operator[] seniorOps = {Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE,
|
|
|
|
|
Operator.POWER, Operator.SQRT, Operator.SIN, Operator.COS, Operator.TAN};
|
|
|
|
|
|
|
|
|
|
// 确保至少有一个三角函数
|
|
|
|
|
boolean hasTrigOp = false;
|
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
|
Operator op = seniorOps[random.nextInt(seniorOps.length)];
|
|
|
|
|
if (op == Operator.SIN || op == Operator.COS || op == Operator.TAN) {
|
|
|
|
|
hasTrigOp = true;
|
|
|
|
|
}
|
|
|
|
|
operators.add(op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!hasTrigOp && count > 0) {
|
|
|
|
|
Operator[] trigOps = {Operator.SIN, Operator.COS, Operator.TAN};
|
|
|
|
|
operators.set(random.nextInt(count), trigOps[random.nextInt(trigOps.length)]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 规范化题目用于查重
|
|
|
|
|
*/
|
|
|
|
|
private String normalizeQuestion(String question) {
|
|
|
|
|
return question.replaceAll("\\s+", "").toLowerCase();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 保存题目到文件
|
|
|
|
|
*/
|
|
|
|
|
private void saveToFile(List<String> questions) {
|
|
|
|
|
String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
|
|
|
|
|
String filename = timestamp + ".txt";
|
|
|
|
|
String userDirPath = baseDir + File.separator + currentUser.username;
|
|
|
|
|
|
|
|
|
|
File userDir = new File(userDirPath);
|
|
|
|
|
if (!userDir.exists()) {
|
|
|
|
|
userDir.mkdirs();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
File file = new File(userDir, filename);
|
|
|
|
|
try (PrintWriter writer = new PrintWriter(new FileWriter(file))) {
|
|
|
|
|
for (int i = 0; i < questions.size(); i++) {
|
|
|
|
|
writer.println((i + 1) + ". " + questions.get(i));
|
|
|
|
|
if (i < questions.size() - 1) {
|
|
|
|
|
writer.println();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
System.out.println("保存文件失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 主方法
|
|
|
|
|
*/
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
MathTestGenerator generator = new MathTestGenerator();
|
|
|
|
|
generator.start();
|
|
|
|
|
}
|
|
|
|
|
}
|