TIL 18. Java Script - [mini_project] Baseball game

신미영·2021년 4월 27일
0

Java Script

목록 보기
13/17

자바스크립트 실전 연습을 위해 숫자 야구 게임을 만들었다. 생각보다 게임 규칙이 까다로워 코드 작성에 어려움이 있었다!
미니 프로젝트 게이트 페이지 바로가기>



최종 결과물

  • 사용자는 0~9까지 숫자가 중복되지 않은 3자리 랜덤 숫자가 무엇인지 맞추어야 한다.
    ex) 123, 453, 653, 128, 392 (O) // 112, 404 (X)
  • 사용자가 선택한 값이 정답과 숫자, 자릿수가 같을 경우 strike로 표시한다. 정답과 숫자는 같고 자릿수는 다를 경우 ball로 표시한다.
    ex) 정답 123, 사용자 325 -> 1 Strike, 1 ball / 정답 123, 사용자 129 -> 2 Strike
  • 사용자가 선택한 값이 정답과 숫자, 자릿수 모두 일치하지 않을 경우 OUT으로 표시한다.
    ex) 정답 123, 사용자 789 -> OUT
  • 사용자가 숫자를 선택할 수 있는 기회는 총 10번이다.

Java Script


정답 숫자 랜덤 생성 및 카운트 초기화

let answerNums = [];

reloadGame();

function reloadGame() {  
    let numsList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];  // 랜덤으로 선택할 숫자 배열
    for (let i=0; i<3; i++) { // 정답 자리수 만큼 반복
        let randomindex = numsList.splice(Math.floor(Math.random() * numsList.length), 1);  
      // numsList 배열에서 랜덤으로 하나의 요소를 추출한 배열
        answerNums[i] = randomindex; // 추출한 숫자를 i번째 정답 숫자로 할당
    }
    remainCount.innerHTML = 10;  // 게임 횟수 초기화
}

게임이 시작되면 0~9까지의 숫자 중 3자리의 랜덤 숫자를 정답으로 생성해야 한다. 처음엔 10개의 숫자 중 3개를 골라 중복 여부를 검사하는 코드를 생각했었는데 코드가 경제적이지 못한 것 같아 처음 랜덤으로 숫자가 생성될 때부터 랜덤으로 숫자를 고르도록 splice를 사용했다.

  1. 처음 0~9까지 10개의 숫자를 요소로 가진 배열을 만든다.
  2. 그 배열에서 splice를 이용해 랜덤으로 하나의 요소를 추출한다.
  3. 기존 배열은 요소가 9개가 된다. 추출한 요소는 정답 배열에 할당된다.

위와 같은 과정을 반복하면 중복되지 않은 숫자로 정답을 얻을 수 있다.


사용자 입력 숫자 유효성 검사

selectNums.addEventListener('change', checkOverlap); // 사용자 입력창에 숫자 입력 시 중복된 숫자 사용 여부 확인 함수 실행
selectNums.addEventListener('change', checkNums);  // 사용자 입력창에 숫자 입력 시 번호 유효성 검사 함수 실행 

function checkOverlap() {  // 사용자 입력 번호 숫자 중복 사용 여부 확인 함수 예) 112, 202
    let overlapStr = document.getElementById('select-number').value; // 입력값 문자열 가져오기
    for(let i=0; i<overlapStr.length; i++) {
        for(let j=i+1; j<overlapStr.length; j++) { // 중복 여부 체크 
            if(overlapStr[i] === overlapStr[j]) { // 중복한다면 
                return true; // true 반환
            } 
        }
    }
}

function checkNums() {  // 사용자가 입력한 번호 유효성 검사 함수
    const numCondition = /^[0-9]*$/;  // 숫자 정규표현식
    if(!numCondition.test(selectNums.value) || selectNums.value.length !== 3 || checkOverlap()) { 
        alert('중복되지 않는 3자리 숫자만 입력 가능합니다.'); // 얼럿 표시
        selectNums.value=""; // 사용자 입력번호 초기화
        selectNums.focus(); // 사용자 입력창 포커스 
    } else { 
        playGame(); // 정답 확인 및 남은 횟수 카운트 함수 실행 
    }
}

