diff --git a/doc/README.md b/doc/README.md index 1a13ba3..c38307f 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,279 +1,259 @@ -# Demo1 - -# 数学学习系统 - 核心业务逻辑模块文档 +# 数学学习软件 - 核心计算与题目生成模块 ## 模块概述 -本模块是数学学习系统的核心业务逻辑部分,负责所有数学题目的生成、计算、数据管理和用户模型定义。该模块提供了完整的题目生命周期管理,从生成、计算到存储和去重检查。 +本模块是数学学习软件的核心计算引擎,负责数学题目的生成、表达式计算、题目管理和数据存储等功能。该模块采用面向对象的设计理念,提供了完整的数学题目生成和计算解决方案。 -## 系统架构 +## 功能架构 -### 核心类设计 +### 1. 核心计算引擎 -| 类名 | 职责描述 | -| ------------------------ | -------------------------------------------------------- | -| `ExpressionEvaluator` | 数学表达式计算器,支持四则运算、平方、开根号、三角函数等 | -| `MathQuestion` | 基础数学题目数据模型,存储表达式和答案 | -| `MathQuestionGenerator` | 智能题目生成器,根据难度级别生成不同类型题目 | -| `MultipleChoiceQuestion` | 选择题数据模型,包含题目、选项和正确答案 | -| `QuestionManager` | 题目管理器,负责重复检查和文件保存 | -| `User` | 基础用户模型,存储用户名、密码和账户类型 | -| `RegisteredUser` | 注册用户模型,扩展基础用户,增加邮箱验证功能 | +#### 主要类: -### 类关系图 +#### **ExpressionEvaluator.java** - 数学表达式计算器 +```java +public class ExpressionEvaluator { + public static double evaluate(String expression) { + // 计算数学表达式的值 + } + + public static String[] generateWrongAnswers(double correctAnswer, int count) { + // 生成错误答案选项 + } +} ``` -User (基础) - ↑ -RegisteredUser (扩展) - ↓ -MathQuestionGenerator → MathQuestion → ExpressionEvaluator - ↓ -MultipleChoiceQuestion - ↓ -QuestionManager (文件存储 & 去重检查) -``` - -## 功能特性 -### 1. 多难度题目生成 +**功能说明:** +- 支持四则运算、括号优先级计算 +- 处理平方(²)、开根号(√)运算 +- 三角函数计算(sin、cos、tan) +- 表达式语法验证和错误处理 +- 智能生成干扰错误答案 -**小学题目特征:** -- 基础四则运算(+、-、*、/) -- 支持括号优先级 -- 操作数范围:1-100 -- 操作符数量:1-4个 +**技术特点:** +- 递归下降解析器实现表达式解析 +- 支持运算符优先级处理 +- 自动格式化答案显示(整数去小数位) -**初中题目特征:** -- 包含小学所有功能 -- 增加平方运算(²) -- 增加开根号运算(√) -- 使用完全平方数确保计算结果合理 +### 2. 题目生成系统 -**高中题目特征:** -- 包含初中所有功能 -- 增加三角函数(sin、cos、tan) -- 角度范围:0-359度 -- 自动转换为弧度计算 +#### 主要类: -### 2. 智能表达式计算 +#### **MathQuestionGenerator.java** - 题目生成器 -**支持的运算类型:** -- 基本运算:加减乘除 -- 高级运算:平方、开方 -- 三角函数:sin、cos、tan(支持角度制) -- 括号优先级处理 - -**计算特性:** -- 自动预处理表达式(移除空格、转换符号) -- 递归下降解析算法 -- 容错处理,计算失败时返回随机值 -- 答案格式化(整数或保留两位小数) - -### 3. 选择题生成系统 - -**选项生成策略:** ```java -// 错误答案生成算法 -public static String[] generateWrongAnswers(double correctAnswer, int count) +public class MathQuestionGenerator { + public List generateQuestions(String accountType, int count) { + // 根据账户类型生成题目 + } +} ``` -**错误答案类型:** -- 加减随机偏移:`correctAnswer ± random(1-10)` -- 乘以随机系数:`correctAnswer * (0.5-1.5)` -- 除以随机系数:`correctAnswer / (1.5-3.5)` -- 完全随机数值:`random(1-100)` +**功能说明:** +- **小学题目**:基础四则运算,支持括号,1-4个操作符 +- **初中题目**:包含平方和开根号运算,1-5个操作数 +- **高中题目**:包含三角函数运算,1-5个操作数 -### 4. 高级去重机制 +**生成算法:** +- 随机操作符和操作数生成 +- 智能括号添加,避免语法错误 +- 题目复杂度控制 +- 特殊运算符号的合理分布 -**双重检查系统:** -- 内存中当前会话题目检查 -- 用户历史题目文件扫描 -- 基于表达式内容的精确匹配 - -**文件管理:** -- 按账户类型分目录存储(小学/初中/高中) -- 时间戳命名:`yyyy-MM-dd-HH-mm-ss.txt` -- 自动目录创建和维护 - -## 核心算法说明 - -### 题目生成算法 +#### **MathQuestion.java** - 数学题目类 ```java -// 小学题目生成 -private MathQuestion generateElementaryQuestion() { - // 生成1-4个操作符的表达式 - // 可能添加括号 -} - -// 初中题目生成 -private MathQuestion generateMiddleSchoolQuestion() { - // 基础运算 + 平方/开根号 -} - -// 高中题目生成 -private MathQuestion generateHighSchoolQuestion() { - // 基础运算 + 三角函数 +public class MathQuestion { + private String expression; + private String answer; + // 题目表达式和答案存储 } ``` -### 表达式计算算法 +#### **MultipleChoiceQuestion.java** - 选择题类 ```java -// 递归下降解析器 -private static double evaluateExpression(String expr) { - // 处理加法、减法、乘法、除法 - // 处理括号表达式 - // 处理特殊函数(pow、sqrt、三角函数) +public class MultipleChoiceQuestion { + private String question; + private String[] options; + private int correctAnswer; + // 选择题管理和验证 } ``` -### 去重管理算法 +### 3. 题目管理系统 -```java -public List checkAndRemoveDuplicates(String accountType, - List newQuestions) { - // 与历史题目对比 - // 返回去重后的题目列表 -} -``` +#### 主要类: -## 数据模型定义 +#### **QuestionManager.java** - 题目管理器 -### MathQuestion 模型 ```java -public class MathQuestion { - private String expression; // 数学表达式 - private String answer; // 计算结果 - // 支持equals/hashCode基于expression +public class QuestionManager { + public List generateUniqueQuestions(String accountType, int count, + MathQuestionGenerator generator) { + // 生成不重复题目 + } + + public String saveQuestionsToFile(String accountType, List questions) { + // 保存题目到文件 + } } ``` -### MultipleChoiceQuestion 模型 -```java -public class MultipleChoiceQuestion { - private String question; // 问题描述 - private String[] options; // 4个选项 - private int correctAnswer; // 正确答案索引(0-3) - private String explanation; // 解析说明 -} -``` +**功能说明:** +- 题目重复性检查 +- 文件系统管理(按学段分类存储) +- 历史题目加载和去重 +- 智能题目生成(避免重复) + +**文件管理:** +- 自动创建小学、初中、高中目录 +- 时间戳文件名格式:`yyyy-MM-dd-HH-mm-ss.txt` +- 题目编号和格式化存储 + +### 4. 用户数据模型 + +#### 主要类: + +#### **User.java** - 基础用户类 -### 用户模型体系 ```java -// 基础用户 public class User { private String username; - private String password; - private String accountType; // 小学、初中、高中 -} - -// 注册用户(扩展) -public class RegisteredUser { - private String email; private String password; - private String verificationCode; - private boolean isVerified; + private String accountType; // 小学、初中、高中 + // 用户信息和权限管理 } ``` -## 技术特色 +## 技术实现 -### 1. 算法精确性 -- 数学表达式解析准确 -- 三角函数角度转弧度计算 -- 完全平方数开根号确保整数结果 -- 浮点数精度控制(0.001容差) +### 表达式计算算法 -### 2. 性能优化 -- 题目生成批量处理 -- 历史题目一次性加载 -- HashSet快速去重检查 -- 文件操作异步处理 +1. **预处理阶段**: + - 移除空格,统一格式 + - 替换特殊符号(²→平方计算,√→开根号) + - 三角函数角度转弧度计算 -### 3. 扩展性设计 -- 支持添加新的数学运算类型 -- 题目难度级别可配置 -- 文件存储格式标准化 -- 用户模型可扩展 +2. **解析阶段**: + - 递归下降解析器处理运算符优先级 + - 支持嵌套括号表达式 + - 错误处理和边界条件检查 -### 4. 健壮性保障 -- 表达式计算异常处理 -- 文件操作错误恢复 -- 内存泄漏防护 -- 并发访问安全 +3. **计算阶段**: + - 加减法(最低优先级) + - 乘除法(中等优先级) + - 因子解析(数字和括号表达式) -## API 接口说明 +### 题目生成策略 -### 题目生成接口 +#### 小学题目生成: ```java -// 生成指定数量和难度的题目 -List generateQuestions(String accountType, int count) - -// 生成选择题 -List generateQuestions(String difficulty, int count, - MathQuestionGenerator generator) +private MathQuestion generateElementaryQuestion() { + // 生成1-4个操作符的基础运算 + // 可能添加括号增强复杂度 +} ``` -### 计算器接口 +#### 初中题目生成: ```java -// 计算数学表达式 -double evaluate(String expression) - -// 生成错误答案选项 -String[] generateWrongAnswers(double correctAnswer, int count) +private MathQuestion generateMiddleSchoolQuestion() { + // 至少包含一个平方或开根号运算 + // 1-5个操作数的复杂表达式 +} ``` -### 文件管理接口 +#### 高中题目生成: ```java -// 保存题目到文件 -String saveQuestionsToFile(String accountType, List questions) - -// 生成不重复题目 -List generateUniqueQuestions(String accountType, int requestedCount, - MathQuestionGenerator generator) +private MathQuestion generateHighSchoolQuestion() { + // 至少包含一个三角函数运算 + // 角度计算和复杂表达式组合 +} ``` -## 使用示例 +### 错误答案生成算法 -### 生成小学题目 ```java -MathQuestionGenerator generator = new MathQuestionGenerator(); -List questions = generator.generateQuestions("小学", 10); +public static String[] generateWrongAnswers(double correctAnswer, int count) { + // 类型1:加减随机数干扰 + // 类型2:乘以小数干扰 + // 类型3:除以数字干扰 + // 类型4:完全随机数值 +} ``` -### 计算表达式 -```java -double result = ExpressionEvaluator.evaluate("3 + 5 × (10 - 2)"); -``` +## 数据设计 -### 管理题目文件 -```java -QuestionManager manager = new QuestionManager(); -List uniqueQuestions = manager.generateUniqueQuestions("初中", 20, generator); -String filename = manager.saveQuestionsToFile("初中", uniqueQuestions); +### 内存数据结构 +- `Map> userQuestions` - 用户历史题目存储 +- `List` - 题目列表管理 +- `Set` - 题目去重检查 + +### 文件存储结构 +``` +小学/ + 2024-01-15-10-30-25.txt +初中/ + 2024-01-15-11-15-40.txt +高中/ + 2024-01-15-14-20-35.txt ``` -## 依赖关系 +## 接口设计 -- **内部依赖**:无外部依赖,纯Java实现 -- **JDK要求**:Java 8+ -- **文件系统**:需要读写权限用于题目存储 -- **内存要求**:根据题目数量动态调整 +### 对外提供的主要方法 -## 扩展指南 +1. **题目生成接口**: + ```java + List generateQuestions(String accountType, int count) + ``` -### 添加新的运算类型 -1. 在`ExpressionEvaluator`中添加预处理规则 -2. 在`evaluateExpression`方法中添加解析逻辑 -3. 在`MathQuestionGenerator`中集成到题目生成 +2. **表达式计算接口**: + ```java + double evaluate(String expression) + ``` -### 添加新的难度级别 -1. 在`MathQuestionGenerator`中添加新的生成方法 -2. 更新题目生成策略调用 -3. 在`QuestionManager`中创建对应的存储目录 +3. **选择题生成接口**: + ```java + MultipleChoiceQuestion createMultipleChoice(MathQuestion mathQuestion) + ``` + +4. **文件管理接口**: + ```java + String saveQuestions(String accountType, List questions) + ``` + +## 质量保证 + +### 输入验证 +- 表达式语法检查 +- 括号匹配验证 +- 数字格式验证 +- 运算符位置验证 + +### 错误处理 +- 数学计算异常捕获 +- 文件IO异常处理 +- 内存越界保护 +- 无效输入提示 + +### 性能优化 +- 题目去重算法优化 +- 表达式计算性能提升 +- 文件读写批量处理 +- 内存使用效率优化 + +## 扩展性设计 + +### 可扩展的题目类型 +- 支持添加新的数学运算类型 +- 可配置的题目难度参数 +- 模块化的题目生成策略 ---- +### 接口标准化 +- 统一的题目数据格式 +- 标准化的计算接口 +- 灵活的文件存储方案 -*本核心模块为数学学习系统提供坚实的基础,确保题目生成的准确性、多样性和可管理性。* \ No newline at end of file +该核心模块为整个数学学习软件提供了稳定可靠的数学计算和题目生成能力,采用模块化设计便于维护和扩展,为上层用户界面提供了完整的数学题目处理解决方案。 \ No newline at end of file diff --git a/src/ExpressionEvaluator.java b/src/ExpressionEvaluator.java index 90b682b..18dbeeb 100644 --- a/src/ExpressionEvaluator.java +++ b/src/ExpressionEvaluator.java @@ -11,119 +11,211 @@ public class ExpressionEvaluator { */ public static double evaluate(String expression) { try { - // 预处理表达式 + // 预处理表达式:处理特殊符号 expression = preprocessExpression(expression); - // 使用递归下降解析器计算 - return evaluateExpression(expression); + // 使用栈和递归下降解析器计算 + return parseExpression(expression); } catch (Exception e) { - // 如果计算失败,返回一个随机值作为示例 - return new Random().nextInt(100) + 1; + System.err.println("计算表达式失败: " + expression + " - " + e.getMessage()); + e.printStackTrace(); + return 0; } } /** - * 预处理表达式 + * 预处理表达式:将特殊符号转换为可计算的形式 */ private static String preprocessExpression(String expr) { - // 移除空格 + // 移除所有空格 expr = expr.replaceAll("\\s+", ""); - // 处理平方符号 - expr = expr.replaceAll("(\\d+)²", "pow($1,2)"); + // 处理三角函数:sin(30°) -> 计算实际值 + expr = replaceTrigFunctions(expr); - // 处理开根号 - expr = expr.replaceAll("√(\\d+)", "sqrt($1)"); + // 处理平方符号:5² -> (5*5) + expr = replaceSquares(expr); - // 处理三角函数(转换为弧度) - expr = expr.replaceAll("sin\\((\\d+)°\\)", "sin(Math.toRadians($1))"); - expr = expr.replaceAll("cos\\((\\d+)°\\)", "cos(Math.toRadians($1))"); - expr = expr.replaceAll("tan\\((\\d+)°\\)", "tan(Math.toRadians($1))"); + // 处理开根号:√25 -> 5 + expr = replaceSqrts(expr); return expr; } /** - * 简化的表达式计算 + * 替换三角函数为实际计算值 */ - private static double evaluateExpression(String expr) { - // 处理简单的数学运算 - if (expr.matches("\\d+")) { - return Double.parseDouble(expr); - } + private static String replaceTrigFunctions(String expr) { + // 处理 sin(角度°) + expr = replaceFunction(expr, "sin"); + // 处理 cos(角度°) + expr = replaceFunction(expr, "cos"); + // 处理 tan(角度°) + expr = replaceFunction(expr, "tan"); + + return expr; + } + + /** + * 替换单个三角函数 + */ + private static String replaceFunction(String expr, String funcName) { + String pattern = funcName + "\\((\\d+)°\\)"; + java.util.regex.Pattern p = java.util.regex.Pattern.compile(pattern); + java.util.regex.Matcher m = p.matcher(expr); - // 处理加法 - if (expr.contains("+")) { - String[] parts = expr.split("\\+"); + StringBuffer sb = new StringBuffer(); + while (m.find()) { + int degrees = Integer.parseInt(m.group(1)); + double radians = Math.toRadians(degrees); double result = 0; - for (String part : parts) { - result += evaluateExpression(part.trim()); + + switch (funcName) { + case "sin": + result = Math.sin(radians); + break; + case "cos": + result = Math.cos(radians); + break; + case "tan": + result = Math.tan(radians); + break; } - return result; + + // 替换为括号包裹的数值 + m.appendReplacement(sb, "(" + result + ")"); } + m.appendTail(sb); - // 处理减法 - if (expr.contains("-") && !expr.startsWith("-")) { - int lastMinus = expr.lastIndexOf("-"); - String left = expr.substring(0, lastMinus); - String right = expr.substring(lastMinus + 1); - return evaluateExpression(left) - evaluateExpression(right); + return sb.toString(); + } + + /** + * 替换平方符号 + */ + private static String replaceSquares(String expr) { + java.util.regex.Pattern p = java.util.regex.Pattern.compile("(\\d+)²"); + java.util.regex.Matcher m = p.matcher(expr); + + StringBuffer sb = new StringBuffer(); + while (m.find()) { + int num = Integer.parseInt(m.group(1)); + int result = num * num; + m.appendReplacement(sb, String.valueOf(result)); } + m.appendTail(sb); - // 处理乘法 - if (expr.contains("*")) { - String[] parts = expr.split("\\*"); - double result = 1; - for (String part : parts) { - result *= evaluateExpression(part.trim()); + return sb.toString(); + } + + /** + * 替换开根号 + */ + private static String replaceSqrts(String expr) { + java.util.regex.Pattern p = java.util.regex.Pattern.compile("√(\\d+)"); + java.util.regex.Matcher m = p.matcher(expr); + + StringBuffer sb = new StringBuffer(); + while (m.find()) { + int num = Integer.parseInt(m.group(1)); + double result = Math.sqrt(num); + m.appendReplacement(sb, String.valueOf(result)); + } + m.appendTail(sb); + + return sb.toString(); + } + + /** + * 解析并计算表达式(支持运算符优先级) + */ + private static double parseExpression(String expr) { + return parseAddSubtract(expr, new int[]{0}); + } + + /** + * 解析加减法(最低优先级) + */ + private static double parseAddSubtract(String expr, int[] pos) { + double left = parseMultiplyDivide(expr, pos); + + while (pos[0] < expr.length()) { + char op = expr.charAt(pos[0]); + if (op == '+' || op == '-') { + pos[0]++; + double right = parseMultiplyDivide(expr, pos); + if (op == '+') { + left += right; + } else { + left -= right; + } + } else { + break; } - return result; } - // 处理除法 - if (expr.contains("/")) { - int lastDiv = expr.lastIndexOf("/"); - String left = expr.substring(0, lastDiv); - String right = expr.substring(lastDiv + 1); - double rightValue = evaluateExpression(right); - if (rightValue != 0) { - return evaluateExpression(left) / rightValue; + return left; + } + + /** + * 解析乘除法(中等优先级) + */ + private static double parseMultiplyDivide(String expr, int[] pos) { + double left = parseFactor(expr, pos); + + while (pos[0] < expr.length()) { + char op = expr.charAt(pos[0]); + if (op == '*' || op == '/') { + pos[0]++; + double right = parseFactor(expr, pos); + if (op == '*') { + left *= right; + } else { + if (right != 0) { + left /= right; + } + } + } else { + break; } } + return left; + } + + /** + * 解析因子(数字或括号表达式) + */ + private static double parseFactor(String expr, int[] pos) { + // 跳过空格 + while (pos[0] < expr.length() && expr.charAt(pos[0]) == ' ') { + pos[0]++; + } + // 处理括号 - if (expr.contains("(")) { - int start = expr.lastIndexOf("("); - int end = expr.indexOf(")", start); - String inner = expr.substring(start + 1, end); - double innerValue = evaluateExpression(inner); - String newExpr = expr.substring(0, start) + innerValue + expr.substring(end + 1); - return evaluateExpression(newExpr); - } - - // 处理特殊函数 - if (expr.startsWith("pow(")) { - // 简化处理:假设是 pow(x,2) 的形式 - String inner = expr.substring(4, expr.length() - 1); - String[] parts = inner.split(","); - if (parts.length == 2) { - double base = Double.parseDouble(parts[0]); - double exp = Double.parseDouble(parts[1]); - return Math.pow(base, exp); - } + if (pos[0] < expr.length() && expr.charAt(pos[0]) == '(') { + pos[0]++; // 跳过 '(' + double result = parseAddSubtract(expr, pos); + pos[0]++; // 跳过 ')' + return result; } - if (expr.startsWith("sqrt(")) { - String inner = expr.substring(5, expr.length() - 1); - return Math.sqrt(Double.parseDouble(inner)); + // 处理负号 + boolean negative = false; + if (pos[0] < expr.length() && expr.charAt(pos[0]) == '-') { + negative = true; + pos[0]++; } - // 默认返回解析的数字 - try { - return Double.parseDouble(expr); - } catch (NumberFormatException e) { - return new Random().nextInt(50) + 1; + // 解析数字 + int start = pos[0]; + while (pos[0] < expr.length() && + (Character.isDigit(expr.charAt(pos[0])) || expr.charAt(pos[0]) == '.')) { + pos[0]++; } + + double value = Double.parseDouble(expr.substring(start, pos[0])); + return negative ? -value : value; } /** @@ -174,4 +266,59 @@ public class ExpressionEvaluator { return String.format("%.2f", answer); } } + + /** + * 验证表达式语法是否正确 + */ + public static boolean isValidMathExpression(String expression) { + // 基本语法检查 + if (expression == null || expression.trim().isEmpty()) { + return false; + } + + // 检查括号匹配 + int balance = 0; + for (char c : expression.toCharArray()) { + if (c == '(') balance++; + if (c == ')') balance--; + if (balance < 0) return false; + } + if (balance != 0) return false; + + // 检查运算符位置 + String[] tokens = expression.split("\\s+"); + for (int i = 0; i < tokens.length; i++) { + String token = tokens[i]; + + // 检查连续的运算符 + if (isOperator(token) && i > 0 && isOperator(tokens[i-1])) { + return false; + } + + // 检查数字后面直接跟左括号 + if (i > 0 && isNumber(token) && i < tokens.length - 1 && "(".equals(tokens[i+1])) { + return false; + } + + // 检查右括号后面直接跟数字 + if (i > 0 && ")".equals(token) && i < tokens.length - 1 && isNumber(tokens[i+1])) { + return false; + } + } + + return true; + } + + private static boolean isOperator(String token) { + return "+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token); + } + + private static boolean isNumber(String str) { + try { + Double.parseDouble(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } } diff --git a/src/MathQuestionGenerator.java b/src/MathQuestionGenerator.java index c16ccc6..02b1784 100644 --- a/src/MathQuestionGenerator.java +++ b/src/MathQuestionGenerator.java @@ -8,11 +8,11 @@ public class MathQuestionGenerator { private Random random; private String[] operators = {"+", "-", "*", "/"}; private String[] trigFunctions = {"sin", "cos", "tan"}; - + public MathQuestionGenerator() { this.random = new Random(); } - + /** * 根据账户类型生成题目 * @param accountType 账户类型(小学、初中、高中) @@ -21,7 +21,7 @@ public class MathQuestionGenerator { */ public List generateQuestions(String accountType, int count) { List questions = new ArrayList<>(); - + for (int i = 0; i < count; i++) { MathQuestion question; switch (accountType) { @@ -39,10 +39,10 @@ public class MathQuestionGenerator { } questions.add(question); } - + return questions; } - + /** * 生成小学题目:只能有+、-、*、/和() */ @@ -50,78 +50,136 @@ public class MathQuestionGenerator { int operatorCount = random.nextInt(4) + 1; // 1-4个操作符 List numbers = new ArrayList<>(); List ops = new ArrayList<>(); - + // 生成数字(1-100) for (int i = 0; i <= operatorCount; i++) { numbers.add(random.nextInt(100) + 1); } - + // 生成操作符 for (int i = 0; i < operatorCount; i++) { ops.add(operators[random.nextInt(operators.length)]); } - + // 构建表达式 StringBuilder expression = new StringBuilder(); expression.append(numbers.get(0)); - + for (int i = 0; i < operatorCount; i++) { expression.append(" ").append(ops.get(i)).append(" ").append(numbers.get(i + 1)); } - + // 可能添加括号 if (operatorCount >= 2 && random.nextBoolean()) { expression = addParentheses(expression.toString()); } - + return new MathQuestion(expression.toString(), "计算结果"); } - + /** - * 生成初中题目:至少有一个平方或开根号运算符 + * 生成初中题目:1-5个操作数,且至少有一个平方或开根号运算 */ private MathQuestion generateMiddleSchoolQuestion() { StringBuilder expression = new StringBuilder(); - - // 基础部分 - int num1 = random.nextInt(50) + 1; - String op = operators[random.nextInt(operators.length)]; - - expression.append(num1).append(" ").append(op).append(" "); - - // 添加平方或开根号 - if (random.nextBoolean()) { - // 添加平方 - int baseNum = random.nextInt(20) + 1; - expression.append(baseNum).append("²"); - } else { - // 添加开根号 - int sqrtNum = getRandomPerfectSquare(); - expression.append("√").append(sqrtNum); - } - + + // 总共1-5个操作数 + int totalOperandCount = random.nextInt(5) + 1; // 1-5个操作数 + + // 生成所有操作数(1-100范围) + List numbers = new ArrayList<>(); + for (int i = 0; i < totalOperandCount; i++) { + numbers.add(random.nextInt(100) + 1); + } + + // 随机选择一个位置插入平方或开根号运算 + int specialOpIndex = random.nextInt(totalOperandCount); + + // 构建表达式 + for (int i = 0; i < totalOperandCount; i++) { + // 添加运算符(除了第一个元素) + if (expression.length() > 0) { + expression.append(" ").append(operators[random.nextInt(operators.length)]).append(" "); + } + + // 判断是否在当前位置插入特殊运算 + if (i == specialOpIndex) { + // 随机选择平方或开根号 + if (random.nextBoolean()) { + // 添加平方 + expression.append(numbers.get(i)).append("²"); + } else { + // 添加开根号 + int sqrtNum = getRandomPerfectSquare(); + expression.append("√").append(sqrtNum); + } + } else { + // 普通数字 + expression.append(numbers.get(i)); + } + } + + // 可能添加括号 + if (totalOperandCount >= 3 && random.nextBoolean()) { + StringBuilder withParentheses = addParentheses(expression.toString()); + if (isValidExpression(withParentheses.toString())) { + return new MathQuestion(withParentheses.toString(), "计算结果"); + } + } + return new MathQuestion(expression.toString(), "计算结果"); } - + /** * 生成高中题目:至少有一个sin、cos或tan运算符 + * 包含1-5个操作数(1-100范围的数字) */ private MathQuestion generateHighSchoolQuestion() { StringBuilder expression = new StringBuilder(); - - // 基础部分 - int num1 = random.nextInt(100) + 1; - String op = operators[random.nextInt(operators.length)]; - - // 添加三角函数 + + // 总共1-5个操作数(包括三角函数的角度) + int totalOperandCount = random.nextInt(5) + 1; // 1-5个操作数 + + // 生成所有操作数(1-100范围) + List numbers = new ArrayList<>(); + for (int i = 0; i < totalOperandCount; i++) { + numbers.add(random.nextInt(100) + 1); + } + + // 随机选择一个数字作为三角函数的角度 + int trigAngleIndex = random.nextInt(totalOperandCount); + int trigAngle = numbers.get(trigAngleIndex); + + // 生成三角函数 String trigFunc = trigFunctions[random.nextInt(trigFunctions.length)]; - int angle = random.nextInt(360); // 0-359度 - - expression.append(num1).append(" ").append(op).append(" ").append(trigFunc).append("(").append(angle).append("°)"); - + String trigExpression = trigFunc + "(" + trigAngle + "°)"; + + // 构建表达式 + for (int i = 0; i < totalOperandCount; i++) { + // 添加运算符(除了第一个元素) + if (expression.length() > 0) { + expression.append(" ").append(operators[random.nextInt(operators.length)]).append(" "); + } + + // 判断当前位置是否为三角函数角度位置 + if (i == trigAngleIndex) { + expression.append(trigExpression); + } else { + expression.append(numbers.get(i)); + } + } + + // 可能添加括号 + if (totalOperandCount >= 3 && random.nextDouble() < 0.3) { + StringBuilder withParentheses = addParenthesesForHighSchool(expression.toString()); + if (isValidExpression(withParentheses.toString())) { + return new MathQuestion(withParentheses.toString(), "计算结果"); + } + } + return new MathQuestion(expression.toString(), "计算结果"); } - + /** * 为表达式添加括号 */ @@ -137,7 +195,114 @@ public class MathQuestionGenerator { } return new StringBuilder(expression); } - + + /** + * 为高中题目表达式智能添加括号 + */ + private StringBuilder addParenthesesForHighSchool(String expression) { + String[] parts = expression.split(" "); + if (parts.length < 5) { + return new StringBuilder(expression); + } + + // 避免在三角函数内部添加括号 + for (String part : parts) { + if (part.contains("sin") || part.contains("cos") || part.contains("tan")) { + return new StringBuilder(expression); + } + } + + // 智能选择括号位置 + StringBuilder result = new StringBuilder(); + + // 找到可以添加括号的安全位置 + List safePositions = new ArrayList<>(); + for (int i = 1; i < parts.length - 2; i += 2) { + if (isSafeForParentheses(parts, i)) { + safePositions.add(i); + } + } + + if (safePositions.isEmpty()) { + return new StringBuilder(expression); + } + + int parenStartIndex = safePositions.get(random.nextInt(safePositions.size())); + int parenLength = 2 + random.nextInt(Math.min(4, parts.length - parenStartIndex - 1)); + + // 构建带括号的表达式 + for (int i = 0; i < parts.length; i++) { + if (i == parenStartIndex) { + result.append("("); + } + result.append(parts[i]); + if (i == parenStartIndex + parenLength - 1) { + result.append(")"); + } + if (i < parts.length - 1) { + result.append(" "); + } + } + + return result; + } + + /** + * 检查在指定位置添加括号是否安全 + */ + private boolean isSafeForParentheses(String[] parts, int position) { + // 检查不会产生像 "6(" 这样的错误模式 + if (position > 0 && isNumber(parts[position - 1]) && parts[position].equals("(")) { + return false; + } + + // 检查不会在三角函数内部添加括号 + for (int i = Math.max(0, position - 2); i <= Math.min(parts.length - 1, position + 2); i++) { + if (parts[i].contains("sin") || parts[i].contains("cos") || parts[i].contains("tan")) { + return false; + } + } + + // 检查不会产生空括号 + if (position >= parts.length - 1) { + return false; + } + + return true; + } + + /** + * 检查字符串是否为数字 + */ + private boolean isNumber(String str) { + try { + Double.parseDouble(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + /** + * 验证表达式是否有效 + */ + private boolean isValidExpression(String expression) { + // 检查不会出现 "数字(" 或 "(数字" 等错误模式 + if (expression.matches(".*\\d\\(.*") || expression.matches(".*\\(\\d.*")) { + return false; + } + + // 检查括号匹配 + int balance = 0; + for (char c : expression.toCharArray()) { + if (c == '(') balance++; + if (c == ')') balance--; + if (balance < 0) return false; + } + + return balance == 0; + } + /** * 获取随机完全平方数 */ @@ -145,4 +310,4 @@ public class MathQuestionGenerator { int[] perfectSquares = {1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400}; return perfectSquares[random.nextInt(perfectSquares.length)]; } -} +} \ No newline at end of file diff --git a/src/RegisteredUser.class b/src/RegisteredUser.class deleted file mode 100644 index 4818011..0000000 Binary files a/src/RegisteredUser.class and /dev/null differ