whatisthis?

project. (js) 숫자야구게임 - 웹 ver (수정) 본문

PRACTICE/SELF

project. (js) 숫자야구게임 - 웹 ver (수정)

thisisyjin 2022. 1. 28. 11:34

 

 

javaScript. 숫자야구게임 - 웹 ver.

https://mywebproject.tistory.com/259?category=875338 javaScript. 숫자야구게임 - (2) javaScript. 숫자야구게임 -(1)  Bulls and Cows (숫자야구) - Rule - - 숫자 제시 횟수 : 10회 이내 - 4자리의 숫자를..

mywebproject.tistory.com

 

지난 포스팅에서 숫자야구 게임을

html요소와 eventListener을 이용하여 플레이할 수 있도록 수정했었다.

 

Guess 버튼을 눌렀을 때를 기준으로 해보았는데,

 

1 / count가 누적이 안됨

2 / 랜덤 숫자가 연동이 안됨

3 / UI 디자인이 너무 안이쁨

과 같은 문제가 있었다. 

 

큰 틀은 유지하되, 폰트나 기본 디자인 요소를 바꿔보았고,

 

 

index.html

<!-- reference : www.zerocho.com -->
<!-- JS Array / Math객체 / String / Loop practice용  -->


<!DOCTYPE html>
<html lang="ko">
<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>숫자야구</title>
    <link rel="stylesheet" href="style.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@700&display=swap" rel="stylesheet">
</head>
<body>
    <div id="input-form">
        <input required type="text" placeholder="Guess the number" maxlength="4" />
        <button>Guess</button>
    </div>
    <div id="container">
        <div id="log"></div>
    </div>

    <script src="app.js"></script>
</body>
</html>

- #log를 감싸는 div를 추가해 디자인적으로 다 감싸는 역할

( 백그라운드 효과를 줄 예정 )

 

- web font를 사용하기 위해 link태그 3줄이 추가되었음. 

 

style.css

* {
    margin: 0;
    box-sizing : border-box;
}

html {
    font-family: 'Poppins', sans-serif;
    font-size: 16px;
    line-height: 2;
    color: #1f2d3d;
}

body {
    text-align: center;
    width: 100%;
    height: 100vh;
    background-color: #f7efde;
}

body::after {
    content: "Bulls and Cows";
    display: block;
    margin-top: 50px;
    color: #736a59;
    font-size: 12px;
    font-weight: 600;
}


#container {
    background-color: #f1e6cd;
}

- 웹 폰트 적용은 font-family로

 

 

app.js

// reference : www.zerocho.com
// JS Array / Math객체 / String / Loop practice용




// 로그 출력
function logMessage(msg, color) {
    if(!color) {color = '#444444';}
    const div = document.createElement('div');
    div.innerHTML = msg;
    div.style.color = color;
    if(color === '#370089') {div.style.fontWeight = 'bold';
        div.style.fontSize = '20px';}
    document.getElementById('log').appendChild(div);
}

// input과 button
const input = document.querySelector('#input-form input');
const button = document.querySelector('#input-form button');

// 


function getNumber() {
    let list = [0,1,2,3,4,5,6,7,8,9];
    let answer = [];
    for (let i=0; i<4; i++) {
        let select = Math.floor(Math.random() * list.length);
        // answer[i] = list.splice(select, 1)[0];
        answer.push(list.splice(select, 1)[0]);
    }
    localStorage.setItem('answer', answer.join(''));   // answer = 2458
}

let count = 1;

function guessNumber() {
    let strike = 0;
    let ball = 0;

    while(count <= 10) {
    let num = input.value;
    let numArr = num.split('');
    strike = 0;
    ball = 0;

    let answerArr = localStorage.getItem('answer').split('');

    for(let j=0; j<4; j++) {
        for (let k=0; k<4; k++) {
            if (answerArr[j] == numArr[k]) {
                if (j == k) {
                strike++;
                } else {
                ball++;
                }
                break;
            }
        }
    }

    if (strike === 4) {
        logMessage('정답입니다!' + count + '회만에 맞춤', '#370089');
        break;
    } else if (count > 10) {
        logMessage('시도 횟수를 초과하셨습니다.\n게임을 다시 하려면 F5를 누르세요.', '#780000');
    } else {
        logMessage(numArr.join('') + ': ' + strike + '스트라이크 ' + ball + '볼');
        count++;
        break;
     }
  }

}


