diff --git a/MANIFEST.MF b/MANIFEST.MF new file mode 100644 index 0000000..1f6430b --- /dev/null +++ b/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: src.Main +Class-Path: . diff --git a/Math.bat b/Math.bat new file mode 100644 index 0000000..6160956 --- /dev/null +++ b/Math.bat @@ -0,0 +1,19 @@ +@echo off +REM Math Question Generator System - Windows Batch File +REM Author: 赵俊杰 +REM Created: 2025 + +@echo off + +REM Set console encoding to GBK to match scanner input +REM GBK code page is 936, which supports Chinese characters +chcp 936 >nul + +echo Starting Math Question Generator System... +echo. + +REM Execute Java program +java -jar MathQuestionGenerator.jar + +REM Pause after program execution to prevent window from closing immediately +pause diff --git a/MathQuestionGenerator.jar b/MathQuestionGenerator.jar new file mode 100644 index 0000000..caa7c2e Binary files /dev/null and b/MathQuestionGenerator.jar differ diff --git a/README.md b/README.md index a373a1b..cf2db69 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ # Personal_Project - diff --git a/doc/项目说明.md b/doc/项目说明.md new file mode 100644 index 0000000..f746afa --- /dev/null +++ b/doc/项目说明.md @@ -0,0 +1,304 @@ +# 数学题目生成系统 - 项目说明 + +## 项目概述 + +本项目是一个基于Java的数学题目生成系统,专门为不同学段(小学、初中、高中)的教师设计。系统能够根据教师类型自动生成相应难度的数学题目,并支持题目查重、文件存储等功能。 + +## 项目结构 + +``` +Personal_Project/ +├── src/ # 源代码目录 +│ ├── Main.java # 程序入口类 +│ ├── SysFunc.java # 系统功能类(登录、操作界面) +│ ├── Teacher.java # 教师抽象基类 +│ ├── PrimaryTea.java # 小学教师类 +│ ├── JuniorTea.java # 初中教师类 +│ └── SeniorTea.java # 高中教师类 +├── doc/ # 文档目录 +│ └── 项目说明.md # 项目说明文档 +├── MANIFEST.MF # JAVA JAR清单文件 +├── 运行程序.bat # Windows批处理文件 +├── 张三1/ # 教师个人文件夹(自动生成) +├── 张三2/ +├── 张三3/ +├── 李四1/ +├── 李四2/ +├── 李四3/ +├── 王五1/ +├── 王五2/ +└── 王五3/ +``` + +## 核心功能 + +### 1. 用户管理 +- **预置用户**:系统预置了9名教师用户(3名小学、3名初中、3名高中) +- **登录验证**:支持用户名和密码验证登录 +- **个人文件夹**:每个教师登录后自动创建个人文件夹用于存储生成的题目 + +### 2. 题目生成 +- **学段适配**:根据教师类型生成相应难度的数学题目 +- **类型切换**:可以切换指定类型出题 +- **题目数量**:支持一次性生成10-30道题目 +- **随机生成**:题目内容和结构随机生成,确保多样性 + +### 3. 题目类型 +- **小学题目**:包含加减乘除四则运算,支持括号 +- **初中题目**:在小学基础上增加平方(^2)和开方(√)运算 +- **高中题目**:在初中基础上增加三角函数(sin, cos, tan)运算 + +### 4. 查重机制 +- **自动查重**:生成题目时会检查是否与个人历史题目重复 +- **文件扫描**:扫描教师个人文件夹中的所有历史题目文件 +- **重复处理**:发现重复题目会自动重新生成 + +### 5. 文件管理 +- **自动存储**:生成的题目自动保存到教师个人文件夹 +- **时间戳命名**:文件名包含生成时间,便于管理 +- **格式规范**:题目按序号排列,格式统一 + +## 技术特点 + +### 面向对象设计 +- **继承体系**:使用抽象类`Teacher`作为基类,三个具体子类实现不同学段的题目生成 +- **统一方法**:由'Teacher'实现子类都具有的类似结构 +- **多态应用**:通过抽象方法实现不同学段题目的差异化生成 +- **封装性**:将用户信息、文件操作等功能封装在相应的类中 + +### 算法设计 +- **随机算法**:使用Java Random类确保题目的随机性 +- **括号处理**:智能添加括号,保证表达式合理性 +- **操作符分布**:合理分布不同难度的操作符 + +### 文件操作 +- **NIO API**:使用Java NIO进行高效的文件读写操作 +- **异常处理**:完善的异常处理机制确保程序稳定性 +- **路径管理**:自动创建和管理教师个人文件夹以及题目文档 + +## 使用流程 + +1. **保存文件**:将项目保存至同一目录 +2. **启动程序**:在当前目录下双击运行 “运行程序.bat” +3. **用户登录**:根据提示输入预置的用户名和密码(格式:用户名 密码) +4. **选择模式**:系统显示当前出题类型,可选择切换 +5. **切换类型**:输入" 切换** "切换至对应出题类型 +6. **生成题目**:输入题目数量(10-30) +7. **查看结果**:题目生成后显示保存路径 +8. **重复使用**:题目生成后可选择继续生成或切换难度 +9. **退出登录**:输入题目数量为-1则退出当前用户,可重新登录 +10. **退出系统**:可选返回登陆或者退出系统 + +## 预置用户信息 + +| 用户名 | 密码 | 类型 | 初始类型 | +|--------|------|------|----------| +| 张三1 | 123 | 小学教师 | 小学 | +| 张三2 | 123 | 小学教师 | 小学 | +| 张三3 | 123 | 小学教师 | 小学 | +| 李四1 | 123 | 初中教师 | 初中 | +| 李四2 | 123 | 初中教师 | 初中 | +| 李四3 | 123 | 初中教师 | 初中 | +| 王五1 | 123 | 高中教师 | 高中 | +| 王五2 | 123 | 高中教师 | 高中 | +| 王五3 | 123 | 高中教师 | 高中 | + +## API文档 + +### Teacher 抽象基类 + +#### 构造函数 +```java +public Teacher(String name, String password, String path) +``` +- **参数**: + - `name`: 教师用户名 + - `password`: 教师密码 + - `path`: 教师文件夹路径(可为null,自动创建) + +#### 公共方法 +```java +public boolean checkDuplicate(String question) +``` +- **功能**: 检查题目是否与历史题目重复 +- **参数**: `question` - 待检查的题目字符串 +- **返回**: `true` - 存在重复,`false` - 无重复 + +```java +public String generatePath() +``` +- **功能**: 生成题目文件的相对存储路径 +- **返回**: 包含时间戳的文件路径 + +```java +public String generateEX(int num) +``` +- **功能**: 生成指定数量的题目并保存到文件 +- **参数**: `num` - 题目数量(10-30) +- **返回**: 保存题目的文件路径 + +#### 抽象方法 +```java +protected abstract String generateSingleQuestion() +``` +- **功能**: 生成单个题目(由子类实现) +- **返回**: 题目字符串 + +```java +public abstract String getType() +``` +- **功能**: 返回教师类型 +- **返回**: "小学"、"初中"或"高中" + +### SysFunc 系统功能类 + +#### 静态字段 +```java +static final int LEAST_NUM = 10 // 最小题目数量 +static final int MAX_NUM = 30 // 最大题目数量 +static ArrayList teachers // 用户列表 +static Teacher teacher // 当前用户 +static HashMap typeMap // 类型映射 +``` + +#### 静态方法 +```java +public static void init() +``` +- **功能**: 初始化系统,预加载用户数据 + +```java +public static Teacher login(Scanner scanner) +``` +- **功能**: 用户登录界面 +- **参数**: `scanner` - 输入扫描器 +- **返回**: 登录成功的教师对象 + +```java +public static void ShiftType(Scanner scanner) +``` +- **功能**: 切换出题类型界面 +- **参数**: `scanner` - 输入扫描器 + +```java +public static void Operate(Scanner scanner) +``` +- **功能**: 主操作界面,处理题目生成流程 +- **参数**: `scanner` - 输入扫描器 + +### PrimaryTea 小学教师类 + +#### 构造函数 +```java +public PrimaryTea(String name, String password, String path) +``` + +#### 特有方法 +```java +public void getRandom() +``` +- **功能**: 生成随机操作数和括号位置 + +#### 重写方法 +```java +@Override +protected String generateSingleQuestion() +``` +- **功能**: 生成小学难度数学题目(四则运算) + +```java +@Override +public String getType() +``` +- **返回**: "小学" + +### JuniorTea 初中教师类 + +#### 构造函数 +```java +public JuniorTea(String name, String password, String path) +``` + +#### 特有方法 +```java +public void getRandom() +``` +- **功能**: 生成随机操作数、特殊运算符和括号位置 + +#### 重写方法 +```java +@Override +protected String generateSingleQuestion() +``` +- **功能**: 生成初中难度数学题目(四则运算 + 平方/开方) + +```java +@Override +public String getType() +``` +- **返回**: "初中" + +### SeniorTea 高中教师类 + +#### 构造函数 +```java +public SeniorTea(String name, String password, String path) +``` + +#### 特有方法 +```java +public void getRandom() +``` +- **功能**: 生成随机操作数、三角函数和括号位置 + +#### 重写方法 +```java +@Override +protected String generateSingleQuestion() +``` +- **功能**: 生成高中难度数学题目(四则运算 + 三角函数) + +```java +@Override +public String getType() +``` +- **返回**: "高中" + +### Main 程序入口类 + +#### 主方法 +```java +public static void main(String[] args) +``` +- **功能**: 程序入口点,启动数学题目生成系统 +- **流程**: + 1. 初始化系统 + 2. 创建GBK编码的Scanner + 3. 进入主循环(登录 → 操作 → 退出选择) + +## 扩展性 + +系统具有良好的扩展性,可以通过以下方式增强功能: +- 添加用户注册功能 +- 添加新的学段类型 +- 增加新的数学运算类型 +- 支持自定义题目难度 +- 添加题目答案计算功能 +- 支持批量导入导出 + +## 开发环境 +- **语言**:Java21.0.4 +- **编码**:标准输入(scanner)为GBK(支持中文输入),文件保存为UTF-8 +- **依赖**:纯Java标准库,无需额外依赖 + +## 项目价值 + +本项目展示了面向对象编程的实际应用,体现了良好的软件工程实践,包括: +- 清晰的代码结构 +- 符合Google编码规范的设计编写 +- 合理,扩展性良好的类设计 +- 完善的异常处理 +- 用户友好的交互界面 +- 实用的业务功能 + +该系统可以实际应用于教育场景,帮助教师快速生成练习题,提高教学效率。 diff --git a/src/JuniorTea.class b/src/JuniorTea.class new file mode 100644 index 0000000..33cc084 Binary files /dev/null and b/src/JuniorTea.class differ diff --git a/src/JuniorTea.java b/src/JuniorTea.java new file mode 100644 index 0000000..c5b30a8 --- /dev/null +++ b/src/JuniorTea.java @@ -0,0 +1,77 @@ +package src; + +public class JuniorTea extends Teacher{ + final static String[] binaryOps = {"+", "-", "*", "/"}; // 操作符 + final static String[] unaryOps = {"^2", "√"}; + int operandCount; + String[] questionParts; // 操作数 + boolean[] specialOpFlags; // 特殊操作符索引序列 + int parenStart; + int parenEnd; + + public JuniorTea(String name, String password, String path) { + super(name, password, path); + } + + // 数据预处理 + public void getRandom(){ + this.operandCount = random.nextInt(4) + 2; + this.questionParts = new String[this.operandCount]; + // 随机决定特殊操作符的数量和位置 + int specialNum = Math.min(this.operandCount, random.nextInt(this.operandCount) + 1); + this.specialOpFlags = new boolean[this.operandCount]; + for (int i = 0; i < specialNum; i++) { + int pos; + do { + pos = random.nextInt(this.operandCount); + } while (this.specialOpFlags[pos]); + this.specialOpFlags[pos] = true; + } + for (int i = 0; i < this.operandCount; i++) { + int operand = random.nextInt(100) + 1; + if (this.specialOpFlags[i]) { + String op = unaryOps[random.nextInt(unaryOps.length)]; + if (op.equals("√")) { + this.questionParts[i] = op + operand; + } else { + this.questionParts[i] = operand + op; + } + } else { + this.questionParts[i] = String.valueOf(operand); + } + } + // 生成有效括号 + boolean useParen = this.operandCount > 2 && random.nextBoolean(); + this.parenStart = 0; + this.parenEnd = this.operandCount - 1; + while (this.parenStart == 0 && this.parenEnd == this.operandCount - 1) { + this.parenStart = useParen ? random.nextInt(this.operandCount - 1) : -2; + this.parenEnd = useParen ? random.nextInt(this.operandCount - 1 - this.parenStart) + this.parenStart + 1 : -2; + } + } + + @Override + protected String generateSingleQuestion(){ + getRandom(); + StringBuilder question = new StringBuilder(); + + for (int i = 0; i < operandCount; i++) { + if (i == parenStart) { + question.append("("); + } + question.append(questionParts[i]); + if (i == parenEnd) { + question.append(")"); + } + if (i < operandCount - 1) { + question.append(" ").append(binaryOps[random.nextInt(binaryOps.length)]).append(" "); + } + } + return question.toString(); + } + + @Override + public String getType(){ + return "初中"; + } +} \ No newline at end of file diff --git a/src/Main.class b/src/Main.class new file mode 100644 index 0000000..d2953ec Binary files /dev/null and b/src/Main.class differ diff --git a/src/Main.java b/src/Main.java new file mode 100644 index 0000000..c2879af --- /dev/null +++ b/src/Main.java @@ -0,0 +1,34 @@ +package src; + +import java.util.Scanner; +import java.util.concurrent.TimeUnit; + +public class Main { + public static void main(String[] args) { + // 用户预加载 + SysFunc.init(); + Scanner scanner = new Scanner(System.in, "GBK"); + while(true){ + // 登录界面 + SysFunc.login(scanner); + // 出题界面 + SysFunc.Operate(scanner); + // 退出选项 + System.out.println("是否返回登陆(y/n)?"); + String choice = scanner.nextLine(); + if (choice.charAt(0) == 'y') { + continue; + } else if (choice.charAt(0) == 'n') { + System.out.println("感谢您的使用"); + break; + } else { + System.out.println("无效输入, 正在返回登陆界面"); + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + } +} diff --git a/src/PrimaryTea.class b/src/PrimaryTea.class new file mode 100644 index 0000000..5d29839 Binary files /dev/null and b/src/PrimaryTea.class differ diff --git a/src/PrimaryTea.java b/src/PrimaryTea.java new file mode 100644 index 0000000..5b0f2d8 --- /dev/null +++ b/src/PrimaryTea.java @@ -0,0 +1,61 @@ +package src; + +public class PrimaryTea extends Teacher{ + final static char[] operators = {'+', '-', '*', '/'}; // 操作符 + int operandCount; // 操作数个数 + int[] operands; // 操作数列表 + int parenStart; // 左括号索引 + int parenEnd; // 右括号 + + public PrimaryTea(String name, String password, String path) { + super(name, password, path); + } + + // 数据预处理 + public void getRandom(){ + // 随机决定操作数个数 + this.operandCount = random.nextInt(4) + 2; + this.operands = new int[operandCount]; + for (int j = 0; j < operandCount; j++) { + operands[j] = random.nextInt(100) + 1; + } + // 产生有效括号 + boolean useParen = this.operandCount > 2 && random.nextBoolean(); + this.parenStart = 0; + this.parenEnd = this.operandCount - 1; + while (this.parenStart == 0 && this.parenEnd == this.operandCount - 1) { + this.parenStart = useParen ? random.nextInt(this.operandCount - 1) : -2; + this.parenEnd = useParen ? random.nextInt(this.operandCount - 1 - this.parenStart) + this.parenStart + 1 : -2; + } + } + + @Override + protected String generateSingleQuestion() { + getRandom(); + StringBuilder question = new StringBuilder(); + + for (int j = 0; j < this.operandCount; j++) { + if (j == this.parenStart) { + question.append("("); + } + question.append(operands[j]); + if (j == this.parenEnd) { + question.append(")"); + } + + if (j < this.operandCount - 1) { + char op = operators[random.nextInt(operators.length)]; + if (op == '/') { + this.operands[j+1] = this.operands[j+1] == 0 ? 1 : this.operands[j+1]; + } + question.append(" ").append(op).append(" "); + } + } + return question.toString(); + } + + @Override + public String getType(){ + return "小学"; + } +} \ No newline at end of file diff --git a/src/SeniorTea.class b/src/SeniorTea.class new file mode 100644 index 0000000..ff62a8f Binary files /dev/null and b/src/SeniorTea.class differ diff --git a/src/SeniorTea.java b/src/SeniorTea.java new file mode 100644 index 0000000..3db2525 --- /dev/null +++ b/src/SeniorTea.java @@ -0,0 +1,75 @@ +package src; + +public class SeniorTea extends Teacher{ + final static String[] binaryOps = {"+", "-", "*", "/"}; // 操作符 + final static String[] trigOps = {"sin", "cos", "tan"}; + int operandCount; + String[] questionParts; // 操作数 + boolean[] specialOpFlags; // 特殊操作符索引序列 + int parenStart; + int parenEnd; + + public SeniorTea(String name, String password, String path) { + super(name, password, path); + } + + // 数据预处理 + public void getRandom(){ + this.operandCount = random.nextInt(4) + 2; + this.questionParts = new String[this.operandCount]; + // 随机决定特殊操作符的数量和位置 + int specialNum = Math.min(this.operandCount, random.nextInt(this.operandCount) + 1); + this.specialOpFlags = new boolean[this.operandCount]; + for (int i = 0; i < specialNum; i++) { + int pos; + do { + pos = random.nextInt(this.operandCount); + } while (this.specialOpFlags[pos]); + this.specialOpFlags[pos] = true; + } + for (int i = 0; i < operandCount; i++) { + int operand = random.nextInt(100) + 1; + if (specialOpFlags[i]) { + String op = trigOps[random.nextInt(trigOps.length)]; + questionParts[i] = op + "(" + operand + ")"; + } else { + questionParts[i] = String.valueOf(operand); + } + } + // 生成有效括号 + boolean useParen = this.operandCount > 2 && random.nextBoolean(); + this.parenStart = 0; + this.parenEnd = this.operandCount - 1; + while (this.parenStart == 0 && this.parenEnd == this.operandCount - 1) { + this.parenStart = useParen ? random.nextInt(this.operandCount - 1) : -2; + this.parenEnd = useParen ? random.nextInt(this.operandCount - 1 - this.parenStart) + this.parenStart + 1 : -2; + } + } + + @Override + protected String generateSingleQuestion(){ + getRandom(); + StringBuilder question = new StringBuilder(); + + for (int i = 0; i < operandCount; i++) { + if (i == parenStart) { + question.append("("); + } + question.append(questionParts[i]); + if (i == parenEnd) { + question.append(")"); + } + + if (i < operandCount - 1) { + String op = binaryOps[random.nextInt(binaryOps.length)]; + question.append(" ").append(op).append(" "); + } + } + return question.toString(); + } + + @Override + public String getType(){ + return "高中"; + } +} \ No newline at end of file diff --git a/src/SysFunc.class b/src/SysFunc.class new file mode 100644 index 0000000..80d0c9c Binary files /dev/null and b/src/SysFunc.class differ diff --git a/src/SysFunc.java b/src/SysFunc.java new file mode 100644 index 0000000..a8b0be7 --- /dev/null +++ b/src/SysFunc.java @@ -0,0 +1,155 @@ +package src; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Scanner; + +public class SysFunc { + // 题目数量 + static final int LEAST_NUM = 10; + static final int MAX_NUM = 30; + // 用户列表 + static ArrayList teachers; + // 当前用户 + static Teacher teacher; + + static HashMap typeMap; + + // ANSI颜色代码 + static final String RESET = "\u001B[0m"; + static final String RED = "\u001B[31m"; + static final String GREEN = "\u001B[32m"; + static final String YELLOW = "\u001B[33m"; + static final String BLUE = "\u001B[34m"; + static final String PURPLE = "\u001B[35m"; + static final String CYAN = "\u001B[36m"; + static final String BOLD = "\u001B[1m"; + + public static void init(){ + // 用户预加载 + teachers = new ArrayList<>(); + teachers.add(new PrimaryTea("张三1", "123", null)); + teachers.add(new PrimaryTea("张三2", "123", null)); + teachers.add(new PrimaryTea("张三3", "123", null)); + teachers.add(new JuniorTea("李四1", "123", null)); + teachers.add(new JuniorTea("李四2", "123", null)); + teachers.add(new JuniorTea("李四3", "123", null)); + teachers.add(new SeniorTea("王五1", "123", null)); + teachers.add(new SeniorTea("王五2", "123", null)); + teachers.add(new SeniorTea("王五3", "123", null)); + typeMap = new HashMap<>(); + typeMap.put("小学", 1); + typeMap.put("初中", 2); + typeMap.put("高中", 3); + } + + // 登陆界面 + public static Teacher login(Scanner scanner) { + boolean flag = false; + System.out.println(BOLD + CYAN + "=== 数学题目生成系统 ===" + RESET); + System.out.println(BOLD + CYAN + "请登录您的账户" + RESET); + while (!flag) { + System.out.println(BOLD + YELLOW + "请输入: 用户名 密码" + RESET); + System.out.print(BOLD + BLUE + "> " + RESET); + + String cur = scanner.nextLine(); + if (cur.indexOf(" ") == -1) { + System.out.println(RED + "请输入用户名和密码,中间用空格隔开"); + continue; + } + String cur_name = cur.substring(0, cur.indexOf(" ")); + String cur_password = cur.substring(cur.indexOf(" ") + 1); + + // 匹配已有帐户 + for (Teacher t : teachers) { + if (t.name.equals(cur_name) && t.password.equals(cur_password)) { + teacher = t; + flag = true; + System.out.println(GREEN + "当前选择为" + teacher.getType() + "出题"); + break; + } + } + if (!flag) { + System.out.println(RED + "请输入正确的用户名、密码"); + } + } + return teacher; + } + + // 切换类型界面 + public static void ShiftType(Scanner scanner) { + int type = SysFunc.typeMap.get(SysFunc.teacher.getType()); + System.out.println(BOLD + PURPLE + "=== 是否切换出题类型(y/n) ===" + RESET); + System.out.print(BOLD + BLUE + "> " + RESET); + + String choice = scanner.nextLine(); + if (choice.equals("y")) { + System.out.println(BOLD + YELLOW + "请输入指令: 切换** (支持小学,初中,高中难度): " + RESET); + while (true) { + System.out.print(BOLD + BLUE + "> " + RESET); + String choice_type = scanner.nextLine(); + if (choice_type.substring(0, 2).equals("切换") && typeMap.containsKey(choice_type.substring(2))) { + type = typeMap.get(choice_type.substring(2)); + if (type == 1) { + teacher = new PrimaryTea(teacher.name, teacher.password, teacher.path); + } else if (type == 2) { + teacher = new JuniorTea(teacher.name, teacher.password, teacher.path); + } else { + teacher = new SeniorTea(teacher.name, teacher.password, teacher.path); + } + System.out.println(GREEN + "准备生成" + teacher.getType() + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):"); + break; + } else { + System.out.println(RED + RESET + "请输入小学、初中和高中三个选项中的一个"); + } + } + } else if (choice.equals("n")) { + System.out.println(GREEN + "请继续输入题目数量:"); + } else { + System.out.println(RED + RESET + "无效输入,已为您设置默认类型:" + teacher.getType()); + System.out.println(GREEN + "请输入题目数量:"); + } + } + + + // 出题界面 + public static void Operate(Scanner scanner){ + boolean logout = false; + while (!logout) { + SysFunc.ShiftType(scanner); + int num = 0; + while (true) { + try { + System.out.print(BOLD + BLUE + "> " + RESET); + String input = scanner.nextLine(); + num = Integer.parseInt(input); + break; + } catch (NumberFormatException e) { + System.out.println(RED + RESET + "请输入有效的数字(10-30之间的整数,或-1退出登录):"); + } + } + while (true) { + if (num == -1) { + System.out.println(BOLD + YELLOW + "已退出登录" + RESET); + logout = true; + break; + } + if (num >= LEAST_NUM && num <= MAX_NUM) { + System.out.println(BOLD + GREEN + "正在生成题目..." + RESET); + String filepath = teacher.generateEX(num); + System.out.println(GREEN + RESET + "题目生成成功,已保存至" + filepath); + System.out.println(BOLD + CYAN + "=== 操作完成 ===" + RESET); + break; + } else { + System.out.println(RED + RESET + "题目数量应在10-30之间,请重新输入"); + try { + System.out.print(BOLD + BLUE + "> " + RESET); + num = Integer.parseInt(scanner.nextLine()); + } catch (NumberFormatException e) { + System.out.println(RED + RESET + "请输入有效的数字:"); + } + } + } + } + } +} diff --git a/src/Teacher.class b/src/Teacher.class new file mode 100644 index 0000000..4242b0f Binary files /dev/null and b/src/Teacher.class differ diff --git a/src/Teacher.java b/src/Teacher.java new file mode 100644 index 0000000..3ad8d36 --- /dev/null +++ b/src/Teacher.java @@ -0,0 +1,113 @@ +package src; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Random; + +public abstract class Teacher { + protected String name; + protected String password; + protected String path = null; // 教师文件夹路径 + public Random random = new Random(); // 共用Random + + public Teacher(String name, String password, String path) { + this.name = name; + this.password = password; + if (path != null) { + this.path = path; + return; + } + // 生成文件夹 + File folder = new File(name); + try { + if (!folder.exists()) { + folder.mkdirs(); + } + } catch (Exception e) { + e.printStackTrace(); + } + this.path = folder.getAbsolutePath(); + } + + // 查重 + public boolean checkDuplicate(String question){ + File folder = new File(this.path); + File[] files = folder.listFiles(); + if (files == null) { + return false; + } + for (File file : files) { + if (!file.getName().endsWith(".txt")) { + continue; + } + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.contains(")")) { + try { + String fileQuestion = line.substring(line.indexOf(")") + 2).trim(); + if (fileQuestion.equals(question)) { + return true; + } + } catch (StringIndexOutOfBoundsException e) { + // 继续处理下一行 + continue; + } + } + } + } catch (IOException e) { + System.err.println("读取文件时出错: " + file.getName()); + e.printStackTrace(); + } + } + return false; + } + + // 生成存储文档 + public String generatePath(){ + Date date = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + File file = new File(this.path, sdf.format(date) + ".txt"); + try { + if (!file.exists()) { + file.createNewFile(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return file.getAbsolutePath(); + } + + // 生成并存储题目 + public String generateEX(int num) { + Path filePath = Paths.get(generatePath()); + for (int i = 0; i < num; i++) { + String question = generateSingleQuestion(); + if (checkDuplicate(question)) { + i--; + continue; + } + String qstr = "(" + (i + 1) + ") " + question + " =\n"; + try { + Files.writeString(filePath, qstr + '\n', StandardOpenOption.APPEND); + } catch (IOException e) { + e.printStackTrace(); + } + } + return filePath.toString(); + } + + // 生成单个题目 + protected abstract String generateSingleQuestion(); + + // 返回教师类型 + public abstract String getType(); +}