프론트엔드 개발일지 #52 - (JS) 숫자 야구 만들기 ⚾

조아라·2024년 11월 16일
1
post-thumbnail

숫자 야구 만들기

나는 일단 숫자야구가 뭔지 몰라서 룰을 좀 배워왔다.
일단 4자리수의 랜덤한 숫자를 만들어 제공하면 그 숫자를 맞추는 게임인데, 만약에 3456이라는 숫자가 있는데 사용자가 3546이런식으로 적었다면 순서와 숫자가 모두 맞으면 : 스트라이크 / 자리는 틀렸지만 숫자가 포함 : 볼
➡️ 2스트라이크 2볼인셈이다 🧢 이 힌트를 조합해서 숫자를 맞추는 게임❗

어떻게 구현할건데❓

이제 좀 내가 구현 할 내용을 토대로 구체적으로 적어보았다.

  1. 게임의 기회는 10번. 게임이 시작되면 정답인 랜덤 숫자 네자리 정수 설정.
  2. 사용자가 네자리 수의 정수를 입력 (유효한 숫자만 입력하도록 한다.)
  3. 입력 후 버튼을 누르거나 엔터를 이용해 입력한 숫자 제출
  4. 제출된 value를 보고
  • 숫자, 인덱스 모두 맞으면 ➡️ 스트라이크
  • 숫자만 맞으면 ➡️ 볼
  1. 결과를 화면에 띄워주고, 그 결과를 토대로 사용자가 재 입력
    (예전 결과를 밑에 이전 결과 내역으로 보여주고싶다.)
  2. 그 뒤에 맞출때까지 힌트 제공.
  3. 맞추면 정답 축하 메세지와 함께 종료 후 새게임할건지 묻기

💚 정답이 될 랜덤 숫자 함수

const $userInput = document.querySelector("#userInput");
const $submitBtn = document.querySelector("#submitBtn");
const $resetBtn = document.querySelector("#resetBtn");
const $prevNum = document.querySelector("#prevNum");
const $result = document.querySelector("#result");
const $attempts = document.querySelector("#attempts");

let secretNum = [];
let attemptsLeft = 10;

// 정답 생성 (중복 없는 4자리 숫자)
function makeRandomNum() {
  secretNum = [];
  while (secretNum.length < 4) {
    const rand = Math.floor(Math.random() * 10);
    if (!secretNum.includes(rand)) {
      secretNum.push(rand);
    }
  }
}

makeRandomNum();
console.log(secretNum); // 테스트용 정답 출력

💡

  • 우선 필요한 변수들을 전부 선언해주고,

  • 정답으로 들어갈 secretNum을 빈 배열로 선언해주었다.

  • 그리고 while문을 사용해서 길이를 0 1 2 3 (4자리) 돌게끔!

  • Math.floor(Math.random()*10)을 통해서 0~9자리 수를 만들어주었다
    (이건 정말 색깔 플립퍼 만들때 정말 많이해서 쉬웠다.)

  • 정답 숫자에 랜덤으로 만든 숫자가 포함되어있지 않으면 랜덤숫자를 push
    (중복 숫자 없는 네자리 숫자를 만들기 위해서!)

    💚 스트라이크와 볼 계산 함수

    function calculateResult(input) {
     let strike = 0;
     let ball = 0;
     const inputArr = input.split("").map(Number);
    
     inputArr.forEach((num, index) => {
       if (num === secretNum[index]) {
         strike++;
       } else if (secretNum.includes(num)) {
         ball++;
       }
     });
     return { strike, ball };
    }

💡
사실 이 부분 구현이 순서도를 그릴때 가장 어렵지 않을까? 했는데 쉽다!

  • 일단 스트라이크와 볼을 변수 선언해주고,
  • 입력이 될 배열을 split을 통해서 ''단위로 잘라주고,
  • 잘라준 배열을 map을 통해서 숫자 배열로 만들어주었다.
  • forEach를 통해서 숫자와 인덱스를 매개 변수로 받고,
  • 숫자가 정답의 인덱스와 같다면 스트라이크의 카운트 ++
  • 숫자가 정답에 포함이 되어있다면 볼의 카운트++

