diff --git a/src/main/java/com/mathapp/MathApp.java b/src/main/java/com/mathapp/MathApp.java index 2a06786..ca0c60d 100644 --- a/src/main/java/com/mathapp/MathApp.java +++ b/src/main/java/com/mathapp/MathApp.java @@ -103,7 +103,7 @@ public class MathApp extends JFrame { // 设置现代化UI外观 FlatLightLaf.setup(); // 全局UI定制 - UIManager.put("Button.arc", 999); + UIManager.put("Button.arc", 15); UIManager.put("Component.arc", 15); UIManager.put("ProgressBar.arc", 999); UIManager.put("TextComponent.arc", 15); diff --git a/src/main/java/com/mathapp/panels/ChangePasswordPanel.java b/src/main/java/com/mathapp/panels/ChangePasswordPanel.java index bf856fc..a29d7ac 100644 --- a/src/main/java/com/mathapp/panels/ChangePasswordPanel.java +++ b/src/main/java/com/mathapp/panels/ChangePasswordPanel.java @@ -20,10 +20,10 @@ public class ChangePasswordPanel extends JPanel { GridBagConstraints gbc = new GridBagConstraints(); JLabel titleLabel = new JLabel("修改密码", SwingConstants.CENTER); - titleLabel.setFont(new Font("思源黑体", Font.BOLD, 32)); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 32)); JLabel infoLabel = new JLabel("新密码需6-10位,且包含大小写字母和数字", SwingConstants.CENTER); - infoLabel.setFont(new Font("思源黑体", Font.PLAIN, 12)); + infoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 12)); oldPasswordField = new JPasswordField(20); newPasswordField = new JPasswordField(20); diff --git a/src/main/java/com/mathapp/panels/LoginPanel.java b/src/main/java/com/mathapp/panels/LoginPanel.java index 683c558..4d5050f 100644 --- a/src/main/java/com/mathapp/panels/LoginPanel.java +++ b/src/main/java/com/mathapp/panels/LoginPanel.java @@ -24,11 +24,11 @@ public class LoginPanel extends JPanel { passwordField = new JPasswordField(20); JButton loginButton = new JButton("登录"); - loginButton.setFont(new Font("思源黑体", Font.PLAIN, 16)); + loginButton.setFont(new Font("微软雅黑", Font.PLAIN, 16)); loginButton.setPreferredSize(new Dimension(120, 40)); JButton registerButton = new JButton("没有账户?立即注册"); - registerButton.setFont(new Font("思源黑体", Font.PLAIN, 12)); + registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 12)); registerButton.setBorderPainted(false); registerButton.setContentAreaFilled(false); registerButton.setFocusPainted(false); @@ -83,7 +83,7 @@ public class LoginPanel extends JPanel { } User user = DataPersistence.findUserByEmail(email); - if (user != null && user.verifyPassword(password)||true) { + if (user != null && user.verifyPassword(password)) { app.setCurrentUserEmail(email); app.showPanel(MathApp.MAIN_MENU_PANEL); } else { diff --git a/src/main/java/com/mathapp/panels/QuizPanel.java b/src/main/java/com/mathapp/panels/QuizPanel.java index 22b25dc..08b9a6b 100644 --- a/src/main/java/com/mathapp/panels/QuizPanel.java +++ b/src/main/java/com/mathapp/panels/QuizPanel.java @@ -24,7 +24,7 @@ public class QuizPanel extends JPanel { // 顶部面板:进度条和题号 JPanel topPanel = new JPanel(new BorderLayout()); questionLabel = new JLabel("题目 1/" + questionCount + ": ", SwingConstants.LEFT); - questionLabel.setFont(new Font("思源黑体", Font.BOLD, 20)); + questionLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); progressBar = new JProgressBar(0, questionCount); progressBar.setValue(0); progressBar.setStringPainted(true); @@ -38,7 +38,7 @@ public class QuizPanel extends JPanel { optionButtons = new JRadioButton[4]; for (int i = 0; i < 4; i++) { optionButtons[i] = new JRadioButton(); - optionButtons[i].setFont(new Font("思源黑体", Font.PLAIN, 16)); + optionButtons[i].setFont(new Font("微软雅黑", Font.PLAIN, 16)); optionsGroup.add(optionButtons[i]); centerPanel.add(optionButtons[i]); centerPanel.add(Box.createVerticalStrut(10)); @@ -67,7 +67,7 @@ public class QuizPanel extends JPanel { } public void displayQuestion(Question question, int currentQuestionIndex, int totalQuestions) { - questionLabel.setText(String.format("题目 %d/%d: %s", currentQuestionIndex + 1, totalQuestions, question.problemStatement())); + questionLabel.setText(String.format("题目 %d/%d: %s", currentQuestionIndex + 1, totalQuestions, question.problemStatement())); progressBar.setValue(currentQuestionIndex); java.util.List options = question.options(); for (int i = 0; i < optionButtons.length; i++) { diff --git a/src/main/java/com/mathapp/panels/RegisterPanel.java b/src/main/java/com/mathapp/panels/RegisterPanel.java index 6655e20..f323757 100644 --- a/src/main/java/com/mathapp/panels/RegisterPanel.java +++ b/src/main/java/com/mathapp/panels/RegisterPanel.java @@ -25,7 +25,7 @@ public class RegisterPanel extends JPanel { titleLabel.setFont(new Font("思源黑体", Font.BOLD, 32)); emailField = new JTextField(20); - codeField = new JTextField(10); + codeField = new JTextField(11); getCodeButton = new JButton("获取验证码"); JButton registerButton = new JButton("验证并设置密码"); JButton backButton = new JButton("返回登录"); diff --git a/src/main/java/com/mathapp/panels/ResultsPanel.java b/src/main/java/com/mathapp/panels/ResultsPanel.java index fc1cb21..4114061 100644 --- a/src/main/java/com/mathapp/panels/ResultsPanel.java +++ b/src/main/java/com/mathapp/panels/ResultsPanel.java @@ -11,14 +11,14 @@ public class ResultsPanel extends JPanel { GridBagConstraints gbc = new GridBagConstraints(); JLabel titleLabel = new JLabel("测验完成!", SwingConstants.CENTER); - titleLabel.setFont(new Font("思源黑体", Font.BOLD, 32)); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 32)); double percentage = (double) score / totalQuestions * 100; JLabel scoreLabel = new JLabel(String.format("你的得分: %.0f 分", percentage), SwingConstants.CENTER); - scoreLabel.setFont(new Font("思源黑体", Font.PLAIN, 24)); + scoreLabel.setFont(new Font("微软雅黑", Font.PLAIN, 24)); JLabel detailsLabel = new JLabel(String.format("(答对 %d 题,共 %d 题)", score, totalQuestions), SwingConstants.CENTER); - detailsLabel.setFont(new Font("思源黑体", Font.PLAIN, 16)); + detailsLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16)); JButton againButton = new JButton("返回选择界面"); diff --git a/src/main/java/com/mathapp/panels/SetPasswordPanel.java b/src/main/java/com/mathapp/panels/SetPasswordPanel.java index d991def..8c1215a 100644 --- a/src/main/java/com/mathapp/panels/SetPasswordPanel.java +++ b/src/main/java/com/mathapp/panels/SetPasswordPanel.java @@ -21,10 +21,10 @@ public class SetPasswordPanel extends JPanel { GridBagConstraints gbc = new GridBagConstraints(); JLabel titleLabel = new JLabel("设置您的密码", SwingConstants.CENTER); - titleLabel.setFont(new Font("思源黑体", Font.BOLD, 32)); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 32)); JLabel infoLabel = new JLabel("密码需6-10位,且包含大小写字母和数字", SwingConstants.CENTER); - infoLabel.setFont(new Font("思源黑体", Font.PLAIN, 12)); + infoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 12)); passwordField = new JPasswordField(20); confirmPasswordField = new JPasswordField(20); diff --git a/src/main/java/com/mathapp/problemGenerators/AbstractProblemGenerator.java b/src/main/java/com/mathapp/problemGenerators/AbstractProblemGenerator.java index e032289..e228391 100644 --- a/src/main/java/com/mathapp/problemGenerators/AbstractProblemGenerator.java +++ b/src/main/java/com/mathapp/problemGenerators/AbstractProblemGenerator.java @@ -63,7 +63,9 @@ public abstract class AbstractProblemGenerator implements IProblemGenerator { addOperandAndOperator(operands, operators, operator, nonNegativeOnly); } - addParentheses(operands, operators); + if(nonNegativeOnly) { + addParentheses(operands, operators); + } return new Equation(operands, operators); } diff --git a/src/main/java/com/mathapp/problemGenerators/HighSchoolProblemGenerator.java b/src/main/java/com/mathapp/problemGenerators/HighSchoolProblemGenerator.java index f09cd73..db8733d 100644 --- a/src/main/java/com/mathapp/problemGenerators/HighSchoolProblemGenerator.java +++ b/src/main/java/com/mathapp/problemGenerators/HighSchoolProblemGenerator.java @@ -4,47 +4,74 @@ import com.mathapp.models.Equation; import com.mathapp.models.Operator; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** - * 高中题目生成器(具体策略)。 - * 它首先生成一个包含初中难度运算(平方/开方)的题目, - * 然后再额外加入一个三角函数运算。 - * 生成的格式与 exp4j 兼容,但依赖计算引擎处理角度单位。 + * 高中题目生成器(最终修正版)。 + * 采用更稳健的“追加”策略,从根本上避免所有索引越界和除零错误。 */ public class HighSchoolProblemGenerator extends MiddleSchoolProblemGenerator { - private static final int[] PREDEFINED_ANGLES = new int[]{0, 30, 45, 60, 90}; - private static final String[] TRIG_FUNCTIONS = new String[]{"sin", "cos", "tan"}; + private static final int[] PREDEFINED_ANGLES = {0, 30, 45, 60, 90}; + private static final String[] TRIG_FUNCTIONS = {"sin", "cos", "tan"}; @Override protected Equation createProblem() { - // 复用初中生成器的逻辑,先生成一个带平方或开方的题目 + // 1. 调用父类方法生成一个包含平方或开方的基础题目 Equation middleSchoolEquation = super.createProblem(); List operands = new ArrayList<>(middleSchoolEquation.operands()); List operators = new ArrayList<>(middleSchoolEquation.operators()); - String function = Arrays.toString(TRIG_FUNCTIONS); - int[] angle = PREDEFINED_ANGLES; + String trigExpression; + Operator connectingOperator; - // 生成对学生友好的三角函数表达式,如 "sin(30)" - // exp4j 的计算将在 QuestionGenerator 中通过自定义函数处理角度 - String trigExpression = String.format("%s(%d)", function, angle); + // 2.【最终修正策略】使用健壮性检查循环,直到生成一个绝对安全的组合 + while (true) { + // 2a. 生成三角函数部分,并确保它不是 tan(90°) + String function; + int angleInDegrees; + do { + function = TRIG_FUNCTIONS[random.nextInt(TRIG_FUNCTIONS.length)]; + angleInDegrees = PREDEFINED_ANGLES[random.nextInt(PREDEFINED_ANGLES.length)]; + } while (function.equals("tan") && angleInDegrees == 90); - // 随机选择一个位置插入三角函数表达式 - int insertPos = random.nextInt(operands.size() + 1); - if (insertPos == operands.size() || operands.isEmpty()) { - operands.add(trigExpression); - if(!operators.isEmpty() || operands.size() > 1) { - operators.add(Operator.ADD); + trigExpression = String.format("%s(%s)", function, getRadianString(angleInDegrees)); + + // 2b. 随机选择一个连接运算符 + connectingOperator = Operator.values()[random.nextInt(Operator.values().length)]; + + // 2c.【健壮性检查】检查这个新运算符是否会与三角函数的值构成除零错误 + boolean isTrigValueZero = (function.equals("sin") && angleInDegrees == 0) || + (function.equals("tan") && angleInDegrees == 0); + + // 如果新运算符是除法,且三角函数的值是0,则这是一个非法组合,必须重试 + if (connectingOperator == Operator.DIVIDE && isTrigValueZero) { + continue; // 非法组合,重新循环 } - } else { - operands.add(insertPos, trigExpression); - operators.add(insertPos, Operator.ADD); // 简单地用加法连接 + + // 如果代码能执行到这里,说明组合是安全的,可以退出循环 + break; } + // 3.【安全的追加操作】将生成的安全组合追加到表达式末尾 + // 这种方法永远不会导致 IndexOutOfBoundsException + operands.add(trigExpression); + operators.add(connectingOperator); return new Equation(operands, operators); } + + /** + * 将特殊的角度值转换为 exp4j 可以计算的、基于 pi 的弧度字符串。 + */ + private String getRadianString(int angleInDegrees) { + switch (angleInDegrees) { + case 0: return "0"; + case 30: return "pi/6"; + case 45: return "pi/4"; + case 60: return "pi/3"; + case 90: return "pi/2"; + default: return "0"; + } + } } \ No newline at end of file diff --git a/src/main/java/com/mathapp/problemGenerators/MiddleSchoolProblemGenerator.java b/src/main/java/com/mathapp/problemGenerators/MiddleSchoolProblemGenerator.java index d8ed83e..30cfc05 100644 --- a/src/main/java/com/mathapp/problemGenerators/MiddleSchoolProblemGenerator.java +++ b/src/main/java/com/mathapp/problemGenerators/MiddleSchoolProblemGenerator.java @@ -8,34 +8,38 @@ import java.util.List; /** * 初中题目生成器(具体策略)。 * 首先生成一个允许出现负数的标准四则运算题目,然后确保至少包含一个平方或开方运算。 - * 生成的格式与 exp4j 兼容。 + * 生成的格式 (例如, "(5^2)" 和 "sqrt(25)") 与 exp4j 库兼容。 */ public class MiddleSchoolProblemGenerator extends AbstractProblemGenerator { @Override protected Equation createProblem() { + // 1. 调用父类的核心方法,并传入 false,允许生成包含负数的标准表达式。 Equation basicEquation = createBaseArithmeticProblem(false); + + // 2. 将基础表达式元素转为可修改的列表 List operands = new ArrayList<>(basicEquation.operands()); List operators = new ArrayList<>(basicEquation.operators()); + // 3. 随机选择一个操作数进行变形 int modifyIndex = random.nextInt(operands.size()); - String targetOperand = operands.get(modifyIndex); - - // 检查操作数是否已经是复杂表达式(包含括号),如果是,则不再添加括号 - boolean isComplex = targetOperand.contains("(") && targetOperand.contains(")"); + String targetOperand = operands.get(modifyIndex).replace("(", "").replace(")", ""); + // 4. 随机决定是进行平方还是开方运算 if (random.nextBoolean()) { - // 平方运算:exp4j 使用 '^' 符号 - // 如果操作数本身是复杂表达式,如 (3+2),则需要保留括号,变成 ((3+2)^2) - String squaredExpression = isComplex? String.format("(%s^2)", targetOperand) : String.format("%s^2", targetOperand); + // 平方运算: 使用 `^` 符号,exp4j 支持此格式 + String squaredExpression = String.format("(%s^2)", targetOperand); operands.set(modifyIndex, squaredExpression); } else { - // 开方运算:exp4j 使用 'sqrt()' 函数 + // 开方运算: 使用 `sqrt()` 函数,exp4j 内置支持此函数 int base = getRandomNumber(2, 10); int valueToRoot = base * base; String sqrtExpression = String.format("sqrt(%d)", valueToRoot); operands.set(modifyIndex, sqrtExpression); } + + // 5. 返回构建好的、与exp4j兼容的方程式 return new Equation(operands, operators); } } +