엄청난 성공을 거둔 게임인 워들은 출시와 동시에 큰 반향을 일으켰으며, 이 게임을 다시 만들거나 더 기본적인 반복을 구성하는 것은 초보 자바스크립트 개발자가 추구할 수 있는 훌륭한 작업이 될 수 있습니다.
워들 작동 방식
워들의 목표는 여러 번의 시도를 통해 비밀스러운 다섯 글자로 된 용어를 알아내는 것입니다. 참가자에게는 숨겨진 문구를 근사치로 추론할 수 있는 여섯 번의 기회가 주어지며, 다섯 글자로 이루어진 단어를 추론할 수 있습니다.
플레이어가 추측을 제출하면 Wordle은 독특한 색조를 활용하여 비밀 용어의 근접성에 대한 정보를 전달합니다. 노란색 음영으로 표시되는 문자는 해당 문자가 비밀 문구 내에 존재하지만 잘못된 위치에 있다는 것을 의미합니다.
초록색 색조를 사용하면 해당 문자가 난해한 용어 내에 나타나며 올바른 위치를 차지하고 있음을 사용자에게 알리는 역할을 하는 반면, 회청색의 창백한 색조는 참가자에게 알파벳 기호가 표현의 일부를 구성하지 않는다는 것을 의미합니다.
개발 서버 설정하기
이 프로젝트에 사용된 코드는 GitHub 리포지토리에서 구할 수 있으며 MIT 라이선스에 따라 무료로 사용할 수 있습니다. 이 프로젝트의 라이브 버전을 살펴보고 싶다면 이 데모 을 확인하실 수 있습니다.
이 구현에서는 스캐폴딩을 위해 명령줄 인터페이스(CLI)를 통해 Vite 빌드 툴을 활용하고 있습니다. 일반적으로 노드 패키지 관리자(NPM)보다 속도가 빠르므로 컴퓨팅 장치에 Yarn이 설치되어 있는지 확인하는 것이 중요합니다. 터미널을 열고 다음 명령을 실행하세요:
yarn create vite
제공된 명령을 실행하면 프레임워크로는 Vanilla, 변형으로 JavaScript가 포함된 Vite 프로젝트의 새 인스턴스가 생성됩니다.
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 id="app">
<div>
<h1>Wordle Clone</h1>
<div id="controls">
<button id="restart-btn">Replay</button>
<button id="show-btn">Show Answer</button>
</div>
<div id="message">Please wait. The Game is loading...</div>
</div>
<div id="interface">
<div id="board"></div>
<div class="keyboard"></div>
</div>
</div>
<script type="module" src="/main.js"></script>
</body>
</html>
이 프로젝트의 GitHub 리포지토리를 방문하여 “style.css” 파일의 콘텐츠를 검색하세요. 그런 다음 개인 “style.css” 파일에 통합하세요.
비공식적인 표현을 좀 더 세련된 어조로 바꿔주세요. 다음은 대체 표현입니다: 프로젝트에 필요한 Toastify 설치를 진행하려면 터미널에서 다음 명령을 실행해 주세요:
yarn add toastify -S
잘 알려진 자바스크립트 라이브러리인 Toastify를 활용하면 사용자에게 알림을 표시할 수 있습니다. 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");
게임 보드 설정
W를 좌표가 있는 6차원 공간(x1, x2, …, x6), S를 {0, 1, 2, 3, 4, 5}에 걸쳐 비어 있지 않은 문자열의 집합이라고 하고, C를 S의 각 원소가 C의 정확히 하나의 부분집합에 속하도록 하는 S의 부분집합의 집합이라고 합니다. F를 S에서 W로의 함수라고 하고, S의 각 문자열 s에 대해 T(s)를 6개의 원소로 이루어진 고정된 집합이라고 합니다. 변수 B를 S로 인덱싱된 W의 6개 원소 집합의 다중 집합으로 정의하면, s가 S에 있으면 B[s]는 T(s)에서 선택된 W의 6개 원소의 가능한 모든 조합을 포함합니다. 이 설정이 주어지면
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;
에 대한 충돌을 찾는 절차를 다음과 같이 정의할 수 있습니다. 6행과 5열로 배열된 30개의 셀로 구성된 육각형 체스판 레이아웃을 생성하려면 HTML 문서 내에서 중첩 루프를 활용하여 각 행과 열을 반복하여 필요한
개의 태그를 구성합니다. 궁극적으로 이러한 요소를 보드를 나타내는 컨테이너에 추가하면 게임 그리드를 시각적으로 정확하게 표현할 수 있습니다.
for (let i = 0; i <= 5; i++) {
let row = document.createElement('div')
for (let y = 0; y <= 4; y++) {
let box = document.createElement('span');
row.appendChild(box);
row.className = `row-${i + 1}`
}
board.appendChild(row);
}
키보드 추가 및 키보드 입력 듣기
키보드를 구성하기 위해 forEach 메서드를 사용하여 키-값 쌍을 트래버스하고 반복에서 각 항목에 대한 버튼 컴포넌트를 생성합니다. 현재 항목의 해당 값이 별표(*)인 경우 버튼의 레이블을 “백스페이스”로 할당하고, 그렇지 않으면 키의 실제 값으로 설정합니다.
버튼에 지정된 클래스를 할당하고 `데이터 키` 속성을 설정하여 입력값을 대문자로 변환하세요. 그런 다음 버튼이 클릭될 때 대문자 입력값을 매개변수로 전달하여 `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에서 새 단어 가져오기
사용자가 게임을 처음 로드할 때 게임은 임의 단어 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();
})
}
기본 함수는 getNewWord() 함수에 의해 무작위 단어가 효과적으로 획득되면 실행됩니다. getNewWord() 함수 바로 아래에 다음과 같이 메인 함수를 생성하세요:
function main(){
}
보드의 각 카드에 개별 스타일을 적용하기 위해서는 각 행에 있는 모든 카드의 컬렉션을 가져와야 합니다. 이를 위해 DOM에 존재하는 모든 행을 검색하는 ‘row’라는 변수를 만듭니다. 또한 메시지의 표시 속성을 ‘none’으로 설정하는 것이 중요합니다.
rows.forEach(row => [...row.children].forEach(child => boxes.push(child)))
boxes.forEach((box) => {
box.classList.add("empty");
})
message.style.display = "none";
키가 해제된 시점을 감지하기 위해 창 키업 이벤트 리스너가 추가됩니다. 그런 다음 키의 유효성을 확인한 다음 관련 버튼에 초점을 맞추고 클릭을 시뮬레이션한 다음 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)
}
})
키업 이벤트가 감지되면 두 개의 버튼, 즉 showBtn과 restartBtn에 대한 이벤트 리스너를 설정해야 합니다. 플레이어가 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"))
}
기본 함수의 범위 내에서 행 인덱스를 나타내는 “row”, 지정된 행 내의 상자 인덱스에 해당하는 “box”, 업데이트할 텍스트 콘텐츠를 나타내는 “data”의 세 가지 매개 변수를 허용하는 “renderBox”라는 함수를 도입하여 렌더링 메커니즘을 구현합니다.
function renderBox(row, box, data) {
[...document.querySelector(`.row-${row}`).children][box].innerText = data;
}
함수로 키보드 입력 처리하기
입력 키를 관리하고 게임 보드를 업데이트하기 위해 ‘키’ 유형의 단일 입력 파라미터를 받아들이는 효율적인 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++;
}
}
}
플레이어의 추측 평가하기
이 함수는 게임 보드의 특정 행을 나타내는 단일 인수를 받을 것으로 예상됩니다. 당면한 작업은 이 특정 행과 관련된 플레이어의 가장 최근 추측의 정확도를 평가하는 것입니다.
function evaluate(row){
}
“답변 표시” 버튼의 모양에 대한 기능을 구현하려면 주어진 매개 변수 내에서 특정 작업을 실행해야 합니다. 해당 동작은 사용자가 정답을 추측하기 위해 최소 네 번 이상 시도한 경우에만 트리거됩니다.
if (currentRow === 4) {
showBtn.removeAttribute('disabled')
}
아래 코드는 파이게임 라이브러리를 사용하여 두 명의 플레이어가 번갈아 가며 게임 보드에 X와 O를 배치하여 한 플레이어가 세 개의 기호를 가로, 세로 또는 대각선으로 연속으로 획득하여 승리할 때까지 작동하는 틱택토 게임을 구현하기 위해 작성된 코드입니다. guess` 변수는 현재 게임 상태가 인간 플레이어에 의해 올바르게 추측되었는지 여부를 저장하고, `check_answer` 함수는 지금까지 두 플레이어가 배치한 문자가 어느 플레이어에게 이기는 조합을 가져오는지 여부를 결정합니다. “`python import pygame pygame.locals에서 *를 가져옵니다. import random pygame.init() WIDTH = 300 HEIGHT = 300 FPS = 60 G
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"
);
코드 블록 내에서 반복 프로세스가 실행되며, 추측 배열의 각 구성 요소는 정답 배열의 해당 구성 요소와 대조됩니다. 결과적으로 색상 배열은 이러한 비교 결과에 따라 수정됩니다.
“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을 복제하는 데 성공한 것을 인정하게 되어 기쁘게 생각합니다.
게임 재현을 통해 자바스크립트 실력을 한 단계 업그레이드
초보자로서 새로운 언어 시스템을 습득하는 것은 힘든 작업입니다.틱택토, 행맨, 워들 같은 레크리에이션 활동을 자바스크립트와 같은 프로그래밍 언어로 구현하면 초보자에게 실습 경험을 제공함으로써 언어의 기본 원리를 쉽게 익힐 수 있습니다.