JavaScriptを使ってワードルをクローンする方法

ワードルは、2022年初めに世界を席巻した人気ゲームです。ワードルゲームを再現したり、少なくともよりシンプルなバージョンを構築したりすることは、JavaScriptを始めたばかりの開発者が検討すべきことです。

ワードルの仕組み

ワードルでは、5文字の秘密の単語があります。プレイヤーには6回の試行があり、5文字の単語を推測して、秘密の単語にどれだけ近いかを確認する必要があります。

プレイヤーが推測を送信すると、ワードルは色を使用してプレイヤーに秘密の単語にどれだけ近いかを伝えます。文字が黄色であれば、その文字は秘密の単語に含まれていますが、位置が間違っています。

緑色は、その文字が秘密の単語に含まれていて、位置が正しいことをユーザーに伝えます。一方、灰色は、その文字が単語に含まれていないことをプレイヤーに伝えます。

開発サーバーの設定

このプロジェクトで使用されているコードはGitHubリポジトリで入手可能で、MITライセンスに基づいて無料で使用できます。このプロジェクトのライブバージョンを確認したい場合は、このデモをご覧ください。

このプロジェクトでは、足場用にコマンドラインインターフェイス(CLI)を介してViteビルドツールを使用しています。Node Package Manager(NPM)よりも一般的に高速であるため、コンピューターにYarnがインストールされていることを確認してください。ターミナルを開き、次のコマンドを実行します。

yarn create vite

これにより、新しいViteプロジェクトが作成されます。フレームワークはVanillaで、バリアントはJavaScriptに設定する必要があります。これで実行します。

yarn

これにより、プロジェクトを機能させるために必要なすべての依存関係がインストールされます。このインストールの後、次のコマンドを実行して開発サーバーを起動します。

yarn dev

ゲームの設定とキーボードの設計

コードエディターでプロジェクトを開き、main.jsファイルの内容をクリアして、プロジェクトフォルダがこのようになります。

次に、index.htmlファイルの内容を次のボイラープレートコードに置き換えます。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JS Wordle</title>
</head>
<body>
<div>
<div>
<h1>Wordle Clone</h1>
<div>
<button>Replay</button>
<button>Show Answer</button>
</div>
<div>Please wait. The Game is loading...</div>
</div>
<div>
<div></div>
<div></div>
</div>
</div>
<script type="module" src="/main.js"></script>
</body>
</html>

CSSについては、このプロジェクトのGitHubリポジトリにアクセスし、style.cssファイルの内容を独自のstyle.cssファイルにコピーします。

次に、ターミナルで次のコマンドを実行して、Toastify NPMパッケージをインストールします。

yarn add toastify -S

Toastifyは、ユーザーにアラートを表示できる人気のJavaScriptパッケージです。次に、main.jsファイルで、style.cssファイルとtoastifyユーティリティをインポートします。

import "./style.css"
import Toastify from 'toastify-js'

DOM要素とのやり取りを容易にするために、次の変数を定義します。

let board = document.querySelector("#board");
let message = document.querySelector("#message");
let keys = "QWERTYUIOPASDFGHJKLZXCVBNM".split("");
let restartBtn = document.querySelector("#restart-btn");
let showBtn = document.querySelector("#show-btn");
showBtn.setAttribute("disabled", "true");
keys.push("Backspace");
let keyboard = document.querySelector(".keyboard");

ゲームボードの設定

ワードルは、ユーザーが6回試行で5文字の単語を推測しなければならないゲームであるため、6つの配列の配列を保持するboardContentという変数を定義します。次に、変数currentRowcurrentBoxを定義して、boardContentをより簡単に走査できるようにします。

let boardContent = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
];
let currentRow = 0;
let currentBox = 0;
let secretWord;

HTML要素を使用して、6行のそれぞれに5つのボックスを含むボードをレンダリングするには、ネストされたループを使用して要素を反復して作成します。最後に、それらをボードに追加します。

