본문 바로가기

업무/기타

[과제] 볼링게임(코드2)

 

 

https://phyho.tistory.com/234

 

볼링게임(코드)

[ 테이블 생성 ] 다른 방법으로 생성 // 테이블 생성 let table = document.createElement('table'); table.classList.add('table'); for (let i = 0; i < 3; i++) { let row = table.insertRow(); for (let j = 0; j < 10; j++) { let cell = row.insertCe

phyho.tistory.com

 


 

 

html, js, css 파일로 분리

 

[ bowling.html ]

 

body부분

<body>
    <div id="container">
        <label for="bowling">게임 횟수</label>
        <select id="bowling" onchange="play(this.value)">
            <option value="0">선택</option>
        </select>
        <button id="playButton">확인</button>
        <button id="reloadButton" class="hideButton">reload</button>
    </div>

</body>

 

script 부분

<script>
    
    let select = document.getElementById("bowling");    // select요소
    let option; // option요소

    // 반복문으로 option값인 실행횟수 생성
    for (let i = 0; i < 20; i++) {
        option = document.createElement('option');  // option태그 생성
        option.setAttribute("value", i+1);          // option_value 값 지정
        option.innerText = i+1;                     // option태그 내부값 지정
        select.append(option);                      // select태그에 option들 추가
    }
    
    // 실행횟수 (기본값 = 0)
    let optionValue = 0;

    // 선택한 실행횟수로 option값 초기화
    function play(option){
        optionValue = option;
        return optionValue;
    }
    
    let playbutton = document.getElementById("playButton"); // 확인버튼
    let reloadButton = document.getElementById("reloadButton"); // reload버튼

    // 확인버튼클릭
    playbutton.addEventListener("click", showTable);
    // 진행함수
    function showTable(){
        let order = 1;              // 테이블이름을 위한 값
        let option = optionValue;   // 선택한 옵션값
        if(option === 0){           // 선택하지 않은경우 팝업창 & 페이지reload
            alert("게임횟수를 선택하세요");
            reload();
        }
        while(option > 0){      
            playing(option, order);    // 테이블 생성함수 실행
            option--;           // 선택한 옵션만큼만 실행
            order++;            
        }

        // 확인버튼 클릭하면 버튼변경(확인 => reload)
        playbutton.classList.add("hideButton");
        reloadButton.classList.add("showButton")
    }

    // reload버튼클릭
    reloadButton.addEventListener("click", reload);
    // 페이지 reload 함수
    function reload(){
        location.reload();
    }

</script>

 

 


 

[ playing.js ]

 

(사용한 함수들)


randomNum(max)
입력값 => max정수값
출력값 => max까지의 랜덤숫자


createScore(n)
입력값 => n (0~10)
출력값 => frameNums = [firstNumber, secondNumber, bonusNumber]

 

calculatePlusScore(Nums1, Nums2, Nums3)
입력값 => frameNums[] 3개
출력값 => plus점수

 

calculateScore(n, frameNums) 
입력값 => n (0~9) , 프레임점수배열     // 10프레임은 별도 계산
출력값 => total점수

