diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..9fc789d --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": false, + "tabWidth": 4 +} diff --git a/README.md b/README.md index 8b2833c..18b213f 100644 --- a/README.md +++ b/README.md @@ -1 +1,52 @@ -# javascript-baseball-precourse \ No newline at end of file +# 숫자 야구 게임 + +## UI +1. **템플릿 구현**: 화면 디자인 및 템플릿을 구현합니다. +2. **처음 게임 시작 시 '결과' 부분 숨기기**: 게임이 시작될 때 '결과' 부분을 숨겨 사용자의 눈을 덜 끌어냅니다. + +## 야구게임 결과 +게임 진행 중에 발생하는 다양한 결과에 대한 설명입니다. + +### 1. 정답인 경우 +- 정답 문구 출력 +- 게임 재시작 문구 출력 +- 게임 재시작 버튼 생성 + +### 2. 오답인 경우 +- N스트라이크 N볼 형식으로 게임 진행 상황 출력 + +### 3. 잘못된 값 입력 시 +- `alert()`로 에러 메시지 출력 + +### 예외 케이스 종류 +1. 문자열 입력 +2. 특수문자 입력 +3. 소수 입력 +4. 중복된 숫자 입력 +5. 3개 이상 또는 이하의 숫자 입력 + +## 기능 구현 + +### 정답 세팅 (SetAnswer) +1. 랜덤 함수로 정답을 생성합니다. + +### 숫자 입력 받기 (HandleInput, OnlyNumber) +1. input 창에 숫자 입력을 받습니다. +2. 확인 버튼 클릭 시, 입력된 숫자를 전달 받습니다. +3. 예외 케이스에 해당하는 입력을 받았을 경우 에러 메시지를 출력합니다. + +### 게임 진행 (CompareValue) +1. 입력된 수와 컴퓨터의 수를 비교합니다. + - 같은 수, 같은 자리 = 스트라이크 + - 같은 수, 다른 자리 = 볼 + - 모두 다른 수 = 낫싱 + + +### 출력 (ShowResult) +1. displayNone으로 숨겨뒀던 결과 content를 보이게 합니다. +2. 비교한 결과를 사용자에게 보여줍니다. + +### 리셋 (ResetValues, EndGame) +1. 게임 재시작 버튼을 눌렀을 시, location.reload()로 초기화합니다. +2. 게임 종료 버튼을 눌렀을 시, 화면을 초기화하고 게임을 종료합니다. + diff --git a/index.html b/index.html index b021b5c..44e22a4 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,35 @@ - + - - - - - - -
- - + + + + + 숫자 야구 게임 + + + + +
+

⚾숫자 야구 게임

+

1~9까지의 수를 중복없이 3개 입력해주세요

+

올바른 예) 139

+

틀린 예) 122

+
+ + +
+

결과

+
+
+
+
+ + +
+
+
+
+ + + diff --git a/src/main.js b/src/main.js index e69de29..718e8b3 100644 --- a/src/main.js +++ b/src/main.js @@ -0,0 +1,14 @@ +import { HandleInput } from "./modules/HandleInput.js"; +import { SetAnswer } from "./modules/SetAnswer.js"; +import { OnlyNumber } from "./modules/OnlyNumber.js"; +import { ResetValues } from "./modules/ResetValues.js"; +import { EndGame } from "./modules/EndGame.js"; + +SetAnswer(); + +document.querySelector("form").addEventListener("submit", HandleInput); +document.querySelector("input").addEventListener("keydown", OnlyNumber); + +// 추가된 버튼의 이벤트 리스너를 할당합니다. +document.getElementById("resetBtn").addEventListener("click", ResetValues); +document.getElementById("endGameBtn").addEventListener("click", EndGame); diff --git a/src/modules/CompareValue.js b/src/modules/CompareValue.js new file mode 100644 index 0000000..d05be9f --- /dev/null +++ b/src/modules/CompareValue.js @@ -0,0 +1,18 @@ +import { ShowResult } from "./ShowResult.js"; +import { answer } from "./SetAnswer.js"; + +export const CompareValue = () => { + const inputEl = document.querySelector("input"); + + let strikes = 0; + let balls = 0; + for (let i = 0; i < 3; i++) { + if (inputEl.value[i] === answer[i]) { + strikes++; + } else if (answer.includes(inputEl.value[i])) { + balls++; + } + } + + ShowResult(strikes, balls); +}; diff --git a/src/modules/EndGame.js b/src/modules/EndGame.js new file mode 100644 index 0000000..3b32e26 --- /dev/null +++ b/src/modules/EndGame.js @@ -0,0 +1,4 @@ +export const EndGame = () => { + const app = document.getElementById("app"); + app.innerHTML = "

