12일차(보충)[shuffleArray / 퀴즈 게임]

진하의 메모장·2025년 1월 18일
3

공부일기

목록 보기
14/66
post-thumbnail

2025 / 01 / 17

수업 시간에 2차원 배열을 배우고 난 뒤 응용으로 퀴즈게임을 만들어보았습니다.
퀴즈게임의 코드와 코드에 사용된 함수를 정리해보겠습니다.
코드에 사용된 shuffleArray( )함수를 먼저 제가 이해한 방식대로 정리하겠습니다.



💌 shuffleArray( )

shuffleArray 함수는 배열의 요소들을 무작위로 섞는 함수입니다.
배열의 순서를 바꾸어서, 원래의 배열 순서와 다른 새로운 순서를 만들어줍니다.

  • 사진 출처 : 구글



💌 구현해보기

1. 배열 생성

  • 원하는 내용을 담은 배열을 하나 생성해줍니다.
let array = ["바나나", "사과", "딸기", "포도", "토마토"];


2. 함수 생성

  • shuffleArray( ) 함수를 만들어줍니다.
function shuffleArray(array){
    for(let i = array.length - 1; i > 0; i--){
        const random = Math.floor(Math.random() * ( i + 1 ));
        [array[i], array[random]] = [array[random], array[i]]
    }
    return array;
}


3. 코드 설명

1. for문
i가 배열의 끝에서부터 시작하여 1까지 감소합니다.


2. Math.random( )
Math.random( )은 0과 1 사이의 랜덤한 숫자를 반환합니다.
여기에 배열의 길이를 고려해서 무작위 인덱스를 계산합니다.


3. 배열의 값 바꾸기
array[ i ]와 array[ random ]의 값을 서로 바꿉니다.
array[ i ]는 현재 위치에 있는 값이고, random은 0부터 i까지의 무작위 인덱스입니다.



4. 무작위 출력

  • 만들어 놓은 array라는 배열에서 인덱스를 섞어 무작위로 출력합니다.
console.log(shuffleArray(array));  
// 예: [ '사과', '딸기', '바나나', '토마토', '포도' ]


💌 퀴즈 게임

  • 사용자에게 입력 받을 문제의 난이도가 있어야합니다. [쉬움 / 보통 / 어려움]
  • 순차적으로 사용자는 5개의 문제를 풀게됩니다.
  • 프롬프트 창에 힌트라고 입력 시 힌트를 제공합니다.
  • 오답 입력 시 한 번의 재입력 기회를 줍니다.
  • 정답을 맞출 시 score이 1점씩 더해집니다.
  • 사용자가 퀴즈를 다 풀면 화면에 문제 / 정답 / 사용자의 답 / 최종 score를 출력합니다.

1. 배열 생성

  • 문제와 정답을 담을 빈 배열을 생성해줍니다.
  • score를 담을 변수를 선언해주고 그 값을 0으로 초기화해줍니다.
let problems = [];
let Answer = [];
let hint = [];
let score = 0;


2. 난이도 입력 받기

  • 사용자에게 난이도를 입력받습니다.
let user = prompt(`난이도를 선택해주세요 [쉬움 : 수학 / 보통 : 넌센스 / 어려움 : 상식]`);


3. 문제 / 정답 작성

  • 각 난이도의 문제와 정답과 힌트를 배열에 담아 줍니다.
  • 사용자가 입력한 조건에 따라 문제와 정답과 힌트를 빈 배열에 push 하였습니다.
  • 쉬움 문제는 힌트를 따로 작성하지 않았습니다.