for (let i = 0; i 

キーボードの追加とキーボード入力のリスニング

キーボードを作成するには、forEachを使用してキーを反復処理し、各エントリにボタン要素を作成します。エントリが*の場合はボタンのテキストをBackspaceに設定し、それ以外の場合はエントリ値に設定します。

ボタンにkeyクラスを割り当て、data-key属性を大文字のエントリ値に設定します。次に、大文字のエントリ値でinsertKey関数を呼び出すクリックイベントリスナーをボタンに追加します。

keys.forEach(entry => {let key = document.createElement("button");if (entry === "*") {key.innerText = "Backspace";} else {key.innerText = entry;}key.className = "key";key.setAttribute("data-key", entry.toUpperCase());key.addEventListener("click", () => {insertKey(entry.toUpperCase())setTimeout(() => {document.querySelector(button[data-key=${entry.toUpperCase()}]).blur();}, 250)})keyboard.append(key);})

APIから新しい単語を取得する

ユーザーが最初にゲームをロードすると、ゲームはRandom word APIから新しい5文字の単語を取得する必要があります。この単語は、secretWord変数に格納されます。

function getNewWord() {async function fetchWord() {try {const response = await fetch("https://random-word-api.herokuapp.com/word?length=5");if (response.ok) {const data = await response.json();return data;} else {throw new Error("Something went wrong!")}} catch (error) {message.innerText = Something went wrong. \n${error}\nCheck your internet connection.;}}fetchWord().then(data => {secretWord = data[0].toUpperCase();main();})}

上記のコードブロックでは、ランダムな単語が正常に取得された場合、main関数が実行されます。getNewWord関数のすぐ下にmain関数を定義します。

function main(){
}

ボード上の各ボックスのスタイルを設定するには、各行のすべてのボックスのリストが必要です。DOMですべての行を取得する変数rowを宣言します。また、message表示スタイルをnoneに設定します。

rows.forEach(row => [...row.children].forEach(child => boxes.push(child)))
boxes.forEach((box) => {
box.classList.add("empty");
})
message.style.display = "none";

次に、ウィンドウオブジェクトにkeyupイベントリスナーを追加し、解放されたキーが有効かどうかを確認します。有効な場合は、対応するボタンにフォーカスし、クリックをシミュレートし、250ミリ秒後にぼかします。

window.addEventListener('keyup', (e) => {if (isValidCharacter(e.key)) {document.querySelector(button[data-key=${e.key.toUpperCase()}]).focus();document.querySelector(button[data-key=${e.key.toUpperCase()}]).click();setTimeout(() => {document.querySelector(button[data-key=${e.key.toUpperCase()}]).blur();}, 250)}})

keyupイベントリスナーの下に、2つのボタンのイベントリスナー、showBtnrestartBtnを設定します。プレイヤーがshowBtnをクリックすると、secretWord変数の値を含むトースト通知が表示されます。

restartBtnをクリックすると、ページがリロードされます。また、キーが有効な文字かどうかを確認するためのisValidCharacter関数を含めるようにしてください。

showBtn.addEventListener('click', () => {Toastify({text: Alright fine! the answer is ${secretWord},duration: 2500,className: "alert",}).showToast();})restartBtn.addEventListener('click', () => {location.reload();})function isValidCharacter(val) {return (val.match(/^[a-zA-Z]+$/) && (val.length === 1 || val === "Backspace"))}

main関数の外に、renderBox関数を作成し、3つのパラメータ、row(行番号)、box(行内のボックスインデックス)、およびdata(更新するテキストコンテンツ)を提供します。

function renderBox(row, box, data) {[...document.querySelector(.row-${row}).children][box].innerText = data;}

関数でキーボード入力を処理する

キー入力を処理し、ボードを更新するために、keyパラメータを持つinsertKey関数を作成します。関数は、渡されたパラメータに従って動作する必要があります。

function insertKey(key) {
if (key === "Backspace".toUpperCase() && currentRow < boardContent.length) {
boardContent[currentRow][currentBox] = 0;
if (currentBox !== 0) {
currentBox--;
renderBox(currentRow + 1, currentBox, "");
}
} else {
if (currentRow < boardContent.length) {
boardContent[currentRow][currentBox] = key;
renderBox(currentRow + 1, currentBox, key);
currentBox++;
}
if (currentRow < boardContent.length && boardContent[currentRow][currentBox] !== 0) {
evaluate(currentRow, key);
currentBox = 0;
currentRow++;
}
}
}

プレイヤーの推測を評価する

行パラメータを受け入れるevaluate関数を作成します。この関数は、プレイヤーの推測を評価する責任があります。

function evaluate(row){
}

すべてのゲームには、ユーザーが4回推測した後でのみ表示されるShow Answerボタンがあります。したがって、関数では、まさにそれを実行する機能を実装します。

if (currentRow === 4) {
showBtn.removeAttribute('disabled')
}

次に、推測変数と、文字が正しい位置にあるかどうかを確認する回答変数を定義します。

let guess = boardContent[row].join('').toUpperCase();
let answer = secretWord.split("");

ここでタイルの塗り分けアルゴリズムが役立ちます。タイルまたは文字は、単語の中にあり、正しい位置にある場合は緑色にする必要があることを思い出してください。

タイルが単語の中にあるが位置が間違っている場合、タイルは黄色になり、最後に単語の中にないタイルは灰色になります。

let colors = guess
.split("")
.map((letter, idx) => letter == answer[idx] ? (answer[idx] = false) : letter)
.map((letter, idx) =>
letter
? (idx = answer.indexOf(letter)) < 0
? "grey"
: (answer[idx] = "yellow")
: "green"
);

上記のコードブロックは、guess配列とanswer配列の間で要素ごとの比較を実行します。この比較の結果に基づいて、コードはcolors配列を更新します。

次に、パラメータとしてcolors配列を取り込み、タイルを適切に塗りつぶすことができるsetColors関数定義します。

function setColor(colors) {colors.forEach((color, index) => {document.querySelector(button[data-key=${guess[index].toUpperCase()}]).style.backgroundColor = color;document.querySelector(button[data-key=${guess[index].toUpperCase()}]).style.color= "black";[...document.querySelector(.row-${row + 1}).children][index].style.backgroundColor = color;})}

これでゲームは完了です。今すぐに行う必要があるのは、getNewWord関数を呼び出すだけで、準備完了です。

getNewWord();

おめでとうございます。Wordleを再現しました。

ゲームを再現することでJavaScriptのスキルを次のレベルへ

初心者として新しい言語を学ぶことは簡単ではありません。JavaScriptなどの言語で、三目並べ、ハングマン、Wordleなどのゲームを再現することで、初心者は言語の概念を実際に使用することで習得することができます。