漢字熟語穴埋めクイズ

中央に入る漢字一字は何?

...

漢字熟語穴埋めクイズ

上下左右の二字熟語に共通する漢字1字を埋めよう!

view source

JavaScript

document.title = '漢字熟語穴埋めクイズ';
//上下左右の二字熟語に共通する漢字1字を埋めよう!

document.body.style.overflow = 'hidden';

let clearCount = 0;
let wordPairs = [];
let allKanji = new Set();
let quizzes = [];

function loadCSVAndGenerateQuiz(csvPath) {
  fetch(csvPath)
    .then(response => {
      if (!response.ok) throw new Error('-');
      return response.text();
    })
    .then(text => {
      setData(text);
      setStage();
    })
    .catch(error => {
      console.error("エラー:", error);
    });
}

function setData(text){
  wordPairs = text.trim().split('\n').map(word => {
    word = word.trim();
    if (word.length !== 2) return null;
    return {
      before: word[0],
      after: word[1],
      word: word
    };
  }).filter(Boolean);

  allKanji = new Set();
  wordPairs.forEach(({ before, after }) => {
    allKanji.add(before);
    allKanji.add(after);
  });

  quizzes = [];

  allKanji.forEach(kanji => {
    const top    = wordPairs.find(w => w.after === kanji);
    const left   = wordPairs.find(w => w.after === kanji && w !== top);
    const right  = wordPairs.find(w => w.before === kanji && w !== top && w !== left);
    const bottom = wordPairs.find(w => w.before === kanji && w !== top && w !== left && w !== right);

    if (top && left && right && bottom) {
      // 重複チェック:すべてのbefore/afterがユニークである必要
      const set = new Set([top.before, left.before, right.after, bottom.after]);
      if (set.size === 4) {
        quizzes.push({
          center: kanji,
          top:    top.before,
          left:   left.before,
          right:  right.after,
          bottom: bottom.after
        });
      }
    }
  });

  if (quizzes.length === 0) {
    console.warn("有効な問題が生成できませんでした。");
    return;
  }

  // 出力エリアにJSONとして書き込む
  const outputText = JSON.stringify(quizzes, null, 2); // 整形付き
  document.getElementById('quizOutput').value = outputText;
}

function loadJsonQuiz(jsonPath) {
  fetch(jsonPath)
    .then(response => {
      if (!response.ok) throw new Error('JSONの読み込み失敗');
      return response.json();
    })
    .then(data => {
      if (!Array.isArray(data)) throw new Error('JSON形式が不正です');

      quizzes = data; // グローバルにセット
      if (quizzes.length === 0) {
        console.warn("読み込んだJSONに有効なクイズがありません");
        return;
      }
      // centerだけをSetに追加
      allKanji = new Set(quizzes.map(q => q.center));

      setStage(); // 初期表示などを行う関数
    })
    .catch(error => {
      console.error("エラー:", error);
    });
}


// 問題1問を出題
function setStage() {
  const quiz = quizzes[Math.floor(Math.random() * quizzes.length)];

  document.getElementById('top').textContent    = quiz.top;
  document.getElementById('left').textContent   = quiz.left;
  document.getElementById('right').textContent  = quiz.right;
  document.getElementById('bottom').textContent = quiz.bottom;
  document.getElementById('center').textContent = '?';
  document.getElementById('result').textContent = '';

  const optionsDiv = document.getElementById('options');
  optionsDiv.innerHTML = '';

  const distractors = [...allKanji].filter(k => k !== quiz.center);
  const shuffled = distractors.sort(() => 0.5 - Math.random());
  const wrongChoices = shuffled.slice(0, 9);
  const finalChoices = [...wrongChoices, quiz.center].sort(() => 0.5 - Math.random());

  finalChoices.forEach(k => {
    const btn = document.createElement("button");
    btn.textContent = k;
    btn.onclick = () => {
      onCheckMeaning(quiz);
      document.getElementById('center').textContent = k;

      if (k === quiz.center) {
        btn.style.backgroundColor = 'lightgreen';
        document.getElementById('result').textContent = '正解!';
        clearCount++;
      } else {
        btn.style.backgroundColor = 'lightcoral';
        document.getElementById('result').textContent = '不正解…';
        clearCount--;

        Array.from(optionsDiv.children).forEach(b => {
          if (b.textContent === quiz.center) {
            b.style.backgroundColor = 'lightgreen';
          }
        });
      }

      // 全ボタンを無効化
      Array.from(optionsDiv.children).forEach(b => b.disabled = true);
    };

    optionsDiv.appendChild(btn);
  });
}


function setLinks(ary) {
  const $links = $('#links');
  $links.empty();

  let h2 = $('<h2>').text('意味を調べる');
  $links.append(h2);

  ary.forEach(function (word) {
    let url = 'https://www.google.com/search?q=' + encodeURIComponent(word + ' 意味');
    let a = $('<a>', {
      target: '_blank',
      href: url,
      text: word,
    });
    $links.append(a);
  });
}

function onCheckMeaning(quiz) {
  const words = [
    quiz.top + quiz.center,
    quiz.center+ quiz.bottom,
    quiz.left + quiz.center,
    quiz.center + quiz.right,
  ];
  setLinks(words);
}

//loadCSVAndGenerateQuiz('words.csv');
loadJsonQuiz('quizKanji4.json');

CSS

HTML

ページのソースを表示 : Ctrl+U , DevTools : F12

view-source:https://hi0a.com/game/quiz-anaume-kanji/

ABOUT

hi0a.com 「ひまあそび」は無料で遊べるミニゲームや便利ツールを公開しています。

プログラミング言語の動作デモやWEBデザイン、ソースコード、フロントエンド等の開発者のための技術を公開しています。

必要な機能の関数をコピペ利用したり勉強に活用できます。

プログラムの動作サンプル結果は画面上部に出力表示されています。

環境:最新のブラウザ GoogleChrome / Windows / Android / iPhone 等の端末で動作確認しています。

画像素材や音素材は半分自作でフリー素材配布サイトも利用しています。LINK参照。

仕様変更、API廃止等、実験途中で動かないページもあります。