# compare_quiz_gui_full.py
# ===========================================================
# Python 比較演算子クイズ(全50問)GUI完全版
# - 解説付き
# - 成績をCSV保存
# - 間違えた問題のみ再出題機能付き
# ===========================================================
import PySimpleGUI as sg
import csv
from datetime import datetime
# -----------------------------
# 問題セット(式, 正解, 解説)
# -----------------------------
quiz_data = [
("5 == 5", True, "同じ値なので True。"),
("5 != 3", True, "5 と 3 は異なるため True。"),
("4 < 2", False, "4 は 2 より小さくない。"),
("10 > 5", True, "10 は 5 より大きい。"),
("7 >= 7", True, "7 は 7 以上なので True。"),
("3 <= 2", False, "3 は 2 以下ではない。"),
("'a' == 'A'", False, "大文字と小文字は異なる。"),
("'abc' != 'abd'", True, "3文字目が違うため異なる。"),
("10 == 10.0", True, "int と float でも値が同じなら True。"),
("True == 1", True, "Pythonでは True は 1 と等しい。"),
("len('cat') == 3", True, "cat の長さは 3。"),
("'dog' < 'zebra'", True, "文字列比較はアルファベット順。"),
("'apple' > 'banana'", False, "a より b は後の文字。"),
("100 >= 200", False, "100 は 200 以上ではない。"),
("5 * 2 == 10", True, "掛け算の結果は 10。"),
("10 / 2 != 5", False, "10 ÷ 2 = 5 なので != は False。"),
("'a' in 'apple'", True, "apple に a は含まれる。"),
("'x' in 'apple'", False, "x は含まれない。"),
("'app' not in 'apple'", False, "app は含まれるので False。"),
("'pp' in 'apple'", True, "pp は含まれる。"),
("[1,2] == [1,2]", True, "リスト内容が同じなら True。"),
("[1,2] is [1,2]", False, "別のオブジェクトなので False。"),
("x = [1,2]; y = x; x is y", True, "同じ参照を指している。"),
("(3 > 2) and (2 > 1)", True, "両方 True。"),
("(3 > 2) and (2 < 1)", False, "後半が False。"),
("(3 > 2) or (2 < 1)", True, "or はどちらかが True でOK。"),
("not (5 > 2)", False, "5>2 は True、not で False。"),
("10 == 5 * 2", True, "5×2=10。"),
("'Hello'.lower() == 'hello'", True, "小文字化で一致。"),
("'HELLO'.isupper() == True", True, "すべて大文字。"),
("10 < 20 < 30", True, "連鎖比較はすべて条件を満たす。"),
("5 < 10 > 2", True, "5<10 かつ 10>2。"),
("10 == 5 + 5 == True", False, "10 == 10 は True、でも True==True? 比較順注意。"),
("not (3 < 5)", False, "3<5 は True、notでFalse。"),
("(3 < 5) and not (2 > 1)", False, "後半が False。"),
("(3 < 5) or not (2 > 1)", True, "or なので前半 True。"),
("None is None", True, "None は同一オブジェクト。"),
("0 == False", True, "False は 0 と等しい。"),
("'' == False", False, "空文字は False と等しくない。"),
("[] == False", False, "空リストも False とは等しくない。"),
("'error' in 'log_error_message'", True, "error を含む。"),
("'ok' not in 'error_log'", True, "ok は含まれない。"),
("10 != 10.0", False, "値は同じなので != は False。"),
("'Python' > 'java'", True, "大文字は小文字より前に並ぶ。"),
("'A' < 'a'", True, "ASCIIコードで 'A'(65) < 'a'(97)。"),
("'あ' > 'い'", False, "Unicode順で 'あ' < 'い'。"),
("'10' == 10", False, "型が違うため False。"),
("type(10) == int", True, "10 は int 型。"),
("type(10.0) == float", True, "10.0 は float 型。"),
("isinstance('abc', str)", True, "abc は str インスタンス。"),
]
# -----------------------------
# GUI 設定
# -----------------------------
sg.theme("DarkBlue3")
def make_window():
layout = [
[sg.Text("Python 比較演算子クイズ", font=("Arial", 20), justification="center", expand_x=True)],
[sg.Text("", key="-QNUM-", font=("Arial", 14))],
[sg.Multiline("", key="-QUESTION-", size=(40, 4), font=("Consolas", 14), disabled=True)],
[sg.Button("True (T)", key="TRUE", size=(10, 2), button_color=("white", "green")),
sg.Button("False (F)", key="FALSE", size=(10, 2), button_color=("white", "red"))],
[sg.Text("", key="-FEEDBACK-", font=("Arial", 13), text_color="yellow")],
[sg.Text("", key="-EXPLAIN-", font=("Arial", 12), text_color="lightblue", size=(40, 3))],
[sg.ProgressBar(len(quiz_data), orientation='h', size=(30, 20), key="-PROG-")],
[sg.Button("終了", key="EXIT", size=(10, 1))]
]
return sg.Window("比較演算子クイズ", layout, finalize=True)
# -----------------------------
# 出題関数
# -----------------------------
def show_question(win, i):
win["-QNUM-"].update(f"Q{i+1}/{len(quiz_data)}")
expr, _, _ = quiz_data[i]
win["-QUESTION-"].update(expr)
win["-FEEDBACK-"].update("")
win["-EXPLAIN-"].update("")
# -----------------------------
# メインロジック
# -----------------------------
def run_quiz(quiz_subset):
window = make_window()
index, score = 0, 0
wrong = []
def show(i):
window["-QNUM-"].update(f"Q{i+1}/{len(quiz_subset)}")
expr, _, _ = quiz_subset[i]
window["-QUESTION-"].update(expr)
window["-FEEDBACK-"].update("")
window["-EXPLAIN-"].update("")
show(index)
while True:
event, _ = window.read()
if event in (sg.WIN_CLOSED, "EXIT"):
window.close()
return None, None
if event in ("TRUE", "FALSE"):
user_ans = (event == "TRUE")
expr, correct, explain = quiz_subset[index]
if user_ans == correct:
feedback = "✅ 正解!"
score += 1
else:
feedback = f"❌ 不正解(正解は {correct})"
wrong.append((expr, correct, explain))
window["-FEEDBACK-"].update(feedback)
window["-EXPLAIN-"].update(explain)
window["-PROG-"].update_bar(index + 1)
index += 1
if index < len(quiz_subset):
show(index)
else:
break
window.close()
return score, wrong
# -----------------------------
# 成績保存
# -----------------------------
def save_result(score, total):
rate = round(score / total * 100, 1)
with open("quiz_result.csv", "a", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow([datetime.now().strftime("%Y-%m-%d %H:%M:%S"), score, total, rate])
# -----------------------------
# メイン実行
# -----------------------------
while True:
score, wrong_list = run_quiz(quiz_data)
if score is None:
break
total = len(quiz_data)
percent = score / total * 100
save_result(score, total)
msg = f"正解数: {score}/{total}\n正答率: {percent:.1f}%"
if percent == 100:
comment = "🎉 パーフェクト!完璧です!"
elif percent >= 80:
comment = "💪 よくできました!"
elif percent >= 50:
comment = "👍 基礎は理解できています。"
else:
comment = "📘 もう少し練習しましょう。"
btns = ["終了"]
if wrong_list:
btns.insert(0, "間違えた問題だけ再挑戦")
event = sg.popup_yes_no(
f"{msg}\n\n{comment}\n\n間違えた問題は {len(wrong_list)} 問です。",
title="結果発表",
custom_text=("再挑戦", "終了") if wrong_list else None,
font=("Arial", 14)
)
if event == "再挑戦":
quiz_data = wrong_list
continue
else:
sg.popup("結果を 'quiz_result.csv' に保存しました。", font=("Arial", 12))
break
Python