From 854ff0e292d26b399f16394675cee2639e2aeba4 Mon Sep 17 00:00:00 2001 From: dkile Date: Thu, 9 Nov 2023 15:41:48 +0900 Subject: [PATCH 1/8] =?UTF-8?q?Feat:=20=EB=9E=9C=EB=8D=A4=20=EC=88=AB?= =?UTF-8?q?=EC=9E=90=20=EC=83=9D=EC=84=B1=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.js | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/index.js b/src/index.js index 1553d753..fce3013d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,27 @@ -export default function BaseballGame() { - this.play = function (computerInputNumbers, userInputNumbers) { - return "결과 값 String"; - }; -} - -// export default class BaseballGame { -// play(computerInputNumbers, userInputNumbers) { -// return "결과 값 String"; -// } -// } - -new BaseballGame(); +import BaseballGame from "./BaseballGame.js"; + +const concatPrimitiveIterToStr = (iter) => + Array.from(iter).reduce((prev, cur) => prev + cur, ""); + +const generateRandomInt = (length = 1) => { + const min = 10 ** (length - 1); + const max = 10 ** length; + + return Math.floor(Math.random() * (max - min)) + min; +}; + +const generateFixedSizeSet = (size = 1, generateValue) => { + const set = new Set(); + while (set.size < size) { + const value = generateValue(); + set.add(value); + } + return set; +}; + +const generateRandomIntArr = (length) => + Array.from(generateFixedSizeSet(length, generateRandomInt)); + +const computerInputNumbers = Number( + concatPrimitiveIterToStr(generateRandomIntArr(3)) +); From b0b7cc30e453ebdd4ae507c1e7f6d309b319f07d Mon Sep 17 00:00:00 2001 From: dkile Date: Fri, 10 Nov 2023 15:09:22 +0900 Subject: [PATCH 2/8] =?UTF-8?q?Feat:=20UI=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=8F=99=EC=9E=91=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.js | 72 ++++++++++++++++++++++++++++++++++++++-------------- src/utils.js | 25 ++++++++++++++++++ 2 files changed, 78 insertions(+), 19 deletions(-) create mode 100644 src/utils.js diff --git a/src/index.js b/src/index.js index fce3013d..69baba76 100644 --- a/src/index.js +++ b/src/index.js @@ -1,27 +1,61 @@ -import BaseballGame from "./BaseballGame.js"; +import BaseballGame from "/src/BaseballGame.js"; +import { + convertDigitArrayToInt, + generateNonDuplicateRandomIntArray, +} from "/src/utils.js"; -const concatPrimitiveIterToStr = (iter) => - Array.from(iter).reduce((prev, cur) => prev + cur, ""); +const generateComputerInputNumbers = () => + convertDigitArrayToInt(generateNonDuplicateRandomIntArray(3, 1)); -const generateRandomInt = (length = 1) => { - const min = 10 ** (length - 1); - const max = 10 ** length; +const userInputEl = document.querySelector("#user-input"); +const submitBtnEl = document.querySelector("#submit"); +const resultEl = document.querySelector("#result"); - return Math.floor(Math.random() * (max - min)) + min; +const baseballGame = new BaseballGame(); +let computerInputNumbers = generateComputerInputNumbers(); + +const handleRestart = (e) => { + userInputEl.disabled = false; + userInputEl.value = null; + userInputEl.focus(); + resultEl.innerHTML = ""; + computerInputNumbers = generateComputerInputNumbers(); }; -const generateFixedSizeSet = (size = 1, generateValue) => { - const set = new Set(); - while (set.size < size) { - const value = generateValue(); - set.add(value); +const handleSubmit = (e) => { + const userInputNumbers = Number(userInputEl?.value); + const result = baseballGame.play(computerInputNumbers, userInputNumbers); + + if (!result) { + alert("유효하지 않은 입력입니다."); + userInputEl.focus(); + return; } - return set; -}; + if (result === "정답을 맞추셨습니다!") { + userInputEl.disabled = true; + + const strongEl = document.createElement("strong"); + strongEl.textContent = result; + resultEl.textContent = ""; + resultEl.appendChild(strongEl); + + const restartMention = document.createElement("span"); + restartMention.textContent = "게임을 새로 시작하시겠습니까?"; + + const restartButtonEl = document.createElement("button"); + restartButtonEl.textContent = "게임 재시작"; + restartButtonEl.addEventListener("click", handleRestart); -const generateRandomIntArr = (length) => - Array.from(generateFixedSizeSet(length, generateRandomInt)); + const restartWrapper = document.createElement("div"); + restartWrapper.appendChild(restartMention); + restartWrapper.appendChild(restartButtonEl); + + resultEl.appendChild(restartWrapper); + + return; + } + + resultEl.textContent = result; +}; -const computerInputNumbers = Number( - concatPrimitiveIterToStr(generateRandomIntArr(3)) -); +submitBtnEl.addEventListener("click", handleSubmit); diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 00000000..2072a047 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,25 @@ +export const convertDigitArrayToInt = (digitArr) => parseInt(digitArr.join("")); + +export const generateRandomInt = (length = 1) => { + const min = 10 ** (length - 1); + const max = 10 ** length; + + return Math.floor(Math.random() * (max - min)) + min; +}; + +export const generateFixedSizeSet = (size = 1, generateValue) => { + const set = new Set(); + while (set.size < size) { + const value = generateValue(); + set.add(value); + } + return set; +}; + +export const generateNonDuplicateRandomIntArray = ( + arraylength, + digitCount = 1 +) => + Array.from( + generateFixedSizeSet(arraylength, () => generateRandomInt(digitCount)) + ); From 4279b4ea4c15049894b3cd40dd55d55ee2b0a986 Mon Sep 17 00:00:00 2001 From: dkile Date: Fri, 10 Nov 2023 15:09:42 +0900 Subject: [PATCH 3/8] =?UTF-8?q?Feat:=20=EC=88=AB=EC=9E=90=20=EC=95=BC?= =?UTF-8?q?=EA=B5=AC=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BaseballGame.js | 71 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/BaseballGame.js diff --git a/src/BaseballGame.js b/src/BaseballGame.js new file mode 100644 index 00000000..7c4512e7 --- /dev/null +++ b/src/BaseballGame.js @@ -0,0 +1,71 @@ +// Controller +export default class BaseballGame { + #DIGIT_LENGTH = 3; + play(computerInputNumbers, userInputNumbers) { + const isValidInput = + this.#validateInputNumbers(computerInputNumbers) && + this.#validateInputNumbers(userInputNumbers); + if (!isValidInput) return ""; + const judgement = this.#judge(computerInputNumbers, userInputNumbers); + const result = this.#formatResult(judgement); + + return result; + } + + // TODO: 널 오브젝트 패턴?? Judgeable을 validate하는 서비스로 추출 + #validateInputNumbers(inputNumbers) { + const inputStr = String(inputNumbers); + if (!this.#validateCorrectLength(inputStr)) return false; + if (!this.#validateAllDigit(inputStr)) return false; + if (!this.#validateDuplication(inputStr)) return false; + + return true; + } + + #validateCorrectLength(input) { + return input.length === this.#DIGIT_LENGTH; + } + + #validateAllDigit(input) { + return /^\d+$/.test(input); + } + + #validateDuplication(input) { + return new Set(input).size === inputStr.length; + } + + // TODO: Judgeable 객체를 두 개를 비즈니스 로직에 따라 처리하는 Referee 서비스로 추출 + #judge(computerInputDigits, userInputDigits) { + const set = new Set(); + let strike = 0; + let ball = 0; + const computerInputDigits = Array.from( + String(computerInputNumbers), + Number + ); + const userInputDigits = Array.from(String(userInputNumbers), Number); + + for (let i = 0; i < computerInputDigits.length; i++) { + if (computerInputDigits[i] === userInputDigits[i]) { + strike += 1; + continue; + } + set.add(computerInputDigits[i]); + } + + for (const userInputDigit of userInputDigits) { + if (set.has(userInputDigit)) ball += 1; + } + + return { strike, ball }; + } + + // TODO: VO 객체(Judge) 내의 로직으로 분리 + #formatResult({ strike, ball }) { + if (strike === 0 && ball === 0) return "낫싱"; + if (strike === this.#DIGIT_LENGTH) return "정답을 맞추셨습니다!"; + if (strike === 0) return `${ball}볼`; + if (ball === 0) return `${strike}스트라이크`; + return `${ball}볼 ${strike}스트라이크`; + } +} From e2699debf46c4de41028cbabe377b62a7869dee9 Mon Sep 17 00:00:00 2001 From: dkile Date: Sat, 11 Nov 2023 17:19:49 +0900 Subject: [PATCH 4/8] =?UTF-8?q?Refactor:=20form=20=EC=9A=94=EC=86=8C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 041e0300..09b05d51 100644 --- a/index.html +++ b/index.html @@ -13,8 +13,10 @@