if (user === "쉬움" || user === "수학") {
	problems.push("2 + 1 =", "10 - 3 =", "2 × 6 =", "12 ÷ 4 =", "8 - 2 =");
	Answer.push(3, 7, 12, 3, 6);
    
} else if (user === "보통" || user === "넌센스") {
	problems.push(
		"진짜 문제 투성이인 것은?", 
		"아무리 예뻐도 미녀라고 못하는 사람은?", 
		"날마다 가슴에 흑심을 품고 있는 것은?", 
		"많이 맞을수록 좋은 것은?", 
		"반성문을 영어로 하면?"
	);
    
	Answer.push("시험지", "미남", "연필", "시험문제", "글로벌");

	hint.push(
		"학교에 가면 정기적으로 볼 수 있습니다.",
		"미녀라고 할 수 없지만, 그럼에도 불구하고 '예쁘다'는 평가를 받을 수 있습니다.",
		"사람에 따라 사용 기간이 다르지만 누구나 한번 씩은 써본 것입니다.",
		"이 문제의 답은 '가치'나 '특성'에 대한 개념이 아닙니다.",
		"이 문제는 단어의 의미보다는 단어의 발음에 초점을 맞춰야 합니다."
	);
    
} else if (user === "어려움" || user === "상식") {
	problems.push(
		"지구에서 가장 큰 대륙은 무엇일까요?", 
		"피사의 사탑은 어느 나라에 있을까요?", 
		"올림픽은 몇 년에 한 번씩 열리나요?", 
		"세계에서 가장 많은 사람이 사용하는 언어는 무엇일까요?", 
		"초콜릿의 주 원료인 식물은 무엇일까요?"
	);
    
	Answer.push("아시아", "이탈리아", "4", "중국어", "카카오");

	hint.push(
		"이 대륙은 유럽과 연결되어 있고, 중국, 인도, 일본이 포함된 곳입니다.",
		"이 탑은 '산타 마리아 아순타 대성당' 옆에 위치해 있습니다.",
		"국회의원 임기와 같습니다.",
		"이 언어는 중국의 공식 언어이며, '푸퉁화'라고도 불립니다.",
		"이 식물은 열대 지역에서 자생하며, 그 열매에서 얻은 씨앗을 주로 사용합니다."
        );
}


4. 함수 생성

  • 배열의 값을 무작위로 출력하기 위한 shuffleArray( )함수를 생성합니다.
  • for문을 사용해 problems이라는 배열의 길이 만큼 반복해줍니다.
  • Math.floor( ) / Math.random( )를 사용해서 랜덤 난수를 변수 j에 할당합니다.
  • i와 j를 사용해서 배열의 값을 교환해줍니다.
function shuffleArray(problems) {
	for (let i = problems.length - 1; i > 0; i--) {
		const j = Math.floor(Math.random() * (i + 1));
		[problems[i], problems[j]] = [problems[j], problems[i]];  // 배열의 값 교환
	}
}


5. 문제 정답 출력

  • 셔플된 문제를 배열에 맞춰서 알맞은 정답과 힌트를 출력합니다.
  • 해당 문제와 정답의 idx를 for문을 사용하여 맞춰줍니다.
  • 프롬프트에 사용자가 입력한 정답을 공백 없이(trim( ) 사용) 받아옵니다.
  • 숫자 문제인 경우 isNaN( )을 사용해 타입 확인 후 숫자 타입으로 변환합니다.
  • 정답이 틀릴 경우 힌트를 제공합니다.
  • 정답이 맞을 때 score를 더해주고 아닐경우 힌트와 재입력 기회를 재공합니다.
  • 재입력 당시 정답을 맞출 경우에도 score를 더해줍니다.
  • 재입력 당시 오답을 작성하면 다음으로 넘어갑니다.
  • 동적으로 HTML에 추가하여 간단하게 꾸며주었습니다.
