diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f68d109
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,29 @@
+### IntelliJ IDEA ###
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..7bc07ec
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Environment-dependent path to Maven home directory
+/mavenHomeManager.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..6f29fee
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..ab3132c
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..79aa82a
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
deleted file mode 100644
index d67864c..0000000
--- a/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# relentless
-
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 0000000..3360855
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,111 @@
+# 中小学数学卷子自动生成程序
+
+## 项目简介
+这是一个命令行界面的数学题目自动生成程序,专为小学、初中和高中数学老师设计。程序可以根据不同难度级别(小学、初中、高中)自动生成符合相应教学要求的数学题目,并支持题目查重功能,确保每位老师生成的题目不会重复。
+
+## 功能特点
+
+### 1. 用户登录验证
+- 支持小学、初中和高中三个级别的用户账号
+- 每个级别预设3个账号,密码统一为123
+- 登录成功后显示当前选择的出题级别
+
+### 2. 题目生成功能
+- 根据账号类型自动选择对应的难度级别生成题目
+- 支持自定义生成题目数量(范围:10-30题)
+- 操作数范围:1-100
+- 操作数个数:2-5个
+
+### 3. 多难度级别支持
+- **小学**:仅包含加减乘除四则运算和括号
+- **初中**:在小学基础上增加平方和开根号运算,且每道题至少包含一个平方或开根号
+- **高中**:在初中基础上增加三角函数(sin、cos、tan),且每道题至少包含一个三角函数
+
+### 4. 题目类型切换
+- 支持在登录状态下切换不同难度级别的题目生成
+- 输入格式:`切换为 小学/初中/高中`
+
+### 5. 题目查重功能
+- 自动检测新生成的题目是否与当前用户历史生成的题目重复
+- 确保每个用户生成的题目都是唯一的
+
+### 6. 文件保存功能
+- 题目以文本文件形式保存
+- 文件名格式:`年-月-日-时-分-秒.txt`
+- 每个用户有独立的文件夹存储题目
+- 题目包含题号,每题之间空一行
+
+## 使用说明
+
+### 登录
+1. 运行程序后,输入用户名和密码(用空格分隔)
+2. 验证成功后,系统提示当前选择的出题级别
+3. 验证失败则提示重新输入
+
+### 生成题目
+1. 登录成功后,系统提示输入题目数量
+2. 输入10-30之间的数字生成对应数量的题目
+3. 输入-1退出当前用户,返回登录界面
+
+### 切换难度
+- 在任何提示输入题目数量的界面,输入`切换为 小学/初中/高中`即可切换题目难度
+- 切换成功后,系统会提示新的难度级别
+
+## 账号列表
+
+| 级别 | 用户名 | 密码 |
+|------|--------|------|
+| 小学 | 张三1 | 123 |
+| 小学 | 张三2 | 123 |
+| 小学 | 张三3 | 123 |
+| 初中 | 李四1 | 123 |
+| 初中 | 李四2 | 123 |
+| 初中 | 李四3 | 123 |
+| 高中 | 王五1 | 123 |
+| 高中 | 王五2 | 123 |
+| 高中 | 王五3 | 123 |
+
+## 项目结构
+```
+quesproject/
+├── src/ # 源代码目录
+│ ├── Main.java # 程序入口类
+│ ├── User.java # 用户类
+│ ├── MathQuestion.java # 数学题目类
+│ ├── QuestionGenerator.java # 题目生成器
+│ ├── QuestionStrategy.java # 题目策略接口
+│ ├── QuestionStrategyFactory.java # 策略工厂类
+│ ├── ElementaryQuestionStrategy.java # 小学题目策略
+│ ├── MiddleSchoolQuestionStrategy.java # 初中题目策略
+│ ├── HighSchoolQuestionStrategy.java # 高中题目策略
+│ └── FileUtils.java # 文件操作工具类
+├── doc/ # 文档目录
+│ └── README.md # 项目说明文档
+├── [用户名]/ # 用户题目文件夹(运行时自动创建)
+```
+
+## 技术实现
+
+### 设计模式
+- **工厂模式**:通过QuestionStrategyFactory创建不同级别的题目生成策略
+- **策略模式**:通过QuestionStrategy接口及其实现类实现不同难度级别的题目生成
+
+### 核心功能实现
+1. **用户验证**:通过预设的账号列表进行验证
+2. **题目生成**:根据不同难度级别使用不同的策略生成题目
+3. **查重功能**:读取用户历史题目文件,确保新生成的题目不重复
+4. **文件管理**:自动创建用户文件夹,按指定格式保存题目文件
+
+## 运行环境
+- Java 8及以上版本
+- 支持Windows、Linux、macOS等操作系统
+
+## 编译运行
+1. 编译:`javac -d out src/*.java`
+2. 运行:`java -cp out Main`
+
+## 注意事项
+1. 题目数量必须在10-30之间,否则会提示重新输入
+2. 切换难度时,请确保输入格式正确:`切换为 级别名称`
+3. 程序会在当前目录下创建用户文件夹存储题目文件
+4. 为保证查重功能正常,请勿手动修改用户文件夹中的题目文件格式
\ No newline at end of file
diff --git a/quesproject.iml b/quesproject.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/quesproject.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ElementaryQuestionStrategy.java b/src/ElementaryQuestionStrategy.java
new file mode 100644
index 0000000..120e106
--- /dev/null
+++ b/src/ElementaryQuestionStrategy.java
@@ -0,0 +1,151 @@
+import java.util.Random;
+
+public class ElementaryQuestionStrategy implements QuestionStrategy {
+ private final Random random = new Random();
+ private final String[] operators = {"+", "-", "*", "/"};
+
+ @Override
+ public String generateQuestion() {
+ int operandsCount = random.nextInt(4) + 2; // 操作数 2~5
+ StringBuilder sb = new StringBuilder();
+
+ // 生成运算符序列
+ String[] chosenOps = generateOperators(operandsCount);
+
+ // 随机决定括号
+ int[] parentheses = decideParentheses(operandsCount, chosenOps);
+
+ // 拼接表达式
+ buildExpression(sb, operandsCount, chosenOps, parentheses);
+
+ return sb.toString();
+ }
+
+ /**
+ * 生成运算符序列
+ * 根据操作数数量,随机生成对应数量的运算符数组
+ *
+ * @param operandsCount 操作数数量
+ * @return 随机生成的运算符数组,长度为操作数数量-1
+ */
+ private String[] generateOperators(int operandsCount) {
+ String[] chosenOps = new String[operandsCount - 1];
+ for (int i = 0; i < operandsCount - 1; i++) {
+ chosenOps[i] = operators[random.nextInt(operators.length)];
+ }
+ return chosenOps;
+ }
+
+ /**
+ * 决定是否需要括号,并返回括号的起始和结束位置
+ * 对于3个及以上操作数,随机决定是否添加括号,并检查括号是否有效
+ *
+ * @param operandsCount 操作数数量
+ * @param chosenOps 运算符数组
+ * @return 包含开括号和闭括号位置的数组,格式为[openParenIndex, closeParenIndex],-1表示不添加括号
+ */
+ private int[] decideParentheses(int operandsCount, String[] chosenOps) {
+ int openParenIndex = -1;
+ int closeParenIndex = -1;
+
+ if (operandsCount > 2 && random.nextBoolean()) {
+ openParenIndex = random.nextInt(operandsCount - 1);
+ closeParenIndex = random.nextInt(operandsCount - openParenIndex - 1) + openParenIndex + 1;
+
+ // 如果括号包裹整个表达式,则不需要括号
+ if (openParenIndex == 0 && closeParenIndex == operandsCount - 1) {
+ openParenIndex = -1;
+ closeParenIndex = -1;
+ } else {
+ // 检查括号内的运算符优先级是否相同,如果相同则不需要括号
+ boolean samePrecedence = checkPrecedenceEquality(chosenOps, openParenIndex, closeParenIndex);
+ if (samePrecedence) {
+ openParenIndex = -1;
+ closeParenIndex = -1;
+ }
+ }
+ }
+ return new int[]{openParenIndex, closeParenIndex};
+ }
+
+ /**
+ * 判断括号内的运算符优先级是否相同
+ * 用于决定是否需要添加括号(如果优先级都相同,则括号是冗余的)
+ *
+ * @param chosenOps 运算符数组
+ * @param openParenIndex 开括号位置
+ * @param closeParenIndex 闭括号位置
+ * @return 如果括号内所有运算符优先级相同则返回true,否则返回false
+ */
+ private boolean checkPrecedenceEquality(String[] chosenOps, int openParenIndex, int closeParenIndex) {
+ int precedence = getPrecedence(chosenOps[openParenIndex]);
+ for (int i = openParenIndex; i < closeParenIndex; i++) {
+ if (getPrecedence(chosenOps[i]) != precedence) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 构建数学表达式
+ * 根据操作数、运算符和括号位置,拼接完整的数学表达式
+ *
+ * @param sb StringBuilder对象,用于构建表达式
+ * @param operandsCount 操作数数量
+ * @param chosenOps 运算符数组
+ * @param parentheses 括号位置数组,格式为[openParenIndex, closeParenIndex]
+ */
+ private void buildExpression(StringBuilder sb, int operandsCount, String[] chosenOps, int[] parentheses) {
+ int prevNum = random.nextInt(100) + 1;
+ int openParenIndex = parentheses[0];
+ int closeParenIndex = parentheses[1];
+
+ // 处理第一个操作数可能的开括号
+ if (openParenIndex == 0) sb.append("(");
+ sb.append(prevNum);
+
+ // 处理最后一个操作数可能的闭括号
+ if (closeParenIndex == operandsCount - 1) sb.append(")");
+
+ // 构建剩余的操作数和运算符
+ for (int i = 1; i < operandsCount; i++) {
+ String op = chosenOps[i - 1];
+ sb.append(" ").append(op).append(" ");
+
+ // 根据运算符生成下一个操作数
+ int num = generateOperand(op, prevNum);
+
+ // 添加括号(如果需要)
+ if (i == openParenIndex) sb.append("(");
+ sb.append(num);
+ if (i == closeParenIndex) sb.append(")");
+
+ prevNum = num; // 更新上一个数字,供下一轮计算使用
+ }
+ }
+
+ /**
+ * 生成每个操作数
+ * 确保生成的操作数符合题目要求,特别是减法不会导致负数结果
+ *
+ * @param op 当前运算符
+ * @param prevNum 前一个操作数的值
+ * @return 生成的操作数
+ */
+ private int generateOperand(String op, int prevNum) {
+ int num = random.nextInt(100) + 1; // 默认生成1-100之间的随机数
+
+ // 如果是减法运算符,确保不会出现负数结果
+ if (op.equals("-") && num > prevNum) {
+ num = random.nextInt(prevNum) + 1; // 保证 num <= prevNum,避免负数结果
+ }
+ return num;
+ }
+
+ private int getPrecedence(String op) {
+ if (op.equals("+") || op.equals("-")) return 1;
+ if (op.equals("*") || op.equals("/")) return 2;
+ return 0;
+ }
+}
diff --git a/src/FileUtils.java b/src/FileUtils.java
new file mode 100644
index 0000000..a24ab81
--- /dev/null
+++ b/src/FileUtils.java
@@ -0,0 +1,64 @@
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * 文件工具类:生成文件名、保存题目、读取已有题目
+ */
+public class FileUtils {
+
+ // 生成文件名
+ public static String generateFileName() {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
+ return sdf.format(new Date()) + ".txt";
+ }
+
+ // 保存题目到用户文件夹
+ public static void saveQuestionsToFile(String userId, String fileName, List questions) {
+ File userFolder = new File(userId);
+ if (!userFolder.exists()) {
+ userFolder.mkdirs();
+ }
+
+ File file = new File(userFolder, fileName);
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ for (MathQuestion question : questions) {
+ writer.write("题号 " + question.getQuestionNumber() + ": " + question.getQuestionText());
+ writer.newLine();
+ writer.newLine();
+ }
+ writer.flush();
+ } catch (IOException e) {
+ throw new RuntimeException("写文件失败: " + file.getAbsolutePath(), e);
+ }
+ }
+
+ // 读取用户文件夹下所有 txt 文件中已存在的题目
+ public static Set loadExistingQuestions(String userId) {
+ Set existingQuestions = new HashSet<>();
+ File userFolder = new File(userId);
+ if (!userFolder.exists() || !userFolder.isDirectory()) return existingQuestions;
+
+ File[] files = userFolder.listFiles((dir, name) -> name != null && name.endsWith(".txt"));
+ if (files == null) return existingQuestions;
+
+ for (File f : files) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(f))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.isEmpty()) continue;
+ if (line.startsWith("题号")) {
+ int idx = line.indexOf(":");
+ if (idx != -1 && idx + 1 < line.length()) {
+ existingQuestions.add(line.substring(idx + 1).trim());
+ }
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return existingQuestions;
+ }
+}
diff --git a/src/HighSchoolQuestionStrategy.java b/src/HighSchoolQuestionStrategy.java
new file mode 100644
index 0000000..85812b9
--- /dev/null
+++ b/src/HighSchoolQuestionStrategy.java
@@ -0,0 +1,42 @@
+import java.util.Random;
+
+public class HighSchoolQuestionStrategy implements QuestionStrategy {
+ private final Random random = new Random();
+ private final String[] basicOps = {"+", "-", "*", "/"};
+ private final String[] trigFuncs = {"sin", "cos", "tan"};
+
+ @Override
+ public String generateQuestion() {
+ // 随机操作数个数 2-5
+ int operandsCount = random.nextInt(4) + 2;
+ StringBuilder sb = new StringBuilder();
+ boolean hasTrig = false;
+
+ for (int i = 0; i < operandsCount; i++) {
+ int num = random.nextInt(100) + 1;
+
+ // 每个操作数有概率加三角函数
+ if (random.nextBoolean()) {
+ String func = trigFuncs[random.nextInt(trigFuncs.length)];
+ sb.append(func).append("(").append(num).append(")");
+ hasTrig = true;
+ } else {
+ sb.append(num);
+ }
+
+ if (i != operandsCount - 1) {
+ String op = basicOps[random.nextInt(basicOps.length)];
+ sb.append(" ").append(op).append(" ");
+ }
+ }
+
+ // 确保至少一个三角函数
+ if (!hasTrig) {
+ String func = trigFuncs[random.nextInt(trigFuncs.length)];
+ int num = random.nextInt(100) + 1;
+ return func + "(" + num + ") + " + sb.toString();
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/src/Main.java b/src/Main.java
new file mode 100644
index 0000000..3a5deeb
--- /dev/null
+++ b/src/Main.java
@@ -0,0 +1,100 @@
+import java.io.IOException;
+import java.util.Scanner;
+
+/**
+ * 程序入口类,负责处理登录和题目生成。
+ */
+public class Main {
+ public static void main(String[] args) throws IOException {
+ Scanner scanner = new Scanner(System.in);
+ User currentUser = null;
+
+ // 登录流程
+ while (true) {
+ while (currentUser == null) {
+ System.out.print("请输入用户名和密码,用空格分隔:");
+ String username = scanner.next();
+ String password = scanner.next();
+
+ currentUser = User.login(username, password);
+
+ if (currentUser == null) {
+ System.out.println("请输入正确的用户名、密码");
+ } else {
+ clearScreen(); //登录成功清屏
+ System.out.println("当前选择为 " + currentUser.getRole() + " 出题");
+ }
+ }
+
+ // 每次登录后初始化当前出题类型(账号默认类型)
+ String currentRole = currentUser.getRole();
+
+ // 题目生成流程
+ while (true) {
+ System.out.println("准备生成 " + currentRole
+ + " 数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):");
+
+ String input = scanner.next();
+
+ // 退出登录
+ if (input.equals("-1")) {
+ currentUser = null;
+ clearScreen();
+ System.out.println("已退出当前用户,重新登录...");
+ break;
+ }
+
+ // 检测切换命令
+ if (input.startsWith("切换为")) {
+ String newRole = input.substring(3).trim();
+ if (!newRole.equals("小学") && !newRole.equals("初中") && !newRole.equals("高中")) {
+ System.out.println("请输入小学、初中和高中三个选项中的一个"+"(当前类型为"+currentRole+")");
+ continue;
+ }
+ currentRole = newRole;
+ clearScreen();
+ System.out.println("系统提示:准备生成 " + currentRole + " 数学题目,请输入生成题目数量");
+ continue;
+ }
+
+ // 输入题目数量
+ int questionCount;
+ try {
+ questionCount = Integer.parseInt(input);
+ } catch (NumberFormatException e) {
+ System.out.println("请输入有效的数字或使用“切换为小学/初中/高中”命令"+"(当前类型为"+currentRole+")");
+ continue;
+ }
+
+ if (questionCount < 10 || questionCount > 30) {
+ System.out.println("请输入有效的题目数量 (10-30) 或 -1 退出");
+ continue;
+ }
+
+ clearScreen();
+
+ // 把 currentRole 传给 QuestionGenerator
+ QuestionGenerator generator = new QuestionGenerator(currentUser, currentRole);
+ generator.generateQuestions(questionCount);
+ System.out.println("题目已生成并保存!\n");
+ }
+ }
+ }
+
+ /**
+ * 清屏方法
+ */
+ public static void clearScreen() {
+ try {
+ if (System.getProperty("os.name").contains("Windows")) {
+ new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
+ } else {
+ new ProcessBuilder("clear").inheritIO().start().waitFor();
+ }
+ } catch (Exception e) {
+ for (int i = 0; i < 50; i++) {
+ System.out.println();
+ }
+ }
+ }
+}
diff --git a/src/MathQuestion.java b/src/MathQuestion.java
new file mode 100644
index 0000000..c727b28
--- /dev/null
+++ b/src/MathQuestion.java
@@ -0,0 +1,21 @@
+/**
+ * 数学题目类,表示每一道数学题。
+ */
+public class MathQuestion {
+ private int questionNumber;
+ private String questionText;
+
+ // 构造方法
+ public MathQuestion(int questionNumber, String questionText) {
+ this.questionNumber = questionNumber;
+ this.questionText = questionText;
+ }
+
+ public int getQuestionNumber() {
+ return questionNumber;
+ }
+
+ public String getQuestionText() {
+ return questionText;
+ }
+}
diff --git a/src/MiddleSchoolQuestionStrategy.java b/src/MiddleSchoolQuestionStrategy.java
new file mode 100644
index 0000000..aa4c595
--- /dev/null
+++ b/src/MiddleSchoolQuestionStrategy.java
@@ -0,0 +1,47 @@
+import java.util.Random;
+
+public class MiddleSchoolQuestionStrategy implements QuestionStrategy {
+ private final Random random = new Random();
+ private final String[] basicOps = {"+", "-", "*", "/"}; // 基本运算符
+
+ @Override
+ public String generateQuestion() {
+ // 随机操作数个数 2-5
+ int operandsCount = random.nextInt(4) + 2;
+ StringBuilder sb = new StringBuilder();
+ boolean hasSquareOrRoot = false;
+
+ // 生成运算符和操作数
+ for (int i = 0; i < operandsCount; i++) {
+ int num = random.nextInt(100) + 1; // 生成1-100之间的数字
+
+ // 每个操作数有概率平方或开根号
+ if (random.nextBoolean()) {
+ if (random.nextBoolean()) {
+ sb.append("(").append(num).append(")^2");
+ hasSquareOrRoot = true; // 标记是否已经使用了平方或根号
+ } else {
+ // 确保根号下的数为正
+ int rootNumber = random.nextInt(100) + 1; // 始终生成正整数
+ sb.append("√(").append(rootNumber).append(")");
+ hasSquareOrRoot = true; // 标记是否已经使用了平方或根号
+ }
+ } else {
+ sb.append(num); // 普通数字
+ }
+
+ // 添加运算符(除最后一个操作数外)
+ if (i != operandsCount - 1) {
+ String op = basicOps[random.nextInt(basicOps.length)];
+ sb.append(" ").append(op).append(" ");
+ }
+ }
+ // 如果没有平方或根号,强制添加一个
+ if (!hasSquareOrRoot) {
+ // 确保根号下的数为正
+ int rootNumber = random.nextInt(100) + 1; // 始终生成正整数
+ sb.append(" + √(").append(rootNumber).append(")");
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/QuestionGenerator.java b/src/QuestionGenerator.java
new file mode 100644
index 0000000..bd56c29
--- /dev/null
+++ b/src/QuestionGenerator.java
@@ -0,0 +1,51 @@
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * 题目生成器类
+ */
+public class QuestionGenerator {
+ private User user;
+ private String role;
+
+ public QuestionGenerator(User user, String role) {
+ this.user = user;
+ this.role = role;
+ }
+
+ public void generateQuestions(int questionCount) throws IOException {
+ // 获取策略
+ QuestionStrategy strategy = QuestionStrategyFactory.getStrategy(role);
+
+ // 读出该用户所有历史题目
+ Set existingQuestions = FileUtils.loadExistingQuestions(user.getUsername());
+ Set newQuestionsSet = new HashSet<>();
+ List questions = new ArrayList<>();
+
+ System.out.println("以下为生成的题目列表:\n");
+
+ int i = 1;
+ int tryCount = 0;
+ while (questions.size() < questionCount) {
+ String questionText = strategy.generateQuestion();
+ tryCount++;
+ if (existingQuestions.contains(questionText) || newQuestionsSet.contains(questionText)) {
+ // 如果题库太小可能死循环,这里设置最大尝试次数
+ if (tryCount > questionCount * 100) {
+ System.out.println("题库不足,无法生成足够不重复的题目");
+ break;
+ }
+ continue;
+ }
+
+ newQuestionsSet.add(questionText);
+ MathQuestion question = new MathQuestion(i, questionText);
+ questions.add(question);
+ System.out.println("题号 " + i + ":" + questionText + "\n");
+ i++;
+ }
+
+ String fileName = FileUtils.generateFileName();
+ FileUtils.saveQuestionsToFile(user.getUsername(), fileName, questions);
+ }
+}
diff --git a/src/QuestionRepository.java b/src/QuestionRepository.java
new file mode 100644
index 0000000..d4fbc17
--- /dev/null
+++ b/src/QuestionRepository.java
@@ -0,0 +1,26 @@
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 题目仓库类,负责管理已生成的题目,避免重复。
+ */
+public class QuestionRepository {
+ private Set generatedQuestions = new HashSet<>();
+
+ /**
+ * 检查题目是否重复
+ * @param question 题目
+ * @return 是否重复
+ */
+ public boolean isDuplicate(String question) {
+ return generatedQuestions.contains(question);
+ }
+
+ /**
+ * 将题目添加到仓库
+ * @param question 题目
+ */
+ public void addQuestion(String question) {
+ generatedQuestions.add(question);
+ }
+}
diff --git a/src/QuestionStrategy.java b/src/QuestionStrategy.java
new file mode 100644
index 0000000..079889b
--- /dev/null
+++ b/src/QuestionStrategy.java
@@ -0,0 +1,6 @@
+/**
+ * 出题策略接口
+ */
+public interface QuestionStrategy {
+ String generateQuestion();
+}
diff --git a/src/QuestionStrategyFactory.java b/src/QuestionStrategyFactory.java
new file mode 100644
index 0000000..e565ff5
--- /dev/null
+++ b/src/QuestionStrategyFactory.java
@@ -0,0 +1,17 @@
+/**
+ * 出题策略工厂类,根据role返回对应策略
+ */
+public class QuestionStrategyFactory {
+ public static QuestionStrategy getStrategy(String role) {
+ switch (role) {
+ case "小学":
+ return new ElementaryQuestionStrategy();
+ case "初中":
+ return new MiddleSchoolQuestionStrategy();
+ case "高中":
+ return new HighSchoolQuestionStrategy();
+ default:
+ throw new IllegalArgumentException("未知的角色: " + role);
+ }
+ }
+}
diff --git a/src/User.java b/src/User.java
new file mode 100644
index 0000000..56f2691
--- /dev/null
+++ b/src/User.java
@@ -0,0 +1,52 @@
+/**
+ * 用户类,包含登录验证和角色管理。
+ */
+public class User {
+ private String username;
+ private String password;
+ private String role;
+
+ // 构造方法
+ public User(String username, String password, String role) {
+ this.username = username;
+ this.password = password;
+ this.role = role;
+ }
+
+ /**
+ * 登录验证
+ * @param username 用户名
+ * @param password 密码
+ * @return 返回用户对象或null
+ */
+ public static User login(String username, String password) {
+ String[][] users = {
+ {"张三1", "123", "小学"}, {"张三2", "123", "小学"}, {"张三3", "123", "小学"},
+ {"李四1", "123", "初中"}, {"李四2", "123", "初中"}, {"李四3", "123", "初中"},
+ {"王五1", "123", "高中"}, {"王五2", "123", "高中"}, {"王五3", "123", "高中"}
+ };
+
+ for (String[] user : users) {
+ if (user[0].equals(username) && user[1].equals(password)) {
+ return new User(username, password, user[2]);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 获取用户角色
+ * @return 用户角色
+ */
+ public String getRole() {
+ return this.role;
+ }
+
+ /**
+ * 获取用户名
+ * @return 用户名
+ */
+ public String getUsername() {
+ return this.username;
+ }
+}
diff --git a/张三1/2025-09-25-09-36-54.txt b/张三1/2025-09-25-09-36-54.txt
new file mode 100644
index 0000000..87c15ff
--- /dev/null
+++ b/张三1/2025-09-25-09-36-54.txt
@@ -0,0 +1,20 @@
+题号 1: 20 + 66
+
+题号 2: 50 * 87
+
+题号 3: 68 - 11
+
+题号 4: 69 + 56
+
+题号 5: 74 + 30
+
+题号 6: 86 - 48
+
+题号 7: 68 / 41
+
+题号 8: 71 / 49
+
+题号 9: 62 / 41
+
+题号 10: 62 - 51
+
diff --git a/张三1/2025-09-25-09-58-07.txt b/张三1/2025-09-25-09-58-07.txt
new file mode 100644
index 0000000..86f86e3
--- /dev/null
+++ b/张三1/2025-09-25-09-58-07.txt
@@ -0,0 +1,20 @@
+题号 1: 10 - 50
+
+题号 2: 61 * 30
+
+题号 3: 93 * 5
+
+题号 4: 80 / 2
+
+题号 5: 16 - 52
+
+题号 6: 38 + 8
+
+题号 7: 38 - 69
+
+题号 8: 9 * 6
+
+题号 9: 31 - 47
+
+题号 10: 28 * 26
+
diff --git a/张三1/2025-09-25-09-59-54.txt b/张三1/2025-09-25-09-59-54.txt
new file mode 100644
index 0000000..8f35d7e
--- /dev/null
+++ b/张三1/2025-09-25-09-59-54.txt
@@ -0,0 +1,24 @@
+题号 1: 43 - 38
+
+题号 2: 59 - 92
+
+题号 3: 61 - 21
+
+题号 4: 11 / 39
+
+题号 5: 56 * 2
+
+题号 6: 65 - 44
+
+题号 7: 41 + 67
+
+题号 8: 71 / 65
+
+题号 9: 76 - 73
+
+题号 10: 36 - 55
+
+题号 11: 12 + 10
+
+题号 12: 77 / 85
+
diff --git a/张三1/2025-09-28-10-07-54.txt b/张三1/2025-09-28-10-07-54.txt
new file mode 100644
index 0000000..850e79e
--- /dev/null
+++ b/张三1/2025-09-28-10-07-54.txt
@@ -0,0 +1,20 @@
+题号 1: 100 - 61
+
+题号 2: 78 - 41
+
+题号 3: 85 - 72
+
+题号 4: 13 - 52
+
+题号 5: 17 / 38
+
+题号 6: 34 / 8
+
+题号 7: 96 * 45
+
+题号 8: 9 - 89
+
+题号 9: 98 - 50
+
+题号 10: 11 / 65
+
diff --git a/张三1/2025-09-28-10-17-00.txt b/张三1/2025-09-28-10-17-00.txt
new file mode 100644
index 0000000..495a7dc
--- /dev/null
+++ b/张三1/2025-09-28-10-17-00.txt
@@ -0,0 +1,20 @@
+题号 1: 65 / 37
+
+题号 2: 48 / 79
+
+题号 3: 37 - 92
+
+题号 4: 20 / 19
+
+题号 5: 63 * 31
+
+题号 6: 27 / 33
+
+题号 7: 59 + 30
+
+题号 8: 34 + 94
+
+题号 9: 96 * 91
+
+题号 10: 26 * 45
+
diff --git a/王五1/2025-09-25-09-36-42.txt b/王五1/2025-09-25-09-36-42.txt
new file mode 100644
index 0000000..ea98bfe
--- /dev/null
+++ b/王五1/2025-09-25-09-36-42.txt
@@ -0,0 +1,20 @@
+题号 1: tan(45)
+
+题号 2: cos(36)
+
+题号 3: tan(17)
+
+题号 4: cos(49)
+
+题号 5: cos(83)
+
+题号 6: cos(82)
+
+题号 7: cos(82)
+
+题号 8: cos(21)
+
+题号 9: tan(38)
+
+题号 10: tan(84)
+
diff --git a/王五1/2025-09-25-10-00-04.txt b/王五1/2025-09-25-10-00-04.txt
new file mode 100644
index 0000000..6c3f0c5
--- /dev/null
+++ b/王五1/2025-09-25-10-00-04.txt
@@ -0,0 +1,26 @@
+题号 1: cos(59)
+
+题号 2: tan(75)
+
+题号 3: cos(87)
+
+题号 4: cos(67)
+
+题号 5: cos(19)
+
+题号 6: tan(9)
+
+题号 7: cos(65)
+
+题号 8: tan(84)
+
+题号 9: tan(69)
+
+题号 10: sin(83)
+
+题号 11: tan(17)
+
+题号 12: sin(35)
+
+题号 13: cos(37)
+