💚 사용자가 입력한 내용 제출, 화면 구현

function submitInput() {
  if (attemptsLeft <= 0) {
    $result.textContent = "기회를 모두 사용하셨습니다. 게임이 종료됩니다.";
    return;
  }

  const userInput = $userInput.value;

  if (userInput.length !== 4 || isNaN(userInput)) {
    $result.textContent = "숫자 4자리를 입력해주세요 😢";
    return;
  }

  const { strike, ball } = calculateResult(userInput);

  attemptsLeft--;
  $attempts.textContent = `남은 기회 : ${attemptsLeft}`;

  if (strike === 4) {
    $result.textContent = "정답을 맞추셨습니다. 축하드립니다 🥳";
    $submitBtn.style.display = "none";
    $resetBtn.style.display = "inline-block";
    $userInput.disabled = true;
  } else if (attemptsLeft > 0) {
    $prevNum.innerHTML += `<p>${userInput} - Strike: ${strike}, Ball: ${ball}</p>`;
    $result.textContent = "아쉽지만 다시 시도해보세요!";
  } else {
    $result.textContent = `기회를 모두 사용했습니다. 정답은 ${secretNum.join("")}였습니다. 😢`;
    $submitBtn.style.display = "none";
    $resetBtn.style.display = "inline-block";
    $userInput.disabled = true;
  }

  $userInput.value = ""; // 입력 필드 초기화
}

// 이벤트 리스너
$submitBtn.addEventListener("click", submitInput);
$userInput.addEventListener("keydown", (e) => {
  if (e.key === "Enter") {
    submitInput();
  }
});

// 초기 기회 표시
$attempts.textContent = `남은 기회 : ${attemptsLeft}`;

💡
이 부분은 어제 딥 다이브 DOM을 공부해서 그런지 어렵지 않았다.

  • 우선은 기회가 열번이니까 기회가 0보다 작다면 메세지를 띄우고 종료
  • 사용자가 입력한 내용이 4자리가 아니거나 숫자가 아니라면 종료
  • 스트라이크와 볼을 계산하는 함수를 구조 분해 할당해주고,
  • 입력할때마다 기회는 한번씩 줄어드니까 attemptsLeft--;, 남은 횟수 알림
  • 이제 스트라이크가 4개 ➡️ 정답. 입력 지우고 새게임 버튼이 나타나게 해준다.
  • 정답을 맞추지 못하고 기회를 소진한다면 스트라이크와 볼의 갯수를 알려준다.
  • 열번의 기회에도 맞추지 못한다면 입력 버튼 다시 없애주고 새 게임 버튼이 나타나게 한다.
  • 입력할때마다 입력 필드는 초기화되게 함수를 구성해주고
  • 이걸 버튼에 이벤트 리스너로 넣어준다 🤗
  • 그리고 사용자의 편의를 위해서 엔터를 눌러도 되게끔 키보드 이벤트도 했다.

💚 새게임 함수

function resetGame() {
  attemptsLeft = 10;
  makeRandomNum();
  $userInput.value = "";
  $prevNum.innerHTML = "";
  $result.textContent = "";
  $attempts.textContent = `남은 기회 : ${attemptsLeft}`;
  $submitBtn.style.display = "inline-block";
  $resetBtn.style.display = "none";
  $userInput.disabled = false;
  console.log(secretNum); // 테스트용 정답 출력
}

$resetBtn.addEventListener("click", resetGame);

💡
모든 부분을 다 초기화 시켜준다고 생각하면 된다.
그걸 새게임 버튼에 적용 시켜주면 끝


완성본

profile
끄적 끄적 배운 걸 적습니다 / FRONT-END STUDY VELOG

0개의 댓글

관련 채용 정보