본문 바로가기
개발/Javascript

[js] 자바스크립트로 로또추첨기 구현하기

by 코딩하는 갓디노 2020. 12. 25.

로또 게임

 

자바스크립트를 이용하여,
로또 추첨기를 구현하는 예제입니다.

 

예제는 인프런의 제로초, "조현영"님의 강의를 들으면서 공부한 내용입니다.

 

구현 순서

번호 순서 사용 메서드
1 45개의 후보 숫자 만들기  
2 후보 숫자 랜덤으로 섞기 while문, Math.random(), splice()
3 보너스 숫자 뽑기: 섞은 배열의 마지막 요소  
4 로또 숫자 뽑기: 섞은 배열의 앞에서 6개의 요소 slice() 또는 splice()
5 추출된 숫자 화면 출력 css, sort()
6 타이머 기능: 1초에 숫자 하나씩 출력 setTimeout

 

순수 자바스크립트

1. 45개의 후보 숫자 만들기

방법1.

const candidates = [];
for (i = 1; i <= 45; i += 1) {
	candidates.push(i);
}

 

방법2.

 const candidates = Array(45).fill().map((v, i) => v = i+1 );
 //결과: (45) [1, 2, 3, 4, 5, ... 41, 42, 43, 44, 45]

 

2. 후보 숫자 랜덤으로 섞기, 3. 보너스 숫자 뽑기

while문 사용

while (candidates.length > 0) {
  let num = Math.floor(Math.random() * candidates.length); //0-44까지의 정수
  //candidates에서 num을 splice()로 하나씩 빼줌
  let leftNum = candidates.splice(num, 1)[0]; //leftNum 배열이므로 [0]
  mixedNum.push(leftNum);
}
let bonus = mixedNum[mixedNum.length - 1] //mixedNum의 마지막 숫자

 

for문 사용 예시-잘못된 경우

 let mixedNum = [];
 
//for문을 썼을 경우
//        for(let j=1; j<=candidates.length; j+=1) {
//            let num = Math.floor(Math.random() * candidates.length);
//            candidates.splice(num, 1);
//            mixedNum.push(num);   
//        }
//결과: (23) [13, 23, 24, 27, 3, 32, 27, 8, 29, 2, 10, 7, 17, 18, 4, 17, 9, 14, 1, 8, 1, 15, 16]

 

  • for문을 사용하면 안 되는 이유
    splice()로 candidate 배열의 요소 개수가 점점 줄어들기 때문 
  • for문 while문 사용법 구분
    for문: 몇 번을 반복하는지 알 때
    while문: 몇 번을 반복하는지 모를 때. 기준값이 계속 바뀔 때

4. 로또 숫자 뽑기

//slice() 예제
let lottoNum = mixedNum.slice(0, 6).sort((prev, curr) => prev - curr); //배열의 0-5번째 요소 추출
//prev - curr 뺀 결과가 양수면 순서를 바꿈. 음수면 그대로.

//splice() 예제
let lottoNum2 = mixedNum.splice(0, 6); //배열의 0부터 6개의 요소 추출

 

5. 추출된 숫자 화면 출력

let show = document.querySelector("#show");
for (let i = 0; i < lottoNum.length; i += 1) {
  let ball = document.createElement('span');
  ball.textContent = lottoNum[i];
  show.appendChild(ball);

//ball css            
  if (lottoNum[i] < 10) {
  color = 'yellow';
  } else if (lottoNum[i] < 20) {
  color = 'aqua';
  } else if (lottoNum[i] < 30) {
  color = 'pink';
  } else if (lottoNum[i] < 40) {
  color = 'skyblue';
  } else {
  color = 'gold';
  }

  ball.style.backgroundColor = color;
  ball.style.display = 'inline-block';
  ball.style.margin = '10px';
  ball.style.padding = '15px';
  ball.style.borderRadius = '50%';
  //ball class 이름 삽입
  ball.className = 'No' + lottoNum[i];
}
let bonusBall = document.createElement('span');
bonusBall.textContent = `보너스: ` + bonus;
show.appendChild(bonusBall);

 

