barcode

자바스크립트로 숫자 야구를 만들어보자

Coding/JavaScript

아니 이게 되더라고?


https://codepen.io/koreanraichu/pen/VwNNZGW

 

숫자야구 ver. JS

...

codepen.io

거기서도 제대로 작동할지는 모르겠는데 일단 코드펜에도 올렸다. 테스트는 월욜에 점심 먹으면서 해봐야징.

 

숫자야구가 약간 코더들에게는 국룰같은건지 언어별로 이게 하나씩 있다. 물론 파이썬에도 있지… 그러다보니 궁금해진게 그럼 JS도 프로그래밍 할 때 쓰는건데 숫자야구가 있겠지? 예, 있습니다. 놀랍게도. 그래서 해봤습니다.


Reference

https://yjg-lab.tistory.com/322

 

[JavaScript] 숫자야구 풀이

숫자야구 4자리 정답 숫자를 찾는 문제. 입력값 4자리 수 중 숫자가 포함되어 있는 경우 볼, 자리까지 동일하면 스트라이크. 모두 맞추면 홈런. 개인 풀이 다이어그램 알고리즘 // 랜덤 정수 4자리

yjg-lab.tistory.com

https://www.freecodecamp.org/korean/news/javascript-splice-method/

 

자바스크립트에서 `.splice()` 배열 메서드 사용하기

자바스크립트의 splice() 메서드는 배열 객체에 사용할 수 있는 내장 메서드입니다. 이는 기존 요소를 삭제하거나 교체하여 배열의 내용을 변경하며, 제거된 요소가 담긴 별도의 배열을 새로 반환

www.freecodecamp.org

https://hianna.tistory.com/379

 

[Javascript] 특정 문자 위치 찾기 (indexOf 함수)

