Compare commits

..

12 Commits

@ -0,0 +1,208 @@
# 小初高数学学习软件 - 结对编程项目介绍
## 一、系统概述
本系统是一个基于 Java 和 JavaFX 技术实现的桌面应用程序旨在为小学、初中及高中学生提供一个交互式的数学学习与练习平台。系统完全通过图形化界面UI进行操作涵盖了从用户注册、登录、密码管理到生成个性化试卷、在线答题和自动评分的全过程。项目严格遵循无数据库要求所有用户数据和生成的试卷均通过本地文件进行存储和管理。
## 二、项目目录结构
```
partner_project/
├── .gitignore # Git忽略配置文件用于排除IDE配置和编译产物
├── pom.xml # Maven配置文件 (如果使用Maven)
├── src/ # 源代码目录
│ ├── auth/ # 用户认证与管理模块
│ │ ├── User.java
│ │ └── AuthService.java
│ ├── generator/ # 题目生成模块
│ │ ├── Problem.java
│ │ ├── ProblemGenerator.java
│ │ ├── PrimaryGenerator.java
│ │ ├── MiddleGenerator.java
│ │ └── HighGenerator.java
│ ├── service/ # 业务逻辑服务模块
│ │ └── ExamService.java
│ ├── ui/ # JavaFX界面控制器模块
│ │ ├── MainApplication.java
│ │ ├── LoginController.java
│ │ ├── RegisterController.java
│ │ ├── ModifyPasswordController.java
│ │ └── ExamController.java
│ ├── util/ # 工具类模块
│ │ ├── EmailService.java
│ │ ├── ExpressionUtils.java
│ │ ├── FileUtils.java
│ │ └── ModifyUtils.java
│ └── Main.java # 主程序入口
└── resources/ # 资源文件目录
├── fxml/ # FXML界面布局文件
│ ├── Login.fxml
│ ├── register-email.fxml
│ └── ...
├── images/ # 存放应用的图片资源
│ ├── logo.png
│ └── background.png
└── styles/ # CSS样式文件
└── style.css
```
## 三、核心功能
1. **用户管理模块**
- **邮箱注册**: 新用户需通过邮箱接收验证码以完成注册 。
- **登录与密码**: 用户使用用户名或邮箱和密码登录。密码长度为6-10位且必须包含大小写字母和数字 2。
- **密码修改**: 用户在登录状态下,可通过验证旧密码来设置新密码 。
2. **试卷生成与答题模块**
- **难度选择**: 用户登录后可选择“小学”、“初中”、“高中”三种难度级别 。
- **个性化试卷**: 用户可指定生成的题目数量 5。系统确保同一张试卷内的题目不会重复且题目均以选择题形式呈现 6。
- **在线答题**: 界面逐一展示题目及其选项,用户选择答案后进入下一题,直至完成所有题目 。
3. **评分与反馈模块**
- **自动评分**: 完成答题后,系统会根据用户的答题正确率自动计算并显示最终得分 。
- **流程选择**: 在分数界面,用户可以选择继续做题(返回难度选择界面)或退出程序 。
## 四、主要包结构与核心类介绍
### (一) 主要包结构
- `auth`: 负责用户认证与管理,包括用户信息的读取、验证、注册和修改。
- `generator`: 负责数学题目的生成逻辑,定义了题目生成的标准接口和针对不同难度的具体实现。
- `service`: 封装核心业务逻辑,协调 `auth``generator` 包,提供生成试卷、计算分数等服务。
- `ui`: 包含所有 JavaFX 的界面控制器,负责处理用户交互和界面跳转。
- `util`: 提供项目所需的通用工具类,如文件操作、邮件发送和表达式计算等。
- `resources/fxml`: 存放所有界面的 FXML 布局文件。
### (二) 核心类介绍
#### 1. 认证与数据模块 (`auth`)
- `User.java`: 用户数据模型,用于封装用户的基本信息,如用户名、密码、学习阶段和邮箱。
- `AuthService.java`: 用户服务核心类。负责处理所有与用户相关的操作,包括登录验证、新用户注册、检查用户名或邮箱是否被占用、以及更新密码和用户难度等级。
#### 2. 题目生成模块 (`generator`)
- `Problem.java`: 题目数据模型,封装了一道题目的所有信息,包括题干表达式、四个选项、正确答案和计算结果。
- `ProblemGenerator.java`: **题目生成器接口**,定义了 `generateProblems(int count)` 的标准方法,确保所有生成器都具有统一的行为。
- `PrimaryGenerator.java`, `MiddleGenerator.java`, `HighGenerator.java`: `ProblemGenerator` 接口的具体实现类,分别用于生成小学、初中和高中难度的数学题目。
#### 3. 业务服务模块 (`service`)
- `ExamService.java`: 考试服务类。它是业务逻辑的中心,负责调用 `ProblemGenerator` 生成指定数量且不重复的试卷,并根据用户的答案计算最终得分。
#### 4. 界面控制模块 (`ui`)
- `MainApplication.java`: JavaFX 应用的入口,负责加载初始界面 (Login.fxml) 并启动窗口。
- `LoginController.java`: 控制登录、跳转注册和修改密码界面的逻辑。
- `RegisterController.java`: 控制用户注册的全过程,包括发送验证码、验证、设置用户名和密码等多个步骤。
- `ExamController.java`: 最核心的界面控制器,负责处理难度选择、试卷生成、题目展示、答案提交、界面跳转以及最终分数展示的所有逻辑。
#### 5. 工具类模块 (`util`)
- `ExpressionUtils.java`: 表达式工具类,提供了计算字符串表达式结果、生成干扰选项等核心数学计算功能。
- `FileUtils.java`: 文件操作工具类,封装了对用户历史题目文件的读取和新试卷的保存功能,是实现题目去重的基础。
- `EmailService.java`: 邮件服务类,负责生成验证码并通过 SMTP 服务器发送邮件给注册用户。
- `ModifyUtils.java`: 一个通用的文件修改工具,用于根据用户名精确地修改 `user.txt` 文件中特定字段(如密码或难度)。
## 五、数据存储
- **用户信息**: 存储在项目根目录下的 `user.txt` 文件中,每行代表一个用户,格式为:`用户名 密码 学习阶段 邮箱`。
- **用户试卷**: 每个用户生成的试卷和答题历史都保存在 `exams/` 目录下以其用户名命名的子文件夹中,用于实现题目去重功能。
## 六、题目特点
- **小学难度**: 包含2到5个操作数的加、减、乘、除运算并随机引入括号以增加复杂性。确保答案为非负整数。
- **初中难度**: 在小学基础上,增加了平方(`^2`)和开平方根(`sqrt()`)运算。
- **高中难度**: 在初中基础上,引入了三角函数 (`sin`, `cos`, `tan`) 运算。
## 七、使用流程
1. 启动 `Main.java` 中的 `MainApplication`,应用显示登录界面。
2. **首次使用**: 点击“注册账户”按钮,通过邮箱验证流程创建新账户并设置密码 。
3. **登录**: 输入用户名/邮箱和密码进行登录。
4. **难度与数量选择**: 登录成功后,进入难度选择界面。选择一个学段(小学/初中/高中并输入希望生成的题目数量10-30
5. **开始答题**: 点击“生成试卷”按钮,系统会加载并显示第一道题。依次回答所有题目 。
6. **查看分数**: 完成最后一题后,界面跳转至分数展示页面 。
7. **后续操作**: 在分数页面,可选择“继续做题”返回难度选择界面,或选择“退出登录”、“退出程序” 。

@ -1,358 +1,337 @@
package util;
import generator.Problem;
import java.util.*;
public class ExpressionUtils {
private static Random rand = new Random();
private static final String[] OPS_PRIMARY = {"+", "-", "*", "/"};
private static final String[] OPS_MIDDLE = {"+", "-", "*", "/"};
//private static final String[] OPS_HIGH = {"+", "-", "*", "/", "^2", "sqrt"};
public static String randomNumber() {
return String.valueOf(rand.nextInt(100) + 1);
}
// --- 表达式求解和选项生成辅助方法 ---
public static double solveExpression(String expr) {
// 预处理表达式,确保格式正确
String parsableExpr = expr
.replaceAll("(\\d+|\\([^)]+\\))\\^2", "pow($1, 2)") // 处理平方
.replaceAll("sqrt\\s+(\\d+)", "sqrt($1)") // 处理缺少括号的sqrt
.replaceAll("\\s+", " "); // 标准化空格
try {
return new Object() {
int pos = -1, ch;
void nextChar() {
ch = (++pos < parsableExpr.length()) ? parsableExpr.charAt(pos) : -1;
}
boolean eat(int charToEat) {
while (ch == ' ') nextChar();
if (ch == charToEat) {
nextChar();
return true;
}
return false;
}
double parse() {
nextChar();
double x = parseExpression();
if (pos < parsableExpr.length()) throw new RuntimeException("Unexpected: " + (char) ch);
return x;
}
double parseExpression() {
double x = parseTerm();
for (; ; ) {
if (eat('+')) x += parseTerm(); // addition
else if (eat('-')) x -= parseTerm(); // subtraction
else return x;
}
}
double parseTerm() {
double x = parseFactor();
for (; ; ) {
if (eat('*')) x *= parseFactor(); // multiplication
else if (eat('/')) { // division
double divisor = parseFactor();
if (divisor == 0) throw new ArithmeticException("Division by zero");
x /= divisor;
} else return x;
}
}
double parseFactor() {
if (eat('+')) return parseFactor(); // unary plus
if (eat('-')) return -parseFactor(); // unary minus
double x;
int startPos = this.pos;
if (eat('(')) { // parentheses
x = parseExpression();
eat(')');
} else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
x = Double.parseDouble(parsableExpr.substring(startPos, this.pos));
} else if (ch >= 'a' && ch <= 'z') { // functions
while (ch >= 'a' && ch <= 'z') nextChar();
String func = parsableExpr.substring(startPos, this.pos);
x = parseFactor();
switch (func) {
case "sqrt":
x = Math.sqrt(x);
break;
case "sin":
x = Math.sin(Math.toRadians(x));
break;
case "cos":
x = Math.cos(Math.toRadians(x));
break;
case "tan":
x = Math.tan(Math.toRadians(x));
break;
case "pow":
eat(',');
double y = parseExpression();
x = Math.pow(x, y);
eat(')');
break;
default:
throw new RuntimeException("Unknown function: " + func);
}
} else {
throw new RuntimeException("Unexpected: " + (char) ch);
}
return x;
}
}.parse();
} catch (Exception e) {
System.err.println("Error parsing expression: '" + expr + "'. Parsable version: '" + parsableExpr + "'. Error: " + e.getMessage());
return Double.NaN;
}
}
private static String formatResult(double result) {
if (Double.isNaN(result)) {
return "Error";
}
if (Math.abs(result - Math.round(result)) < 0.0001) {
return String.valueOf((int) Math.round(result));
}
return String.format("%.2f", result);
}
/**
* MODIFICATION:
*/
private static String generateDistractor(double correctResult, List<String> existingOptions) {
if (Double.isNaN(correctResult)) {
return String.valueOf(rand.nextInt(100));
}
// 检查正确答案是否为整数
boolean isIntegerResult = Math.abs(correctResult - Math.round(correctResult)) < 0.0001;
double distractor;
String distractorStr;
do {
if (isIntegerResult) {
// 生成一个整数干扰项
int offset = rand.nextInt(20) + 1; // 扩大随机范围以避免重复
distractor = rand.nextBoolean() ? Math.round(correctResult) + offset : Math.round(correctResult) - offset;
// 确保干扰项不为负数
if (distractor < 0) {
distractor = Math.round(correctResult) + offset;
}
} else {
// 答案是小数,则生成小数干扰项
distractor = correctResult +
(rand.nextInt(10) + 1) * (rand.nextBoolean() ? 1 : -1) +
(rand.nextDouble() * 0.9);
}
distractorStr = formatResult(distractor);
} while (existingOptions.contains(distractorStr)); // 确保选项不重复
return distractorStr;
}
public static List<String> generateOptions(double correctResult) {
List<String> options = new ArrayList<>();
options.add(formatResult(correctResult));
for (int i = 0; i < 3; i++) {
options.add(generateDistractor(correctResult, options));
}
Collections.shuffle(options);
return options;
}
public static Problem createProblem(String expression) {
double result = solveExpression(expression);
// 如果解析失败返回null让调用者重新生成
if (Double.isNaN(result)) {
return null;
}
String correctAnswerOption = formatResult(result);
List<String> options = generateOptions(result);
return new Problem(expression, result, options, correctAnswerOption);
}
// --- 题目生成方法 ---
private static int getDivisor(int dividend) {
List<Integer> divisors = new ArrayList<>();
for (int j = 1; j <= dividend; j++) {
if (dividend % j == 0) {
divisors.add(j);
}
}
return divisors.get(rand.nextInt(divisors.size()));
}
/**
* MODIFICATION:
*/
public static Problem generatePrimaryExpr() {
Problem problem;
double result;
do {
// 生成 2 到 4 个操作数
int operands = rand.nextInt(3) + 2;
List<String> parts = new ArrayList<>();
for (int i = 0; i < operands; i++) {
if (i > 0) {
parts.add(OPS_PRIMARY[rand.nextInt(OPS_PRIMARY.length)]);
}
// 仅当操作数 >= 3 时,才有可能生成括号
if (operands >= 3 && rand.nextBoolean() && i < operands - 1) {
int num1 = rand.nextInt(50) + 1;
String innerOp = OPS_PRIMARY[rand.nextInt(OPS_PRIMARY.length)];
int num2;
if (innerOp.equals("/")) {
num2 = getDivisor(num1);
} else {
num2 = rand.nextInt(50) + 1;
}
parts.add("(" + num1 + " " + innerOp + " " + num2 + ")");
i++; // 括号表达式计为2个操作数
} else {
int num;
if (i > 0 && parts.get(parts.size() - 1).equals("/")) {
String dividendStr = parts.get(parts.size() - 2);
if (dividendStr.startsWith("(")) {
// 为避免 (a+b)/c 这种复杂情况无法保证整数结果,直接替换运算符
parts.set(parts.size() - 1, OPS_PRIMARY[rand.nextInt(3)]); // +, -, *
num = rand.nextInt(100) + 1;
} else {
int dividend = Integer.parseInt(dividendStr);
num = getDivisor(dividend);
}
} else {
num = rand.nextInt(100) + 1;
}
parts.add(String.valueOf(num));
}
}
String expression = String.join(" ", parts);
problem = createProblem(expression);
result = problem.getResult();
// 循环直到答案为非负整数
} while (result < 0 || Double.isNaN(result) || Math.abs(result - Math.round(result)) > 0.0001);
return problem;
}
public static Problem generateMiddleExpr() {
int operands = rand.nextInt(5) + 1;
StringBuilder expr = new StringBuilder();
boolean hasSquareOrSqrt = false;
for (int i = 0; i < operands; i++) {
if (i > 0) {
expr.append(" ").append(OPS_MIDDLE[rand.nextInt(OPS_MIDDLE.length)]).append(" ");
}
int num = rand.nextInt(100) + 1;
if (!hasSquareOrSqrt && rand.nextBoolean()) {
expr.append(rand.nextBoolean() ? "sqrt(" + num + ")" : num + "^2");
hasSquareOrSqrt = true;
} else {
expr.append(num);
}
}
if (!hasSquareOrSqrt) {
expr.append(" + ").append(rand.nextInt(50) + 1).append("^2");
}
return createProblem(expr.toString());
}
public static Problem generateHighExpr() {
int attempts = 0;
final int maxAttempts = 10;
while (attempts < maxAttempts) {
int operands = rand.nextInt(3) + 2; // 2-4个操作数
StringBuilder expr = new StringBuilder();
boolean hasTrig = false;
for (int i = 0; i < operands; i++) {
if (i > 0) {
String[] validOps = {"+", "-", "*", "/"};
String op = validOps[rand.nextInt(validOps.length)];
expr.append(" ").append(op).append(" ");
}
// 强制至少有一个操作数是三角函数
if (!hasTrig && (i == operands - 1 || rand.nextBoolean())) {
String[] funcs = {"sin", "cos", "tan"};
String func = funcs[rand.nextInt(funcs.length)];
int angle = rand.nextInt(90) + 1; // 1-90度
expr.append(func).append("(").append(angle).append(")");
hasTrig = true;
} else {
// 其他操作数可以是普通数字、平方或开方
int num = rand.nextInt(100) + 1;
if (rand.nextBoolean() && hasTrig) { // 确保已经有三角函数后再添加其他函数
if (rand.nextBoolean()) {
expr.append(num).append("^2");
} else {
expr.append("sqrt(").append(num).append(")");
}
} else {
expr.append(num);
}
}
}
// 如果没有三角函数,强制添加一个
if (!hasTrig) {
String[] funcs = {"sin", "cos", "tan"};
String func = funcs[rand.nextInt(funcs.length)];
int angle = rand.nextInt(90) + 1;
if (rand.nextBoolean()) {
// 在开头添加
expr.insert(0, func + "(" + angle + ") + ");
} else {
// 在结尾添加
expr.append(" + ").append(func).append("(").append(angle).append(")");
}
hasTrig = true;
}
String expression = expr.toString();
// 验证表达式
Problem problem = createProblem(expression);
if (problem != null) {
return problem;
}
attempts++;
System.err.println("生成高中题目失败,尝试次数: " + attempts + ", 表达式: " + expression);
}
return createProblem("sin(30) + cos(60)");
}
package util;
import generator.Problem;
import java.util.*;
public class ExpressionUtils {
private static Random rand = new Random();
private static final String[] OPS_PRIMARY = {"+", "-", "*", "/"};
private static final String[] OPS_MIDDLE = {"+", "-", "*", "/"};
public static String randomNumber() {
return String.valueOf(rand.nextInt(100) + 1);
}
// --- 表达式求解和选项生成辅助方法 ---
public static double solveExpression(String expr) {
String parsableExpr = expr
.replaceAll("(\\d+|\\([^)]+\\))\\^2", "pow($1, 2)")
.replaceAll("sqrt\\s+(\\d+)", "sqrt($1)")
.replaceAll("\\s+", " ");
try {
return new ExpressionParser(parsableExpr).parse();
} catch (Exception e) {
System.err.println("Error parsing expression: '" + expr + "'. Parsable version: '" + parsableExpr + "'. Error: " + e.getMessage());
return Double.NaN;
}
}
private static class ExpressionParser {
private final String expr;
private int pos = -1, ch;
public ExpressionParser(String expr) {
this.expr = expr;
}
void nextChar() {
ch = (++pos < expr.length()) ? expr.charAt(pos) : -1;
}
boolean eat(int charToEat) {
while (ch == ' ') {
nextChar();
}
if (ch == charToEat) {
nextChar();
return true;
}
return false;
}
double parse() {
nextChar();
double x = parseExpression();
if (pos < expr.length()) {
throw new RuntimeException("Unexpected: " + (char) ch);
}
return x;
}
double parseExpression() {
double x = parseTerm();
for (;;) {
if (eat('+')) {
x += parseTerm();
} else if (eat('-')) {
x -= parseTerm();
} else {
return x;
}
}
}
double parseTerm() {
double x = parseFactor();
for (;;) {
if (eat('*')) {
x *= parseFactor();
} else if (eat('/')) {
double divisor = parseFactor();
if (divisor == 0) {
throw new ArithmeticException("Division by zero");
}
x /= divisor;
} else {
return x;
}
}
}
double parseFactor() {
if (eat('+')) {
return parseFactor();
}
if (eat('-')) {
return -parseFactor();
}
double x;
int startPos = this.pos;
if (eat('(')) {
x = parseExpression();
eat(')');
} else if ((ch >= '0' && ch <= '9') || ch == '.') {
while ((ch >= '0' && ch <= '9') || ch == '.') {
nextChar();
}
x = Double.parseDouble(expr.substring(startPos, this.pos));
} else if (ch >= 'a' && ch <= 'z') {
while (ch >= 'a' && ch <= 'z') {
nextChar();
}
String func = expr.substring(startPos, this.pos);
x = parseFunction(func); // 委托给新的辅助方法
} else {
throw new RuntimeException("Unexpected: " + (char) ch);
}
return x;
}
private double parseFunction(String func) {
double x = parseFactor();
switch (func) {
case "sqrt": return Math.sqrt(x);
case "sin": return Math.sin(Math.toRadians(x));
case "cos": return Math.cos(Math.toRadians(x));
case "tan": return Math.tan(Math.toRadians(x));
case "pow":
eat(',');
double y = parseExpression();
eat(')');
return Math.pow(x, y);
default:
throw new RuntimeException("Unknown function: " + func);
}
}
}
private static String formatResult(double result) {
if (Double.isNaN(result)) {
return "Error";
}
if (Math.abs(result - Math.round(result)) < 0.0001) {
return String.valueOf((int) Math.round(result));
}
return String.format("%.2f", result);
}
private static String generateDistractor(double correctResult, List<String> existingOptions) {
if (Double.isNaN(correctResult)) {
return String.valueOf(rand.nextInt(100));
}
boolean isIntegerResult = Math.abs(correctResult - Math.round(correctResult)) < 0.0001;
double distractor;
String distractorStr;
do {
if (isIntegerResult) {
int offset = rand.nextInt(20) + 1;
distractor = rand.nextBoolean() ? Math.round(correctResult) + offset : Math.round(correctResult) - offset;
if (distractor < 0) {
distractor = Math.round(correctResult) + offset;
}
} else {
distractor = correctResult + (rand.nextInt(10) + 1) * (rand.nextBoolean() ? 1 : -1) + (rand.nextDouble() * 0.9);
}
distractorStr = formatResult(distractor);
} while (existingOptions.contains(distractorStr));
return distractorStr;
}
public static List<String> generateOptions(double correctResult) {
List<String> options = new ArrayList<>();
options.add(formatResult(correctResult));
for (int i = 0; i < 3; i++) {
options.add(generateDistractor(correctResult, options));
}
Collections.shuffle(options);
return options;
}
public static Problem createProblem(String expression) {
double result = solveExpression(expression);
if (Double.isNaN(result)) {
return null;
}
String correctAnswerOption = formatResult(result);
List<String> options = generateOptions(result);
return new Problem(expression, result, options, correctAnswerOption);
}
// --- 题目生成方法 ---
private static int getDivisor(int dividend) {
List<Integer> divisors = new ArrayList<>();
for (int j = 1; j <= dividend; j++) {
if (dividend % j == 0) {
divisors.add(j);
}
}
return divisors.get(rand.nextInt(divisors.size()));
}
public static Problem generatePrimaryExpr() {
Problem problem;
double result;
do {
int operands = rand.nextInt(3) + 2;
List<String> parts = new ArrayList<>();
for (int i = 0; i < operands; i++) {
if (i > 0) {
parts.add(OPS_PRIMARY[rand.nextInt(OPS_PRIMARY.length)]);
}
if (operands >= 3 && rand.nextBoolean() && i < operands - 1) {
int num1 = rand.nextInt(50) + 1;
String innerOp = OPS_PRIMARY[rand.nextInt(OPS_PRIMARY.length)];
int num2 = innerOp.equals("/") ? getDivisor(num1) : rand.nextInt(50) + 1;
parts.add("(" + num1 + " " + innerOp + " " + num2 + ")");
i++;
} else {
int num;
if (i > 0 && parts.get(parts.size() - 1).equals("/")) {
String dividendStr = parts.get(parts.size() - 2);
if (dividendStr.startsWith("(")) {
parts.set(parts.size() - 1, OPS_PRIMARY[rand.nextInt(3)]);
num = rand.nextInt(100) + 1;
} else {
num = getDivisor(Integer.parseInt(dividendStr));
}
} else {
num = rand.nextInt(100) + 1;
}
parts.add(String.valueOf(num));
}
}
String expression = String.join(" ", parts);
problem = createProblem(expression);
result = (problem != null) ? problem.getResult() : Double.NaN;
} while (result < 0 || Double.isNaN(result) || Math.abs(result - Math.round(result)) > 0.0001);
return problem;
}
public static Problem generateMiddleExpr() {
int operands = rand.nextInt(5) + 1;
StringBuilder expr = new StringBuilder();
boolean hasSquareOrSqrt = false;
for (int i = 0; i < operands; i++) {
if (i > 0) {
expr.append(" ").append(OPS_MIDDLE[rand.nextInt(OPS_MIDDLE.length)]).append(" ");
}
int num = rand.nextInt(100) + 1;
if (!hasSquareOrSqrt && rand.nextBoolean()) {
expr.append(rand.nextBoolean() ? "sqrt(" + num + ")" : num + "^2");
hasSquareOrSqrt = true;
} else {
expr.append(num);
}
}
if (!hasSquareOrSqrt) {
expr.append(" + ").append(rand.nextInt(50) + 1).append("^2");
}
return createProblem(expr.toString());
}
public static Problem generateHighExpr() {
final int maxAttempts = 10;
for (int attempts = 0; attempts < maxAttempts; attempts++) {
String expression = buildHighLevelExpression();
Problem problem = createProblem(expression);
if (problem != null) {
return problem;
}
System.err.println("生成高中题目失败,尝试次数: " + (attempts + 1) + ", 表达式: " + expression);
}
return createProblem("sin(30) + cos(60)"); // Fallback
}
private static String buildHighLevelExpression() {
int operands = rand.nextInt(3) + 2; // 2-4个操作数
StringBuilder expr = new StringBuilder();
boolean hasTrig = false;
for (int i = 0; i < operands; i++) {
if (i > 0) {
String[] validOps = {"+", "-", "*", "/"};
expr.append(" ").append(validOps[rand.nextInt(validOps.length)]).append(" ");
}
if (!hasTrig && (i == operands - 1 || rand.nextBoolean())) {
appendTrigonometricFunction(expr);
hasTrig = true;
} else {
appendOtherOperand(expr, hasTrig);
}
}
ensureTrigonometricFunction(expr, hasTrig);
return expr.toString();
}
private static void appendTrigonometricFunction(StringBuilder expr) {
String[] funcs = {"sin", "cos", "tan"};
String func = funcs[rand.nextInt(funcs.length)];
int angle = rand.nextInt(90) + 1;
expr.append(func).append("(").append(angle).append(")");
}
private static void appendOtherOperand(StringBuilder expr, boolean hasTrig) {
int num = rand.nextInt(100) + 1;
if (hasTrig && rand.nextBoolean()) {
expr.append(rand.nextBoolean() ? num + "^2" : "sqrt(" + num + ")");
} else {
expr.append(num);
}
}
private static void ensureTrigonometricFunction(StringBuilder expr, boolean hasTrig) {
if (!hasTrig) {
String trigPart = " + " + "sin" + "(" + (rand.nextInt(90) + 1) + ")";
if (rand.nextBoolean()) {
expr.insert(0, trigPart.substring(3) + " + ");
} else {
expr.append(trigPart);
}
}
}
}

@ -1,76 +1,77 @@
package util;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class to modify specific fields in user.txt.
* ModifyClass.java ModifyPassword.java
*/
public class ModifyUtils {
private static List<String> readAllLines(String filePath, List<String> lines) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
}
return lines;
}
private static void writeAllLines(String filePath, List<String> lines) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
for (String l : lines) {
writer.write(l + System.lineSeparator());
}
}
}
private static int findTargetLine(List<String> lines, String targetName) {
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i).trim();
if (line.isEmpty()) continue;
String[] parts = line.split("\\s+");
if (parts.length > 0 && parts[0].equals(targetName)) {
return i; // 0-based index
}
}
return -1;
}
// 核心逻辑:修改文件中特定用户的某个字段 (0-based)
public static int modifyFileField(String filePath, String targetName,
int fieldIndex, String newValue) {
List<String> lines = new ArrayList<>();
try {
readAllLines(filePath, lines);
} catch (IOException e) {
System.err.println("读取文件错误: " + e.getMessage());
return -1;
}
int idx = findTargetLine(lines, targetName);
if (idx == -1) {
return -1;
}
String[] parts = lines.get(idx).trim().split("\\s+");
if (parts.length > fieldIndex) {
parts[fieldIndex] = newValue;
lines.set(idx, String.join(" ", parts));
try {
writeAllLines(filePath, lines);
return idx + 1; // 返回 1-based 行号
} catch (IOException e) {
System.err.println("写入文件错误: " + e.getMessage());
return -1;
}
} else {
System.out.println("目标行元素不足。");
return -1;
}
}
package util;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class to modify specific fields in user.txt.
* ModifyClass.java ModifyPassword.java
*/
public class ModifyUtils {
private static List<String> readAllLines(String filePath, List<String> lines) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
}
return lines;
}
private static void writeAllLines(String filePath, List<String> lines) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
for (String l : lines) {
writer.write(l + System.lineSeparator());
}
}
}
private static int findTargetLine(List<String> lines, String targetName) {
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i).trim();
if (line.isEmpty()) {
continue;
}
String[] parts = line.split("\\s+");
if (parts.length > 0 && parts[0].equals(targetName)) {
return i; // 0-based index
}
}
return -1;
}
// 核心逻辑:修改文件中特定用户的某个字段 (0-based)
public static int modifyFileField(String filePath, String targetName,
int fieldIndex, String newValue) {
List<String> lines = new ArrayList<>();
try {
readAllLines(filePath, lines);
} catch (IOException e) {
System.err.println("读取文件错误: " + e.getMessage());
return -1;
}
int idx = findTargetLine(lines, targetName);
if (idx == -1) {
return -1;
}
String[] parts = lines.get(idx).trim().split("\\s+");
if (parts.length > fieldIndex) {
parts[fieldIndex] = newValue;
lines.set(idx, String.join(" ", parts));
try {
writeAllLines(filePath, lines);
return idx + 1; // 返回 1-based 行号
} catch (IOException e) {
System.err.println("写入文件错误: " + e.getMessage());
return -1;
}
} else {
System.out.println("目标行元素不足。");
return -1;
}
}
}
Loading…
Cancel
Save