【ゲーム】JavaScript:20 世界の国旗当てクイズ

 「世界の国旗当てクイズ」は、画面に表示される国旗の絵文字を見て、4択の中から該当する国名を選ぶ知識クイズゲームです。全20カ国の中からランダムに10問出題され、正答率を競います。

遊び方・操作方法

  • スタート:タイトル画面の「スタート」ボタンをクリック
  • 問題:画面中央に国旗の絵文字が表示
  • 選択:4つの国名ボタンからひとつをクリック
  • フィードバック:正解なら「✅ 正解です!」、不正解なら「❌ 不正解… 正解は『〇〇』です。」と表示
  • 次へ:フィードバック後に表示される「次の問題」ボタンをクリック
  • 結果:10問回答後、正答率をパーセンテージで表示
  • タイトルに戻る:結果画面の「タイトルに戻る」ボタンをクリック

ルール

  1. 全20カ国からランダムに10問を出題
  2. 各問題につき1回のみ選択可
  3. 回答後に正誤フィードバック表示
  4. 10問回答後、正答率(%)を表示
  5. 再挑戦したい場合はタイトル画面に戻って再スタート

🎮ゲームプレイ

以下のリンク先から実際にプレイできます。

20 世界の国旗当てクイズ

素材のダウンロード

以下のリンクから使用する素材をダウンロードできます。

world_flags_quiz_title.pngworld_flags_quiz_bg.png

ゲーム画面イメージ

プログラム全文(world_flags_quiz.html)

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>🌏 世界の国旗当てクイズ 🌏</title>
    <style>
        /* 全体リセット */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Arial', sans-serif;
            background-color: #f4f4f9;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            text-align: center;
            background-image: url('world_flags_quiz_bg.png');
            background-size: cover;
            background-position: center;
            color: #fff;
        }

        /* クイズコンテナ */
        #quiz-container {
            background-color: rgba(0, 0, 0, 0.75);
            padding: 30px;
            border-radius: 10px;
            width: 90%;
            max-width: 600px;
            height: 700px;           /* 固定高さを指定して全画面と同じサイズに */
            overflow-y: auto;        /* 中身がはみ出す場合はスクロール */
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
        }

        /* メインタイトル */
        #quiz-container > h1 {
            font-size: 2.2rem;
            color: #FFD700;
            margin-bottom: 20px;
        }

        /* タイトル画面の画像 */
        #title-screen img {
            max-width: 80%;
            height: auto;
            margin-bottom: 20px;
        }

        /* 画面切り替え */
        #title-screen,
        #game-screen,
        #result-screen {
            display: none;
        }
        #title-screen.active,
        #game-screen.active,
        #result-screen.active {
            display: block;
        }

        /* 問題番号 */
        #question-number {
            font-size: 1.2rem;
            color: #FFD;
            margin-bottom: 10px;
        }

        /* 国旗表示 */
        #flag-display {
            font-size: 6rem;   /* 国旗を大きく */
            margin: 20px 0;
        }
        /* Twemoji 画像サイズを合わせる */
        #flag-display img {
            width: 6rem;
            height: auto;
        }

        /* 選択肢ボタン群 */
        #choices-container {
            display: flex;
            flex-direction: column;
            gap: 12px;
            margin-bottom: 20px;
        }
        #choices-container button {
            padding: 12px;
            font-size: 1.1rem;
            border: none;
            border-radius: 5px;
            background-color: #1E90FF;
            color: #fff;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }
        #choices-container button:hover {
            background-color: #104E8B;
        }

        /* フィードバック&結果テキスト */
        #feedback,
        #result-message {
            font-size: 1.2rem;
            font-weight: bold;
            margin-bottom: 20px;
        }

        /* 各種ボタン */
        #start-button,
        #next-button,
        #return-button {
            padding: 10px 24px;
            font-size: 1rem;
            border: none;
            border-radius: 5px;
            background-color: #32CD32;
            color: #fff;
            cursor: pointer;
            transition: background-color 0.3s ease;
            margin-top: 10px;
        }
        #start-button:hover,
        #next-button:hover,
        #return-button:hover {
            background-color: #228B22;
        }
    </style>
    <!-- Twemoji API 読み込み -->
    <script src="https://cdn.jsdelivr.net/npm/@twemoji/api@latest/dist/twemoji.min.js" crossorigin="anonymous"></script>
