Compare commits

..

3 Commits

28
.gitignore vendored

@ -1,29 +1,3 @@
# 编译后的类文件
*.class
# 打包文件
*.jar
*.war
*.ear
# IDE 文件
/.idea/
/.settings/
/*.iml
/*.ipr
/*.iws
# 构建工具目录
/target/
/build/
/out/
# 日志文件
*.log
# 系统文件
.DS_Store
Thumbs.db0
### IntelliJ IDEA ###
out/
!**/src/main/**/out/
@ -52,4 +26,4 @@ bin/
.vscode/
### Mac OS ###
.DS_Store
.DS_Store

@ -0,0 +1,10 @@
<component name="ArtifactManager">
<artifact type="jar" build-on-make="true" name="MathLearningSoftware:jar">
<output-path>$PROJECT_DIR$/out/artifacts/MathLearningSoftware_jar</output-path>
<root id="archive" name="MathLearningSoftware.jar">
<element id="module-output" name="MathLearningSoftware" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/com/sun/mail/javax.mail/1.6.2/javax.mail-1.6.2.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/javax/activation/activation/1.1/activation-1.1.jar" path-in-jar="/" />
</root>
</artifact>
</component>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

@ -1,45 +1,46 @@
# 数学学习软件
## 项目简介
这是一个基于Java Swing开发的数学学习软件旨在为不同学段的学生提供个性化的数学练习体验。软件支持用户注册、登录、密码管理以及根据小学、初中、高中不同难度生成相应的数学题目。
## 功能特性
### 用户管理
- **用户注册**: 通过邮箱注册,系统发送注册码验证
- **用户登录**: 安全的邮箱密码登录机制
- **密码管理**: 支持密码修改,密码强度验证
### 学习功能
- **难度选择**: 小学、初中、高中三个难度级别
- **题目生成**: 根据难度自动生成相应数学题目
- **答题系统**: 选择题形式,实时反馈
- **成绩统计**: 答题结果分析和详细报告
### 技术特点
- 基于Java Swing的图形界面
- 数据持久化存储
- 模块化设计,易于扩展
- 代码结构清晰,注释完整
## 系统要求
- Java 8 或更高版本
- 支持Java Swing的桌面环境
- 至少 100MB 可用磁盘空间
## 注意
- 发送验证码邮件的邮箱账号为```3602474328@qq.com```
- 包含验证码的邮件可能会被归类为垃圾邮件,若迟迟未收到验证码请到垃圾箱中翻找一下
- 用户名和密码都不能出现字符```|```,否则判定为非法
## 安装和运行
### 方法一使用预编译JAR文件
1. 下载项目的最新发布版本
2. 确保系统已安装Java运行环境
3. 双击JAR文件运行或使用命令行
```bash
# 数学学习软件
## 项目简介
这是一个基于Java Swing开发的数学学习软件旨在为不同学段的学生提供个性化的数学练习体验。软件支持用户注册、登录、密码管理以及根据小学、初中、高中不同难度生成相应的数学题目。
## 功能特性
### 用户管理
- **用户注册**: 通过邮箱注册,系统发送注册码验证
- **用户登录**: 安全的邮箱密码登录机制
- **密码管理**: 支持密码修改,密码强度验证
### 学习功能
- **难度选择**: 小学、初中、高中三个难度级别
- **题目生成**: 根据难度自动生成相应数学题目
- **答题系统**: 选择题形式,实时反馈
- **成绩统计**: 答题结果分析和详细报告
### 技术特点
- 基于Java Swing的图形界面
- 数据持久化存储
- 模块化设计,易于扩展
- 代码结构清晰,注释完整
## 系统要求
- JDK24 或更高版本
- 支持Java Swing的桌面环境
- 至少 100MB 可用磁盘空间
## 注意
- 发送验证码邮件的邮箱账号为```3602474328@qq.com```
- 包含验证码的邮件可能会被归类为垃圾邮件,若迟迟未收到验证码请到垃圾箱中翻找一下
- 用户名和密码都不能出现字符```|```,否则判定为非法
- 登录时使用的是邮箱+密码登录,不是用户名+密码
## 安装和运行
### 方法一使用预编译JAR文件
1. 下载项目的最新发布版本
2. 确保系统已安装Java运行环境
3. 双击JAR文件运行或使用命令行
```bash
java -jar MathLearningSoftware.jar

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: com.mathlearning.Main

@ -28,9 +28,7 @@ public abstract class AbstractQuestionGenerator implements QuestionGenerator {
do {
question = generateQuestion(level, index);
attempt++;
} while (question != null
&& questionTexts.contains(question.getQuestionText())
&& attempt < 10);
} while (question != null && questionTexts.contains(question.getQuestionText()) && attempt < 10);
if (question != null) {
questionTexts.add(question.getQuestionText());
@ -40,4 +38,4 @@ public abstract class AbstractQuestionGenerator implements QuestionGenerator {
}
protected abstract Question generateQuestion(String level, int index);
}
}