// 셔플된 문제 배열에 맞춰서 문제와 힌트를 출력
for (let idx = 0; idx < problems.length; idx++) {
	const problem = problems[idx];
	const result = Answer[idx];

	let userAnswer = prompt(`${problem} 정답은?`).trim();  
    // 입력 값에 대한 trim()을 사용하여 공백 제거

	// 숫자 문제의 경우 숫자 타입으로 변환하여 비교
	if (!isNaN(result)) {
		userAnswer = Number(userAnswer);  // 숫자로 변환
	}

	// 문제와 사용자가 입력한 답을 동적으로 HTML에 추가
	const resultList = document.getElementById("result-list");
	const questionLi = document.createElement("li");
	questionLi.classList.add("Q");
	questionLi.textContent = `Q${idx + 1}.  ${problem}    정답 : ${Answer[idx]}`;
            
	const answerLi = document.createElement("li");
	answerLi.classList.add("A");
	answerLi.textContent = `사용자의 답: ${userAnswer}`;

	resultList.appendChild(questionLi);
	resultList.appendChild(answerLi);

	// 정답이 맞을 때
	if (userAnswer == result) {
		score += 1;
	} else {
		// '쉬움' 난이도에서는 힌트를 제공하지 않음, 다시 묻지 않음
		if (user !== "쉬움" && hint[idx]) {
			alert(`정답이 아닙니다! \n힌트: ${hint[idx]}`);
            
			userAnswer = prompt(`${problem} 다시 정답은?`).trim();  
            // 두 번째 시도에서도 trim() 사용

			// 숫자 문제의 경우 숫자 타입으로 변환하여 비교
			if (!isNaN(result)) {
				userAnswer = Number(userAnswer);
			}

			// 두 번째 답이 맞으면 점수 추가
			if (userAnswer === result) {
				score += 1;
			}
		}
	}
}


6. 최종 점수 출력

  • 최종 점수를 동적으로 HTML에 넘겨줍니다.
// 최종 점수 출력
const finalScoreElement = document.getElementById("final-score");
finalScoreElement.textContent = `최종 점수: ${score}`;


💌 전체 코드

  • 위에 작성한 코드를 모두 합쳐놓은 것입니다.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }

        .box{
            border: 2px solid rgb(95, 129, 141);
            width: 500px;
            height: auto;
            margin: 0 auto;
            box-shadow: 7px 14px 30px 2px rgba(163, 174, 184, 0.6);
        }

        h2{
            background-color: rgb(188, 218, 228);
            padding: 20px;
            text-align: center;
            line-height: 40px;
        }

        ul{
            list-style: none;
        }

        li{
            text-align: center;
            padding: 10px;
            margin: 10px 0;
        }

        .Q{
            padding: 20px;
            font-weight: bold;
        }

        .score {
            font-size: 20px;
            text-align: center;
            margin-top: 20px;
            font-weight: bold;
        }

        #final-score{
            padding: 20px;
            background-color: rgb(188, 218, 228);
        }
    </style>