</head>
<body>
    <div id="quiz-container">
        <!-- メインタイトル -->
        <h1>🌏 世界の国旗当てクイズ 🌏</h1>

        <!-- タイトル画面 -->
        <div id="title-screen" class="active">
            <img id="title-image" src="world_flags_quiz_title.png" alt="世界の国旗当てクイズ">
            <p>表示される国旗(絵文字)に対応する国名を4択の中から選んでください。</p>
            <p>全10問の正答率を競うクイズゲームです。</p>
            <button id="start-button">スタート</button>
        </div>

        <!-- ゲーム画面 -->
        <div id="game-screen">
            <div id="question-number"></div>
            <div id="flag-display"></div>
            <div id="choices-container"></div>
            <p id="feedback"></p>
            <button id="next-button">次の問題 ➡️</button>
        </div>

        <!-- 結果画面 -->
        <div id="result-screen">
            <p id="result-message"></p>
            <button id="return-button">タイトルに戻る</button>
        </div>
    </div>

    <script>
        // ──────────────────────────────────────────
        // 国旗データ定義(全20カ国)
        // ──────────────────────────────────────────
        const flags = [
            { emoji: '🇯🇵', country: '日本' },
            { emoji: '🇺🇸', country: 'アメリカ合衆国' },
            { emoji: '🇫🇷', country: 'フランス' },
            { emoji: '🇩🇪', country: 'ドイツ' },
            { emoji: '🇬🇧', country: 'イギリス' },
            { emoji: '🇨🇦', country: 'カナダ' },
            { emoji: '🇮🇹', country: 'イタリア' },
            { emoji: '🇧🇷', country: 'ブラジル' },
            { emoji: '🇨🇳', country: '中国' },
            { emoji: '🇰🇷', country: '韓国' },
            { emoji: '🇷🇺', country: 'ロシア' },
            { emoji: '🇪🇸', country: 'スペイン' },
            { emoji: '🇲🇽', country: 'メキシコ' },
            { emoji: '🇦🇺', country: 'オーストラリア' },
            { emoji: '🇮🇳', country: 'インド' },
            { emoji: '🇹🇷', country: 'トルコ' },
            { emoji: '🇸🇦', country: 'サウジアラビア' },
            { emoji: '🇿🇦', country: '南アフリカ' },
            { emoji: '🇳🇿', country: 'ニュージーランド' },
            { emoji: '🇪🇬', country: 'エジプト' },
            { emoji: '🇸🇪', country: 'スウェーデン' },
            { emoji: '🇳🇴', country: 'ノルウェー' },
            { emoji: '🇫🇮', country: 'フィンランド' },
            { emoji: '🇳🇱', country: 'オランダ' },
            { emoji: '🇨🇭', country: 'スイス' },
            { emoji: '🇧🇪', country: 'ベルギー' },
            { emoji: '🇦🇷', country: 'アルゼンチン' },
            { emoji: '🇨🇱', country: 'チリ' },
            { emoji: '🇬🇷', country: 'ギリシャ' },
            { emoji: '🇵🇹', country: 'ポルトガル' }
        ];

        let quizFlags = [];       // 出題用フラグ一覧(10問)
        let currentQuestion = 0;  // 現在の問題インデックス
        let correctCount = 0;     // 正解数カウント

        // ── DOM 要素取得 ──
        const titleScreen   = document.getElementById('title-screen');
        const gameScreen    = document.getElementById('game-screen');
        const resultScreen  = document.getElementById('result-screen');
        const startButton   = document.getElementById('start-button');
        const questionNumEl = document.getElementById('question-number');
        const flagDisplay   = document.getElementById('flag-display');
        const choicesEl     = document.getElementById('choices-container');
        const feedbackEl    = document.getElementById('feedback');
        const nextButton    = document.getElementById('next-button');
        const resultMsgEl   = document.getElementById('result-message');
        const returnButton  = document.getElementById('return-button');

        // ── 配列シャッフル関数 (Fisher–Yates) ──
        function shuffleArray(array) {
            for (let i = array.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [array[i], array[j]] = [array[j], array[i]];
            }
        }

        // ── ゲーム開始処理 ──
        function startGame() {
            quizFlags = [...flags];
            shuffleArray(quizFlags);
            quizFlags = quizFlags.slice(0, 10);  // 10問設定

            currentQuestion = 0;
            correctCount = 0;

            titleScreen.classList.remove('active');
            resultScreen.classList.remove('active');
            gameScreen.classList.add('active');

            showQuestion();
        }

        // ── 問題表示処理 ──
        function showQuestion() {
            const { emoji, country } = quizFlags[currentQuestion];

            questionNumEl.textContent = `問題 ${currentQuestion + 1} / ${quizFlags.length}`;

            flagDisplay.textContent = emoji;
            twemoji.parse(flagDisplay, {
                folder: 'svg',
                ext: '.svg'
            });

            const choices = [country];
            const others = flags.filter(f => f.country !== country);
            shuffleArray(others);
            for (let i = 0; i < 3; i++) {
                choices.push(others[i].country);
            }
            shuffleArray(choices);

            choicesEl.innerHTML = '';
            choices.forEach(choice => {
                const btn = document.createElement('button');
                btn.textContent = choice;
                btn.addEventListener('click', () => selectAnswer(choice, country));
                choicesEl.appendChild(btn);
            });

            feedbackEl.textContent = '';
            nextButton.style.display = 'none';
        }

        // ── 回答選択処理 ──
        function selectAnswer(selected, correct) {
            if (selected === correct) {
                feedbackEl.textContent = '✅ 正解です!';
                correctCount++;
            } else {
                feedbackEl.textContent = `❌ 不正解… 正解は「${correct}」です。`;
            }
            nextButton.style.display = 'inline-block';
        }

        // ── 次へ or 終了判定 ──
        function nextQuestion() {
            currentQuestion++;
            if (currentQuestion < quizFlags.length) {
                showQuestion();
            } else {
                endGame();
            }
        }

        // ── 終了処理 ──
        function endGame() {
            gameScreen.classList.remove('active');
            resultScreen.classList.add('active');
            const accuracy = Math.round((correctCount / quizFlags.length) * 100);
            resultMsgEl.textContent = `🎉 クイズ終了!あなたの正答率は ${accuracy}% です!`;
        }

        // ── イベントリスナー登録 ──
        startButton.addEventListener('click', startGame);
        nextButton.addEventListener('click', nextQuestion);
        returnButton.addEventListener('click', () => {
            resultScreen.classList.remove('active');
            titleScreen.classList.add('active');
        });
    </script>
