Python | レベル別練習問題:比較演算子

Python
スポンサーリンク

改良ポイント

機能内容
🧾 解説付きモード各問題に「なぜそうなるか」の解説を表示
💾 成績CSV保存日時・正解数・正答率を quiz_result.csv に自動保存
🔁 間違えた問題のみ再出題結果画面で「間違えた問題だけ再挑戦」ボタンあり

ファイル名:compare_quiz_gui_full.py

# 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

この完全版の特徴

機能内容
🧩 解説付き各問題ごとに下部に理由を表示
💾 CSV保存quiz_result.csv にスコア履歴を追記保存
🔁 再出題機能間違えた問題のみ再挑戦可能
📊 プログレスバー進捗がひと目でわかる
🎨 わかりやすいUIボタン操作だけで完結
タイトルとURLをコピーしました