機能一覧
✅ 問題をランダムに出題
✅ 問題数を変更できる(例:5問中3問をランダム出題)
✅ 「リセット」ボタンで平均点を初期化
✅ 正解時に「解説ポップアップ」表示
✅ 履歴を自動で CSV に保存(日時・得点・平均点)
💻 コード:LogicQuizPro.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
public class LogicQuizPro extends JFrame implements ActionListener {
// 全問題データ
private String[] questions = {
"true && false の結果は?",
"true || false の結果は?",
"!(true && true) の結果は?",
"false || (true && false) の結果は?",
"!(false || true) の結果は?",
"true && (false || true) の結果は?",
"!(false && false) の結果は?"
};
private String[][] options = {
{"true", "false"},
{"true", "false"},
{"true", "false"},
{"true", "false"},
{"true", "false"},
{"true", "false"},
{"true", "false"}
};
private int[] answers = {1, 0, 1, 1, 1, 0, 0};
private String[] explanations = {
"true && false → どちらかが false なので結果は false。",
"true || false → どちらかが true なので結果は true。",
"!(true && true) → true && true は true、否定すると false。",
"false || (true && false) → true && false は false、よって全体は false。",
"!(false || true) → false || true は true、否定して false。",
"true && (false || true) → (false || true) は true、よって全体は true。",
"!(false && false) → false && false は false、否定して true。"
};
// 出題・GUI関係
private int[] selectedIndices;
private ButtonGroup[] groups;
private JRadioButton[][] radios;
private JPanel mainPanel;
private JButton submitButton, resetButton;
private JLabel resultLabel, avgLabel;
private JProgressBar progressBar;
// 採点・履歴
private int totalScore = 0;
private int attempts = 0;
private final int NUM_QUESTIONS = 4; // 出題数
public LogicQuizPro() {
setTitle("論理演算子クイズ Pro - 豪華版");
setSize(520, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
// ランダム出題
selectedIndices = randomizeQuestions(NUM_QUESTIONS);
// 問題パネル
mainPanel = new JPanel();
mainPanel.setLayout(new GridLayout(NUM_QUESTIONS + 2, 1));
groups = new ButtonGroup[NUM_QUESTIONS];
radios = new JRadioButton[NUM_QUESTIONS][2];
for (int i = 0; i < NUM_QUESTIONS; i++) {
int qIndex = selectedIndices[i];
JPanel qPanel = new JPanel(new GridLayout(3, 1));
qPanel.setBorder(BorderFactory.createTitledBorder("問" + (i + 1) + ": " + questions[qIndex]));
groups[i] = new ButtonGroup();
for (int j = 0; j < 2; j++) {
radios[i][j] = new JRadioButton(options[qIndex][j]);
groups[i].add(radios[i][j]);
qPanel.add(radios[i][j]);
}
mainPanel.add(qPanel);
}
// ボタン群
JPanel buttonPanel = new JPanel();
submitButton = new JButton("採点する");
resetButton = new JButton("リセット");
submitButton.addActionListener(this);
resetButton.addActionListener(e -> resetAverage());
buttonPanel.add(submitButton);
buttonPanel.add(resetButton);
mainPanel.add(buttonPanel);
// 結果表示部
resultLabel = new JLabel("ここに結果が表示されます", SwingConstants.CENTER);
avgLabel = new JLabel("平均点: 0%", SwingConstants.CENTER);
progressBar = new JProgressBar(0, 100);
progressBar.setValue(0);
progressBar.setStringPainted(true);
progressBar.setForeground(new Color(100, 180, 255));
JPanel resultPanel = new JPanel(new GridLayout(3, 1));
resultPanel.add(resultLabel);
resultPanel.add(avgLabel);
resultPanel.add(progressBar);
add(mainPanel, BorderLayout.CENTER);
add(resultPanel, BorderLayout.SOUTH);
}
// 出題をランダムに選ぶ
private int[] randomizeQuestions(int count) {
List<Integer> indices = new ArrayList<>();
for (int i = 0; i < questions.length; i++) indices.add(i);
Collections.shuffle(indices);
return indices.subList(0, count).stream().mapToInt(Integer::intValue).toArray();
}
@Override
public void actionPerformed(ActionEvent e) {
int score = 0;
StringBuilder popupMsg = new StringBuilder();
for (int i = 0; i < NUM_QUESTIONS; i++) {
int qIndex = selectedIndices[i];
for (int j = 0; j < 2; j++) {
if (radios[i][j].isSelected()) {
if (j == answers[qIndex]) {
score++;
popupMsg.append("問").append(i + 1).append(" ✅ 正解! ")
.append(explanations[qIndex]).append("\n\n");
} else {
popupMsg.append("問").append(i + 1).append(" ❌ 不正解。 ")
.append(explanations[qIndex]).append("\n\n");
}
}
}
}
int percent = (int) ((score / (double) NUM_QUESTIONS) * 100);
resultLabel.setText("今回の得点: " + percent + "点 (" + score + "/" + NUM_QUESTIONS + ")");
JOptionPane.showMessageDialog(this, popupMsg.toString(), "解説", JOptionPane.INFORMATION_MESSAGE);
// 平均スコア更新
attempts++;
totalScore += percent;
int avg = totalScore / attempts;
avgLabel.setText("平均点: " + avg + "%");
animateProgressBar(avg);
// 履歴を保存
saveToCSV(percent, avg);
// 新しい問題を再生成
regenerateQuiz();
}
// 平均点リセット
private void resetAverage() {
totalScore = 0;
attempts = 0;
avgLabel.setText("平均点: 0%");
progressBar.setValue(0);
}
// プログレスバー演出
private void animateProgressBar(int target) {
new Thread(() -> {
int current = progressBar.getValue();
if (target < current) {
for (int i = current; i >= target; i--) {
progressBar.setValue(i);
sleep(10);
}
} else {
for (int i = current; i <= target; i++) {
progressBar.setValue(i);
sleep(10);
}
}
}).start();
}
private void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
// CSV出力(履歴保存)
private void saveToCSV(int score, int avg) {
try (FileWriter fw = new FileWriter("quiz_history.csv", true);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(bw)) {
String time = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date());
pw.println(time + "," + score + "," + avg);
} catch (IOException ex) {
ex.printStackTrace();
}
}
// 新しい問題を再出題
private void regenerateQuiz() {
selectedIndices = randomizeQuestions(NUM_QUESTIONS);
getContentPane().removeAll();
new LogicQuizPro().setVisible(true);
dispose();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new LogicQuizPro().setVisible(true));
}
}
Java機能の動作解説
| 機能 | 内容 |
|---|---|
| ランダム出題 | Collections.shuffle()で問題を毎回シャッフル |
| 出題数調整 | NUM_QUESTIONS の値を変更するだけ |
| リセット | 平均スコアと進捗バーを初期化 |
| ポップアップ解説 | JOptionPane.showMessageDialog()で正誤+説明表示 |
| CSV出力 | quiz_history.csv に日時・得点・平均点を追記保存 |
| 演出 | バーが伸びるアニメーション付きで学習意欲UP! |
履歴ファイル(例)
2025/10/22 16:10:35,75,75
2025/10/22 16:15:41,100,87
2025/10/22 16:20:10,50,75
次の拡張アイデア
- 🕓 タイマー付き出題(制限時間モード)
- 🧩 出題カテゴリを選べる(論理演算・比較演算など)
- 🏆 最高点ランキング表示
- 📈 平均スコアの推移グラフ表示(
JFreeChartなどで)