getNumber();       // 숫자 뽑기
button.addEventListener('click', guessNumber);     // eventListener - 버튼 클릭시

- 지난번에 작성했던 코드와 비교해보면

더보기
더보기
// 로그 출력
function logMessage(msg, color) {
    if(!color) {color = 'black';}
    const div = document.createElement('div');
    div.innerHTML = msg;
    div.style.color = color;
    document.getElementById('log').appendChild(div);

}

// input과 button
const input = document.querySelector('#input-form input');
const button = document.querySelector('#input-form button');

// 
function guessNumber() {

    let list = [0,1,2,3,4,5,6,7,8,9];
    let answer = [];
    for (let i=1; i<4; i++) {
        let select = Math.floor(Math.random() * list.length);
        answer[i] = list.splice(select, 1)[0];
    }
    let count = 1;
    let strike = 0;
    let ball = 0;
    while(count <= 10) {
    let num = input.value;
    let numArr = num.split('');
    strike = 0;
    ball = 0;
    count++;
    for(let j=0; j<4; j++) {
        for (let k = 0; k < 4; k++) {
            if ([j] == numArr[k]) {
                if (j === k) {
                strike++;
                } else {
                ball++;
                }
                break;
            }
        }
    }

    if (strike === 4) {
        logMessage('정답입니다!');
        break;
    } else if (count > 10) {
        logMessage('시도 횟수를 초과하셨습니다.\n게임을 다시 하려면 F5를 누르세요.', 'red');
    } else {
        logMessage(numArr.join('') + ': ' + strike + '스트라이크 ' + ball + '볼', 'blue');
        break;
     }
}

}


// eventListener - 버튼 클릭시 
button.addEventListener('click', guessNumber);

function logMessage
- 색상이름 (예> black, blue)에서 HEX 코드값으로 변경함.
- 정답일 때에는 bold와 font-size 를 크게.


지난번에는 eventListener가 버튼을 클릭할 떄 마다 
guessNumber함수가 실행되도록 했다.

 

(form을 제출할 때를 기준으로도 만들 수 있다. 

굳이 버튼 안누르고 enter키로도 가능하니까)

>> 이것은 지난번 크롬 클론코딩에서 했었다!

 


그러나, 한번 클릭할 때마다
정답인 수(answer)를 매번 다시 뽑으므
이번에는 getNumber 함수를 추가해서
정답인 수는 한번만 뽑고,
guess는 10번까지 할 수 있도록 하였다. (while count <= 10)


___


또, count가 올라가지 않는 문제가 있었는데
이는 count = 1 이 guessNumber안에 있기 떄문에
이벤트리스너에 의해 매번 count=1로 초기화되기
때문이다.

따라서, count는 함수 밖으로 뺴서 
default = 1로 하고,
(적어도 한번은 시도하고 맞춰야하니까)

 

>>> 이부분은 나중에 do~while문으로도 고칠 수 있을듯?

마지막 if-elseif-else문에서
정답이면 >  count = 1에서 끝냄 (break)
정답 아니면 > count++ 하고나서 break. (다시 버튼 누르면 실행)

count 변수는 함수 밖에 있으므로 count가 계속 누적해서
올라갈 수 있다.


__

여기까지 해결하고 나니, 이제는 getNumber()에서
랜덤하게 뽑은  4자리수 (사실은 4개의 아이템을 가지는 배열)
, 즉 정답인 수를 
guessNumber에 사용하지 못하게 되었다.

왜냐면 answer 변수는 getNumber 함수의 '지역객체' 이니까.

>> 나는 이 해결방법을 생각해보다가
localStorage를 일단 이용하였다.
지금도 이 방법을 잘 쓸지는 모르겠다만
다른 방법들도 있겠지만 우선 이걸 활용해보았다.


localStorage.setItem('key값', value);로 저장한 후에
나중에 불러올 떄에는
localStorge.getItem('key값'); 으로 하면 된다.

__

나머지는 이전과 동일하다.

아래 실행부에
getNumber();로 함수를 호출해 먼저 정답인 수를 뽑고
button.addEventListener('click', guessNumber);
로 버튼을 클릭할 때 마다 함수를 호출한다.

 

 

 


플레이 화면

플레이 화면

 

 

 

 

 

 

 

** reference : www.zerocho.com

 

 

 

 

 

 

 

 


사담 👻

 

역시 프로젝트를 해봐야 실력이 늘 수 있구나 ㅡ 싶었다.