playing(option, order _ 테이블생성 및 위의 함수들로 반복문실행

입력값 => option(실행횟수)

            => order(테이블이름순서)


 

randomNum(max)

 

// 랜덤정수 생성함수
// - 최댓값을 매개변수로 받고, 매개변수 이하의 랜덤정수를 리턴
function randomNum(max) {
    let number = Math.floor(Math.random() * (max + 1));
    return number;
}

 

 

 

createScore(n)

 

// 점수생성 함수 [1투구, 2투구, 보너스]
// - 프레임 순서를 매개변수로 받고, 각 프레임 점수배열을 리턴
function createScore(n) {

    // 랜덤점수생성
    let firstNumber = randomNum(10);                // 1투구점수
    let secondNumber = randomNum(10 - firstNumber); // 2투구점수
    let bonusNumber = 0;      // 10프레임 보너스점수

    // 10프레임 보너스점수 생성
    if (n === 9) {
        // strike인 경우 보너스점수 생성
        if (firstNumber === 10) {   
            secondNumber = randomNum(10);
            bonusNumber = randomNum(10 - secondNumber);
        // spare인 경우 보너스점수 생성
        } else if (firstNumber + secondNumber === 10) { 
            bonusNumber = randomNum(10);
        }
    }

    // 각 프레임점수 [1투구, 2투구, 보너스]
    let Nums = [firstNumber, secondNumber, bonusNumber]; 

    return Nums;
}

 

 

 

calculatePlusScore(fNums1, fNums2, fNums3)

 

// plus점수 계산함수
// - 세개의 프레임점수를 매개변수로 받고, 각 프레임의 가산점을 리턴
function calculatePlusScore(fNums1, fNums2, fNums3) {

    let plus = 0;

    if (fNums1[0] === 10) {
        // double인 경우
        if (fNums2[0] === 10) {
            plus = fNums2[0] + fNums2[1] + fNums3[0] + fNums3[1];
            //console.log("더블 plus : " + plus);
        // strike인 경우
        } else {
            plus = fNums2[0] + fNums2[1];
            //console.log("스트라이크 plus : " + plus);
        }
        // spare인 경우
    } else if (fNums1[0] + fNums1[1] === 10) {
        plus = fNums2[0]
        //console.log("스페어 plus : " + plus);
    }

    return plus;
}

 

 

 

calculateScore(n, frameNums) 

// total 점수 계산 함수
// - 프레임순서, 프레임점수배열을 매개변수로 받고, 각 프레임의 총점을 리턴
function calculateScore(n, frameNums) {

    let plus = 0;
    let total = 0;

    // plus 점수 계산
    if (n === 8) {  // 9프레임
        plus = calculatePlusScore(frameNums[n], frameNums[n + 1], [0, 0])
    } else {        // 1~8 프레임
        plus = calculatePlusScore(frameNums[n], frameNums[n + 1], frameNums[n + 2]);
    }

    // total 점수 계산
    total = plus + frameNums[n][0] + frameNums[n][1];

    return total;
}

 

 

playing(option, order)  

// 테이블 생성 및 진행
function playing(option, order) {

    // ****** 테이블생성 start ******
    let table = document.createElement('table');
    table.classList.add('table'+option);

    for (let i = 0; i < 3; i++) {       // 테이블행 생성
        let row = table.insertRow();

        for (let j = 0; j < 11; j++) {  // 테이블열 생성
            let cell = row.insertCell();
            
            if (i === 0) {                      // 1행
                cell.textContent = j + 1;       // 프레임순서넣기
                cell.classList.add("firstRow");
                if (j === 10) {
                    cell.textContent = "Total"; // 1행 마지막열은 Total 넣기
                }            

            } else if (i === 1 && j != 10) {    // 2행
                cell.classList.add("score");

                // 1투구점수칸 생성
                let span1 = document.createElement('span');
                span1.classList.add("firstScore");
                cell.appendChild(span1);

                // 2투구점수칸 생성
                let span2 = document.createElement('span');
                span2.classList.add("secondScore");
                cell.appendChild(span2);

                // 보너스점수칸 생성
                let span3 = document.createElement('span');
                span3.classList.add("bonusScore");

                // 10프레임에만 보너스점수칸 넣기
                if (j === 9) {
                    cell.appendChild(span3);
                }
                if (j === 10) {
                    cell.classList.add("showTotal");
                }

            } else if (j != 10) {               // 3행
                cell.classList.add("totalScore");
            }
        }

    }
    // ****** 테이블생성 end ******


    // 테이블이름 생성
    let div = document.createElement('div');
    div.innerText = "Game "+ order;
    div.classList.add("gameTitle")

    // 생성한 테이블&이름 body에 추가
    document.body.append(div, table);


    // 테이블의 마지막열 Total점수 표시를 위한 테이블정리
    let lastCell = table.rows[1].cells[10];
    lastCell.rowSpan = 2;
    lastCell.classList.add("showTotal");
    table.rows[2].cells[10].remove();


    // 테이블 요소들 변수에 할당
    let firstScore = document.querySelectorAll(".table"+option+" td span:first-child");
    let secondScore = document.querySelectorAll(".table"+option+" td span:nth-child(2)");
    let bonusScore = document.querySelector(".table"+option+" .bonusScore");
    let totalScore = document.querySelectorAll(".table"+option+" .totalScore");
    let showTotal = document.querySelector(".table"+option+" .showTotal");

    let Nums = [];          // 1투구, 2투구, 보너스(10프레임) 점수배열
    let frameNums = [];     // Nums들 배열
    let total = [];         // 총점(1투구+2투구+가산)
    let bonusNumber = 0;    // 10프레임 보너스점수

    // 1~10프레임 점수생성 & 테이블에 넣기
    for (let n = 0; n < 10; n++) {

        // 점수생성
        Nums = createScore(n);  // [1투구, 2투구, 보너스]
        frameNums[n] = Nums;    // Nums들 배열

        // 테이블에 1투구&2투구 점수표시
        firstScore[n].innerText = open(Nums[0]);
        secondScore[n].innerText = open(Nums[1]);
        bonusNumber = Nums[2];

    }

    // 10프레임에 보너스 점수 표시
    if ((frameNums[9][3] != 'P' || frameNums[9][3] == 'S') && frameNums[9][1] + bonusNumber === 10) {
        bonusScore.innerText = "/";
    } else {    
        bonusScore.innerText = open(bonusNumber);
    }

    
    // 1~10프레임 총점 계산 & 테이블에 넣기
    for (let n = 0; n < 9; n++) {

    // 각 프레임별 총점 계산
        if (n === 0) { // 1프레임
            total[0] = calculateScore(n, frameNums);
        } else {       // 2~9 프레임
            total[n] = total[n-1] + calculateScore(n, frameNums);
        }

        // 테이블에 total점수 표시
        totalScore[n].innerHTML = total[n];
    }

    // 10프레임 총점 & Total점수 표시
    let TotalScore = total[8] + bonusNumber + frameNums[9][0] + frameNums[9][1] + frameNums[9][2];
    totalScore[9].innerHTML = TotalScore;
    showTotal.innerHTML = TotalScore;


    // strike or spare인 경우 X or / 로 표시
    for (let n = 0; n < 10; n++) {
        console.log("frameNums "+(n+1)+ " : " + frameNums[n]);

        // calculateScore 함수에서 추가한 문자열로 strike or spare 판별
        if (frameNums[n][3] == "S") {
            firstScore[n].innerText = "X";
        } else if (frameNums[n][3] == "P") {
            secondScore[n].innerText = "/";
        } 
    }
    console.log("*********************")

}

 


 

[ bowling.css]

 

#container{
    display: flex;
    align-items: center;
    margin-left: 20px;
}

