pull/1/head
Violet 7 months ago
parent a5c791ba47
commit ba6b3108f0

@ -0,0 +1,124 @@
# 数学题目生成系统 - 项目说明
## 项目概述
本项目是一个基于Java的数学题目生成系统专门为不同学段小学、初中、高中的教师设计。系统能够根据教师类型自动生成相应难度的数学题目并支持题目查重、文件存储等功能。
## 项目结构
```
Personal_Project/
├── src/ # 源代码目录
│ ├── Main.java # 程序入口类
│ ├── SysFunc.java # 系统功能类(登录、操作界面)
│ ├── Teacher.java # 教师抽象基类
│ ├── PrimaryTea.java # 小学教师类
│ ├── JuniorTea.java # 初中教师类
│ └── SeniorTea.java # 高中教师类
├── doc/ # 文档目录
│ └── 项目说明.md # 项目说明文档
├── 张三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`作为基类,三个具体子类实现不同学段的题目生成
- **多态应用**:通过抽象方法实现不同学段题目的差异化生成
- **封装性**:将用户信息、文件操作等功能封装在相应的类中
### 算法设计
- **随机算法**使用Java Random类确保题目的随机性
- **括号处理**:智能添加括号,保证表达式合理性
- **操作符分布**:合理分布不同难度的操作符
### 文件操作
- **NIO API**使用Java NIO进行高效的文件读写操作
- **异常处理**:完善的异常处理机制确保程序稳定性
- **路径管理**:自动创建和管理教师个人文件夹
## 使用流程
1. **启动程序**运行Main.java
2. **用户登录**:输入预置的用户名和密码(格式:用户名 密码)
3. **选择模式**:系统显示当前出题类型,可选择切换
4. **生成题目**输入题目数量10-30
5. **查看结果**:题目生成后显示保存路径
6. **重复使用**:题目生成后可选择继续生成或切换难度
7. **退出登录**:输入题目数量为-1则退出当前用户可重新登录
## 预置用户信息
| 用户名 | 密码 | 类型 | 初始类型 |
|--------|------|------|----------|
| 张三1 | 123 | 小学教师 | 小学 |
| 张三2 | 123 | 小学教师 | 小学 |
| 张三3 | 123 | 小学教师 | 小学 |
| 李四1 | 123 | 初中教师 | 初中 |
| 李四2 | 123 | 初中教师 | 初中 |
| 李四3 | 123 | 初中教师 | 初中 |
| 王五1 | 123 | 高中教师 | 高中 |
| 王五2 | 123 | 高中教师 | 高中 |
| 王五3 | 123 | 高中教师 | 高中 |
## 扩展性
系统具有良好的扩展性,可以通过以下方式增强功能:
- 添加新的学段类型
- 增加新的数学运算类型
- 支持自定义题目难度
- 添加题目答案计算功能
- 支持批量导入导出
## 开发环境
- **语言**Java
- **编码**GBK支持中文输入
- **依赖**纯Java标准库无需额外依赖
## 项目价值
本项目展示了面向对象编程的实际应用,体现了良好的软件工程实践,包括:
- 清晰的代码结构
- 符合Google编码规范的设计编写
- 合理,扩展性良好的类设计
- 完善的异常处理
- 用户友好的交互界面
- 实用的业务功能
该系统可以实际应用于教育场景,帮助教师快速生成练习题,提高教学效率。

