야구게임이란 네자리의 숫자를 맞추는 게임입니다. 주어진 기회는 10번이며 중복되는 숫자나 문자는 입력할 수 없습니다.
플레이어가 4자리의 숫자를 입력 시, 정답인 숫자와 비교했을 때 정답에 포함되는 숫자가 있고 그 숫자의 자리수도 맞는 경우 STRIKE, 정답에 포함되는 숫자가 있지만 자리수가 다른 경우 BALL을 출력합니다.
ex) 1234 입력
1차시도 STRIKE = 0, BALL =2
<!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>
<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>
@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;
}
즉시실행함수와 use strict 선언하고 작성을 시작합니다. use strict 선언하지 않고 문법에 맞지 않는 코드를 작성하는 경우 에러가 쌓여 런타임에서 문제가 발생하기 때문에 어디서 에러가 났는지 찾기가 어렵습니다.
;(function () {
'use strict'
})()
;(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에 정의된 함수를 불러옴
})()
;
(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()
})()