ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CS50 Week8: Lab8, Trivia
    Programming/CS50 2023. 7. 26. 20:33

    하버드 CS50 강의 8주차 Lab 과제 Trivia 의 풀이를 다룹니다.
    가벼운 상식 퀴즈를 내는 웹 사이트를 만드는 과제입니다.
    HTML, CSS, JavaScript를 사용하여 정적 웹 페이지를 만들어야 합니다.
    퀴즈를 내고 정답 여부에 따라 피드백을 남기는 기능을 구현해야 합니다.

    Task

    Trivia_img

    Requirements

    코드 템플릿이 주어져있다.

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500&display=swap" rel="stylesheet">
            <link href="styles.css" rel="stylesheet">
            <title>Trivia!</title>
            <script>
                // TODO: Add code to check answers to questions
            </script>
        </head>
        <body>
            <div class="header">
                <h1>Trivia!</h1>
            </div>
    
            <div class="container">
                <div class="section">
                    <h2>Part 1: Multiple Choice </h2>
                    <hr>
                    <!-- TODO: Add multiple choice question here -->
                </div>
    
                <div class="section">
                    <h2>Part 2: Free Response</h2>
                    <hr>
                    <!-- TODO: Add free response question here -->
                </div>
            </div>
        </body>
    </html>

    다음 사항들을 구현해야한다.

    • Part 1: 다지선다 문제(multiple-choice question) 만들기
      • 질문 text는 h3 heading 사용
      • 질문의 답변은 버튼을 통해 선택하는 구조
      • 오답 클릭 시, 버튼이 붉게 변하고 아래에 "Incorrect" 문구가 보여져야 함
      • 정답 클릭 시, 버튼이 초록색으로 변하고 아래에 "Correct!" 문구가 보여져야 함
    • Part 2: 서술형 문제 만들기
      • 질문 text는 h3 heading 사용
      • 응답을 받는 input 필드와 정답을 확인하는 button 필드가 있어야 함
      • 오답 입력 시 input text 필드가 붉게 변하고 아래에 "Incorrect" 문구가 보여져야 함
      • 정답 입력 시 input text 필드가 붉게 변하고 아래에 "Correct" 문구가 보여져야 함
    • 선호에 따라 CSS 자유롭게 수정 가능

    Implementation

    먼저 코드를 작성하기 전에 사이트에 넣을 문항 구성이 필요하다.

    Trivia Question 이라는 주제에 맞게 가벼우면서도 재밌는 문제가 필요하다.
    괜찮은 거 찾으려고 구글링을 하는데 마음에 드는 거 찾기가 너무 어려웠다. 주객이 전도되기 전에 그냥 빠르게 ChatGPT에게 물어보기로 했다.

    프로그래밍 주제로 5개 정도 뽑아 가장 괜찮은 문항을 선별했다.

    4지선다형

    Who are credited as the inventors of the Unix operating system?

    1. Bill Gates and Paul Allen
    2. Linus Torvalds
    3. Ken Thompson and Dennis Ritchie
    4. Steve Jobs and Steve Wozniak

    서술형

    What does the "www" stands for in a website's URL?

    Part 1

    HTML 구성하기

    <div class="section" id="part1">
      <h2>Part 1: Multiple Choice</h2>
      <hr />
      <h3>Who are credited as the inventors of the Unix operating system?</h3>
      <button type="button">Bill Gates and Paul Allen</button>
      <button type="button">Linus Torvalds</button>
      <button type="button">Ken Thompson and Dennis Ritchie</button>
      <button type="button">Steve Jobs and Steve Wozniak</button>
      <p class="feedback"></p>
    </div>

    먼저 버튼을 만들어 준다.

    CS50 강의 예제에서는 form 태그와 submit 타입 버튼을 사용했다.
    우리 사이트는 내부에서 정답을 처리하는 구조인데 굳이 submit을 써야 하나 싶었다.

    찾아보니 더 간단한 방식 이 있어서 활용해줬다.

    정답 처리 방식은 처음에는 버튼 별로 .correct/.incorrect 클래스를 지정하는 방식을 고안했다.
    근데 타이핑하기도 귀찮고, 문제 수정 시 script와 문서 양쪽을 수정해야 되는 문제가 있다.
    그래서 그냥 script에서 버튼의 textContent를 비교하는 방식으로 바꿔줬다.

    정답 피드백 표시는 <p> 태그로 하기로 한다.
    강의에서는 visible/hidden 특성으로 문단을 표시하고 숨기는 방식을 보여줬었다.

    이번 과제에 적용하기엔 불필요한 on/off 조건이 생기는 것 같아 그냥 문단 자체를 빈칸으로 두고 정/오답 여부에 따라 문단 내용을 변화 시키기로 한다.

    마지막으로 섹션의 클래스 id을 붙여주었다.
    JavaScript의 querySelectorALL() 메서드로 part1 내부의 버튼을 전부 가져올 때, 각 파트를 구분 할 방법으로 div.section에 파트를 구분하는 id를 추가 해주었다.

    Javascript 작성하기

    <script>
      document.addEventListener("DOMContentLoaded", () => {
        // Who Created Unix system
        const ANSWER_PART1 = "Ken Thompson and Dennis Ritchie";
        let feedbackPart1 = document.querySelector("#part1 p.feedback");
    
        let buttons = document.querySelectorAll("#part1 button");
        buttons.forEach((button) => {
          button.addEventListener("click", (event) => {
            if (button.textContent.trim() === ANSWER_PART1) {
              button.style.backgroundColor = "green";
              feedbackPart1.textContent = "Correct!";
            } else {
              button.style.backgroundColor = "red";
              feedbackPart1.textContent = "Incorrect";
            }
          });
        });
      });
    </script>

    인터넷으로 필요한 매서드 사용법을 찾아보는데, 다들 코드가 제각각에, 간단한 변수나 함수 선언하는 방식도 죄다 달라서 감 잡기가 어려웠다.

    그래서 구글 JavaScript 스타일 가이드를 참조하기로 했다.
    물론 아직 처음이라 대부분 이해하기 어려운 내용이었다.
    그래도 내용 따라 indent size도 2칸으로 바꾸고 함수 정의도 화살표 방식을 채택했다.

    특히 함수 내부에서 함수를 선언하고 쓰는 방식이 처음에는 별로 직관적이지 않았는데 기존 function() 키워드 대신 화살표를 쓰니 이해가 쉬워졌다.

    Part 2

    HTML 구성하기

    크게 특이사항은 없다.

    <div class="section" id="part2">
      <h2>Part 2: Free Response</h2>
      <hr />
      <h3>What does the "www" stands for in a website's URL?</h3>
      <input autocomplete="off" type="text" />
      <button type="button">Check Answer</button>
      <p class="feedback"></p>

    Javascript 작성하기

    <script>
      document.addEventListener('DOMContentLoaded', () => {
        const ANSWERS = {
          // Who Created Unix system
          part1: 'Ken Thompson and Dennis Ritchie',
          // What 'www' is
          part2: 'World Wide Web',
        };
    
        let feedback = {
          part1: document.querySelector('#part1 p.feedback'),
          part2: document.querySelector('#part2 p.feedback'),
        };
    
        let buttons = document.querySelectorAll('#part1 button');
        buttons.forEach((button) => {
          button.addEventListener('click', (event) => {
            if (button.textContent.trim() === ANSWERS.part1) {
              button.style.backgroundColor = 'green';
              feedback.part1.textContent = 'Correct!';
            } else {
              button.style.backgroundColor = 'red';
              feedback.part1.textContent = 'Incorrect';
            }
          });
        });
    
        document
          .querySelector('#part2 button')
          .addEventListener('click', (event) => {
            let inputField = document.querySelector('#part2 input');
            let userAnswer = inputField.value;
            if (userAnswer === ANSWERS.part2) {
              inputField.style.backgroundColor = 'green';
              feedback.part2.textContent = 'Correct!';
            } else {
              inputField.style.backgroundColor = 'red';
              feedback.part2.textContent = 'Incorrect';
            }
          });
      });
    </script>

    역시 크게 다른 부분은 없고 문제 답안, 피드백을 묶어줬다.

    CSS

    이 부분은 너무 파고들면 끝도 없을 것 같아서, 몇몇 부분만 변경하기로 했다.

    .header {
        background-color: #05277ece;  /* 변경 */
        color: #fff;
        margin-bottom: 2rem;
        padding: 2rem 1rem;
        text-align: center;
    }
    
    button, input[type="submit"] {
        background-color: #193f9fbd;  /* 변경 */
        border: 1px solid transparent;
        border-radius: 0.25rem;
        color: #edede8;    /* 추가 */
        font-size: 0.95rem;
        font-weight: 400;
        line-height: 1.5;
        padding: 0.375rem 0.75rem;
        text-align: center;
        transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
        vertical-align: middle;
    }
    
    /* 추가 */
    button:hover {
        box-shadow: 0 0 10px rgba(0,0,0,0.5);
    }

    댓글