JavaScript - 로또추첨 예제, var, let, 클로저 문제

Jenna·2022년 12월 16일
1

javascript

목록 보기
9/16
post-thumbnail

자바스크립트 예제 - 로또 추첨기 만들기


💫 순서도 그리기

역시 프로그램을 작성하기에 앞서 순서도를 생각해보는 과정이 가장 중요하다.
로또 추첨기는 다른 게임 예제들에 비해서 간략한 순서를 가진다.



💫 코드 작성

<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>
    <style>
        .ball {
            display: inline-block;
            border: 1px solid black;
            border-radius: 20px;
            width: 40px;
            height: 40px;
            line-height: 40px;
            font-size: 20px;
            text-align: center;
            margin-right: 20px;
        }
    </style>
</head>


<body>
    <div id="result">추첨 결과는?</div>
    <div id="bonus">보너스:</div>
    <script>
        const candidate = Array(45).fill().map((v, i) => i + 1);
        //피셔=예이츠셔플
        const shuffle = [];
        while (candidate.length > 0) {
            const random = Math.floor(Math.random() * candidate.length); //무작위 인덱스 뽑기
            const spliceArray = candidate.splice(random, 1); //뽑은 값은 배열에 들어있음
            const value = spliceArray[0]; //배열에 들어 있는 값을 꺼내어
            shuffle.push(value); //shuffle 배열에 넣기
        }
		const winBalls = shuffle.slice(0, 6).sort((a, b) => a - b);
        //slice 원본은 건드리지않고 자르기 가능 splice는 원본을 수정함 
        //정렬메서드 sort 원본을 수정 
        //a-b = 오름차순 / b-a =내림차순
        const bonus = shuffle[6];
        console.log(winBalls, bonus);

        const $result = document.querySelector('#result');
        const $bonus = document.querySelector('#bonus');

        //중복되는 부분은 함수로 빼주고 변하는 부분은 매개변수로 빼줌.
        //중복제거 후 똑같이 돌아가는지 확인하기! 
        const showBall = (number, $target) => {
            const $ball = document.createElement('div');
            $ball.className = 'ball';
            colorize(number, $ball); //색칠해주는 함수 
            $ball.textContent = number;
            $target.appendChild($ball);
        }
        for (let i = 0; i < winBalls.length; i++) {
            setTimeout(() => {
                showBall(winBalls[i], $result);
            }, (i + 1) * 1000);
        }

        setTimeout(() => {
            showBall(bonus, $bonus);
        }, 7000);
    </script>
</body>

✍🏻 코드 공부하기


📌 알고리즘 : 피셔-예이츠 셔플

로또 번호를 무작위로 섞기위해 사용된 알고리즘.
피셔-예이츠 셔플(Fisher-Yates shuffle)은 유한 수열의 무작위 순열을 생성하기 위한 알고리즘이다.
45개의 수를 map 메서드를 이용해 저장하고 피셔-예이츠 셔플 알고리즘을 이용해 섞어준다.


const candidate = Array(45).fill().map((v, i) => i + 1);
        //피셔=예이츠셔플
        const shuffle = [];
        while (candidate.length > 0) {
            const random = Math.floor(Math.random() * candidate.length); //무작위 인덱스 뽑기
            const spliceArray = candidate.splice(random, 1); //뽑은 값은 배열에 들어있음
            const value = spliceArray[0]; //배열에 들어 있는 값을 꺼내어
            shuffle.push(value); //shuffle 배열에 넣기
        }

📌 slice와 sort

  1. slice는 원본을 건드리지 않고 자르기가 가능해서 편리하게 쓰인다.
    slice로 생성된 배열과 원래 배열은 같지 않다.
    splice는 원본을 수정하기 때문에 불편한 부분이 생길 수 있다.
  2. 정렬메서드 sort는 원본을 수정한다.
    sort((a,b)=>a-b); 와 같은 형식으로 쓰이며 a-b는 오름차순, b-a는 내림차순 정렬이다.

const winBalls = shuffle.slice(0, 6).sort((a, b) => a - b);

📌 var, let 변수와 클로저문제

for (let i = 0; i < winBalls.length; i++) {
            setTimeout(() => {
                showBall(winBalls[i], $result);
            }, (i + 1) * 1000);
        }

위 코드를 작성할 때 let 대신 var 변수를 넣으면 공 안의 숫자가 나타나지않는다.
바로 var가 함수 스코프이기때문.
var를 넣어주면 i가 먼저 실행되어서 undefined, 6 이라는 값을 연속적으로 나타내게 된다.
따라서 블록스코프인 let을 사용해 블록안의 함수를 먼저 실행할 수 있도록 차단시켜줘야한다.
비동기처리방식, var가 만나면 클로저 문제가 발생한다.


응용문제 : 공에 색 칠하기

당첨 공의 숫자를 기준으로 색을 칠해준다.


function colorize(number, $tag) {
            if (number < 10) {
                $tag.style.backgroundColor = 'red';
                $tag.style.color = 'white';
            } else if (number < 20) {
                $tag.style.backgroundColor = 'orange';
            } else if (number < 30) {
                $tag.style.backgroundColor = 'yellow';
            } else if (number < 40) {
                $tag.style.backgroundColor = 'blue';
                $tag.style.color = 'white';
            } else {
                $tag.style.backgroundColor = 'green';
                $tag.style.color = 'white';
            }
        }

그리고 위의 함수를 const showBall부분에 넣어준다.
colorize(number, $ball); 추가


profile
connecting the dots 💫

0개의 댓글