6. 타이머 기능

setTimeout을 이용하여 1초에 하나씩 숫자 출력, 보너스까지 총 7개의 숫자 출력

참고로 setTimeout에서 var -> let 으로 변수 선언시, 클로저 문제 발생 안함(es6 문법)

//로또 화면 출력
let show = document.querySelector("#show");

//중복되는 부분 함수로
//중복안되는 다른 부분만 매개변수로 만들고, 중복되는 부분은 함수로 { } 안에 넣기
function showFn(num, show) {
  let ball = document.createElement('span');
  //ball.textContent = lottoNum[num];
  ball.textContent = num;
  show.appendChild(ball);

  //ball css            
  if (num < 10) {
    color = 'yellow';
  } else if (num < 20) {
    color = 'aqua';
  } else if (num < 30) {
    color = 'pink';
  } else if (num < 40) {
    color = 'skyblue';
  } else {
    color = 'gold';
  }

  ball.style.backgroundColor = color;
  ball.style.display = 'inline-block';
  ball.style.margin = '10px';
  ball.style.padding = '15px';
  ball.style.borderRadius = '50%';
  //ball class 이름 삽입
  ball.className = 'No' + lottoNum[num];

};

//로또 번호 1초에 하나씩 출현
//클로저 문제
for (var i = 0; i < lottoNum.length; i += 1) {
  //closure함수의 매개변수 j는 function scope 성격으로 밖으로 나가지 못함.
  function closure(j) { //i의 값(0~5)를 j에게 전달
    //함수안에서 j의 값만 그대로 사용
    setTimeout(function() {
      showFn(lottoNum[j], show);
    }, j * 1000);
  }
  closure(i); //i가 0-5까지의 값
}

//보너스 공 7초 후 출현
setTimeout(function() {
  showFn(bonus, show);
}, 7000);

 

스크립트 전체 코드

<!DOCTYPE html>
<html lang="ko">

  <head>
    <meta charset="UTF-8">
    <title>로또 추첨기</title>
  </head>

  <body>
    <div id="show"></div>
    <script>
      const candidates = [];
      for (i = 1; i <= 45; i += 1) {
        candidates.push(i);
      }
      let mixedNum = [];
  
      while (candidates.length > 0) {
        let num = Math.floor(Math.random() * candidates.length); 
        let leftNum = candidates.splice(num, 1)[0]; 
        mixedNum.push(leftNum);
      }
      console.log(mixedNum);
      let bonus = mixedNum[mixedNum.length - 1] 
      console.log(bonus);

      let lottoNum = mixedNum.slice(0, 6).sort((prev, curr) => prev - curr); 
      console.log(lottoNum);

    console.log(`로또숫자 ${lottoNum} / 보너스 숫자 ${bonus}`)

      let show = document.querySelector("#show");
      function showFn(num, show) {
        let ball = document.createElement('span');
        //ball.textContent = lottoNum[num];
        ball.textContent = num;
        show.appendChild(ball);
        
        if (num < 10) {
          color = 'yellow';
        } else if (num < 20) {
          color = 'aqua';
        } else if (num < 30) {
          color = 'pink';
        } else if (num < 40) {
          color = 'skyblue';
        } else {
          color = 'gold';
        }

        ball.style.backgroundColor = color;
        ball.style.display = 'inline-block';
        ball.style.margin = '10px';
        ball.style.padding = '15px';
        ball.style.borderRadius = '50%';
        //ball class 이름 삽입
        ball.className = 'No' + lottoNum[num];
      };

      for (var i = 0; i < lottoNum.length; i += 1) {
        function closure(j) { 
          setTimeout(function() {
            showFn(lottoNum[j], show);
          }, j * 1000);
        }
        closure(i); 
      }

      setTimeout(function() {
        showFn(bonus, show);
      }, 7000);

    </script>
  </body>

</html>

 

화면 결과(Result 클릭)

반응형

댓글