10.16

qixunlu發表於2024-10-16

完成了生成四則運算的程式
分為QixunluGUI類主程式完成介面顯示,QuestionGenerator類題目父類,Grade2QuestionGenerator類實現二年級的題目生成繼承QuestionGenerator類
Grade3QuestionGenerator類實現三年級的題目生成繼承Grade2QuestionGenerator類,Grade4QuestionGenerator類實現三年級的題目生成繼承Grade3QuestionGenerator類
QuestionGeneratorFactory類題目生成防止報錯
具體程式碼如下:
QixunluGUI類

點選檢視程式碼
package qixun;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.Timer;

public class QixunluGUI extends JFrame {
    private static final int TIME_LIMIT = 60;
    private int questionCount;
    private String[] questions;
    private double[] correctAnswers;
    private JTextField[] answerFields;
    private JLabel[] resultLabels;
    private JLabel timerLabel = new JLabel("剩餘時間: " + TIME_LIMIT + "秒");
    private int correctCount = 0;
    private int timeRemaining = TIME_LIMIT;

    // 錯題記錄集
    private List<MistakeRecord> mistakeList = new ArrayList<>();

    public QixunluGUI(int questionCount, int gradeLevel) {
        this.questionCount = questionCount;
        this.questions = new String[questionCount];
        this.correctAnswers = new double[questionCount];
        this.answerFields = new JTextField[questionCount];
        this.resultLabels = new JLabel[questionCount];

        setTitle("數學測驗");
        setSize(500, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        // 生成問題
        QuestionGenerator generator = QuestionGeneratorFactory.createGenerator(gradeLevel);
        for (int i = 0; i < questionCount; i++) {
            questions[i] = generator.getQuestion();
            correctAnswers[i] = generator.getAnswer(questions[i]);
        }

        // 建立一個皮膚用於問題佈局,三道題一行
        JPanel questionPanel = new JPanel(new GridLayout((questionCount + 2) / 3, 4));
        for (int i = 0; i < questionCount; i++) {
            questionPanel.add(new JLabel("問題 " + (i + 1) + ": " + questions[i]));
            answerFields[i] = new JTextField(10);
            questionPanel.add(answerFields[i]);
            resultLabels[i] = new JLabel();
            questionPanel.add(resultLabels[i]);

            JButton checkButton = new JButton("提交");
            int finalI = i;
            checkButton.addActionListener(e -> submitSingleAnswer(finalI, resultLabels[finalI]));
            questionPanel.add(checkButton);
        }

        // 建立一個皮膚用於放置總提交按鈕
        JPanel submitPanel = new JPanel(new FlowLayout());
        JButton finalSubmitButton = new JButton("提交所有答案");
        JButton retryMistakesButton = new JButton("錯題重練");
        JLabel finalResultLabel = new JLabel();

        // 處理倒數計時
        Timer timer = new Timer(1000, e -> {
            timeRemaining--;
            timerLabel.setText("剩餘時間: " + timeRemaining + "秒");
            if (timeRemaining <= 0) {
                ((Timer) e.getSource()).stop();
                JOptionPane.showMessageDialog(null, "時間到!");
                submitAllAnswers(finalResultLabel);
            }
        });
        timer.start();

        // 設定總提交按鈕事件
        finalSubmitButton.addActionListener(e -> {
            timer.stop();
            submitAllAnswers(finalResultLabel);
        });

        // 設定錯題重練按鈕事件
        retryMistakesButton.addActionListener(e -> retryMistakes());

        // 將按鈕和結果標籤加入提交皮膚
        submitPanel.add(finalSubmitButton);
        submitPanel.add(retryMistakesButton);
        submitPanel.add(finalResultLabel);

        add(timerLabel, BorderLayout.NORTH);
        add(new JScrollPane(questionPanel), BorderLayout.CENTER); // 新增問題皮膚
        add(submitPanel, BorderLayout.SOUTH); // 提交按鈕單獨一行

        setVisible(true);
    }

    // 提交單個答案
    private void submitSingleAnswer(int index, JLabel resultLabel) {
        try {
            double userAnswer = Double.parseDouble(answerFields[index].getText());
            if (Math.abs(userAnswer - correctAnswers[index]) < 0.001) {
                correctCount++;
                resultLabel.setText("正確");
            } else {
                resultLabel.setText("錯誤,正確答案是: " + correctAnswers[index]);
                // 記錄錯題
                mistakeList.add(new MistakeRecord(questions[index], correctAnswers[index], userAnswer));
            }
        } catch (NumberFormatException ex) {
            resultLabel.setText("請輸入有效的數字");
        }
    }

    // 提交所有答案
    private void submitAllAnswers(JLabel finalResultLabel) {
        finalResultLabel.setText("總正確率: " + (correctCount / (double) questionCount * 100) + "%");
    }

    // 錯題重練功能
    private void retryMistakes() {
        if (mistakeList.isEmpty()) {
            JOptionPane.showMessageDialog(this, "沒有錯題可以重練!");
            return;
        }

        JFrame retryFrame = new JFrame("錯題重練");
        retryFrame.setSize(400, 400);
        retryFrame.setLayout(new GridLayout(mistakeList.size(), 3));

        // 重練錯題
        for (MistakeRecord mistake : mistakeList) {
            retryFrame.add(new JLabel("題目: " + mistake.getQuestion()));
            JTextField retryAnswerField = new JTextField(10);
            retryFrame.add(retryAnswerField);
            JLabel retryResultLabel = new JLabel();
            retryFrame.add(retryResultLabel);

            JButton retryCheckButton = new JButton("重練提交");
            retryCheckButton.addActionListener(e -> {
                try {
                    double retryAnswer = Double.parseDouble(retryAnswerField.getText());
                    if (Math.abs(retryAnswer - mistake.getCorrectAnswer()) < 0.001) {
                        retryResultLabel.setText("正確");
                    } else {
                        retryResultLabel.setText("錯誤,正確答案是: " + mistake.getCorrectAnswer());
                        mistake.incrementAttempt(); // 增加錯題重練次數
                    }
                } catch (NumberFormatException ex) {
                    retryResultLabel.setText("請輸入有效的數字");
                }
            });
            retryFrame.add(retryCheckButton);
        }

        retryFrame.setVisible(true);
    }

    // 錯題記錄類
    private static class MistakeRecord {
        private String question;
        private double correctAnswer;
        private double userAnswer;
        private int attemptCount = 1; // 錯題初始嘗試次數

        public MistakeRecord(String question, double correctAnswer, double userAnswer) {
            this.question = question;
            this.correctAnswer = correctAnswer;
            this.userAnswer = userAnswer;
        }

        public String getQuestion() {
            return question;
        }

        public double getCorrectAnswer() {
            return correctAnswer;
        }

        public int getAttemptCount() {
            return attemptCount;
        }

        public void incrementAttempt() {
            attemptCount++;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        boolean flag = true;
        while (flag) {
            System.out.print("請輸入題目數量: ");
            int questionCount = scanner.nextInt();
            System.out.print("請輸入年級(2-4): ");
            int gradeLevel = scanner.nextInt();
            new QixunluGUI(questionCount, gradeLevel);
            System.out.println("再來一次(輸入yse)");
            String angan=scanner.next();
            if(angan.equals("yes")){
                flag = true;
            }else {
                flag = false;
            }
        }
    }
}

QuestionGenerator類
點選檢視程式碼
package qixun;

import java.util.*;

public abstract class QuestionGenerator {
    protected int operandCount;
    protected int maxOperandValue;
    protected boolean allowMultiplication;
    protected boolean allowDivision;

    // 抽象方法,子類需要實現具體的題目生成邏輯
    public abstract String getQuestion();

    // 獲取題目的答案
    public abstract double getAnswer(String question);
}

Grade2QuestionGenerator類
點選檢視程式碼
package qixun;

import java.util.Random;

public class Grade2QuestionGenerator extends QuestionGenerator {
    public Grade2QuestionGenerator() {
        this.operandCount = 2; // 運算元為兩個
        this.maxOperandValue = 100; // 運算元範圍不超過100
        this.allowMultiplication = true;
        this.allowDivision = true;
    }

    @Override
    public String getQuestion() {
        Random random = new Random();
        int operand1 = random.nextInt(maxOperandValue) + 1;
        int operand2 = random.nextInt(maxOperandValue) + 1;
        String operator = generateOperator(); // 使用生成的運算子

        // 確保除法時可以整除且不超過100
        if (operator.equals("/")) {
            while (operand1 % operand2 != 0 || operand1 > 100) {
                operand1 = random.nextInt(maxOperandValue) + 1;
                operand2 = random.nextInt(maxOperandValue) + 1;
            }
        }

        return operand1 + " " + operator + " " + operand2;
    }

    @Override
    public double getAnswer(String question) {
        String[] parts = question.split(" ");
        int operand1 = Integer.parseInt(parts[0]);
        String operator = parts[1];
        int operand2 = Integer.parseInt(parts[2]);

        switch (operator) {
            case "+":
                return operand1 + operand2;
            case "-":
                return operand1 - operand2;
            case "*":
                return operand1 * operand2;
            case "/":
                return (double) operand1 / operand2;
            default:
                throw new IllegalArgumentException("無效的運算子!");
        }
    }

    protected String generateOperator() {
        Random random = new Random();
        String[] operators = {"+", "-", "*", "/"};
        return operators[random.nextInt(operators.length)];
    }
}

Grade3QuestionGenerator類
點選檢視程式碼
package qixun;

import java.util.Random;

public class Grade3QuestionGenerator extends Grade2QuestionGenerator {
    public Grade3QuestionGenerator() {
        this.operandCount = 4; // 運算元不超過4個
        this.maxOperandValue = 1000; // 運算元範圍不超過1000
    }

    @Override
    public String getQuestion() {
        Random random = new Random();
        StringBuilder question = new StringBuilder();

        // 生成最多4個運算元的表示式
        for (int i = 0; i < operandCount - 1; i++) {
            int operand = random.nextInt(maxOperandValue) + 1;
            String operator = generateOperator(); // 呼叫父類的 generateOperator()
            question.append(operand).append(" ").append(operator).append(" ");
        }
        question.append(random.nextInt(maxOperandValue) + 1); // 最後一個運算元

        return question.toString();
    }

    @Override
    public double getAnswer(String question) {
        double result = super.getAnswer(question);
        // 確保結果不超過10000
        if (result > 10000) {
            throw new IllegalArgumentException("結果不能超過10000!");
        }
        return result;
    }
}

Grade4QuestionGenerator類
點選檢視程式碼
package qixun;

import java.util.*;

public class Grade4QuestionGenerator extends Grade3QuestionGenerator {
    public Grade4QuestionGenerator() {
        this.operandCount = 5;
    }

    @Override
    public String getQuestion() {
        Random random = new Random();
        StringBuilder question = new StringBuilder();

        // 生成最多5個運算元的表示式,並可能加入括號
        boolean useBrackets = random.nextBoolean();
        if (useBrackets) {
            question.append("(");
        }

        for (int i = 0; i < operandCount - 1; i++) {
            int operand = random.nextInt(maxOperandValue) + 1;
            String operator = generateOperator();
            question.append(operand).append(" ").append(operator).append(" ");

            if (useBrackets && i == 2) {
                question.append(") ");
                useBrackets = false; // 防止括號重複使用
            }
        }
        question.append(random.nextInt(maxOperandValue) + 1); // 最後一個運算元

        return question.toString();
    }
}

QuestionGeneratorFactory類
點選檢視程式碼
package qixun;

public class QuestionGeneratorFactory {

    public static QuestionGenerator createGenerator(int gradeLevel) {
        switch (gradeLevel) {
            case 2:
                return new Grade2QuestionGenerator();
            case 3:
                return new Grade3QuestionGenerator();
            case 4:
                return new Grade4QuestionGenerator();
            default:
                throw new IllegalArgumentException("年級只能是2, 3或4");
        }
    }
}