본문 바로가기

풀스택 개발/간단 개발 실습

[JS] 단어 추측

게임 규칙

목표: 사용자는 비밀 단어를 맞추는 것이 목표입니다. 이번 비밀 단어는 "mouse"이다.

입력: 화면에는 5개의 입력 필드가 있다.사용자는 각 입력 필드에 문자 하나씩 입력한다.

 

제출

입력이 완료되면, "제출" 버튼을 클릭한다.

제출 버튼 클릭 시, 입력된 단어와 비밀 단어를 비교한다.

각 입력된 문자에 대해 다음과 같이 색상으로 피드백을 제공한다:

  • 파란색: 해당 문자가 비밀 단어에서 올바른 위치에 있을 때.
  • 노란색: 해당 문자가 비밀 단어에 포함되지만 올바른 위치에 있지 않을 때.
  • 빨간색: 해당 문자가 비밀 단어에 포함되지 않을 때.

시도 횟수

  • 사용자는 최대 10번의 시도까지 할 수 있다.
  • 각 시도 후에 새로운 입력 행이 추가된다.

제출 후 처리:

  • 최대 시도 횟수(10회)에 도달하면 "제출" 버튼이 사라지고 "리셋" 버튼이 나타난다.
  • 새로운 단어를 시도하려면 "리셋" 버튼을 클릭하여 게임을 초기화할 수 있다.

리셋

  • "리셋" 버튼을 클릭하면 입력 필드와 시도 횟수가 초기화된다.
  • 초기 입력 필드로 돌아가며, "제출" 버튼이 다시 나타나고 "리셋" 버튼은 사라진다.

코드 분석

<!DOCTYPE html>
<html lang="en">
<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>Document</title>
    <style>
        /* CSS 스타일 정의 */
    </style>
</head>
<body>
    <div class="box">
        <div id="fixed-container" class="input-container">
            <input class="input">
            <input class="input">
            <input class="input">
            <input class="input">
            <input class="input">
        </div>
        <div id="dynamic-container"></div>
        <div class="buttons">
            <a href="ex.html" class="description-button">설명</a>
            <button id="submit-button">제출</button>
            <button id="reset-button">리셋</button>
        </div>
    </div>
    <script>
        /* JavaScript 코드 정의 */
    </script>
</body>
</html>

HTML: 문서의 기본 구조를 정의한다.
<div class="box">: 전체 컨테이너로, 화면의 중앙에 위치하며 세로 방향으로 스크롤이 가능
<div id="fixed-container">: 최초에 보여지는 고정 입력 필드 5개를 포함
<div id="dynamic-container">: 동적으로 추가되는 입력 필드를 담는 영역
<div class="buttons">: 설명 링크, 제출 버튼, 리셋 버튼을 포함하는 버튼 영역

 

.box {
    display: flex;
    flex-direction: column;
    align-items: center;
    height: 100vh;
    position: relative;
    overflow-y: auto;
}

.input-container {
    display: aflex; /* 타이포: 'flex'로 수정 필요 */
    justify-content: center;
    margin-bottom: 10px;
}

input {
    width: 40px;
    height: 40px;
    font-size: 30px;
    text-align: center;
    margin-right: 5px;
}

.buttons {
    position: absolute;
    bottom: 10px;
    right: 10px;
}

button, a {
    padding: 10px 20px;
    font-size: 20px;
    text-decoration: none;
    color: white;
    border: none;
    border-radius: 5px;
    margin-left: 10px;
}

button {
    background-color: #28a745; /* 버튼의 녹색 배경 */
}

.description-button {
    background-color: #17a2b8; /* 설명 버튼의 파란색 배경 */
}

#reset-button {
    display: none; /* 리셋 버튼은 처음에 숨김 */
}

.buttons a {
    background-color: #007bff; /* 링크의 기본 파란색 배경 */
}

.box: 페이지의 중앙에 내용을 배치하고, 전체 높이를 100vh로 설정하여 화면 전체를 차지하게 한다
.input-container: 입력 필드를 가로로 정렬하며 가운데 정렬, display: aflex는 타이포가 있으며, display: flex로 수정해야 함.
input: 입력 필드의 크기, 글자 크기, 정렬 및 여백을 설정
.buttons: 버튼을 페이지 하단 오른쪽에 위치시킴.
button, a: 버튼과 링크의 공통 스타일(여백, 글자 크기, 색상, 테두리 등)을 정의한다.
#reset-button: 리셋 버튼을 기본적으로 숨긴다.

 

var 답 = 'horse';
var attempts = 0;
var maxAttempts = 10;

document.querySelector('#submit-button').addEventListener('click', function() {
    if (attempts >= maxAttempts) return;

    var inputContainers = document.querySelectorAll('#dynamic-container .input-container');
    var latestContainer = inputContainers.length > 0 ? inputContainers[inputContainers.length - 1] : null;
    var inputs = latestContainer ? latestContainer.querySelectorAll('.input') : document.querySelectorAll('#fixed-container .input');

    for (let i = 0; i < 5; i++) {
        if (inputs[i].value == 답[i]) {
            inputs[i].style.background = 'blue';
        } else if (답.includes(inputs[i].value)) {
            inputs[i].style.background = 'yellow';
        } else {
            inputs[i].style.background = 'red';
        }
    }

    attempts++;
    
    if (attempts < maxAttempts) {
        var template = `
            <div class="input-container">
                <input class="input">
                <input class="input">
                <input class="input">
                <input class="input">
                <input class="input">
            </div>`;
        document.querySelector('#dynamic-container').insertAdjacentHTML('beforeend', template);
    }

    if (attempts >= maxAttempts) {
        document.querySelector('#submit-button').style.display = 'none';
        document.querySelector('#reset-button').style.display = 'inline-block';
    }
});