</head>
<body>
    <div class="box">
        <h2>Quiz 결과</h2>

        <ul id="result-list">
            <!-- 문제와 답이 여기에 동적으로 추가됩니다. -->
        </ul>

        <p id="final-score" class="score"></p> <!-- 최종 점수를 여기에 출력 -->
    </div>

    <script>
        let problems = [];
        let Answer = [];
        let hint = [];
        let score = 0;

        let user = prompt(`난이도를 선택해주세요 [쉬움 : 수학 / 보통 : 넌센스 / 어려움 : 상식]`);

        if (user === "쉬움" || user === "수학") {
            problems.push("2 + 1 =", "10 - 3 =", "2 × 6 =", "12 ÷ 4 =", "8 - 2 =");
            Answer.push(3, 7, 12, 3, 6);
        } else if (user === "보통" || user === "넌센스") {
            problems.push(
                "진짜 문제 투성이인 것은?", 
                "아무리 예뻐도 미녀라고 못하는 사람은?", 
                "날마다 가슴에 흑심을 품고 있는 것은?", 
                "많이 맞을수록 좋은 것은?", 
                "반성문을 영어로 하면?"
            );
            Answer.push("시험지", "미남", "연필", "시험문제", "글로벌");

            hint.push(
                "학교에 가면 정기적으로 볼 수 있습니다.",
                "미녀라고 할 수 없지만, 그럼에도 불구하고 '예쁘다'는 평가를 받을 수 있습니다.",
                "사람에 따라 사용 기간이 다르지만 누구나 한번 씩은 써본 것입니다.",
                "이 문제의 답은 '가치'나 '특성'에 대한 개념이 아닙니다.",
                "이 문제는 단어의 의미보다는 단어의 발음에 초점을 맞춰야 합니다."
            );
        } else if (user === "어려움" || user === "상식") {
            problems.push(
                "지구에서 가장 큰 대륙은 무엇일까요?", 
                "피사의 사탑은 어느 나라에 있을까요?", 
                "올림픽은 몇 년에 한 번씩 열리나요?", 
                "세계에서 가장 많은 사람이 사용하는 언어는 무엇일까요?", 
                "초콜릿의 주 원료인 식물은 무엇일까요?"
            );
            Answer.push("아시아", "이탈리아", "4", "중국어", "카카오");

            hint.push(
                "이 대륙은 유럽과 연결되어 있고, 중국, 인도, 일본이 포함된 곳입니다.",
                "이 탑은 '산타 마리아 아순타 대성당' 옆에 위치해 있습니다.",
                "국회의원 임기와 같습니다.",
                "이 언어는 중국의 공식 언어이며, '푸퉁화'라고도 불립니다.",
                "이 식물은 열대 지역에서 자생하며, 그 열매에서 얻은 씨앗을 주로 사용합니다."
            );
        }

        function shuffleArray(problems) {
            for (let i = problems.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                
                [problems[i], problems[j]] = [problems[j], problems[i]];  
                // 배열의 값 교환
            }
        }

        // 셔플된 문제 배열에 맞춰서 문제와 힌트를 출력
        for (let idx = 0; idx < problems.length; idx++) {
            const problem = problems[idx];
            const result = Answer[idx];

            let userAnswer = prompt(`${problem} 정답은?`).trim();  
            // 입력 값에 대한 trim()을 사용하여 공백 제거

            // 숫자 문제의 경우 숫자 타입으로 변환하여 비교
            if (!isNaN(result)) {
                userAnswer = Number(userAnswer);  // 숫자로 변환
            }

            // 문제와 사용자가 입력한 답을 동적으로 HTML에 추가
            const resultList = document.getElementById("result-list");
            const questionLi = document.createElement("li");
            questionLi.classList.add("Q");
            questionLi.textContent = `Q${idx + 1}.  ${problem}   정답 : ${Answer[idx]}`;
            
            const answerLi = document.createElement("li");
            answerLi.classList.add("A");
            answerLi.textContent = `사용자의 답: ${userAnswer}`;

            resultList.appendChild(questionLi);
            resultList.appendChild(answerLi);

            // 정답이 맞을 때
            if (userAnswer == result) {
                score += 1;
            } else {
                // '쉬움' 난이도에서는 힌트를 제공하지 않음, 다시 묻지 않음
                if (user !== "쉬움" && hint[idx]) {
                    alert(`정답이 아닙니다! \n힌트: ${hint[idx]}`);
                    
                    userAnswer = prompt(`${problem} 다시 정답은?`).trim();  
                    // 두 번째 시도에서도 trim() 사용

                    // 숫자 문제의 경우 숫자 타입으로 변환하여 비교
                    if (!isNaN(result)) {
                        userAnswer = Number(userAnswer);
                    }

                    // 두 번째 답이 맞으면 점수 추가
                    if (userAnswer === result) {
                        score += 1;
                    }
                }
            }
        }

        // 최종 점수 출력
        const finalScoreElement = document.getElementById("final-score");
        finalScoreElement.textContent = `최종 점수: ${score}`;
    </script>
</body>
</html>



12일차(보충) 후기

  • 새로운 함수를 사용해 원하는대로 배열을 섞을 수 있어서 좋았습니다.
  • 대략 2시간동안 만들어보면서 부분적으로 이해가 힘든 부분도 생겼습니다.
  • 모르는 부분은 부분적으로 공부를 진행하며 코드를 작성하였습니다.
  • 어떻게 보면 게임이 아닌 것 같아 보이지만 직접 만들어 볼 수 있어서 좋았습니다.
  • 도중 도중 만들면서 오류를 찾아내 수정하는 부분이 조금 힘들었습니다.
  • 문제를 그대로 출력하는게 아니라 인덱스 값을 교환하여 무작위로 출력하기 때문에 코드가 더 복잡해지고 어려운 것 같습니다.
  • 그래도 포기하지 않고 끝까지 완성해서 뿌듯했습니다. «٩(´ ꒳ `)۶»
profile
૮꒰ ྀི〃´꒳`〃꒱ა

2개의 댓글

comment-user-thumbnail
2025년 1월 22일

덕분에 배열섞기가 가능했습니다!! 감사합니다!!

1개의 답글