diff --git a/doc/README.md b/doc/README.md index 3360855..56b990c 100644 --- a/doc/README.md +++ b/doc/README.md @@ -9,31 +9,35 @@ - 支持小学、初中和高中三个级别的用户账号 - 每个级别预设3个账号,密码统一为123 - 登录成功后显示当前选择的出题级别 +- 支持用户退出功能,可重新登录 ### 2. 题目生成功能 - 根据账号类型自动选择对应的难度级别生成题目 - 支持自定义生成题目数量(范围:10-30题) - 操作数范围:1-100 -- 操作数个数:2-5个 +- 操作数个数:1-5个 +- 生成题目时实时显示题目内容 ### 3. 多难度级别支持 -- **小学**:仅包含加减乘除四则运算和括号 -- **初中**:在小学基础上增加平方和开根号运算,且每道题至少包含一个平方或开根号 -- **高中**:在初中基础上增加三角函数(sin、cos、tan),且每道题至少包含一个三角函数 +- **小学**:仅包含加减乘除四则运算和括号,支持随机括号嵌套 +- **初中**:在小学基础上增加平方和开根号运算,题目包含1-5个操作数;若只有1个操作数,则必须是平方或根号表达式;确保每道题至少包含一个平方或开根号 +- **高中**:在初中基础上增加三角函数(sin、cos、tan),题目包含1-5个操作数;若只有1个操作数,则强制为三角函数表达式;确保每道题至少包含一个三角函数 ### 4. 题目类型切换 - 支持在登录状态下切换不同难度级别的题目生成 - 输入格式:`切换为 小学/初中/高中` +- 切换成功后系统清屏并提示新的难度级别 ### 5. 题目查重功能 - 自动检测新生成的题目是否与当前用户历史生成的题目重复 +- 设置最大尝试次数,防止在题库不足时陷入死循环 - 确保每个用户生成的题目都是唯一的 ### 6. 文件保存功能 - 题目以文本文件形式保存 -- 文件名格式:`年-月-日-时-分-秒.txt` -- 每个用户有独立的文件夹存储题目 -- 题目包含题号,每题之间空一行 +- 文件名格式:`yyyy-MM-dd-HH-mm-ss.txt`(基于生成时间) +- 每个用户有独立的文件夹存储题目(文件夹名为用户名) +- 题目包含题号,每题之间空一行,便于阅读 ## 使用说明 @@ -45,11 +49,13 @@ ### 生成题目 1. 登录成功后,系统提示输入题目数量 2. 输入10-30之间的数字生成对应数量的题目 -3. 输入-1退出当前用户,返回登录界面 +3. 系统将显示生成的题目并保存到用户文件夹 +4. 输入-1退出当前用户,返回登录界面 ### 切换难度 - 在任何提示输入题目数量的界面,输入`切换为 小学/初中/高中`即可切换题目难度 - 切换成功后,系统会提示新的难度级别 +- 输入无效时,系统会提示错误信息并保持当前难度 ## 账号列表 @@ -67,7 +73,7 @@ ## 项目结构 ``` -quesproject/ +relentless1/ ├── src/ # 源代码目录 │ ├── Main.java # 程序入口类 │ ├── User.java # 用户类 @@ -81,26 +87,74 @@ quesproject/ │ └── FileUtils.java # 文件操作工具类 ├── doc/ # 文档目录 │ └── README.md # 项目说明文档 -├── [用户名]/ # 用户题目文件夹(运行时自动创建) +└── [用户名]/ # 用户题目文件夹(运行时自动创建) ``` ## 技术实现 ### 设计模式 -- **工厂模式**:通过QuestionStrategyFactory创建不同级别的题目生成策略 -- **策略模式**:通过QuestionStrategy接口及其实现类实现不同难度级别的题目生成 - -### 核心功能实现 -1. **用户验证**:通过预设的账号列表进行验证 -2. **题目生成**:根据不同难度级别使用不同的策略生成题目 -3. **查重功能**:读取用户历史题目文件,确保新生成的题目不重复 -4. **文件管理**:自动创建用户文件夹,按指定格式保存题目文件 +- **策略模式**:通过`QuestionStrategy`接口定义题目生成策略,不同难度级别(小学、初中、高中)实现各自的题目生成算法 +- **工厂模式**:通过`QuestionStrategyFactory`根据用户角色动态创建对应的题目生成策略对象 + +### 核心类功能 + +#### Main.java +- 程序入口,处理用户交互逻辑 +- 实现登录流程、题目数量输入和难度切换功能 +- 包含清屏方法,提升用户体验 + +#### User.java +- 表示用户实体,包含用户名、密码和角色属性 +- 提供静态登录方法,验证用户凭据 +- 用户信息硬编码在程序中,每个角色有3个预设账号 + +#### QuestionGenerator.java +- 根据用户角色使用对应策略生成题目 +- 实现题目查重逻辑,确保题目唯一性 +- 协调策略选择、题目生成和文件保存 + +#### QuestionStrategy.java及其实现类 +- `QuestionStrategy`:定义题目生成的接口 +- `ElementaryQuestionStrategy`:实现小学题目的生成,包含加减乘除和括号 +- `MiddleSchoolQuestionStrategy`:实现初中题目生成,增加平方和开根号运算 +- `HighSchoolQuestionStrategy`:实现高中题目生成,增加三角函数运算 + +#### MathQuestion.java +- 表示单道数学题,包含题号和题目内容 + +#### FileUtils.java +- 提供文件操作工具方法 +- 生成时间戳格式的文件名 +- 保存题目到用户文件夹 +- 加载用户历史题目进行查重 + +### 算法特点 +1. **小学题目**:支持随机括号位置,确保数学表达式的多样性 +2. **初中题目**: + - 题目包含1-5个操作数 + - 若只有1个操作数,则必须是平方或根号表达式 + - 有50%概率生成平方或根号操作数 + - 确保每道题至少有一个平方或开根号运算 +3. **高中题目**: + - 题目包含1-5个操作数 + - 若只有1个操作数,则强制生成三角函数表达式 + - 支持sin、cos、tan三种三角函数 + - 确保每道题至少有一个三角函数 +4. **查重机制**:使用HashSet高效检测重复题目,设置最大尝试次数避免死循环 ## 运行环境 - Java 8及以上版本 -- 支持Windows、Linux、macOS等操作系统 +- 支持Windows和Linux操作系统(清屏功能自适应) + +## 扩展建议 +1. 添加自定义操作数范围和运算符的功能 +2. 实现题目答案自动计算功能 +3. 支持更多类型的数学表达式和运算符号 +4. 添加图形用户界面,提升用户体验 +5. 实现用户注册和密码修改功能 +6. 支持题目导入导出功能 -## 编译运行 +## 编译与运行 1. 编译:`javac -d out src/*.java` 2. 运行:`java -cp out Main` diff --git a/src/HighSchoolQuestionStrategy.java b/src/HighSchoolQuestionStrategy.java index 7709e08..e5f3527 100644 --- a/src/HighSchoolQuestionStrategy.java +++ b/src/HighSchoolQuestionStrategy.java @@ -2,47 +2,89 @@ import java.util.Random; /** * 高中题目生成策略实现类。 - *
- * 随机生成包含基本运算和三角函数的数学表达式。 + * + *
随机生成包含基本运算符和三角函数的数学表达式。 + * 操作数数量范围为 1–5;当只有 1 个操作数时,表达式必定包含三角函数。
*/ public class HighSchoolQuestionStrategy implements QuestionStrategy { + + /** 基本四则运算符。 */ private static final String[] BASIC_OPS = {"+", "-", "*", "/"}; + + /** 支持的三角函数。 */ private static final String[] TRIG_FUNCS = {"sin", "cos", "tan"}; + /** 随机数生成器。 */ private final Random random = new Random(); + /** + * 生成随机高中数学题。 + * + * @return 包含至少一个三角函数的数学表达式字符串 + */ @Override public String generateQuestion() { - // 随机操作数个数:2~5 - int operandsCount = random.nextInt(4) + 2; - StringBuilder sb = new StringBuilder(); + // 操作数个数:1~5 + int operandsCount = random.nextInt(5) + 1; + StringBuilder expression = new StringBuilder(); boolean hasTrig = false; - for (int i = 0; i < operandsCount; i++) { - int num = random.nextInt(100) + 1; + // 仅一个操作数时,强制生成一个三角函数表达式 + if (operandsCount == 1) { + return buildTrigOperand(); + } - // 每个操作数有概率带三角函数 - if (random.nextBoolean()) { - String func = TRIG_FUNCS[random.nextInt(TRIG_FUNCS.length)]; - sb.append(func).append("(").append(num).append(")"); + // 生成多个操作数与运算符 + for (int i = 0; i < operandsCount; i++) { + String operand = buildOperand(); + expression.append(operand); + if (operand.matches(".*(sin|cos|tan).*")) { hasTrig = true; - } else { - sb.append(num); } + // 添加运算符(除最后一个操作数外) if (i != operandsCount - 1) { - String op = BASIC_OPS[random.nextInt(BASIC_OPS.length)]; - sb.append(" ").append(op).append(" "); + expression.append(' ') + .append(BASIC_OPS[random.nextInt(BASIC_OPS.length)]) + .append(' '); } } // 确保至少包含一个三角函数 if (!hasTrig) { - String func = TRIG_FUNCS[random.nextInt(TRIG_FUNCS.length)]; - int num = random.nextInt(100) + 1; - return func + "(" + num + ") + " + sb; + expression.append(" + ").append(buildTrigOperand()); + } + + return expression.toString(); + } + + /** + * 随机生成一个操作数,可为普通数字或三角函数表达式。 + */ + private String buildOperand() { + int num = random.nextInt(100) + 1; + if (random.nextBoolean()) { + return buildTrigOperandWithNumber(num); } + return String.valueOf(num); + } + + /** + * 随机生成一个仅包含三角函数的操作数。 + */ + private String buildTrigOperand() { + int num = random.nextInt(100) + 1; + return buildTrigOperandWithNumber(num); + } - return sb.toString(); + /** + * 生成指定数字的三角函数操作数。 + * + * @param number 角度值(1~100) + * @return 形如 sin(45) 的字符串 + */ + private String buildTrigOperandWithNumber(int number) { + String func = TRIG_FUNCS[random.nextInt(TRIG_FUNCS.length)]; + return func + "(" + number + ")"; } } diff --git a/src/MiddleSchoolQuestionStrategy.java b/src/MiddleSchoolQuestionStrategy.java index 629cabe..f53c7c0 100644 --- a/src/MiddleSchoolQuestionStrategy.java +++ b/src/MiddleSchoolQuestionStrategy.java @@ -1,50 +1,78 @@ import java.util.Random; /** - * 初中数学题策略实现类。用于生成包含平方和根号的数学题目。 + * 初中数学题策略实现类。 + *用于生成包含平方和根号运算的随机数学题。
*/ public class MiddleSchoolQuestionStrategy implements QuestionStrategy { - private final Random random = new Random(); - private final String[] basicOps = {"+", "-", "*", "/"}; + /** 随机数生成器,生成操作数和运算符索引 */ + private static final Random RANDOM = new Random(); + + /** 基本运算符集合 */ + private static final String[] BASIC_OPS = {"+", "-", "*", "/"}; + + /** + * 生成一条随机数学题。 + *题目包含 1–5 个操作数;若只有 1 个操作数,则必须是平方或根号表达式。
+ * + * @return 随机生成的数学题字符串 + */ @Override public String generateQuestion() { - // 随机操作数个数 2-5。 - int operandsCount = random.nextInt(4) + 2; + int operandsCount = RANDOM.nextInt(5) + 1; // 操作数个数 1–5 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(")"); + // 若只有一个操作数,则直接生成平方或根号表达式 + if (operandsCount == 1) { + sb.append(generateSquareOrRoot()); + } else { + // 多个操作数:依次生成操作数和运算符 + for (int i = 0; i < operandsCount; i++) { + String operand = generateOperand(); + sb.append(operand); + if (operand.contains("^2") || operand.contains("√")) { hasSquareOrRoot = true; } - } else { - sb.append(num); - } - - // 添加运算符(除最后一个操作数外)。 - if (i != operandsCount - 1) { - String op = basicOps[random.nextInt(basicOps.length)]; - sb.append(" ").append(op).append(" "); + if (i != operandsCount - 1) { + sb.append(" ").append(BASIC_OPS[RANDOM.nextInt(4)]).append(" "); + } } } - // 如果没有平方或根号,强制添加一个。 + // 如果多操作数情况下没有出现平方或根号,强制追加一个根号项 if (!hasSquareOrRoot) { - int rootNumber = random.nextInt(100) + 1; - sb.append(" + √(").append(rootNumber).append(")"); + sb.append(" + ").append(generateSquareOrRoot()); } + return sb.toString(); } + + /** + * 生成一个随机操作数。 + *有 50% 概率为普通数字,50% 概率为平方或根号表达式。
+ * + * @return 操作数字符串 + */ + private String generateOperand() { + int num = RANDOM.nextInt(100) + 1; + if (RANDOM.nextBoolean()) { + return RANDOM.nextBoolean() + ? "(" + num + ")^2" + : "√(" + (RANDOM.nextInt(100) + 1) + ")"; + } + return String.valueOf(num); + } + + /** + * 强制生成一个平方或根号表达式。 + * + * @return 平方或根号的字符串 + */ + private String generateSquareOrRoot() { + return RANDOM.nextBoolean() + ? "(" + (RANDOM.nextInt(100) + 1) + ")^2" + : "√(" + (RANDOM.nextInt(100) + 1) + ")"; + } }