사용자가 입력창에 숫자를 입력할 경우 그 숫자가 게임을 진행 할 수 있는 숫자인지 확인하고 유효할 경우 playGame() 함수를 실행하여 게임을 진행하도록 하고 자릿수, 중복숫자 입력 등 조건에 맞지 않을 경우 입력창 초기화 및 얼럿이 표시 되도록 했다.
addEventListener 함수는 한 객체에 여러 개의 이벤트를 연결할 수 있기 때문에 사용해 중복된 숫자를 사용했는지(예 - 112, 233)를 검사하는 checkOverlap()함수와 그 외의 조건을 확인하는 checkNums() 함수를 연결했다.
checkOverlap()함수는 다른 조건들과 분리시켜 숫자가 중복되었을 경우(유효하지 않을 경우) true를 반환시켜 checkNums() 함수에 콜백되도록 만들어 주었는데, 숫자 입력 규칙 마다 얼럿을 표시하는 것 때문에 코드가 길어질 수 있을 것 같아 얼럿 노출 코드를 한 번만 짜기 위해 분리하였다.


정답 확인 및 남은 횟수 카운트


function playGame() { // 정답 확인 및 남은 횟수 카운트 함수
    if (remainCount.innerHTML > 1 && answerNums.join("") !== selectNums.value) { // 남은 횟수가 1이상 이고 정답을 맞추지 못했다면 
        remainCount.innerHTML = remainCount.innerHTML - 1;  // 카운트 1회 줄어듦
        var userNumsText = document.createTextNode(`${selectNums.value}\n`);  // 사용자 입력 숫자 텍스트 노드 생성
        userNumbers.appendChild(userNumsText); // 텍스트 노드 표시
        countScore();  // 점수 계산 함수 실행 
    } else if (selectNums.value === answerNums.join("")){  // 정답을 맞췄다면
        alert(`You win! :)`);  // 얼럿 표시 
        location.reload(); // 게임 새로고침 
    } else {  // 10회 소진 및 정답 맞추지 못했다면
        alert(`You lose :( The answer is '${answerNums.join("")}'`);  //얼럿 표시 
        location.reload(); // 게임 새로고침
    }
}

사용자가 입력한 값이 규칙에 맞는 값으로 확인 되었다면 이 숫자가 정답인지, 정답이 아니라면 남은 입력 횟수를 차감하고 countScore()함수를 실행시켜 Strike, Ball, Out 힌트를 표시하도록 했다.


스트라이크, 볼, 아웃 계산 및 표시

function countScore() { 
    strikeCount = 0; // 스트라이크 점수 초기화
    ballCount = 0; // 스트라이크 점수 초기화
    for(let i=0; i<answerNums.length; i++) {
        if(answerNums[i] == selectNums.value[i]){  
          // 정답의 i번째 요소와 사용자 번호의 i번째 요소가 동일하다면(스트라이크라면)
            strikeCount += 1; // 스트라이크 점수에 1 추가
        } else { // 스트라이크를 제외하고 
            for(let j=0; j<answerNums.length; j++) {  
                if (answerNums[i] == selectNums.value[j]) { // 정답의 i번째 요소와 사용자 번호의 0~2번째 요소가 동일하다면(볼이라면)
                   ballCount += 1; // 볼 점수에 1 추가
                }
            }
        }
    }

    selectNums.value="";  // 사용자 입력번호 초기화
    selectNums.focus(); // 사용자 입력창 포커스

    if (strikeCount !== 0 || ballCount !== 0) { // 스트라이크, 볼 중 하나라도 0이 아니면
        totalScore.innerHTML = `Strike: ${strikeCount}, Ball: ${ballCount}`; // 스트라이크, 볼 점수 표시
    } else { // 둘 다 0이라면
        totalScore.innerHTML = `OUT!` // out 표시
    }
}

Strike와 Ball을 각각 0으로 초기화 한 후 점수 계산 반복문을 실행시켰다. 먼저 Strike 점수를 계산해 정답 배열의 i번째 요소와 사용자 입력 숫자(문자열)의 i번째 숫자가 같을 경우 1점이 추가되는 방식이다. Strike에 해당하지 않을 경우 정답 배열의 i번째 요소와 사용자 입력 숫자의 전체를 비교해 같은 숫자가 있는지 확인하고 Ball 점수를 얻을 수 있도록 했다.
점수 계산이 완료되면 Strike와 Ball중 하나라도 0이 아니라면 점수를 표시하고, 둘 다 0점이라면 'OUT!'을 표시하도록 했다.

profile
Hello World!

0개의 댓글