[BaseballGame] 야구게임

youngseo·2022년 3월 1일
0

JS프로젝트

목록 보기
9/18
post-thumbnail

야구게임

1. 야구게임의 원리

야구게임이란 네자리의 숫자를 맞추는 게임입니다. 주어진 기회는 10번이며 중복되는 숫자나 문자는 입력할 수 없습니다.

플레이어가 4자리의 숫자를 입력 시, 정답인 숫자와 비교했을 때 정답에 포함되는 숫자가 있고 그 숫자의 자리수도 맞는 경우 STRIKE, 정답에 포함되는 숫자가 있지만 자리수가 다른 경우 BALL을 출력합니다.

ex) 1234 입력
1차시도 STRIKE = 0, BALL =2

2. 야구게임 마크업

2-1 index.html 기본틀

<!DOCTYPE html>
<html lang="ko-KF">    //=>한국 국적의 한국언어
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover"
    />
    <title>Baseball</title>
    <link rel="stylesheet" href="../../utils/reset.css">
    <link rel="stylesheet" href="style.css" />
  </head>

  <body>
    <main>
      <h1>Baseball</h1>
      <section></section>
    </main>
    <script src="script.js"></script>
  </body>
</html>

2-2 마크업

  <body>
    <main>
      <section>
        <div class="ball_answer">정답은?</div>
        <form>
          <label for="question"></label>
          <input type="number" id="question" name="question min="0" max="9999">
          <!-- button은 form내에 있을 때 기본적으로 submit으로 동작 그것을 하고 싶지 않은 경우 type="button" 추가 -->
          <button>도전</button> 
        </form>
        <div class="ball_question">결과</div>
      </section>
    </main>
    <script src="script.js"></script>
  </body>
</html>

3. main.css

@charset "utf-8";

main {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 100%;
  height: 100vh;
}

main::before {
  content: '';
  display: block;
  position: absolute;
  /*설정하지 않으면 화면 아래로 html이 밀려납니다*/
  width: 100%;
  height: 100%;
  background: url('./assets/bg.jpg') no-repeat 0 0 / cover;
  opacity: .6;
}

section {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
  /*부여하지 않으면 stacking요소로서 각각의 엘레멘트들이 뷰에 쌓이다가 position요소를 만나면 그 요소가 가장 위로  이동하게 됩니다. 그렇기 때문에 stacking요소 해지를 위해 그 다음 요소에 position:relative 요소를 부여합니다.=>section이 더 위에 놓이게 됨.*/
  z-index: 1;
  width: calc(100vw - 20px);
  height: 100vh;
}

.ball_answer {
  text-align: center;
  width: 180px;
  padding: 20px;
  border: 1px solid #ccc;
  background-color: #fff;
  font-size: 16px;
}

.ball_question {
  margin-top: 30px;
  padding: 30px;
  font-size: 20px;
  background-color: #333;
  text-align: center;
  color: #fff;
}

.ball_question span {
  display: block;
  margin-top: 20px;
  font-size: 16px;
}

.ball_question span em {
  font-style: normal;
}

form {
  display: flex;
  margin-top: 30px;
}

form .ball_input {
  width: 100px;
  height: 30px;
  border: 1px solid #ccc;
}

form button {
  background-color: #333;
  border: non;
  width: 70px;
  height: 30px;
  margin-left: 10px;
  padding: 0 10px;
  color: #fff;
  cursor: pointer;
}

form button:hover, form button:active, form button:focus {
  opacity: .8;
}

4. main.js

4-1 base

즉시실행함수와 use strict 선언하고 작성을 시작합니다. use strict 선언하지 않고 문법에 맞지 않는 코드를 작성하는 경우 에러가 쌓여 런타임에서 문제가 발생하기 때문에 어디서 에러가 났는지 찾기가 어렵습니다.

;(function () {
  'use strict'
})()

4-2 기본 틀 및 변수 설정

;(function () {
  'use strict'

  const get = (target) => document.querySelector(target) // 편의성을 위해 get으로 변수처리

  const init =() => { // 시작한다는 의미의 init함수 작성
    get('.form').addEventListener('submit', (event) => { // submit발생시 playGame함수 실행
      playGame(event);
    })
    setPassword()
  }

  const baseball = {      //게임옵션들을 설정해 추후 유동적으로 옵션을 바꿔가며 즐길 수 있도록 설정
    limit: 10,  //횟수
    digit: 4,  //자리수
    trial: 0,  //시도 횟수
    end: false,  // 끝나지 않았으니 false
    $question: get('.ball_question'), //각 셀렉터를 미리 instance로 잡아 둠
    $answer: get('.ball_answer'),
    $input: get('.ball_input'),
  }
  
  const { limit, digit, $question, $answer, $input } = baseball // 디스트럭쳐링을 통해 각 객체의 값들을 미리 선언
  let { trial, end } = baseball

  const setPassword = () => { 
    // 패스워드 지정
  }

  const onPlayed = (number, hint) => {
    // 시도를 했을 떄 number: 내가 입력한 숫자, hint: 현재 어떤 상황?
    return `<em>${trial}차 시도</em>: ${number}, ${hint}` //시도 횟수를 노출
  }

  const isCorrect = () => {
    // 번호가 같은가?
  }

  const inDuplicate = () => {
    // 중복번호가 있는가?
  }

  const getStrikes = () => {
    // 스트라이크 카운트는 몇개?
  }

  const getBalls = () => {
    // 볼 카운트는 몇개?
  }

  const getResult = () => {
    // 시도에 따른 결과는?
  }

  const playGame = () => {
    // 게임을 플레이 했을 때
  }

  init()  // int에 정의된 함수를 불러옴

})()