⚾ 숫자 야구 게임

올바른 예) 139
틀린 예) 122

- - +
+ + +

📄 결과

From 97cd89bf9fb30a323f32cb21d421975cdbb31247 Mon Sep 17 00:00:00 2001 From: dkile Date: Sat, 11 Nov 2023 17:21:47 +0900 Subject: [PATCH 5/8] =?UTF-8?q?Refactor:=20generateNonDuplicateRandomIntAr?= =?UTF-8?q?ray=20=ED=95=A8=EC=88=98=20=EC=9D=B8=EC=9E=90=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.js | 7 ++++++- src/utils.js | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 69baba76..f2949e7c 100644 --- a/src/index.js +++ b/src/index.js @@ -5,7 +5,12 @@ import { } from "/src/utils.js"; const generateComputerInputNumbers = () => - convertDigitArrayToInt(generateNonDuplicateRandomIntArray(3, 1)); + convertDigitArrayToInt( + generateNonDuplicateRandomIntArray({ + arraylength: 3, + digitCount: 1, + }) + ); const userInputEl = document.querySelector("#user-input"); const submitBtnEl = document.querySelector("#submit"); diff --git a/src/utils.js b/src/utils.js index 2072a047..398f2f69 100644 --- a/src/utils.js +++ b/src/utils.js @@ -16,10 +16,10 @@ export const generateFixedSizeSet = (size = 1, generateValue) => { return set; }; -export const generateNonDuplicateRandomIntArray = ( +export const generateNonDuplicateRandomIntArray = ({ arraylength, - digitCount = 1 -) => + digitCount = 1, +}) => Array.from( generateFixedSizeSet(arraylength, () => generateRandomInt(digitCount)) ); From d7b75c595018b8ddc6c125ab907445209fffef00 Mon Sep 17 00:00:00 2001 From: dkile Date: Sat, 11 Nov 2023 17:23:22 +0900 Subject: [PATCH 6/8] =?UTF-8?q?Refactor:=20generateFixedSizeSet=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20size=20=EC=9D=B8=EC=9E=90=20option?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/utils.js b/src/utils.js index 398f2f69..24140575 100644 --- a/src/utils.js +++ b/src/utils.js @@ -7,7 +7,7 @@ export const generateRandomInt = (length = 1) => { return Math.floor(Math.random() * (max - min)) + min; }; -export const generateFixedSizeSet = (size = 1, generateValue) => { +export const generateFixedSizeSet = (generateValue, { size = 1 }) => { const set = new Set(); while (set.size < size) { const value = generateValue(); @@ -21,5 +21,7 @@ export const generateNonDuplicateRandomIntArray = ({ digitCount = 1, }) => Array.from( - generateFixedSizeSet(arraylength, () => generateRandomInt(digitCount)) + generateFixedSizeSet(() => generateRandomInt(digitCount), { + size: arraylength, + }) ); From 24aec7e2ce1f5d98df1de404b83b3969fa8c7467 Mon Sep 17 00:00:00 2001 From: dkile Date: Sat, 11 Nov 2023 17:24:21 +0900 Subject: [PATCH 7/8] =?UTF-8?q?Refactor:=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.js | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/index.js b/src/index.js index f2949e7c..a546b0f0 100644 --- a/src/index.js +++ b/src/index.js @@ -19,11 +19,39 @@ const resultEl = document.querySelector("#result"); const baseballGame = new BaseballGame(); let computerInputNumbers = generateComputerInputNumbers(); -const handleRestart = (e) => { +const resetUserInput = () => { userInputEl.disabled = false; userInputEl.value = null; userInputEl.focus(); +}; + +const resetResultEl = () => { resultEl.innerHTML = ""; +}; + +const showWinningResult = () => { + const strongEl = document.createElement("strong"); + strongEl.textContent = result; + resultEl.textContent = ""; + resultEl.appendChild(strongEl); + + const restartMention = document.createElement("span"); + restartMention.textContent = "게임을 새로 시작하시겠습니까?"; + + const restartButtonEl = document.createElement("button"); + restartButtonEl.textContent = "게임 재시작"; + restartButtonEl.addEventListener("click", handleRestart); + + const restartWrapper = document.createElement("div"); + restartWrapper.appendChild(restartMention); + restartWrapper.appendChild(restartButtonEl); + + resultEl.appendChild(restartWrapper); +}; + +const handleRestart = (e) => { + resetUserInput(); + resetResultEl(); computerInputNumbers = generateComputerInputNumbers(); }; @@ -38,25 +66,7 @@ const handleSubmit = (e) => { } if (result === "정답을 맞추셨습니다!") { userInputEl.disabled = true; - - const strongEl = document.createElement("strong"); - strongEl.textContent = result; - resultEl.textContent = ""; - resultEl.appendChild(strongEl); - - const restartMention = document.createElement("span"); - restartMention.textContent = "게임을 새로 시작하시겠습니까?"; - - const restartButtonEl = document.createElement("button"); - restartButtonEl.textContent = "게임 재시작"; - restartButtonEl.addEventListener("click", handleRestart); - - const restartWrapper = document.createElement("div"); - restartWrapper.appendChild(restartMention); - restartWrapper.appendChild(restartButtonEl); - - resultEl.appendChild(restartWrapper); - + showWinningResult(); return; } From 0a9cbda2927a597563f1fb76def7f9bd68f3f48e Mon Sep 17 00:00:00 2001 From: dkile Date: Sat, 11 Nov 2023 17:53:57 +0900 Subject: [PATCH 8/8] =?UTF-8?q?Fix:=20judge=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=9E=98=20=EB=AA=BB=20=ED=91=9C=EA=B8=B0=EB=90=9C=20=EC=9D=B8?= =?UTF-8?q?=EC=9E=90=20=EC=9D=B4=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BaseballGame.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/BaseballGame.js b/src/BaseballGame.js index 7c4512e7..6e386b1c 100644 --- a/src/BaseballGame.js +++ b/src/BaseballGame.js @@ -1,11 +1,18 @@ // Controller export default class BaseballGame { #DIGIT_LENGTH = 3; + #referee; + + constructor(referee) { + this.#referee = referee; + } + play(computerInputNumbers, userInputNumbers) { const isValidInput = this.#validateInputNumbers(computerInputNumbers) && this.#validateInputNumbers(userInputNumbers); if (!isValidInput) return ""; + const judgement = this.#judge(computerInputNumbers, userInputNumbers); const result = this.#formatResult(judgement); @@ -35,7 +42,7 @@ export default class BaseballGame { } // TODO: Judgeable 객체를 두 개를 비즈니스 로직에 따라 처리하는 Referee 서비스로 추출 - #judge(computerInputDigits, userInputDigits) { + #judge(computerInputNumbers, userInputNumbers) { const set = new Set(); let strike = 0; let ball = 0;