컴퓨터가 랜덤으로 만든 수를 5번의 기회 안에 맞추는 게임을 만드려다 실패하다.
나의 접근 과정을 보기 위해 작성함
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Do+Hyeon:400" rel="stylesheet">
<style>
body {
background: url("https://media.istockphoto.com/photos/clear-blue-sky-as-a-background-wallpaper-pastel-sky-wallpaper-picture-id608634136?k=20&m=608634136&s=170667a&w=0&h=QqB80Ci9iSHOw0OjdM1fNbEeDrSvHG7-YuXNf_TcQnE=");
background-repeat: no-repeat;
background-size: cover;
text-align: center;
height: 100vh;
font-family: "do hyeon";
}
.container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 600px;
padding: 50px;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 25px;
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
}
#result-area,
#chance-area {
font-size: 1.5em;
}
#user-input {
width: 300px;
height: 50px;
font-size: 1.5em;
text-align: center;
margin-top: 10px;
outline: 0;
border: 0;
border-radius: 10px;
}
#btn-area {
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<h1>숫자 맞추기 게임</h1>
<div id="result-area">결과값이 여기 나옵니다!</div>
<div id="chance-area">남은 기회: 5번</div>
<input type="text" id="user-input" placeholder="숫자를 입력하세요.">
<div id="btn-area">
<button id="play-button" class="btn btn-success">확인</button>
<button id="reset-button" class="btn btn-danger">초기화</button>
</div>
</div>
<!-- JavaScript -->
<script>
/*
[숫자 맞추기 게임]
1. 랜덤숫자 생성 ㅇ
2. 숫자 입력 후 확인 버튼 누르기
3. 유저의 입력 값과 랜덤 숫자 값을 비교 후 결과 웹페이지에 출력
3 - 1 입력 값 == 랜덤 값 => "정답입니다👍"
3 - 2 입력 값 > 랜덤 값 => "입력한 수보다 작은 수 입니다..🤣"
3 - 3 입력 값 < 랜덤 값 => "입력한 수보다 큰 수 입니다..🤣"
4. 5번의 기회를 모두 소진하면 게임 종료. (확인 버튼 비활성화)
-> "게임이 종료되었습니다.."
5. 초기화버튼을 누르면 게임이 리셋된다.
6. 유저가 1 ~ 100 범위 밖의 수를 입력할 시 남은 기회는 감소하지 않는다.
-> 범위 이외의 숫자입니다. 다시 입력해주세요.
7. 유저가 이미 입력한 숫자를 또 입력하면 기회는 감소하지 않는다.
-> 10은 한 번 입력했던 숫자입니다. 다른 숫자를 입력해주세요.
*/
let ranNum = parseInt((Math.random() * 100) + 1)
console.log("랜덤 숫자: ", ranNum)
let cnt = 4;
let numList = []; // 이전에 입력했던 수 확인용 배열
// 확인 버튼 눌렀을 때
document.getElementById("play-button").addEventListener("click", () => {
let userInput = document.getElementById("user-input")
let userNum = parseInt(userInput.value) // 유저가 입력한 숫자
console.log("유저 입력: ", userNum)
let result = document.getElementById("result-area") // 결과 요소
let result_text = result.innerText // 결과 텍스트
let chance = document.getElementById("chance-area")
let chance_text = chance.innerText // 남은 기회: n번
if (cnt > 0) {
if (userNum < 1 || userNum > 100) {
result.innerText = "범위 이외의 숫자입니다. 다시 입력해주세요."
chance.innerText = `남은 기회: ${cnt + 1}번`
}
else {
if (numList.includes(userNum)) {
result.innerText = `${userNum}은 이미 입력했던 숫자입니다. 다른 숫자를 입력해주세요.`
}
else {
if (userNum > ranNum) {
result.innerText = `${userNum}보다 작은 수 입니다..🤣`
numList.push(userNum)
// console.log("입력기록: ", numList)
cnt--
chance.innerText = `남은 기회: ${cnt + 1}번`
userInput.value = ""
}
else if (userNum < ranNum) {
result.innerText = `${userNum}보다 큰 수 입니다..🤣`
numList.push(userNum)
// console.log("입력기록: ", numList)
cnt--
chance.innerText = `남은 기회: ${cnt + 1}번`
userInput.value = ""
}
else if (userNum === ranNum) {
result.innerText = `${userNum}정답입니다👍`
document.getElementById("play-button").disabled = true;
// 버튼 비활성화
}
}
}
}
else {
chance.innerText = `남은 기회: ${cnt}번`
result.innerText = "게임이 종료되었습니다..."
document.getElementById("play-button").disabled = true; //버튼 비활성화
}
// end play button
// 초기화 버튼 눌렀을 때
document.getElementById("reset-button").addEventListener("click", () => {
let ranNum = parseInt((Math.random() * 100) + 1)
console.log("랜덤 숫자: ", ranNum)
let result = document.getElementById("result-area") // 결과 요소
let result_text = result.innerText // 결과 텍스트
result.innerText = "결과값이 여기 나옵니다!"
let chance = document.getElementById("chance-area")
let chance_text = chance.innerText // 남은 기회: n번
cnt = 4
chance.innerText = `남은 기회: ${cnt + 1}번`
let numList = [];
// console.log("초기화 후 배열", numList)
let userInput = document.getElementById("user-input")
userInput.value = "" // 입력창 초기화
document.getElementById("play-button").disabled = false; // 버튼 활성화
})
})
</script>
</body>
</html>
이상한 점
- cnt = 4로 시작
- 숫자 입력하고 확인버튼 누르고 초기화하면 랜덤 숫자 생성과정이 1번 일어나야 하는데 버그처럼 2번, 4번, 5번 일어나는 현상,
- 초기화를 했음에도 불구하고 초기화 전에 입력했던 값을 입력하면 전에 입력했다고 뜨는 현상
1. 랜덤 숫자 생성 및 변수 선언
let ranNum = parseInt((Math.random() * 100) + 1)
console.log("랜덤 숫자: ", ranNum)
let cnt = 4;
let numList = []; // 이전에 입력했던 수 확인용 배열
사용자가 맞혀야할 랜덤 숫자를 생성하기 위해 Math.random()을 사용해 준다. 1 ~ 100의 범위를 가져야 하니까 100만 곱하면 0 ~ 99 이까 + 1까지 해준다.
남은 기회를 나타내는 cnt 변수, 이전에 입력했던 수를 확인하기 위해 만든 배열 numList이다.
여기서 의문점이 드는 건 분명 남은 기회는 5회인데 왜 cnt를 4로 주는 가? 일 것이다.
코드를 짜면서 큰 틀과 세세한 기능들을 만드는 과정에서 남은 기회와 관련된 기능이 작동할 때 생겨난 일이다.
2. 확인 버튼의 기능과 숫자 입력받기
// 확인 버튼 눌렀을 때
document.getElementById("play-button").addEventListener("click", () => {
let userInput = document.getElementById("user-input")
let userNum = parseInt(userInput.value) // 유저가 입력한 숫자
console.log("유저 입력: ", userNum)
let result = document.getElementById("result-area") // 결과 요소
let result_text = result.innerText // 결과 텍스트
let chance = document.getElementById("chance-area")
let chance_text = chance.innerText // 남은 기회: n번
if (cnt > 0) {
if (userNum < 1 || userNum > 100) {
result.innerText = "범위 이외의 숫자입니다. 다시 입력해주세요."
chance.innerText = `남은 기회: ${cnt + 1}번`
}
else {
if (numList.includes(userNum)) {
result.innerText = `${userNum}은 이미 입력했던 숫자입니다. 다른 숫자를 입력해주세요.`
}
else {
if (userNum > ranNum) {
result.innerText = `${userNum}보다 작은 수 입니다..🤣`
numList.push(userNum)
// console.log("입력기록: ", numList)
cnt--
chance.innerText = `남은 기회: ${cnt + 1}번`
userInput.value = ""
}
else if (userNum < ranNum) {
result.innerText = `${userNum}보다 큰 수 입니다..🤣`
numList.push(userNum)
// console.log("입력기록: ", numList)
cnt--
chance.innerText = `남은 기회: ${cnt + 1}번`
userInput.value = ""
}
else if (userNum === ranNum) {
result.innerText = `${userNum}정답입니다👍`
document.getElementById("play-button").disabled = true;
// 버튼 비활성화
}
}
}
}
else {
chance.innerText = `남은 기회: ${cnt}번`
result.innerText = "게임이 종료되었습니다..."
document.getElementById("play-button").disabled = true; //버튼 비활성화
}
// end play button
2 - 1) 숫자 입력받기
play-button을 아이디로 갖는 요소에 클릭 이벤트를 걸어주고, 클릭했을 때의 실행될 함수를 써줘야 한다.
일단 숫자를 입력 받아야하니까 DOM으로 접근하고 입력값이니. value 해주고 숫자는 입력받을 때 문자형으로 입력받기 때문에 숫자형으로 변환하는 과정까지 거쳐준다. 그렇게 userNum에 유저의 입력값이 숫자형으로 보관된다.
2 - 2) 랜덤 숫자와 유저 숫자를 비교하기 및 남은 기회 감소 기능
if (userNum > ranNum) {
result.innerText = `${userNum}보다 작은 수 입니다..🤣`
numList.push(userNum)
// console.log("입력기록: ", numList)
cnt--
chance.innerText = `남은 기회: ${cnt + 1}번`
userInput.value = ""
}
else if (userNum < ranNum) {
result.innerText = `${userNum}보다 큰 수 입니다..🤣`
numList.push(userNum)
// console.log("입력기록: ", numList)
cnt--
chance.innerText = `남은 기회: ${cnt + 1}번`
userInput.value = ""
}
else if (userNum === ranNum) {
result.innerText = `${userNum}정답입니다👍`
document.getElementById("play-button").disabled = true;
// 버튼 비활성화
}
입력 숫자와 랜덤 숫자를 비교하는 과정은 너무 많이 했기 때문에 건너뛴다.
생각해야 할 것은 정답이 아닐 때 어떤 일이 일어나는가? 정답일 때는 어떤 일이 일어나는가?이다.
두 수가 다를 땐 크거나 작거나 상관없이 남은 기회가 -1 되야한다. 나는 cnt변수를 남은 기회를 위해 만들었다고 했다.
그래서 cnt-- 를 했다. 그래놓고 남은 기회의 텍스트에는 변수로 cnt + 1을 넣고 있다.
cnt = 4로 한 이유
cnt = 5, 남은 기회 cnt 번으로 했을 때 내가 겪었던 문제가 뭐냐면
원래대로라면 남은 기회가 1에서 0으로 가는 순간 게임 종료가 돼야 하는데, 내가 겪은 문제는 남은 기회 0번에서 한번 더 해야 게임 종료가 되는 것이었다. 남은 기회 0번이 1번으로 보이면 제대로 작동된다는 의미로 받아들였다.
제대로 작동만 되게 해 보자 하고 눈에 보이는 부분인 cnt번을 cnt + 1로 해주었다. 그렇게 하니 처음 기회가 6으로 된다.
그래서 cnt = 4로 시작하였고 그렇게 정상 작동하게 되었다. 버그를 고치려고 해서 cnt = 4로 시작했다.
(아마 4, 3, 2, 1, 0 총 5개 이런 식의 느낌이라 이렇게 된 거 같다.)
중복으로 입력하는 것을 방지하기 위해 numList에 입력값을 push 해서 사용자가 입력했던 수를 기록했다.
틀렸을 때 userInput.value = " "을 넣어준 이유는 틀렸을 때 또 입력해야 하는데, 언제 전에 입력한 걸 지우고 쓰고 하기 귀찮아서 틀리면 그냥 초기화시켜버렸다. 사용자를 위한 코드라고 볼 수 있다.
정답을 맞히면 더 이상 확인할 필요가 없으니까 속성값 추가하는 방식으로 disabled = true를 넣어주었다.
(앞에서 배우지 않은 내용이라 코드를 다 짜고 수업을 듣고 추가한 내용, 원래는 없었음)
3. 기회가 0이 되면 확인 버튼 비활성화 및 "게임이 종료되었습니다." 출력
else {
chance.innerText = `남은 기회: ${cnt}번`
result.innerText = "게임이 종료되었습니다..."
document.getElementById("play-button").disabled = true; //버튼 비활성화
}
기회가 0이라는 건 cnt가 0부터 게임이 종료된다는 의미다. 그래서 나는 과정 2에서 만든 조건문 전체를 중괄호로 감싸고 앞에 if(cnt > 0)을 넣었다.
4. 초기화 버튼 기능 만들기
document.getElementById("reset-button").addEventListener("click", () => {
let ranNum = parseInt((Math.random() * 100) + 1)
console.log("랜덤 숫자: ", ranNum)
let result = document.getElementById("result-area") // 결과 요소
let result_text = result.innerText // 결과 텍스트
result.innerText = "결과값이 여기 나옵니다!"
let chance = document.getElementById("chance-area")
let chance_text = chance.innerText // 남은 기회: n번
cnt = 4
chance.innerText = `남은 기회: ${cnt + 1}번`
let numList = [];
// console.log("초기화 후 배열", numList)
let userInput = document.getElementById("user-input")
userInput.value = "" // 입력창 초기화
document.getElementById("play-button").disabled = false; // 버튼 활성화
})
초기화 버튼을 눌렀을 때 돼야 하는 것들
- 새로운 랜덤 숫자 생성
- 결과 텍스트 초기화
- 남은 기회 5회로 초기화
- 전에 입력한 숫자 기록 배열 초기화
- 입력창 초기화
- 확인 버튼 활성화
5. 범위 밖의 숫자 입력 처리 및 중복 방지
if (userNum < 1 || userNum > 100) {
result.innerText = "범위 이외의 숫자입니다. 다시 입력해주세요."
chance.innerText = `남은 기회: ${cnt + 1}번`
}
입력받을 숫자의 범위는 1 <= userNum <= 100이다. 그럼 userNum < 1 ||(or) userNum > 100이면 비교조차 안 해도 된다는 것이다. 남은 기회는 감소하지 않으니까 그대로.
if (cnt > 0) {
if (userNum < 1 || userNum > 100) {
result.innerText = "범위 이외의 숫자입니다. 다시 입력해주세요."
chance.innerText = `남은 기회: ${cnt + 1}번`
}
else {
if (numList.includes(userNum)) {
result.innerText = `${userNum}은 이미 입력했던 숫자입니다. 다른 숫자를 입력해주세요.`
}
else {
if (userNum > ranNum) {
result.innerText = `${userNum}보다 작은 수 입니다..🤣`
numList.push(userNum)
// console.log("입력기록: ", numList)
cnt--
chance.innerText = `남은 기회: ${cnt + 1}번`
userInput.value = ""
}
else if (userNum < ranNum) {
result.innerText = `${userNum}보다 큰 수 입니다..🤣`
numList.push(userNum)
// console.log("입력기록: ", numList)
cnt--
chance.innerText = `남은 기회: ${cnt + 1}번`
userInput.value = ""
}
else if (userNum === ranNum) {
result.innerText = `${userNum}정답입니다👍`
document.getElementById("play-button").disabled = true;
// 버튼 비활성화
}
}
}
}
else {
chance.innerText = `남은 기회: ${cnt}번`
result.innerText = "게임이 종료되었습니다..."
document.getElementById("play-button").disabled = true; //버튼 비활성화
}
만든 조건문들을 이 경우일 때만 이게 실행되야 하니까 생각하면서 조합해 주면 이런 식으로 된다.
왜 틀렸는가?
이 글에서 버튼을 비활성화하는 코드, 이후에 올릴 선생님 코드에서 DOM으로 접근한 후 이벤트 리스너 안의 익명 함수 안에서 반복문의 break 기능과 유사하게 return으로 중간에서 멈추게 하는 방법을 몰랐다.
비활성화 코드는 배우지 않아서 몰랐고, return으로 끊는 방법은 return은 알고 있었지만 끊는 용도로 응용하는 방법을 몰랐기 때문에 내가 작성한 코드가 더 복잡하고 틀린 코드가 된 것이다.
배운 점
- DOM으로 접근하는 것은 변수 선언과 같이 전역에서 해주면 간결해지고 편하다.
- 버튼 비활성화 요소.disabled = true
- 복잡하게 다중 if 안하고 return으로 원하는 부분에서 함수를 끝낼 수 있다. 조건문 적는 순서도 중요하다.
그래도 사용자의 입장을 생각하고 코드를 작성하는 부분도 스스로 생각해서 어떻게 하면 사용자가 편하게 느낄까? 하면서 시키지 않은 것들을 코드에 영향이 가지 않는 선에서 해보았다. ex) input 속성으로 placholder로 입력창에 숫자를 입력하세요. 띄우기, 결과창에 입력한 수 띄워주기, 틀렸을 때 입력창 자동으로 지워주기
틀려서 오히려 좋아!
'Front-End > 3. JavaScript 실전' 카테고리의 다른 글
[JS] Ex15_To do List.html (0) | 2023.06.21 |
---|---|
[JS] Ex14_숫자맞추기 실습.html (선생님 코드.ver) (0) | 2023.06.21 |
[JS] Ex13_DOM스타일.html (0) | 2023.06.20 |
[JS] Ex12_DOM속성실습.html (0) | 2023.06.20 |
[JS] Ex11_DOM속성.html (0) | 2023.06.20 |