4-3 완성본

;
(function () {
  'use strict'

  const get = (target) => document.querySelector(target)

  const init = () => {
    get('.form').addEventListener('submit', (event) => {
      playGame(event);
    })
    setPassword()
  }

  const baseball = { //게임옵션 설정
    limit: 10,
    digit: 4,
    trial: 0,
    end: false,
    $question: get('.ball_question'),
    $answer: get('.ball_answer'),
    $input: get('.ball_input'),
  }

  const {
    limit,
    digit,
    $question,
    $answer,
    $input
  } = baseball // 디스트럭쳐링을 통해 각 객체의 값들을 미리 선언
  let {
    trial,
    end
  } = baseball

  const setPassword = () => {
    //패스워드 지정해줍니다.
    const gameLimit = Array(limit).fill(false) //Array는 배열을 생성하는 함수 10칸의 방안에 false가 듬
    let password = ''
    while (password.length < digit) { //현재 password는 0 4자리수까지 반복을 함
      const random = parseInt(Math.random() * 10, 10) // 10자리 빈칸이 있기 때문에 10을 곱함

      if (gameLimit[random]) { //배열로 설정한 false가 10개 들어있는 상자에 random 카운터가 존대한다면 계속 진행
        continue
      }
      password += random //생성된 random 변수를 각각의 칸에 입력
      gameLimit[random] = true //true가 반환될 때는 그 반복문을 건너뜀
    }
    baseball.password = password
  }

  const onPlayed = (number, hint) => {
    // 시도를 했을 떄 number: 내가 입력한 숫자, hint: 현재 어떤 상황?
    return `<em>${trial}차 시도</em>: ${number}, ${hint}` //시도 횟수를 노출
  }

  const isCorrect = (number, answer) => {
    // 번호가 같은가?
    return number === answer
  }

  const isDuplicate = (number) => {
    // 중복번호가 있는가?
    return [...new Set(number.split(''))].length !== digit
  }

  const getStrikes = (number, answer) => {
    // 스트라이크 카운트는 몇개?
    let strike = 0
    const nums = number.split('')

    nums.map((digit, index) => {
      if (digit === answer[index]) {
        strike++
      }
    })

    return strike
  }

  const getBalls = (number, answer) => {
    // 볼 카운트는 몇개?
    let ball = 0
    const nums = number.split('')
    const gameLimit = Array(limit).fill(false)

    answer.split('').map((num) => {
      gameLimit[num] = true
    })

    nums.map((num, index) => {
      if (answer[index] !== num && !!gameLimit[num]) {
        ball++
      }
    })
    return ball
  }

  const getResult = (number, answer) => {
    // 시도에 따른 결과는?
    if (isCorrect(number, answer)) {
      end = true
      $answer.innerHtml = baseball.password
      return '홈런!!'
    }

    const strikes = getStrikes(number,answer)
    const balls = getBalls(number, answer)

    return 'STRIKE: '+strikes + ',BALL: '+balls
  }

  const playGame = (event) => {
    // 게임을 플레이 했을 때
    event.preventDefault();

    if (!!end) {
      return
    }

    const inputNumber = $input.value
    const {
      password
    } = baseball // 각 함수에서도 사용이 가능

    if (inputNumber.length !== digit) { // 자리가 4자리 숫자가 아닌경우
      alert(`${digit}자리 숫자를 입력해주세요.`)
    } else if (isDuplicate(inputNumber)) {
      alert('중복 숫자가 있습니다.')
    } else { //예외처리를 모두 통과하고 난다면
      trial++
      const result = onPlayed(inputNumber, getResult(inputNumber, password)) //시도에 따른 결과에 입력한 값과 실제 정답 값을 넣어 비교해주고 맞다면 승리조건, 아니면 실패를 넘겨주도록 함 이후 onPlayed에 넣음
      $question.innerHTML += `<span>${result}</span>`

      if (limit <= trial && !isCorrect(inputNumber, password)) {
        alert('쓰리아웃!')
        end = true;
        $answer.innerHTML = password
      }
    }
    $input.value = ''
    $input.focus()
  }

  init()

})()

Object destructuring

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring

0개의 댓글