</body>
</html>

アルゴリズムの流れ

ステップ処理内容主な関数/命令
1. シャッフル&抽出flags 配列をシャッフルし、先頭10要素を quizFlags に設定shuffleArray()slice(0,10)
2. 問題表示現在の国旗絵文字と正解文字列を取得し、選択肢(正解+ダミー3つ)を生成・シャッフルshowQuestion()
3. 回答選択クリックした選択肢と正解を比較し、フィードバック表示・正解数カウントselectAnswer()
4. 次へ/終了次の問題へ進む or 10問終了で正答率計算&結果画面表示nextQuestion()endGame()
5. 再スタート準備結果画面の「タイトルに戻る」でタイトル画面へ復帰returnButton イベント

関数・クラスの詳しい解説

名称説明
shuffleArray(array)Fisher–Yates アルゴリズムで配列要素をランダムに並び替える
startGame()問題配列の初期化、ステート変数リセット、画面切り替え、最初の問題表示
showQuestion()現在の問題データから国旗絵文字表示、4択ボタン生成、フィードバック・次へボタンの初期化
selectAnswer(sel, cor)プレイヤーの選択と正解を比較し、フィードバック表示・正解数増加・次へボタン表示
nextQuestion()問題インデックスを進め、次問題表示か終了処理を実行
endGame()ゲーム画面を隠し、正答率を計算して結果画面に表示

改造のポイント

  • 出題数・選択肢数変更quizFlags.slice(0,10) の数値、選択肢数(現在は3つのダミー)を変えて難易度調整
  • 画像化対応:Twemoji の絵文字ではなく、国旗画像ファイルを利用するように flagDisplay 部分を <img> に変更
  • 問題バリエーション追加:都市名や通貨当てなど別テーマのクイズに応用可能
  • 制限時間導入:各問題にタイマーを設け、制限時間内に回答しないと不正解扱い
  • スコアボード機能localStorage へ正答率やクリア時間を保存し、ランキング表示画面を追加
  • 音声フィードバック:正解/不正解時に効果音を再生し、臨場感をアップ

アドバイス:出題データを外部JSONに分割し、国旗や国名を動的にロードすると、問題の追加・修正が容易になります。また、スマホ対応としてタッチ操作やレスポンシブUIを強化すると幅広いユーザーに親しみやすくなります。