GoogleColabでPythonを使って４択クイズを作成してみた

## はじめに
 Pyhonは、近年ではスタンダードになりつつあるプログラミング言語で、プログラミング初心者にもとっつきやすく、一方でAI開発などの高度な使い方までができるのが特徴となっています。
　以前に、Pythonの超初心者向けとして、
 
【初心者向け】GoogleColabでPythonを使ってみよう！
https://qiita.com/tech-nami/items/5ccc313539563eeab117

という記事を投稿させていただきましたが、その後、子供の情報の授業で、GoogleColabでPythonを使って何かプログラムを作れという課題が出て頑張っているのを見て、私も少しやってみようと思い、４択形式の問題を出題するプログラムを作ってみました。

　CやJavaは理解しているつもりですが、Pythonは配列などのデータの扱いがこれまでの言語とは異なるため、少し苦労しました。もちろん便利に自動化してくれていると思うのですが、逆にC言語等で開発してきた私にとっては少し理解しにくく、難しく感じます。正直まだ完成形とは言えない状態ですが、こんな感じで使えるよ、といった参考になれば幸いです。
 ＃ここをこう改善すべきというご意見がございましたら、ぜひコメントください！

## GoogleColabでPythonを使って４択クイズを作成
　まずは、GoogleColabで新しいノートブックを準備をしてください。

（参考）【初心者向け】GoogleColabでPythonを使ってみよう！
https://qiita.com/tech-nami/items/5ccc313539563eeab117

１．「Colaboratoryへようこそ」画面にて、
「ファイル」「ドライブの新しいノートブック」を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/602c71e6-33b3-edba-bff7-7cdaaa36334c.png" width=100%>

２．新しいノートブックが表示されるので、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/65ee9d86-5897-305e-0811-0bbf5869b866.png" width=100%>

早速ですが、下記のように入力して実行してみてください。

```py:Google Colab
import ipywidgets as widgets
from IPython.display import display, clear_output
import pandas as pd
import random
from google.colab import files

import importlib
if not importlib.util.find_spec('japanize_matplotlib'):
  !pip install japanize-matplotlib
import japanize_matplotlib

uploaded = files.upload()

# ダイアログにてファイル名を取得
file_name = list(uploaded.keys())[0]

try:
    if file_name.endswith('.csv'):
        df = pd.read_csv(file_name, encoding='utf-8')
        df_original = pd.read_csv(file_name, encoding='utf-8') # 元のDataFrameを保存
    elif file_name.endswith(('.xls', '.xlsx')):
        df = pd.read_excel(file_name)
        df_original = pd.read_excel(file_name) # 元のDataFrameを保存
    else:
        print("対応していないファイル形式です。CSVまたはExcel(xls/xlsx)形式を使用してください。")
        exit()

    # 問題文の列名が"問題"でない場合は、ここで修正する
    if "問題" not in df.columns:
        print("問題文の列名が\"問題\"ではありません。ファイルを確認してください。")
        exit()

    # 正誤判定を保存するリスト
    results = []
    question_count = 10 # 出題する問題数
    asked_questions = []

    def show_question(question_data):
        question = question_data["問題"]
        choices = [question_data["正解"], question_data["不正解１"], question_data["不正解２"], question_data["不正解３"]]
        random.shuffle(choices)

        print(f"問題{len(asked_questions) + 1}: {question}")

        buttons = []
        for i, choice in enumerate(choices):
            button = widgets.Button(description=str(i+1) + ". " + choice)
            button.on_click(lambda b, c=choice, correct=question_data["正解"]: on_answer(b, c, correct))
            buttons.append(button)
            display(button)

    def on_answer(button, clicked_choice, correct_answer):
        global results
        is_correct = clicked_choice == correct_answer
        results.append((button.description, is_correct))
        clear_output()
        show_next_question()

    def show_next_question():
        if len(asked_questions) < question_count and len(df) > 0:
          question_data = df.sample(n=1).iloc[0].to_dict()

          # 同じ問題が出題されないようにチェックする
          while question_data['問題'] in asked_questions:
              question_data = df.sample(n=1).iloc[0].to_dict()
          asked_questions.append(question_data['問題'])
          df.drop(index=df.index[df["問題"] == question_data['問題']].tolist()[0], inplace=True) #問題文を削除


          show_question(question_data)
        else:
          show_results()

    def show_results():
        correct_count = sum(1 for _, is_correct in results if is_correct)
        accuracy = (correct_count / len(results)) * 100 if results else 0

        print("結果発表！")
        #結果（問題、正解、回答、回答の正誤）を、DataFlameに格納する
        df_results = pd.DataFrame(results, columns=['回答', '正誤'])
        df_results['問題'] = asked_questions
        df_results['正解'] = df_results['問題'].apply(lambda x: next((item['正解'] for index, item in df_original.iterrows() if item['問題'] == x), None))
        df_results = df_results[['問題', '正解', '回答', '正誤']]
        display(df_results)

        print(f"正解率: {accuracy:.2f}%")

    show_next_question()

except Exception as e:
    print(f"エラーが発生しました: {e}")
```

これを実行すると、入力するファイルを聞かれますので、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/5be24fa9-071b-4a64-beb4-4dafd803caa8.png)

デスクトップ等に下記の様なExcelファイル（またはCSVファイル）を作成しておき、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/4d03c15c-cd90-4392-bc66-40f07396f34f.png" width=80%>

「ファイル選択」で表示されるファイルダイアログで指定します。

すると、下記の様な感じで問題が開始されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/6e667fb9-5c48-40f8-9841-10ac0476e826.png" width=30%>

一通り問題が終わると、結果発表として、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/e0bb9702-6953-494c-9b60-bfdaf7aea8ad.png" width=60%>

の様に採点されて、一覧表示されます。
（実を言いますと、問題番号が０、１、２となっており、本来１、２、３となっているべきなのですが、これを補正することができておりません。このところご容赦ください）

 今回も、GoogleColab の「AIで生成」に、ある程度のソースを作成してもらいましたが、細かいところは思った通りに行きませんでした。続けてPythonの勉強を進めて、より良いソースにしていきたいと思います。

## まとめ
　今回は、GoogleColab上で、Pythonを使って、４択クイズを出題するプログラムを作成しました。
　①ExcelまたはCSVに記載した問題を読み込み、ランダムな順序で出題する
　②４択の選択肢も、並び順を毎回同じでなく、ランダムに並び替える
　③選択肢をボタンにしており、次々に回答ができる
　といったところをポイントです。
　みなさんも、Pythonを使っていろいろなプログラムを作ってみてください！