#bowling{
    width: 45px;
    height: 25px;
    margin: 20px 10px;
}
#playButton, #reloadButton{
    width: 50px;
    height: 25px;
    margin: 5px;
}
.hideButton{
    display: none;
}
.showButton{
    display: inline;
}
table{
    border-collapse: collapse;
    width: 500px;
    margin: 10px 0 30px 20px;
}

.score{
    white-space: nowrap;
    padding: 0;
}

td{
    border: 1px solid black;
    border-collapse: collapse;
    text-align: center;
    padding: 7px;
}

td span{
    display: inline-block;
    border: 0.01px solid gray;
    width: 20px;
    padding: 7px;
}
.firstRow{
    background-color: lightgray;
    font-weight: bolder;
}
.showTotal{
    font-weight: bolder;
}

 


 

Strike인 경우 10점대신 => X

Spare인 경우 점수대신 => /

Open(0점)인 경우 0점대신 => -

볼링 점수 테이블에 위처럼 넣어준다.

 

 

calculateScore(n, frameNums) 

*** strike(S), spare(P), None(N) 판별문자를 frameNums배열 마지막 요소에 넣는 조건문 추가

// total 점수 계산 함수
// - 프레임순서, 프레임점수배열을 매개변수로 받고, 각 프레임의 총점을 리턴
function calculateScore(n, frameNums) {

    let plus = 0;
    let total = 0;

    // plus 점수 계산
    if (n === 8) {  // 9프레임
        plus = calculatePlusScore(frameNums[n], frameNums[n + 1], [0, 0])
    } else {        // 1~8 프레임
        plus = calculatePlusScore(frameNums[n], frameNums[n + 1], frameNums[n + 2]);
    }

// total 점수 계산
    total = plus + frameNums[n][0] + frameNums[n][1];

    // strike(S), spare(P) 판별문자 frameNums배열 마지막 요소에 추가
    if(frameNums[n][0] === 10){
        frameNums[n][3] = "S";
    } else if(frameNums[n][0] + frameNums[n][1] === 10){
        frameNums[n][3] = "P"
    } else {
        frameNums[n][3] = "N"
    }

    return total;
}

 

 

10프레임은 별도로 계산했기 때문에 문자도 별도로 추가해줬다.

 

createScore(n)

*** 10프레임은 strike(S), spare(P), None(N) 판별문자를 bonus점수 생성 시에 추가

(어차피 S or P 판별하여 bonus점수를 생성하기에 여기에서 문자만 추가해줌)