게임이 종료되었습니다.

"; +}; diff --git a/src/modules/HandleInput.js b/src/modules/HandleInput.js new file mode 100644 index 0000000..e0b9f68 --- /dev/null +++ b/src/modules/HandleInput.js @@ -0,0 +1,16 @@ +import { CompareValue } from "./CompareValue.js"; + +export const HandleInput = (e) => { + e.preventDefault(); + const inputEl = document.querySelector("input"); + const contents = document.getElementById("contents"); + + if (inputEl.value.length < 3) { + alert("3글자 이상 입력해주세요."); + return; + } + + contents.setAttribute("class", ""); + + CompareValue(); +}; diff --git a/src/modules/OnlyNumber.js b/src/modules/OnlyNumber.js new file mode 100644 index 0000000..3e3f263 --- /dev/null +++ b/src/modules/OnlyNumber.js @@ -0,0 +1,21 @@ +export const OnlyNumber = (event) => { + const key = event.key; + + // 입력된 키가 숫자인지, 백스페이스 또는 엔터인지 확인합니다. + if (/\d/.test(key) || key === "Backspace" || key === "Enter") { + const inputEl = document.querySelector("input"); + const value = inputEl.value; + + // 현재 입력된 값과 이전 값이 같으면 입력을 막고 경고창을 표시합니다. + if (value.length > 0 && value[value.length - 1] === key) { + event.preventDefault(); + alert("중복된 값을 입력할 수 없습니다."); + return false; + } + return true; + } else { + event.preventDefault(); + alert("숫자만 입력 가능합니다."); + return false; + } +}; diff --git a/src/modules/ResetValues.js b/src/modules/ResetValues.js new file mode 100644 index 0000000..d011a63 --- /dev/null +++ b/src/modules/ResetValues.js @@ -0,0 +1,8 @@ +export const ResetValues = () => { + const inputEl = document.querySelector("input"); + const ansEl = document.getElementById("ansEl"); + inputEl.value = ""; + ansEl.innerText = ""; + + location.reload(); +}; diff --git a/src/modules/SetAnswer.js b/src/modules/SetAnswer.js new file mode 100644 index 0000000..3c07dc1 --- /dev/null +++ b/src/modules/SetAnswer.js @@ -0,0 +1,14 @@ +let answer; + +export const SetAnswer = () => { + answer = ""; + while (answer.length < 3) { + let num = Math.floor(Math.random() * 9) + 1; + if (!answer.includes(num.toString())) { + answer += num.toString(); + } + } + console.log(answer); +}; + +export { answer }; diff --git a/src/modules/ShowResult.js b/src/modules/ShowResult.js new file mode 100644 index 0000000..fbdffc4 --- /dev/null +++ b/src/modules/ShowResult.js @@ -0,0 +1,12 @@ +export const ShowResult = (strikes, balls) => { + const ansEl = document.getElementById("ansEl"); + + if (strikes === 3) { + ansEl.innerHTML = + "🎉정답을 맞추셨습니다!🎉
게임을 새로 시작하시겠습니까?
"; + } else if (strikes === 0 && balls === 0) { + ansEl.innerText = "낫싱"; + } else { + ansEl.innerText = `${strikes} 스트라이크, ${balls} 볼`; + } +}; diff --git a/src/style/style.css b/src/style/style.css new file mode 100644 index 0000000..b81fc8e --- /dev/null +++ b/src/style/style.css @@ -0,0 +1,27 @@ +.displayNone { + display: none; +} + +#result__section { + width: 350px; + height: 200px; + border-radius: 10px; + background-color: beige; + + position: relative; +} + +#ansEl { + width: 100%; + text-align: center; + position: absolute; + top: 48%; + left: 50%; + transform: translate(-50%, -50%); +} + +.btn-wrap{ + position: absolute; + bottom: 15px; + right: 15px; +}