英語しりとり

英語しりとり | ひまあそび-ミニゲーム hi0a.com

view source

JavaScript

document.title = '英語しりとり';
document.body.style.overflow = 'hidden';

const demo = document.getElementById('demo');

const h1 = document.createElement("h1");
h1.textContent = document.title;
h1.style.textAlign = "center";
demo.appendChild(h1);

const container = document.createElement("div");
demo.appendChild(container);
//js-shiritori-english

let englishWords = [];
const history = [];

fetch("english.json")
  .then(res => res.json())
  .then(data => {
    englishWords = data;
    setStage();
  })
  .catch(err => {
    console.error("Failed to load english.json", err);
    document.getElementById("demo").textContent = "データ読み込み失敗";
  });



function setStage() {
  container.innerHTML = "";

  let currentWord = getRandomWord();
  let nextWord = getNextWord(currentWord.en.slice(-1));
  if (!nextWord) {
    container.innerText = "次の単語が見つかりません。ゲーム終了!";
    return;
  }

  // 表示初期化
  renderWordStage(currentWord, nextWord);

  function renderWordStage(prev, next) {
    container.innerHTML = "";
    //history.unshift(`${prev.en.toUpperCase()} (${prev.ja})`);
    //history.unshift(`${prev.en} (${prev.ja})`);
    history.unshift(`<ruby>${prev.en.toUpperCase()}<rt>${prev.ja}</rt></ruby>`);

    if (history.length > 3) history.pop();

    // 履歴表示
    const historyBox = document.createElement("div");
    historyBox.classList.add('history');
    const revHistory = [...history].reverse();
    historyBox.innerHTML = revHistory.join(" → ") + " →";
    container.appendChild(historyBox);


    // 日本語ヒント
    const hint = document.createElement("p");
    hint.classList.add('ja');
    hint.textContent = `ヒント: ${next.ja}`;
    container.appendChild(hint);

    // 英語単語の入力フィールド(1文字目だけ埋まる)
    //const answer = next.en.toLowerCase();
    const answer = next.en.toUpperCase();
    let userInput = [answer[0]];
    const slots = [];

    const slotBox = document.createElement("div");
    slotBox.classList.add('word');

    for (let i = 0; i < answer.length; i++) {
      const span = document.createElement("span");
      span.textContent = i === 0 ? answer[0] : "_";

      slotBox.appendChild(span);
      slots.push(span);
    }
    container.appendChild(slotBox);

    // ボタン生成
    const buttonsBox = document.createElement("div");
    buttonsBox.classList.add('btns');
    const remainingLetters = answer.slice(1).split("");
/*
    const buttonLetters = [...remainingLetters];
    while (buttonLetters.length < 8) {
      const r = String.fromCharCode(97 + Math.floor(Math.random() * 26));
      if (!buttonLetters.includes(r)) buttonLetters.push(r);
    }
*/

    // ユニークな文字ボタンを8つ生成する
    const buttonSet = new Set(remainingLetters); // 答えの文字をまず追加

    while (buttonSet.size < 8) {
      const r = String.fromCharCode(65 + Math.floor(Math.random() * 26)); // A-Z
      buttonSet.add(r);
    }

    const buttonLetters = Array.from(buttonSet);
    shuffle(buttonLetters); // 順番はシャッフル

    shuffle(buttonLetters).forEach(char => {
      const btn = document.createElement("button");
      btn.textContent = char.toUpperCase();


      btn.onclick = () => {
        if (userInput.length >= answer.length) return;

        const expectedChar = answer[userInput.length];
        userInput.push(char.toUpperCase());

        slots[userInput.length - 1].textContent = char;

        if (char === expectedChar) {
          // 正解で進行
          if (userInput.join("") === answer) {
            setTimeout(() => {
              const next2 = getNextWord(answer.slice(-1));
              if (next2) {
                renderWordStage(next, next2);
              } else {
                container.innerHTML = "おめでとう!最後の単語です 🎉";
              }
            }, 999);
          }
        } else {
          // ❌ 間違い:2文字目だけ埋めてやり直し
          userInput = [answer[0], answer[1]];
          slots.forEach((span, index) => {
            if (index === 0) {
              span.textContent = answer[0];
            } else if (index === 1) {
              span.textContent = answer[1];
            } else {
              span.textContent = "_";
            }
          });
        }
      };

      buttonsBox.appendChild(btn);
    });

    container.appendChild(buttonsBox);
  }

  function getRandomWord() {
    return englishWords[Math.floor(Math.random() * englishWords.length)];
  }

  function getNextWord(startChar) {
    const candidates = englishWords.filter(w => w.en[0].toLowerCase() === startChar.toLowerCase());
    if (candidates.length === 0) return null;
    return candidates[Math.floor(Math.random() * candidates.length)];
  }

  function shuffle(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]];
    }
    return array;
  }
}

CSS

#demo{
  font-size:48px;
  text-align:center;
}
button{
  font-size:48px;
  padding:5px;
  width:60px;
}


.history,
.ja{
  margin-top:10px;
  font-size:24px;
}

.word {
  margin: 20px auto;
  display: flex;
  justify-content: center;
  flex-wrap: nowrap;
  overflow-x: auto;
}

.word span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 36px;
  font-weight: bold;
  border: 1px solid #333;
  height: 60px;
  width: 60px;
  margin: 1px;
  box-sizing: border-box;
  white-space: nowrap; /* 改行禁止 */
  overflow: hidden;
  text-overflow: ellipsis;
}


.btns {
  display: grid;
  grid-template-columns: repeat(4, 1fr); /* 4列 */
  gap: 2px;
  justify-items: center;
  align-items: center;
  max-width: 300px; /* 必要に応じて調整 */
  margin: 20px auto;
}

.btns button {
  min-width: 64px;
  height: 60px;
  font-size: 24px;
  font-weight: bold;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border: 2px solid #555;
  border-radius: 5px;
  background-color: #f0f0f0;
  cursor: pointer;
  flex-shrink: 0;
}

HTML

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

view-source:https://hi0a.com/game/shiritori-english/

ABOUT

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

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

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

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

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

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

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