@ -25,18 +25,10 @@ public abstract class BaseQuestionGenerator {
protected void appendOperator(StringBuilder sb, int operation) {
switch (operation) {
case 0:
sb.append(" + ");
break;
case 1:
sb.append(" - ");
break;
case 2:
sb.append(" × ");
break;
case 3:
sb.append(" ÷ ");
break;
case 0: sb.append(" + "); break;
case 1: sb.append(" - "); break;
case 2: sb.append(" × "); break;
case 3: sb.append(" ÷ "); break;
}
}
@ -44,6 +36,7 @@ public abstract class BaseQuestionGenerator {
return !(answer < 0 || Double.isNaN(answer) || Double.isInfinite(answer));
}
// 修改使用double进行精确计算只在最后保留小数
protected double calculateExpression(double[] values, int[] operations) {
List<Double> numbers = new ArrayList<>();
List<Integer> ops = new ArrayList<>();
@ -102,22 +95,20 @@ public abstract class BaseQuestionGenerator {
result = performOperation(result, nextNum, op);
}
// 修改只在最后一步进行四舍五入保留2位小数
return Math.round(result * 100) / 100.0;
}
private double performOperation(double left, double right, int operation) {
switch (operation) {
case 0:
return left + right;
case 1:
return left - right;
case 2:
return left * right;
case 0: return left + right;
case 1: return left - right;
case 2: return left * right;
case 3:
if (right == 0) return Double.NaN;
// 修改:直接进行除法,不在这里保留小数
return left / right;
default:
return left;
default: return left;
}
}
@ -125,8 +116,9 @@ public abstract class BaseQuestionGenerator {
String[] options = new String[4];
Set<String> usedValues = new HashSet<>();
boolean isIntegerAnswer = (answer == (int) answer);
String correctAnswer = formatAnswer(answer);
// 修改:判断是否为整数的逻辑
boolean isIntegerAnswer = Math.abs(answer - Math.round(answer)) < 1e-10;
String correctAnswer = formatAnswer(answer, isIntegerAnswer);
options[0] = correctAnswer;
usedValues.add(correctAnswer);
@ -138,15 +130,16 @@ public abstract class BaseQuestionGenerator {
return new Question(questionText, options, correctIndex, level);
}
private void generateWrongOptions(
String[] options, Set<String> usedValues, double answer, boolean isIntegerAnswer) {
private void generateWrongOptions(String[] options, Set<String> usedValues,
double answer, boolean isIntegerAnswer) {
for (int i = 1; i < 4; i++) {
String wrongAnswer;
int attempts = 0;
do {
double wrongValue = generateWrongValue(answer, isIntegerAnswer);
wrongAnswer = formatAnswer(wrongValue);
wrongAnswer = formatAnswer(wrongValue,
Math.abs(wrongValue - Math.round(wrongValue)) < 1e-10);
attempts++;
} while (usedValues.contains(wrongAnswer) && attempts < 20);
@ -159,19 +152,26 @@ public abstract class BaseQuestionGenerator {
double offset = (random.nextDouble() * 5) + 1;
if (isIntegerAnswer) {
int intAnswer = (int) answer;
int intAnswer = (int) Math.round(answer);
int intOffset = random.nextInt(10) + 1;
double wrongValue =
random.nextBoolean() ? intAnswer + intOffset : Math.max(1, intAnswer - intOffset);
return (int) wrongValue;
double wrongValue = random.nextBoolean() ?
intAnswer + intOffset : Math.max(1, intAnswer - intOffset);
return wrongValue;
} else {
double wrongValue = random.nextBoolean() ? answer + offset : answer - offset;
// 修改错误选项也保留2位小数
return Math.round(wrongValue * 100) / 100.0;
}
}
private String formatAnswer(double answer) {
return (answer == (int) answer) ? String.valueOf((int) answer) : String.format("%.2f", answer);
// 修改:格式化答案,只在最后一步处理小数位数
private String formatAnswer(double answer, boolean isInteger) {
if (isInteger) {
return String.valueOf((int) Math.round(answer));
} else {
// 确保显示2位小数即使末尾是0
return String.format("%.2f", answer);
}
}
private void shuffleArray(String[] array) {
@ -189,4 +189,4 @@ public abstract class BaseQuestionGenerator {
}
return 0;
}
}
}

@ -18,4 +18,4 @@ public class ConcreteQuestionGenerator extends AbstractQuestionGenerator {
return primaryGenerator.generateQuestion(index);
}
}
}
}

@ -45,15 +45,14 @@ public class HighSchoolQuestionGenerator extends BaseQuestionGenerator {
private void generateOperandsWithTrig(int[] operands, boolean[] hasTrigOp) {
for (int i = 0; i < operands.length; i++) {
operands[i] =
hasTrigOp[i]
? SPECIAL_ANGLES[random.nextInt(SPECIAL_ANGLES.length)]
: random.nextInt(100) + 1;
operands[i] = hasTrigOp[i] ?
SPECIAL_ANGLES[random.nextInt(SPECIAL_ANGLES.length)] :
random.nextInt(100) + 1;
}
}
private String buildQuestionText(
int[] operands, int[] operations, boolean[] hasTrigOp, int[] trigFunctions) {
private String buildQuestionText(int[] operands, int[] operations,
boolean[] hasTrigOp, int[] trigFunctions) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operands.length; i++) {
@ -72,20 +71,14 @@ public class HighSchoolQuestionGenerator extends BaseQuestionGenerator {
private void appendTrigFunction(StringBuilder sb, int operand, int trigFunction) {
switch (trigFunction) {
case 0:
sb.append("sin(").append(operand).append("°)");
break;
case 1:
sb.append("cos(").append(operand).append("°)");
break;
case 2:
sb.append("tan(").append(operand).append("°)");
break;
case 0: sb.append("sin(").append(operand).append("°)"); break;
case 1: sb.append("cos(").append(operand).append("°)"); break;
case 2: sb.append("tan(").append(operand).append("°)"); break;
}
}
private double calculateAnswer(
int[] operands, int[] operations, boolean[] hasTrigOp, int[] trigFunctions) {
private double calculateAnswer(int[] operands, int[] operations,
boolean[] hasTrigOp, int[] trigFunctions) {
double[] processedValues = processTrigOperations(operands, hasTrigOp, trigFunctions);
return calculateExpression(processedValues, operations);
}
@ -108,15 +101,12 @@ public class HighSchoolQuestionGenerator extends BaseQuestionGenerator {
double radians = Math.toRadians(angle);
switch (trigFunction) {
case 0:
return Math.sin(radians);
case 1:
return Math.cos(radians);
case 0: return Math.sin(radians);
case 1: return Math.cos(radians);
case 2:
if (angle % 180 == 90 && angle % 360 != 270) return Double.NaN;
return Math.tan(radians);
default:
return 0;
default: return 0;
}
}
}
}

@ -27,8 +27,7 @@ public class MiddleSchoolQuestionGenerator extends BaseQuestionGenerator {
return generateOptions(questionText, answer, "初中");
}
private void ensureSpecialOperation(
boolean[] hasSpecialOp, int[] specialOpTypes, int operandCount) {
private void ensureSpecialOperation(boolean[] hasSpecialOp, int[] specialOpTypes, int operandCount) {
boolean hasSpecialOperation = false;
for (int i = 0; i < operandCount; i++) {
@ -43,8 +42,8 @@ public class MiddleSchoolQuestionGenerator extends BaseQuestionGenerator {
}
}
private String buildQuestionText(
int[] operands, int[] operations, boolean[] hasSpecialOp, int[] specialOpTypes) {
private String buildQuestionText(int[] operands, int[] operations,
boolean[] hasSpecialOp, int[] specialOpTypes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < operands.length; i++) {
@ -69,20 +68,19 @@ public class MiddleSchoolQuestionGenerator extends BaseQuestionGenerator {
}
}
private double calculateAnswer(
int[] operands, int[] operations, boolean[] hasSpecialOp, int[] specialOpTypes) {
private double calculateAnswer(int[] operands, int[] operations,
boolean[] hasSpecialOp, int[] specialOpTypes) {
double[] processedValues = processSpecialOperations(operands, hasSpecialOp, specialOpTypes);
return calculateExpression(processedValues, operations);
}
private double[] processSpecialOperations(
int[] operands, boolean[] hasSpecialOp, int[] specialOpTypes) {
private double[] processSpecialOperations(int[] operands, boolean[] hasSpecialOp, int[] specialOpTypes) {
double[] processedValues = new double[operands.length];
for (int i = 0; i < operands.length; i++) {
if (hasSpecialOp[i]) {
processedValues[i] =
(specialOpTypes[i] == 0) ? operands[i] * operands[i] : Math.sqrt(operands[i]);
processedValues[i] = (specialOpTypes[i] == 0) ?
operands[i] * operands[i] : Math.sqrt(operands[i]);
} else {
processedValues[i] = operands[i];
}
@ -90,4 +88,4 @@ public class MiddleSchoolQuestionGenerator extends BaseQuestionGenerator {
return processedValues;
}
}
}

@ -21,10 +21,10 @@ public class PrimaryQuestionGenerator extends BaseQuestionGenerator {
boolean useParentheses = random.nextDouble() < 0.3 && operandCount >= 3;
int[] parenthesesPositions = findParenthesesPositions(operations, useParentheses);
questionText =
buildQuestionText(operands, operations, parenthesesPositions[0], parenthesesPositions[1]);
answer =
calculateAnswer(operands, operations, parenthesesPositions[0], parenthesesPositions[1]);
questionText = buildQuestionText(operands, operations,
parenthesesPositions[0], parenthesesPositions[1]);
answer = calculateAnswer(operands, operations,
parenthesesPositions[0], parenthesesPositions[1]);
} while (!isValidAnswer(answer));
@ -45,7 +45,7 @@ public class PrimaryQuestionGenerator extends BaseQuestionGenerator {
}
}
return new int[] {parenStart, parenEnd};
return new int[]{parenStart, parenEnd};
}
private int findSuitableParenthesesPosition(int[] operations) {
@ -86,12 +86,12 @@ public class PrimaryQuestionGenerator extends BaseQuestionGenerator {
return calculateWithParentheses(operands, operations, parenStart, parenEnd);
}
private double calculateWithParentheses(
int[] operands, int[] operations, int parenStart, int parenEnd) {
List<Integer> numbers = new ArrayList<>();
private double calculateWithParentheses(int[] operands, int[] operations, int parenStart, int parenEnd) {
// 修改使用Double列表
List<Double> numbers = new ArrayList<>();
List<Integer> ops = new ArrayList<>();
for (int operand : operands) numbers.add(operand);
for (int operand : operands) numbers.add((double) operand);
for (int operation : operations) ops.add(operation);
double parenthesesResult = calculateParenthesesContent(numbers, ops, parenStart, parenEnd);
@ -99,28 +99,45 @@ public class PrimaryQuestionGenerator extends BaseQuestionGenerator {
if (!isValidAnswer(parenthesesResult)) return -1;
replaceWithParenthesesResult(numbers, ops, parenStart, parenEnd, parenthesesResult);
return calculateWithoutParentheses(numbers, ops);
// 修改:调用新的方法名
return calculateDoubleList(numbers, ops);
}
private double calculateParenthesesContent(
List<Integer> numbers, List<Integer> ops, int start, int end) {
List<Integer> parenNumbers = new ArrayList<>();
private double calculateParenthesesContent(List<Double> numbers, List<Integer> ops, int start, int end) {
List<Double> parenNumbers = new ArrayList<>();
List<Integer> parenOps = new ArrayList<>();
for (int i = start; i <= end; i++) parenNumbers.add(numbers.get(i));
for (int i = start; i < end; i++) parenOps.add(ops.get(i));
return calculateWithoutParentheses(parenNumbers, parenOps);
// 修改:调用新的方法名
return calculateDoubleList(parenNumbers, parenOps);
}
private void replaceWithParenthesesResult(
List<Integer> numbers, List<Integer> ops, int start, int end, double result) {
private void replaceWithParenthesesResult(List<Double> numbers, List<Integer> ops,
int start, int end, double result) {
int numCountToRemove = end - start + 1;
int opCountToRemove = end - start;
for (int i = 0; i < numCountToRemove; i++) numbers.remove(start);
for (int i = 0; i < opCountToRemove; i++) ops.remove(start);
numbers.add(start, (int) Math.round(result));
// 修改直接添加double结果不转换为int
numbers.add(start, result);
}
}
// 修改:重命名方法,避免与父类冲突
private double calculateDoubleList(List<Double> numbers, List<Integer> ops) {
double[] doubleNumbers = new double[numbers.size()];
for (int i = 0; i < numbers.size(); i++) {
doubleNumbers[i] = numbers.get(i);
}
int[] intOps = new int[ops.size()];
for (int i = 0; i < ops.size(); i++) {
intOps[i] = ops.get(i);
}
return calculateExpression(doubleNumbers, intOps);
}
}

@ -44,4 +44,4 @@ public class Question {
public void setLevel(String level) {
this.level = level;
}
}
}

@ -4,4 +4,4 @@ import java.util.List;
public interface QuestionGenerator {
List<Question> generateQuestions(String level, int count);
}
}

@ -1,7 +1,7 @@
package com.mathlearning.model;
public class User {
private String user_name;
private String user_name; // 从第一个版本保留
private String email;
private String password;
private String registrationCode;
@ -12,6 +12,7 @@ public class User {
this.registrationCode = registrationCode;
this.isRegistered = false;
this.password = null;
this.user_name = null; // 添加初始化
}
// Getters and setters
@ -19,6 +20,11 @@ public class User {
return email;
}
public void setEmail(String email) {
this.email = email;
}
// user_name 相关方法(从第一个版本保留)
public String getUser_name() {
return user_name;
}
@ -27,10 +33,6 @@ public class User {
this.user_name = user_name;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
@ -54,4 +56,4 @@ public class User {
public void setRegistered(boolean registered) {
isRegistered = registered;
}
}
}
Loading…
Cancel
Save