0
0

FlaskとHTMLでシンプルな小学生向け算数クイズアプリを作成する方法

Posted at

はじめに

この記事では、FlaskとHTMLを使用してシンプルなクイズアプリを作成する方法を紹介します。このアプリケーションでは、サーバーサイドでFlaskを利用して問題を生成し、クライアントサイドではHTMLとJavaScriptを使って問題を表示し、ユーザーからの回答を受け付けます。クイズの問題は算数の基本的な計算問題をランダムに生成し、ユーザーが選択肢をクリックして回答できるインターフェースを提供します。さらに、ユーザーがクイズを提出すると、正答率を計算して結果を表示します。

このアプリを作成することで、Flaskの基本的な使い方や、HTML、CSS、JavaScriptの連携方法を学ぶことができます。以下に、ディレクトリ構成やプログラムの詳細な説明を示しますので、ぜひ参考にしてみてください。

ディレクトリ構成

まず、アプリケーションのディレクトリ構成は以下のようになります。

quiz_app/
├── app.py
├── static/
│   └── style.css
└── templates/
    └── index.html
  • app.py: Flaskアプリケーションのメインファイル
  • static/style.css: アプリケーションのスタイルを定義するCSSファイル
  • templates/index.html: アプリケーションのHTMLテンプレートファイル

プログラムの説明

app.py

Flaskを使ってサーバーサイドのロジックを処理します。

from flask import Flask, render_template, request, jsonify, session
import random

app = Flask(__name__)
app.secret_key = 'your_secret_key'  # セッションを使用するために必要

def generate_math_question():
    operators = ['+', '-', '*']
    num1 = random.randint(1, 10)
    num2 = random.randint(1, 10)
    operator = random.choice(operators)
    question = f"{num1} {operator} {num2}"
    answer = eval(question)
    
    # 正解を含む4つの選択肢を生成
    options = [answer,
               random.randint(answer - 10, answer + 10),
               random.randint(answer - 10, answer + 10),
               random.randint(answer - 10, answer + 10)]
    random.shuffle(options)
    
    return {
        "question": f"What is {question}?",
        "options": options,
        "answer": answer
    }

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/get_question', methods=['POST'])
def get_question():
    quiz = [generate_math_question() for _ in range(10)]  # 10問ランダムに生成
    session['questions'] = quiz  # セッションに質問を保存
    return jsonify(quiz)

@app.route('/submit_answers', methods=['POST'])
def submit_answers():
    user_answers = request.json.get('answers', [])
    questions = session.get('questions', [])
    
    if not questions:
        return jsonify({'error': 'No questions found in session'}), 400
    
    score = 0
    for user_answer, question in zip(user_answers, questions):
        if user_answer is not None and int(user_answer) == question['answer']:
            score += 1

    percentage = (score / len(questions)) * 100
    return jsonify({'score': percentage})

if __name__ == '__main__':
    app.run(debug=True)
  • generate_math_question(): ランダムな数学の問題を生成し、正解と選択肢を含む辞書を返します。
  • / (ルート): index.htmlテンプレートをレンダリングして返します。
  • /get_question: クイズの10問を生成し、セッションに保存してJSON形式で返します。
  • /submit_answers: ユーザーが送信した回答をセッションに保存された質問と比較し、正解率を計算して返します。

templates/index.html

HTMLファイルで、フロントエンドのUIを提供します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Quiz App</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <h1>Quiz App</h1>
    <div id="quiz-container"></div>
    <button onclick="submitQuiz()">Submit Quiz</button>
    <div id="result"></div>

    <script>
        let questions = [];
        let userAnswers = [];

        window.onload = async function() {
            const response = await fetch('/get_question', { method: 'POST' });
            questions = await response.json();
            displayQuiz();
        };

        function displayQuiz() {
            const container = document.getElementById('quiz-container');
            container.innerHTML = '';
            questions.forEach((q, index) => {
                const questionDiv = document.createElement('div');
                questionDiv.classList.add('question');
                questionDiv.innerHTML = `<p>${q.question}</p>`;
                q.options.forEach(option => {
                    const optionButton = document.createElement('button');
                    optionButton.textContent = option;
                    optionButton.classList.add('option-button');
                    optionButton.onclick = () => selectAnswer(index, option, optionButton);
                    questionDiv.appendChild(optionButton);
                });
                container.appendChild(questionDiv);
            });
        }

        function selectAnswer(questionIndex, answer, button) {
            userAnswers[questionIndex] = answer;

            // 選択されたボタンのスタイルを変更
            const questionDiv = button.parentElement;
            const optionButtons = questionDiv.getElementsByClassName('option-button');
            for (let btn of optionButtons) {
                btn.classList.remove('selected');
            }
            button.classList.add('selected');
        }

        async function submitQuiz() {
            const response = await fetch('/submit_answers', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ answers: userAnswers })
            });
            const result = await response.json();
            if (result.error) {
                document.getElementById('result').textContent = result.error;
            } else {
                document.getElementById('result').textContent = `Your score: ${result.score}%`;
            }
        }
    </script>
</body>
</html>
  • window.onload: ページが読み込まれたときにサーバーから問題を取得し、表示します。
  • displayQuiz(): 取得した問題をHTMLに表示します。
  • selectAnswer(): ユーザーが選択肢をクリックしたときの処理を行い、選択された回答を記録します。
  • submitQuiz(): ユーザーの回答をサーバーに送信し、結果を表示します。

static/style.css

アプリケーションのスタイルを定義します。

body {
    font-family: Arial, sans-serif;
    background-color: #f0f0f0;
    margin: 0;
    padding: 0;
}

h1 {
    text-align: center;
    margin-top: 20px;
}

#quiz-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin: 20px;
}

.question {
    margin-bottom: 20px;
}

.option-button {
    display: block;
    margin: 5px 0;
    padding: 10px;
    background-color: #ffffff;
    border: 1px solid #cccccc;
    border-radius: 5px;
    cursor: pointer;
}

.option-button.selected {
    background-color: #d3ffd3;
}

button {
    display: block;
    margin: 20px auto;
    padding: 10px 20px;
    font-size: 16px;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

button:hover {
    background-color: #45a049;
}

#result {
    text-align: center;
    font-size: 18px;
    font-weight: bold;
}
  • スタイルの設定で、ボタンのデザインやページ全体の見た目を整えています。

実行

以下のコマンドで Flask アプリケーションを実行します。

python app.py

ブラウザで http://127.0.0.1:5000/ にアクセスすると以下の画面が出ます

screencapture-localhost-5000-2024-08-21-16_23_20.png

おわりに

この記事では、FlaskとHTMLを使ったシンプルなクイズアプリの作成方法を説明しました。サーバーサイドで問題を生成し、クライアントサイドでユーザーインターフェースを構築することで、Webアプリケーションの基本的なフローを学ぶことができたかと思います。

このクイズアプリをもとに、さらに複雑な機能を追加することもできます。例えば、ユーザー認証機能や問題の難易度選択、ユーザーごとの成績管理などの機能を追加して、自分だけのオリジナルアプリを作成してみてください。

質問やコメントがあれば、お気軽にお知らせください。最後までお読みいただき、ありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0