// 점수생성 함수 [1투구, 2투구, 보너스]
// - 프레임 순서를 매개변수로 받고, 각 프레임 점수배열을 리턴
function createScore(n) {

    // 랜덤점수생성
    let firstNumber = randomNum(10);                // 1투구점수
    let secondNumber = randomNum(10 - firstNumber); // 2투구점수
    let bonusNumber = 0;      // 10프레임 보너스점수
    let SorP = "N";

    // 10프레임 보너스점수 생성
    if (n === 9) {
        // strike인 경우 보너스점수 생성
        if (firstNumber === 10) {
            secondNumber = randomNum(10);
            bonusNumber = randomNum(10 - secondNumber);
            SorP = "S";
            // spare인 경우 보너스점수 생성
        } else if (firstNumber + secondNumber === 10) {
            bonusNumber = randomNum(10);
            SorP = "P"
        }
    }

 

이렇게 추가해주면 frameNums 배열 구성은 아래처럼 된다.


 

open(score) 함수 생성

// 0점 표시 함수
// - 점수가 0인경우 '-'로 표시
function open(score){
    if(score == 0){
        return "-";
    } else {
        return score;
    }

}

 

open 함수는 각 투구 점수들 & 보너스점수가 테이블에 들어가는 시점에 적용시켰다.

    // 1~10프레임 점수생성 & 테이블에 넣기
    for (let n = 0; n < 10; n++) {

        // 점수생성
        Nums = createScore(n);  // [1투구, 2투구, 보너스]
        frameNums[n] = Nums;    // Nums들 배열

        // 테이블에 1투구&2투구 점수표시
        firstScore[n].innerText = open(Nums[0]);
        secondScore[n].innerText = open(Nums[1]);
        bonusNumber = Nums[2];

    }
    // 10프레임에 보너스 점수 표시
    bonusScore.innerText = open(bonusNumber);

 

 


예외케이스는 10프레임의 bonusNumber에 대한 적용

 

if (bonusNumber === 10)    보너스가 스트라이크
          bonusScore.innerText = "X"
else ( frameNumber[9][2] + bonusNumber === 10 )  보너스가 스페어
          bonusScore.innerText = "/"

 

 

 

1. 보너스가 스트라이크인 경우

=> open 함수에 조건 추가

*** 2투구 점수가 10점인 경우에도 X가 들어가지만

다른 투구 점수들에 문자열을 넣는 로직이 이후 실행되기 때문에 /로 덮어씌워진다.

// 0점 표시 함수
// - 점수가 0인경우 '-'로 표시
function open(score){
    if(score === 0){
        return "-";
    } else if(score === 10){    // bonusNumber가 10인 경우를 위해 추가
        return "X";
    } else {
        return score;
    }

}

 

 

2. 보너스가 스페어인 경우

    // 10프레임에 보너스 점수 표시
    if ((frameNums[9][3] == 'P' && frameNums[9][1] + bonusNumber === 10) {
        bonusScore.innerText = "/";
    } else {
        bonusScore.innerText = open(bonusNumber);
    }

 

 

이렇게 했더니 오류

 


 

조건문 수정 

 

(S이면서)

bonusNumber =10 인 경우 => X (스트라이크) __ else의 open함수로 보내버린다.

frameNums[9][1] + bonusNumber = 10 인 경우 => / (스페어) __ if 조건문에 걸림

(P이면서)

frameNums[9][1] + bonusNumber = 10 인 경우 => / (스페어) 가 아닌 점수가 표시되어야 한다.  __ else로 빠짐

(1 - 9 - 1 의 경우)

 

    // 10프레임에 보너스 점수 표시
    if ((frameNums[9][3] != 'P' || frameNums[9][3] == 'S') && frameNums[9][1] + bonusNumber === 10) {
        bonusScore.innerText = "/";
    } else {
        bonusScore.innerText = open(bonusNumber);
    }

 

 

 

오류잡았다 야호

 

 


 

 

 

 

선택한 게임 횟수만큼 점수판 생성 완료!

 

 

'업무 > 기타' 카테고리의 다른 글

[과제] MySQL 쿼리 작성 ( 2차 & 3차 )  (0) 2024.03.04
[과제] MySQL 쿼리 작성 (1차)  (0) 2024.02.29
[과제] 별찍기  (0) 2024.02.23
[과제] 볼링게임_ 설계  (0) 2024.02.18
[과제] 볼링게임(코드)  (0) 2024.02.18