@ -20,18 +20,18 @@ public class JuniorTea extends Teacher{
// 随机决定特殊操作符的数量
int specialNum = random.nextInt(operandCount - 1) + 1;
int[] Index = new int[operandCount];
for(int i=0; i<operandCount; i++) Index[i] = i;
for (int i=0; i<operandCount; i++) {
Index[i] = i;
}
Collections.shuffle(Arrays.asList(Index));
StringBuilder specialOpPositions = new StringBuilder();
for(int i=0; i<specialNum; i++){
for (int i=0; i<specialNum; i++) {
specialOpPositions.append(Index[i]);
}
//int specialOpPos = random.nextInt(operandCount);
for (int i = 0; i < operandCount; i++) {
int operand = random.nextInt(100) + 1;
//if (i == specialOpPos) {
if(specialOpPositions.indexOf(String.valueOf(i)) != -1){
if (specialOpPositions.indexOf(String.valueOf(i)) != -1) {
String op = unaryOps[random.nextInt(unaryOps.length)];
if (op.equals("√")) {
questionParts[i] = op + operand;
@ -48,9 +48,13 @@ public class JuniorTea extends Teacher{
int parenStart = useParen ? random.nextInt(operandCount - 1) : -2;
for (int i = 0; i < operandCount; i++) {
if (i == parenStart) question.append("(");
if (i == parenStart) {
question.append("(");
}
question.append(questionParts[i]);
if (i == parenStart + 1) question.append(")");
if (i == parenStart + 1) {
question.append(")");
}
if (i < operandCount - 1) {
question.append(" ").append(binaryOps[random.nextInt(binaryOps.length)]).append(" ");

@ -23,9 +23,13 @@ public class PrimaryTea extends Teacher{
int parenStart = useParen ? random.nextInt(operandCount - 1) : -2;
for (int j = 0; j < operandCount; j++) {
if (j == parenStart) question.append("(");
if (j == parenStart) {
question.append("(");
}
question.append(operands[j]);
if (j == parenStart + 1) question.append(")");
if (j == parenStart + 1) {
question.append(")");
}
if (j < operandCount - 1) {
char op = operators[random.nextInt(operators.length)];

@ -20,18 +20,18 @@ public class SeniorTea extends Teacher{
// 随机决定特殊操作符的数量
int specialNum = random.nextInt(operandCount - 1) + 1;
int[] Index = new int[operandCount];
for(int i=0; i<operandCount; i++) Index[i] = i;
for (int i=0; i<operandCount; i++) {
Index[i] = i;
}
Collections.shuffle(Arrays.asList(Index));
StringBuilder specialOpPositions = new StringBuilder();
for(int i=0; i<specialNum; i++){
for (int i=0; i<specialNum; i++) {
specialOpPositions.append(Index[i]);
}
//int trigOpPos = random.nextInt(operandCount);
for (int i = 0; i < operandCount; i++) {
int operand = random.nextInt(100) + 1;
//if (i == trigOpPos) {
if(specialOpPositions.indexOf(String.valueOf(i)) != -1){
if (specialOpPositions.indexOf(String.valueOf(i)) != -1) {
String op = trigOps[random.nextInt(trigOps.length)];
questionParts[i] = op + "(" + operand + ")";
} else {
@ -44,9 +44,13 @@ public class SeniorTea extends Teacher{
int parenStart = useParen ? random.nextInt(operandCount - 1) : -2;
for (int i = 0; i < operandCount; i++) {
if (i == parenStart) question.append("(");
if (i == parenStart) {
question.append("(");
}
question.append(questionParts[i]);
if (i == parenStart + 1) question.append(")");
if (i == parenStart + 1) {
question.append(")");
}
if (i < operandCount - 1) {
String op = binaryOps[random.nextInt(binaryOps.length)];

@ -38,7 +38,7 @@ public class SysFunc {
System.out.println("-------请登录您的账户-------");
System.out.println(" 请输入: 用户名 密码 ");
String cur = scanner.nextLine();
if(cur.indexOf(" ") == -1){
if (cur.indexOf(" ") == -1) {
System.out.println("请输入用户名和密码,中间用空格隔开");
continue;
}
@ -46,18 +46,18 @@ public class SysFunc {
String cur_password = cur.substring(cur.indexOf(" ") + 1);
// 匹配已有帐户
for(Teacher t : teachers){
if(t.name.equals(cur_name) && t.password.equals(cur_password)){
for (Teacher t : teachers) {
if (t.name.equals(cur_name) && t.password.equals(cur_password)) {
teacher = t;
flag = true;
System.out.println("当前选择为" + teacher.getType() + "出题");
break;
}
}
if(!flag){
System.out.println("请输入正确的用户名、密码");
}
if (!flag) {
System.out.println("请输入正确的用户名、密码");
}
}
return teacher;
}
@ -66,30 +66,26 @@ public class SysFunc {
int type = SysFunc.typeMap.get(SysFunc.teacher.getType());
System.out.println("-------是否切换出题类型(y/n)-------");
String choice = scanner.nextLine();
if(choice.equals("y")){
if (choice.equals("y")) {
System.out.println("请输入类型:");
while(true){
while (true) {
String choice_type = scanner.nextLine();
if(choice_type.substring(0,2).equals("切换") && typeMap.containsKey(choice_type.substring(2))){
if (choice_type.substring(0, 2).equals("切换") && typeMap.containsKey(choice_type.substring(2))) {
type = typeMap.get(choice_type.substring(2));
if(type == 1){
if (type == 1) {
teacher = new PrimaryTea(teacher.name, teacher.password, teacher.path);
}
else if(type == 2){
} else if (type == 2) {
teacher = new JuniorTea(teacher.name, teacher.password, teacher.path);
}
else{
} else {
teacher = new SeniorTea(teacher.name, teacher.password, teacher.path);
}
System.out.println("准备生成" + teacher.getType() + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):");
break;
}
else{
} else {
System.out.println("请输入小学、初中和高中三个选项中的一个");
}
}
}
else if(choice.equals("n")){
} else if (choice.equals("n")) {
System.out.println("请继续输入题目数量:");
}
}
@ -98,23 +94,22 @@ public class SysFunc {
// 出题界面
public static void Operate(Scanner scanner){
boolean logout = false;
while(!logout){
while (!logout) {
SysFunc.ShiftType(scanner);
int num = scanner.nextInt();
scanner.nextLine();
while(true){
if(num == -1) {
while (true) {
if (num == -1) {
// 返回登录界面
System.out.println("已退出登录");
logout = true;
break;
}
if(num >= LEAST_NUM && num <= MAX_NUM) {
if (num >= LEAST_NUM && num <= MAX_NUM) {
String filepath = teacher.GenerateEX(num);
System.out.println("题目生成成功,已保存至" + filepath);
break;
}
else {
} else {
System.out.println("题目数量应在10-30之间,请重新输入");
num = scanner.nextInt();
}

@ -18,17 +18,17 @@ public abstract class Teacher {
public Teacher(String name, String password, String path) {
this.name = name;
this.password = password;
if(this.path != null){
if (this.path != null) {
this.path = path;
return ;
return;
}
// 生成文件夹
File folder = new File(name);
try{
if(!folder.exists()){
try {
if (!folder.exists()) {
folder.mkdirs();
}
} catch(Exception e) {
} catch (Exception e) {
e.printStackTrace();
}
this.path = folder.getAbsolutePath();
@ -38,13 +38,15 @@ public abstract class Teacher {
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 (files == null) {
return false;
}
for (File file : files) {
List<String> lines = null;
try {
lines = Files.readAllLines(Paths.get(file.getAbsolutePath()));
for(String line : lines){
if(line.substring(line.indexOf(")") + 2).equals(question)){
for (String line : lines) {
if (line.substring(line.indexOf(")") + 2).equals(question)) {
return true;
}
}
@ -60,11 +62,11 @@ public abstract class Teacher {
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()){
try {
if (!file.exists()) {
file.createNewFile();
}
} catch(IOException e){
} catch (IOException e) {
e.printStackTrace();
}
return file.getAbsolutePath();
@ -75,7 +77,7 @@ public abstract class Teacher {
Path filePath = Paths.get(generatePath());
for (int i = 0; i < num; i++) {
String question = generateSingleQuestion();
if(checkDuplicate(question)){
if (checkDuplicate(question)) {
i--;
continue;
}

Loading…
Cancel
Save