document.querySelector('#reset-button').addEventListener('click', function() {
    attempts = 0;
    document.querySelector('#dynamic-container').innerHTML = '';
    var fixedInputs = document.querySelectorAll('#fixed-container .input');
    fixedInputs.forEach(input => {
        input.value = '';
        input.style.background = '';
    });
    document.querySelector('#submit-button').style.display = 'inline-block';
    document.querySelector('#reset-button').style.display = 'none';
});

변수 설정:

답: 맞추어야 할 비밀 단어 (현재 "mouse"로 설정됨)
attempts: 현재 시도 횟수
maxAttempts: 최대 시도 횟수(10번)
제출 버튼 클릭 이벤트

시도 횟수가 최대값에 도달했는지 확인
가장 최근의 입력 필드 그룹을 가져와서 각 입력의 값을 비밀 단어와 비교
입력된 문자에 따라 배경색을 설정
시도가 끝나지 않았다면 새로운 입력 필드 그룹을 추가
최대 시도 횟수에 도달하면 제출 버튼을 숨기고 리셋 버튼을 표시
리셋 버튼 클릭 이벤트:

시도 횟수를 0으로 초기화
동적으로 추가된 입력 필드 그룹을 제거
초기 입력 필드의 값을 지우고 스타일을 초기화
제출 버튼을 다시 표시하고 리셋 버튼을 숨김


↓ ↓ 전체 코드

더보기

<!DOCTYPE html>
<html lang="en">
<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>Document</title>
    <style>
        .box {
            display: flex;
            flex-direction: column;
            align-items: center;
            height: 100vh;
            position: relative;
            overflow-y: auto;
        }
        .input-container {
            display: aflex;
            justify-content: center;
            margin-bottom: 10px;
        }
        input {
            width: 40px;
            height: 40px;
            font-size: 30px;
            text-align: center;
            margin-right: 5px;
        }
        .buttons {
            position: absolute;
            bottom: 10px;
            right: 10px;
        }
        button, a {
            padding: 10px 20px;
            font-size: 20px;
            text-decoration: none;
            color: white;
            border: none;
            border-radius: 5px;
            margin-left: 10px;
        }
        button {
            background-color: #28a745; /* Green color for the button */
        }
        .description-button {
            background-color: #17a2b8; /* Blue color for the description button */
        }
        #reset-button {
            display: none;
        }
        .buttons a {
            background-color: #007bff; /* Default blue for links */
        }
    </style>
</head>
<body>
    <div class="box">
        <div id="fixed-container" class="input-container">
            <input class="input">
            <input class="input">
            <input class="input">
            <input class="input">
            <input class="input">
        </div>
        <div id="dynamic-container"></div>
        <div class="buttons">
            <a href="ex.html" class="description-button">설명</a>
            <button id="submit-button">제출</button>
            <button id="reset-button">리셋</button>
        </div>
    </div>
    <script>
        var 답 = 'mouse';
        var attempts = 0;
        var maxAttempts = 10;

        document.querySelector('#submit-button').addEventListener('click', function() {
            if (attempts >= maxAttempts) return;

            var inputContainers = document.querySelectorAll('#dynamic-container .input-container');
            var latestContainer = inputContainers.length > 0 ? inputContainers[inputContainers.length - 1] : null;
            var inputs = latestContainer ? latestContainer.querySelectorAll('.input') : document.querySelectorAll('#fixed-container .input');

            for (let i = 0; i < 5; i++) {
                if (inputs[i].value == 답[i]) {
                    inputs[i].style.background = 'blue';
                } else if (답.includes(inputs[i].value)) {
                    inputs[i].style.background = 'yellow';
                } else {
                    inputs[i].style.background = 'red';
                }
            }

            attempts++;
            
            if (attempts < maxAttempts) {
                var template = `
                    <div class="input-container">
                        <input class="input">
                        <input class="input">
                        <input class="input">
                        <input class="input">
                        <input class="input">
                    </div>`;
                document.querySelector('#dynamic-container').insertAdjacentHTML('beforeend', template);
            }

            if (attempts >= maxAttempts) {
                document.querySelector('#submit-button').style.display = 'none';
                document.querySelector('#reset-button').style.display = 'inline-block';
            }
        });

        document.querySelector('#reset-button').addEventListener('click', function() {
            attempts = 0;
            document.querySelector('#dynamic-container').innerHTML = '';
            var fixedInputs = document.querySelectorAll('#fixed-container .input');
            fixedInputs.forEach(input => {
                input.value = '';
                input.style.background = '';
            });
            document.querySelector('#submit-button').style.display = 'inline-block';
            document.querySelector('#reset-button').style.display = 'none';
        });
    </script>
</body>
</html>