지난 번에는 특정 위치의 문자를 찾는 방법, 즉, index값을 입력으로 전달하여, 해당 위치에 있는 문자를 읽는 방법을 알아보았습니다. [Javascript] 특정 위치 문자 찾기 2가지 방법 (charAt 함수, 대괄

hianna.tistory.com

https://ingnoh.tistory.com/172

 

[JS] slice, splice endIndex에 undefined 넣었을 때

const arr1 = [1, 2, 3]; const arr2 = [1, 2, 3]; const sliced = arr1.slice(0, undefined); const spliced = arr2.splice(0, undefined); console.log(`original: ${arr1} / sliced: ${sliced}`); console.log(`original: ${arr2} / spliced: ${spliced}`); /* 실행 결

ingnoh.tistory.com

https://velog.io/@abc2752/JS-Set

 

Javascript - Set

해당 포스트는 자바스크립트를 학습한 내용을 일부 정리한 내용입니다. 교재의 모든 내용을 정리하기 보다는 간단히 개념을 정리하고 활용할 수 있는 방법을 위주로 작성하였습니다.

velog.io


일단 숫자야구에는 기본적인 규칙이 있는데

 

1. 숫자 세자리(네자리 하는 경우도 있다)를 맞추면 되는 대단히 심플한 게임인데, 일단 세자리 수에 중복이 없다. 그니까 111 666 이딴거 없음.

2. 몇 번째 자리인지랑 숫자를 정확히 맞추면 스트라이크다.

3. 몇 번째 자리인지는 틀렸는데 그 숫자가 있으면 볼이다.

4. 만약 세자리 수가 다 없으면 아웃이다. (근데 이럴 일은 잘 없음)

 

그래서 세 자리 숫자를 맞추면 되는 정말 대단히 심플한(데 코딩하기 빡센) 게임이다. 횟수는 10회로 제한하는 코드도 있긴 한데 일단 내껀 제한 없으니까 편히 즐기십셔.

 

숫자야구 코드는 크게 두 파트인데 첫번째가 맞춰야 할 숫자를 만드는거고, 두번째가 본게임 로직이다. 빡세기는 아래가 제일 빡셌음... 근데 배열 만드는데도 버그터져서 아오... 그 얘기는 인제 지금부터 할거니까 VScode 켜고 오십시오.

 

문제 만들기

for (let i = 0;i < 3;i++) {
    ballQuestion[i] = Math.floor(Math.random() * 10);
}

길이가 3인 배열을 만들려면 이렇게 하면 된다. 근데 이렇게 하면 숫자가 중복될 수 있다. 아, 참고로 자바스크립트는 Python처럼 randrange 이딴거 없습니다.

 

let numberArray = ['0','1','2','3','4','5','6','7','8','9'];
let ballQuestion = [];
for (let i = 0;i < 3;i++) {
    let ballPick = [];
    ballPick = numberArray.splice(Math.floor(Math.random() * (10 - i)),1)[0];
    ballQuestion.push(ballPick);
}

그래서 이렇게 했는데 문제가 뭐냐면 가끔 1부터 9까지를 다 입력했는데 2스트라이크인 경우가 생겼다. 그래서 확인해보니까 배열에 숫자가 아니라 undefined가 들어가있는겨. 저 코드는 배열을 만들 숫자를 하나씩 빼가면서 배열 길이가 줄어들어서 최종적으로 6이 되는 구조여야 맞는데, undefined가 껴버리면 배열 길이가 7이 되는거다.

 

let numberArray = ['1','2','3','4','5','6','7','8','9'];
let ballQuestion = [];
for (let i = 0;i < 3;i++) {
    let ballPick = [];
    ballPick = numberArray.splice(Math.floor(Math.random() * (numberArray.length - i)),1)[0];
    console.log(ballPick, numberArray)
    ballQuestion.push(ballPick);
}
// 배열 만들기

응~ 짤르고 길이 줄여버리면 그만이여~

 

로직짜기

round ++;
strike = 0; //스트라이크
ball = 0; //볼
let ballOut = `<p>아웃!</p>`
ballButton.addEventListener('click',()=>{
    console.log(ballInput.value, ballInput.value[0])
    for (let i = 0;i < 3;i++) {
        if (ballQuestion[i] == ballInput.value[i]) {
            strike ++;
        }
        else if (ballQuestion[i] == ballInput.value[i]) {
            ball ++;
        }
    };
    let ballText = document.createElement('p');
    ballText.innerText = `Round ${round}: ${strike}S ${ball}B`;
    ballAnswer.appendChild(ballText);
});

이 코드는 아직 문제가 매우 많은 상태인데, 일단 스트라이크는 로직이 저게 맞다. 맞는데 볼은 저게 아니기때문에 수정해야 한다. 잘 보면 스트라이크랑 볼이랑 로직 같은데 일단 저 상태로 스트라이크는 잘 찾나 봤다. 그리고 잘찾는다.

 

ballButton.addEventListener('click',()=>{
    strike = 0; //스트라이크
    ball = 0; //볼
    round ++;
    for (let i = 0;i < 3;i++) {
        if (ballQuestion[i] == ballInput.value[i]) {
            strike ++;
        }
        else if (ballInput.value.indexOf([i]) != -1) {
            ball ++;
        }
    };
    let ballText = document.createElement('p');
    ballText.innerText = `Round ${round}: ${ballInput.value}, ${strike}S ${ball}B`;
    ballAnswer.appendChild(ballText);
});

라운드 안 더래지는 문제도 손봤음... 위에도 썼지만 스트라이크는 숫자가 있고 위치까지 딱 맞는거고 볼은 숫자는 있는데 자리수가 다른경우다. 일단 저거 몇번 해봤는데 맞긴 맞았음... 그럼 이제 자잘한 기능을 붙여보자.

 

ballButton.addEventListener('click',()=>{
    if (ballInput.value.length != 3) {
        strike = 0; //스트라이크
        ball = 0; //볼
        alert('세 자리 숫자를 입력해주세요! ');
        ballInput.value = '';
    }
    else if (new Set(ballInput.value).size < 3) {
        strike = 0; //스트라이크
        ball = 0; //볼
        alert('숫자는 중복되지 않는 세 자리 숫자입니다. ');
        ballInput.value = '';
    }
    else {
        strike = 0; //스트라이크
        ball = 0; //볼
        round ++;
        for (let i = 0;i < 3;i++) {
            if (ballQuestion[i] == ballInput.value[i]) {
                strike ++;
            }
            else if (ballInput.value.indexOf([i]) != -1) {
                ball ++;
            }
        };
        if (ball == 0 && strike == 0) {
            let ballText = document.createElement('p');
            ballText.innerText = `Round ${round}: ${ballInput.value}, Out! 😥`;
            ballText.classList.add('nohit');
            ballAnswer.appendChild(ballText);
        }
        else if (strike == 3) {
            let ballText = document.createElement('p');
            ballText.innerText = `Round ${round}: ${ballInput.value}, ${strike}S ${ball}B ⚾`;
            ballText.classList.add('homerun');
            ballAnswer.appendChild(ballText);
        }
        else {
            let ballText = document.createElement('p');
            ballText.innerText = `Round ${round}: ${ballInput.value}, ${strike}S ${ball}B`;
            ballAnswer.appendChild(ballText);
        }
        ballInput.value = '';
    }
});
//아 정말 힘들다...

뭐가 많이 추가됐는데 일단 1) 입력한 숫자가 세자리수가 아니거나 2) 입력한 숫자에 중복이 있을 경우(예: 222) 알림창을 띄워준다. 그리고 아웃일 때랑 정답을 맞췄을 때 텍스트 색이 다르고(클래스 안더해져서 몇번 고생함...) 입력하고 버튼을 누르면 인풋창을 알아서 비워주기까지 한다. 솔직히 이정도면 장족의 발전이여...

 

결과물

그래서 3스트라이크, 그러니까 정답일 때는 이렇게 된다.

 

정말 작정하지 않는 이상 볼 일은 없지만 아웃 뜨면 이렇게 나온다.

 

PS.

이게 하다보니까 2S 1B가 나올 때가 있는데, 문제가 뭐냐면 2스트라이크 1볼은 나와서는 안 된다. 4자리수면 몰라도 3자리수에서 이건 패러독스다. 숫자 두 개가 자리가 맞는데 하나가 자리가 뻑났다? 이거는 있을 수 없는 일인겁니다.

 

이거는 어떻게 해결하느냐...

for (let i = 0; i < 3; i++) {
    if (ballQuestion[i] == ballInput.value[i]) {
        strike++;
    } else if (ballInput.value.indexOf([i]) != -1) {
        ball++;
    }
};

저기 자리수 안맞는거 밑에 중복 밑에 보여요? 그 스트라이크 0 볼 0 그거. 거기 보면 반복문 있는데 이 부분에 else if문을

 

for (let i = 0; i < 3; i++) {
    if (ballQuestion[i] == ballInput.value[i]) {
        strike++;
    } else if (ballInput.value.indexOf(ballQuestion[i]) != -1) {
        ball++;
    }
};

이걸로 바꿔주자. 사실 나도 제보받긴 했는데 코드펜은 모바일에서조작하기가 개 그지같아서 정확히 어떤 현상인지는 모르겠음. 근데 코드만 놓고 보면 i가 0, 1, 2니까 아마 답에 1이나 2가 들어가있으면 볼로 치는 듯…