From e93f6620a58466383d845a7e164d0a5a4061282b Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Fri, 31 Oct 2025 16:41:42 +0900 Subject: [PATCH 01/13] =?UTF-8?q?docs(readme):=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=9A=94=EA=B5=AC=20=EC=82=AC=ED=95=AD=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 15bb106b5..4a2c2721e 100644 --- a/README.md +++ b/README.md @@ -1 +1,12 @@ # javascript-lotto-precourse +# 로또 +## 기능 요구 사항 +- [ ] 로또 구입 금액 입력 받기 +- [ ] 입력 구입 금액 유효성 검사하기 +- [ ] 1 ~ 45 숫자중 6개 중복없이 선택하기 +- [ ] 당첨 번호, 보너스 번호 입력받기 +- [ ] 발행한 로또 수량 및 번호 출력하기 +- [ ] 사용자가 구입한 로또번호, 당첨번호 비교하기 +- [ ] 당첨 내역 및 수익률 계산하기 +- [ ] 당첨 내역 및 수익률 출력하기 +- [ ] 잘못된 값 입력에 Error발생시키기 \ No newline at end of file From e7260cd2697c5a3bd281bc9c46c6129d6c28d4a5 Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Fri, 31 Oct 2025 16:56:50 +0900 Subject: [PATCH 02/13] =?UTF-8?q?docs(readme):=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EB=9E=98=EB=B0=8D=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a2c2721e..765991169 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,11 @@ - [ ] 사용자가 구입한 로또번호, 당첨번호 비교하기 - [ ] 당첨 내역 및 수익률 계산하기 - [ ] 당첨 내역 및 수익률 출력하기 -- [ ] 잘못된 값 입력에 Error발생시키기 \ No newline at end of file +- [ ] 잘못된 값 입력에 Error발생시키기 + +## 프로그래밍 요구 사항 +- [ ] 함수의 길이가 15라인을 넘어가지 않도록 구현한다. +- [ ] else를 지양한다. +- [ ] 구현한 기능에 대한 단위 테스트를 작성한다. +- [ ] Lotto 클래스에 numbers 이외의 필드를 추가할 수 없다. +- [ ] numbers의 접근 제어자인 #은 변경할수 없다. \ No newline at end of file From 5aebd283711db27cded977aa664a63370d6ef2df Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 18:55:14 +0900 Subject: [PATCH 03/13] =?UTF-8?q?feat(LottoManager.getPurchaseAmount):=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=EB=A1=9C=EB=B6=80=ED=84=B0=20?= =?UTF-8?q?=EA=B5=AC=EC=9E=85=EA=B8=88=EC=95=A1=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/App.js | 14 ++++++++++++-- src/LottoManager.js | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/LottoManager.js diff --git a/README.md b/README.md index 765991169..feded7e8e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # javascript-lotto-precourse # 로또 ## 기능 요구 사항 -- [ ] 로또 구입 금액 입력 받기 +- [X] 로또 구입 금액 입력 받기 - [ ] 입력 구입 금액 유효성 검사하기 - [ ] 1 ~ 45 숫자중 6개 중복없이 선택하기 - [ ] 당첨 번호, 보너스 번호 입력받기 diff --git a/src/App.js b/src/App.js index 091aa0a5d..3c46d77b4 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,15 @@ +import { Console, MissionUtils } from "@woowacourse/mission-utils"; +import Lotto from "./Lotto.js"; +import LottoManager from "./LottoManager.js"; + class App { - async run() {} + async run() { + const lottoManager = new LottoManager(); + await lottoManager.getPurchaseAmout(); + Console.print("로또 구입이 완료되었습니다."); + + + } } -export default App; +export default App; \ No newline at end of file diff --git a/src/LottoManager.js b/src/LottoManager.js new file mode 100644 index 000000000..c81acc447 --- /dev/null +++ b/src/LottoManager.js @@ -0,0 +1,19 @@ +import { Console, MissionUtils } from "@woowacourse/mission-utils"; + +class LottoManager { + constructor() { + this.lottos = []; + this.spentMoney = 0; + } + + async getPurchaseAmout() { + const input = await Console.readLineAsync("구입금액을 입력해 주세요.\n") + this.spentMoney = parseInt(input, 10); + Console.print(`입력한 로또금액은 ${input}입니다.`); + } + + validateSpentMoney() { + + } +} +export default LottoManager; \ No newline at end of file From faca678947a8861eef91c1e5efa8fe24f82f4c72 Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 19:06:10 +0900 Subject: [PATCH 04/13] =?UTF-8?q?issue:=20=EC=9E=AC=EA=B7=80=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=EC=8B=9C=20await=EA=B0=80=20=ED=92=80=EB=A6=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/LottoManager.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/LottoManager.js b/src/LottoManager.js index c81acc447..6d59842d8 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -8,12 +8,20 @@ class LottoManager { async getPurchaseAmout() { const input = await Console.readLineAsync("구입금액을 입력해 주세요.\n") + // if(!this.validateSpentMoney(input)) new Error("[ERROR] 올바른 금액을 입력해 주세요."); + if(!this.validateSpentMoney(input)) { + Console.print("[ERROR] 올바른 금액을 입력해 주세요."); + this.getPurchaseAmout(); + return; + } this.spentMoney = parseInt(input, 10); Console.print(`입력한 로또금액은 ${input}입니다.`); } - - validateSpentMoney() { - + validateSpentMoney(price) { + // if(!Number(price)) Console.print("숫자로 입력해주세요") + // if(Number(price) % 1000 != 0) Console.print("1000원단위로") + return Number(price) && Number(price) % 1000 === 0; + // return Number(price) % 1000 === 0 && Number(price) > 0; } } export default LottoManager; \ No newline at end of file From 52ed33e50c3ce57effb184dd69e33935cdab2751 Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 19:20:26 +0900 Subject: [PATCH 05/13] =?UTF-8?q?feat(LottoManager.validateSpentMoney):=20?= =?UTF-8?q?=EA=B5=AC=EC=9E=85=EA=B8=88=EC=95=A1=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=EC=84=B1=20=EA=B2=80=EC=82=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/LottoManager.js | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index feded7e8e..7b94b2990 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # 로또 ## 기능 요구 사항 - [X] 로또 구입 금액 입력 받기 -- [ ] 입력 구입 금액 유효성 검사하기 +- [X] 입력 구입 금액 유효성 검사하기 - [ ] 1 ~ 45 숫자중 6개 중복없이 선택하기 - [ ] 당첨 번호, 보너스 번호 입력받기 - [ ] 발행한 로또 수량 및 번호 출력하기 diff --git a/src/LottoManager.js b/src/LottoManager.js index 6d59842d8..95528684d 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -6,22 +6,24 @@ class LottoManager { this.spentMoney = 0; } + // 깊이가 좀 깊은가? async getPurchaseAmout() { - const input = await Console.readLineAsync("구입금액을 입력해 주세요.\n") - // if(!this.validateSpentMoney(input)) new Error("[ERROR] 올바른 금액을 입력해 주세요."); - if(!this.validateSpentMoney(input)) { - Console.print("[ERROR] 올바른 금액을 입력해 주세요."); - this.getPurchaseAmout(); - return; + while (true) { + const input = await Console.readLineAsync("구입금액을 입력해 주세요.\n") + try { + if (!this.validateSpentMoney(input)) throw new Error("[ERROR] 구입 금액은 1000원 단위의 숫자로 입력해 주세요."); + this.spentMoney = Number(input); + break; + } catch (e) { + Console.print(e.message); + continue; + } } - this.spentMoney = parseInt(input, 10); - Console.print(`입력한 로또금액은 ${input}입니다.`); } + validateSpentMoney(price) { - // if(!Number(price)) Console.print("숫자로 입력해주세요") - // if(Number(price) % 1000 != 0) Console.print("1000원단위로") - return Number(price) && Number(price) % 1000 === 0; - // return Number(price) % 1000 === 0 && Number(price) > 0; + const parsedPrice = Number(price); + return !isNaN(parsedPrice) && parsedPrice % 1000 === 0 && parsedPrice > 0; } } export default LottoManager; \ No newline at end of file From 4c4e582abf3511348b66f2116fd7e9e30d30635e Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 20:14:44 +0900 Subject: [PATCH 06/13] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/App.js | 5 ++--- src/Lotto.js | 9 +++++++++ src/LottoManager.js | 20 ++++++++++++++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7b94b2990..9b4d792a9 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## 기능 요구 사항 - [X] 로또 구입 금액 입력 받기 - [X] 입력 구입 금액 유효성 검사하기 -- [ ] 1 ~ 45 숫자중 6개 중복없이 선택하기 +- [X] 1 ~ 45 숫자중 6개 중복없이 선택하기 - [ ] 당첨 번호, 보너스 번호 입력받기 - [ ] 발행한 로또 수량 및 번호 출력하기 - [ ] 사용자가 구입한 로또번호, 당첨번호 비교하기 diff --git a/src/App.js b/src/App.js index 3c46d77b4..ae15a6d5a 100644 --- a/src/App.js +++ b/src/App.js @@ -6,9 +6,8 @@ class App { async run() { const lottoManager = new LottoManager(); await lottoManager.getPurchaseAmout(); - Console.print("로또 구입이 완료되었습니다."); - - + // Console.print("계산이 완료되었습니다."); + lottoManager.generateLottos(); } } diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e..de213f160 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -1,9 +1,13 @@ +import { Console } from "@woowacourse/mission-utils"; + class Lotto { #numbers; constructor(numbers) { this.#validate(numbers); this.#numbers = numbers; + Console.print(this.#numbers); + // 구매한 로또 번호 출력은 누구 책임인가? } #validate(numbers) { @@ -13,6 +17,11 @@ class Lotto { } // TODO: 추가 기능 구현 + /* + getNumbers() { + return this.#numbers; + } + */ } export default Lotto; diff --git a/src/LottoManager.js b/src/LottoManager.js index 95528684d..4fd7fe0d2 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -1,4 +1,5 @@ import { Console, MissionUtils } from "@woowacourse/mission-utils"; +import Lotto from "./Lotto.js"; class LottoManager { constructor() { @@ -25,5 +26,24 @@ class LottoManager { const parsedPrice = Number(price); return !isNaN(parsedPrice) && parsedPrice % 1000 === 0 && parsedPrice > 0; } + + generateLottos() { + const printNums = this.spentMoney / 1000; + Console.print(`${printNums}개를 구매했습니다.`); + + for (let i = 0; i < printNums; i++) { + const combination = MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6).sort((a, b) => a - b); + this.lottos.push(new Lotto(combination)); + } + } + + /* + printLottos() { + for (const lotto of this.lottos) { + // Console.print(`[${lotto.getNumbers().join(", ")}]`); + } + } + */ + } export default LottoManager; \ No newline at end of file From 6fb30493fbfe2bffe8336ae11be8b837cd745c6a Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 20:49:32 +0900 Subject: [PATCH 07/13] =?UTF-8?q?feat(LottoManager.getWinNumbers):=20?= =?UTF-8?q?=EB=8B=B9=EC=B2=A8=EB=B2=88=ED=98=B8=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 3 +++ src/Lotto.js | 2 +- src/LottoManager.js | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/App.js b/src/App.js index ae15a6d5a..54b9db43d 100644 --- a/src/App.js +++ b/src/App.js @@ -8,6 +8,9 @@ class App { await lottoManager.getPurchaseAmout(); // Console.print("계산이 완료되었습니다."); lottoManager.generateLottos(); + + await lottoManager.getWinNumbers(); + } } diff --git a/src/Lotto.js b/src/Lotto.js index de213f160..bb3445465 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -7,7 +7,7 @@ class Lotto { this.#validate(numbers); this.#numbers = numbers; Console.print(this.#numbers); - // 구매한 로또 번호 출력은 누구 책임인가? + // 구매한 로또 번호 출력은 누구 책임인가? 이게 잘못됐을지도? 그러면 매니저에서 받아서 프린트 } #validate(numbers) { diff --git a/src/LottoManager.js b/src/LottoManager.js index 4fd7fe0d2..78079c779 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -5,6 +5,7 @@ class LottoManager { constructor() { this.lottos = []; this.spentMoney = 0; + this.winNumbers = []; } // 깊이가 좀 깊은가? @@ -13,6 +14,7 @@ class LottoManager { const input = await Console.readLineAsync("구입금액을 입력해 주세요.\n") try { if (!this.validateSpentMoney(input)) throw new Error("[ERROR] 구입 금액은 1000원 단위의 숫자로 입력해 주세요."); + // 여기서 if 쓰지말고, 그냥 validateSpentMoney에서 에러 던지기해도 잡힐것같은데? this.spentMoney = Number(input); break; } catch (e) { @@ -27,6 +29,7 @@ class LottoManager { return !isNaN(parsedPrice) && parsedPrice % 1000 === 0 && parsedPrice > 0; } + // 로또 생성 generateLottos() { const printNums = this.spentMoney / 1000; Console.print(`${printNums}개를 구매했습니다.`); @@ -36,6 +39,18 @@ class LottoManager { this.lottos.push(new Lotto(combination)); } } + // 당첨 번호 입력 받기 + async getWinNumbers() { + while (true) { + const input = await Console.readLineAsync("당첨 번호를 입력해 주세요.\n") + try { + // const numbers = input.split(",").map(Number) + } catch (e) { + + } + } + } + /* printLottos() { @@ -44,6 +59,6 @@ class LottoManager { } } */ - + } export default LottoManager; \ No newline at end of file From 866ed9ce0590dd4bfaade2ee1c1c4bed9f14a725 Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 21:14:43 +0900 Subject: [PATCH 08/13] =?UTF-8?q?feat(LottoManager.validateWinNumbers):=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EB=8B=B9=EC=B2=A8=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/LottoManager.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/LottoManager.js b/src/LottoManager.js index 78079c779..4bc51ac21 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -45,12 +45,28 @@ class LottoManager { const input = await Console.readLineAsync("당첨 번호를 입력해 주세요.\n") try { // const numbers = input.split(",").map(Number) + this.validateWinNumbers(input); + this.winNumbers = input.split(",").map(Number); + break; } catch (e) { - + Console.print(e.message); + continue; } } } + validateWinNumbers(numbers) { + const numTokens = numbers.split(",").map(Number); + const isLengthValid = numTokens.length === 6; + if (!isLengthValid) throw new Error("[ERROR] 당첨 번호는 6개여야 합니다."); + + const isAllinRange = numTokens.every(num => Number.isInteger(num) && num >= 1 && num <= 45); + if (!isAllinRange) throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + // if () throw new Error("[ERROR] 당첨 번호는 중복될 수 없습니다."); + + const isNotDuplicated = new Set(numTokens).size === numTokens.length; + if (!isNotDuplicated) throw new Error("[ERROR] 당첨 번호는 중복될 수 없습니다."); + } /* printLottos() { From a9887f313b5813e28f37dcd7d81a1d5729a544cf Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 21:43:38 +0900 Subject: [PATCH 09/13] =?UTF-8?q?feat:=20=EB=B3=B4=EB=84=88=EC=8A=A4=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/App.js | 4 ++++ src/LottoManager.js | 25 +++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9b4d792a9..63e4e2e0b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ - [X] 로또 구입 금액 입력 받기 - [X] 입력 구입 금액 유효성 검사하기 - [X] 1 ~ 45 숫자중 6개 중복없이 선택하기 -- [ ] 당첨 번호, 보너스 번호 입력받기 +- [X] 당첨 번호, 보너스 번호 입력받기 - [ ] 발행한 로또 수량 및 번호 출력하기 - [ ] 사용자가 구입한 로또번호, 당첨번호 비교하기 - [ ] 당첨 내역 및 수익률 계산하기 diff --git a/src/App.js b/src/App.js index 54b9db43d..649cefc12 100644 --- a/src/App.js +++ b/src/App.js @@ -10,7 +10,11 @@ class App { lottoManager.generateLottos(); await lottoManager.getWinNumbers(); + + await lottoManager.getBonusNumber(); + + } } diff --git a/src/LottoManager.js b/src/LottoManager.js index 4bc51ac21..24e3716a4 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -5,7 +5,8 @@ class LottoManager { constructor() { this.lottos = []; this.spentMoney = 0; - this.winNumbers = []; + this.winNumbers = null; + this.bonusNumber = null; } // 깊이가 좀 깊은가? @@ -26,7 +27,7 @@ class LottoManager { validateSpentMoney(price) { const parsedPrice = Number(price); - return !isNaN(parsedPrice) && parsedPrice % 1000 === 0 && parsedPrice > 0; + return Number.isInteger(parsedPrice) && parsedPrice % 1000 === 0 && parsedPrice > 0; } // 로또 생성 @@ -68,6 +69,26 @@ class LottoManager { if (!isNotDuplicated) throw new Error("[ERROR] 당첨 번호는 중복될 수 없습니다."); } + async getBonusNumber() { + while (true) { + const input = await Console.readLineAsync("보너스 번호를 입력해 주세요.\n") + try { + this.validateBonusNumber(input); + this.bonusNumber = Number(input); + break; + } catch (e) { + Console.print(e.message); + continue; + } + } + } + + validateBonusNumber(number) { + const num = Number(number); + + if (!Number.isInteger(num)) throw new Error("[ERROR] 보너스 번호는 정수여야 합니다."); + if (num < 1 || num > 45) throw new Error("[ERROR] 보너스 번호는 1~45 사이여야 합니다."); + } /* printLottos() { for (const lotto of this.lottos) { From 11dee8d60e44e1d0808de41dfd1823bde412b351 Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 22:44:49 +0900 Subject: [PATCH 10/13] =?UTF-8?q?feat:=20=EB=8B=B9=EC=B2=A8=20=EB=82=B4?= =?UTF-8?q?=EC=97=AD=20=EA=B3=84=EC=82=B0=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +-- src/App.js | 2 +- src/Lotto.js | 4 +-- src/LottoManager.js | 85 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 63e4e2e0b..970ab0d1a 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ - [X] 입력 구입 금액 유효성 검사하기 - [X] 1 ~ 45 숫자중 6개 중복없이 선택하기 - [X] 당첨 번호, 보너스 번호 입력받기 -- [ ] 발행한 로또 수량 및 번호 출력하기 -- [ ] 사용자가 구입한 로또번호, 당첨번호 비교하기 +- [X] 발행한 로또 수량 및 번호 출력하기 +- [X] 사용자가 구입한 로또번호, 당첨번호 비교하기 - [ ] 당첨 내역 및 수익률 계산하기 - [ ] 당첨 내역 및 수익률 출력하기 - [ ] 잘못된 값 입력에 Error발생시키기 diff --git a/src/App.js b/src/App.js index 649cefc12..7daa0c7f2 100644 --- a/src/App.js +++ b/src/App.js @@ -13,7 +13,7 @@ class App { await lottoManager.getBonusNumber(); - + lottoManager.getGameResult(); } } diff --git a/src/Lotto.js b/src/Lotto.js index bb3445465..9e952a06e 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -16,11 +16,11 @@ class Lotto { } } - // TODO: 추가 기능 구현 - /* getNumbers() { return this.#numbers; } + // TODO: 추가 기능 구현 + /* */ } diff --git a/src/LottoManager.js b/src/LottoManager.js index 24e3716a4..af0f3f8a5 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -2,11 +2,28 @@ import { Console, MissionUtils } from "@woowacourse/mission-utils"; import Lotto from "./Lotto.js"; class LottoManager { + + static winningPriceMap = { + "1등": 2000000000, + "2등": 30000000, + "3등": 1500000, + "4등": 50000, + "5등": 5000 + } + constructor() { this.lottos = []; this.spentMoney = 0; this.winNumbers = null; this.bonusNumber = null; + this.result = { + "1등": 0, + "2등": 0, + "3등": 0, + "4등": 0, + "5등": 0, + "winningPrice": 0, + } } // 깊이가 좀 깊은가? @@ -89,6 +106,74 @@ class LottoManager { if (!Number.isInteger(num)) throw new Error("[ERROR] 보너스 번호는 정수여야 합니다."); if (num < 1 || num > 45) throw new Error("[ERROR] 보너스 번호는 1~45 사이여야 합니다."); } + + getGameResult() { + // 최종적으로 몇게임이 몇등인지 알아야함 + for(let i = 0; i < this.lottos.length; i++) { + const curLotto = this.lottos[i]; + this.getLottoResult(curLotto); + } + Console.print(this.result) + this.getPriceResult(); + // Console.print(this.lottos[0].getNumbers()); + } + + getLottoResult(lotto) { + const lottoNumbers = lotto.getNumbers(); + let matchCount = 0; + let isBonusMatched = false; + + for (let number of lottoNumbers) { + if (this.winNumbers.includes(number)) matchCount++; + if (number === this.bonusNumber) isBonusMatched = true; + } + Console.print(`일치하는 번호 개수: ${matchCount}, 보너스 번호 일치: ${isBonusMatched}`); + this.updateResult(matchCount, isBonusMatched); + } + + updateResult(matchCount, isBonusMatched) { + Console.print(`Updating result for matchCount: ${matchCount}, isBonusMatched: ${isBonusMatched}`); + switch (Number(matchCount)) { + case 6: + Console.print(`1등 당첨!`); + this.result["1등"]++; + break; + case 5: + if (isBonusMatched) { + Console.print(`2등 당첨!`); + this.result["2등"]++; + } else { + Console.print(`3등 당첨!`); + this.result["3등"]++; + } + break; + case 4: + Console.print(`4등 당첨!`); + this.result["4등"]++; + break; + case 3: + Console.print(`5등 당첨!`); + this.result["5등"]++; + break; + default: + break; + } + } + + + getPriceResult() { + const entries = Object.entries(this.result); // [ ["1등", 0], ["2등", 2], ...] + const totalPrice = entries.reduce((acc, [key, value]) => { + if (key === "winningPrice") return acc; + Console.print(`key: ${key}, value: ${value}`); + Console.print(`winningPriceMap[key]: ${LottoManager.winningPriceMap[key]}`); + acc += LottoManager.winningPriceMap[key] * value; + return acc; + }, 0) + + this.result.winningPrice = Number(totalPrice); + Console.print(`총 당첨 금액은 ${totalPrice}원 입니다.`); + } /* printLottos() { for (const lotto of this.lottos) { From c3b295a05c0c89e79962ae30d9a544ffc354d570 Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 22:52:28 +0900 Subject: [PATCH 11/13] =?UTF-8?q?feat:=20=EB=8B=B9=EC=B2=A8=EB=82=B4?= =?UTF-8?q?=EC=97=AD=20=EB=B0=8F=20=EC=88=98=EC=9D=B5=EB=A5=A0=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- src/App.js | 2 +- src/LottoManager.js | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 970ab0d1a..8ef01d0ff 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ - [X] 당첨 번호, 보너스 번호 입력받기 - [X] 발행한 로또 수량 및 번호 출력하기 - [X] 사용자가 구입한 로또번호, 당첨번호 비교하기 -- [ ] 당첨 내역 및 수익률 계산하기 -- [ ] 당첨 내역 및 수익률 출력하기 -- [ ] 잘못된 값 입력에 Error발생시키기 +- [X] 당첨 내역 및 수익률 계산하기 +- [X] 당첨 내역 및 수익률 출력하기 +- [X] 잘못된 값 입력에 Error발생시키기 ## 프로그래밍 요구 사항 - [ ] 함수의 길이가 15라인을 넘어가지 않도록 구현한다. diff --git a/src/App.js b/src/App.js index 7daa0c7f2..c12c7b40e 100644 --- a/src/App.js +++ b/src/App.js @@ -14,7 +14,7 @@ class App { await lottoManager.getBonusNumber(); lottoManager.getGameResult(); - + lottoManager.printGameResult(); } } diff --git a/src/LottoManager.js b/src/LottoManager.js index af0f3f8a5..fe84631bb 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -24,6 +24,7 @@ class LottoManager { "5등": 0, "winningPrice": 0, } + this.winningRate = 0 } // 깊이가 좀 깊은가? @@ -105,6 +106,7 @@ class LottoManager { if (!Number.isInteger(num)) throw new Error("[ERROR] 보너스 번호는 정수여야 합니다."); if (num < 1 || num > 45) throw new Error("[ERROR] 보너스 번호는 1~45 사이여야 합니다."); + if (this.winNumbers.includes(num)) throw new Error("[ERROR] 보너스 번호는 기존 당첨 번호와 중복될 수 없습니다."); } getGameResult() { @@ -172,8 +174,20 @@ class LottoManager { }, 0) this.result.winningPrice = Number(totalPrice); + this.winningRate = (totalPrice / this.spentMoney) * 100; Console.print(`총 당첨 금액은 ${totalPrice}원 입니다.`); } + + printGameResult() { + Console.print("당첨 통계"); + Console.print("---"); + Console.print(`3개 일치 (5,000원) - ${this.result["5등"]}개`); + Console.print(`4개 일치 (50,000원) - ${this.result["4등"]}개`); + Console.print(`5개 일치 (1,500,000원) - ${this.result["3등"]}개`); + Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${this.result["2등"]}개`); + Console.print(`6개 일치 (2,000,000,000원) - ${this.result["1등"]}개`); + Console.print(`총 수익률은 ${this.winningRate.toFixed(2)}%입니다.`); + } /* printLottos() { for (const lotto of this.lottos) { From 5ef1c5a2d78e52e364544b54e9cc030b430f595f Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 23:16:31 +0900 Subject: [PATCH 12/13] =?UTF-8?q?refactor:=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=BD=98=EC=86=94=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++-- src/App.js | 6 --- src/Lotto.js | 3 -- src/LottoManager.js | 90 +++++++++++++++++---------------------------- 4 files changed, 38 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 8ef01d0ff..40c04cdb7 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ - [X] 잘못된 값 입력에 Error발생시키기 ## 프로그래밍 요구 사항 -- [ ] 함수의 길이가 15라인을 넘어가지 않도록 구현한다. -- [ ] else를 지양한다. +- [X] 함수의 길이가 15라인을 넘어가지 않도록 구현한다. +- [X] else를 지양한다. - [ ] 구현한 기능에 대한 단위 테스트를 작성한다. -- [ ] Lotto 클래스에 numbers 이외의 필드를 추가할 수 없다. -- [ ] numbers의 접근 제어자인 #은 변경할수 없다. \ No newline at end of file +- [X] Lotto 클래스에 numbers 이외의 필드를 추가할 수 없다. +- [X] numbers의 접근 제어자인 #은 변경할수 없다. \ No newline at end of file diff --git a/src/App.js b/src/App.js index c12c7b40e..9b39f96cf 100644 --- a/src/App.js +++ b/src/App.js @@ -1,18 +1,12 @@ -import { Console, MissionUtils } from "@woowacourse/mission-utils"; -import Lotto from "./Lotto.js"; import LottoManager from "./LottoManager.js"; class App { async run() { const lottoManager = new LottoManager(); await lottoManager.getPurchaseAmout(); - // Console.print("계산이 완료되었습니다."); lottoManager.generateLottos(); - await lottoManager.getWinNumbers(); - await lottoManager.getBonusNumber(); - lottoManager.getGameResult(); lottoManager.printGameResult(); } diff --git a/src/Lotto.js b/src/Lotto.js index 9e952a06e..314c1a60d 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -19,9 +19,6 @@ class Lotto { getNumbers() { return this.#numbers; } - // TODO: 추가 기능 구현 - /* - */ } export default Lotto; diff --git a/src/LottoManager.js b/src/LottoManager.js index fe84631bb..83d7edab5 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -2,7 +2,6 @@ import { Console, MissionUtils } from "@woowacourse/mission-utils"; import Lotto from "./Lotto.js"; class LottoManager { - static winningPriceMap = { "1등": 2000000000, "2등": 30000000, @@ -10,30 +9,31 @@ class LottoManager { "4등": 50000, "5등": 5000 } - + static result = { + "1등": 0, + "2등": 0, + "3등": 0, + "4등": 0, + "5등": 0, + "winningPrice": 0, + } + constructor() { this.lottos = []; this.spentMoney = 0; this.winNumbers = null; this.bonusNumber = null; - this.result = { - "1등": 0, - "2등": 0, - "3등": 0, - "4등": 0, - "5등": 0, - "winningPrice": 0, - } + this.result = { ...LottoManager.result }; this.winningRate = 0 } // 깊이가 좀 깊은가? + // 구입 금액 입력 받기 async getPurchaseAmout() { while (true) { const input = await Console.readLineAsync("구입금액을 입력해 주세요.\n") try { - if (!this.validateSpentMoney(input)) throw new Error("[ERROR] 구입 금액은 1000원 단위의 숫자로 입력해 주세요."); - // 여기서 if 쓰지말고, 그냥 validateSpentMoney에서 에러 던지기해도 잡힐것같은데? + this.validateSpentMoney(input); this.spentMoney = Number(input); break; } catch (e) { @@ -43,9 +43,10 @@ class LottoManager { } } + // 구입 금액 유효성 검사 validateSpentMoney(price) { const parsedPrice = Number(price); - return Number.isInteger(parsedPrice) && parsedPrice % 1000 === 0 && parsedPrice > 0; + if (!Number.isInteger(parsedPrice) || parsedPrice % 1000 !== 0 || parsedPrice <= 0) throw new Error("[ERROR] 구입 금액은 1000원 단위의 숫자로 입력해 주세요."); } // 로또 생성 @@ -63,7 +64,6 @@ class LottoManager { while (true) { const input = await Console.readLineAsync("당첨 번호를 입력해 주세요.\n") try { - // const numbers = input.split(",").map(Number) this.validateWinNumbers(input); this.winNumbers = input.split(",").map(Number); break; @@ -74,6 +74,7 @@ class LottoManager { } } + // 당첨 번호 유효성 검사 validateWinNumbers(numbers) { const numTokens = numbers.split(",").map(Number); const isLengthValid = numTokens.length === 6; @@ -81,12 +82,12 @@ class LottoManager { const isAllinRange = numTokens.every(num => Number.isInteger(num) && num >= 1 && num <= 45); if (!isAllinRange) throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); - // if () throw new Error("[ERROR] 당첨 번호는 중복될 수 없습니다."); const isNotDuplicated = new Set(numTokens).size === numTokens.length; if (!isNotDuplicated) throw new Error("[ERROR] 당첨 번호는 중복될 수 없습니다."); } + // 보너스 번호 입력 받기 async getBonusNumber() { while (true) { const input = await Console.readLineAsync("보너스 번호를 입력해 주세요.\n") @@ -101,6 +102,7 @@ class LottoManager { } } + // 보너스 번호 유효성 검사 validateBonusNumber(number) { const num = Number(number); @@ -109,17 +111,17 @@ class LottoManager { if (this.winNumbers.includes(num)) throw new Error("[ERROR] 보너스 번호는 기존 당첨 번호와 중복될 수 없습니다."); } + // 게임 결과 계산 getGameResult() { // 최종적으로 몇게임이 몇등인지 알아야함 for(let i = 0; i < this.lottos.length; i++) { const curLotto = this.lottos[i]; - this.getLottoResult(curLotto); + this.getLottoResult(curLotto); // 한 로또의 결과 계산 } - Console.print(this.result) this.getPriceResult(); - // Console.print(this.lottos[0].getNumbers()); } + // 한 로또의 결과 계산 getLottoResult(lotto) { const lottoNumbers = lotto.getNumbers(); let matchCount = 0; @@ -129,55 +131,39 @@ class LottoManager { if (this.winNumbers.includes(number)) matchCount++; if (number === this.bonusNumber) isBonusMatched = true; } - Console.print(`일치하는 번호 개수: ${matchCount}, 보너스 번호 일치: ${isBonusMatched}`); this.updateResult(matchCount, isBonusMatched); } + // 결과 업데이트 updateResult(matchCount, isBonusMatched) { - Console.print(`Updating result for matchCount: ${matchCount}, isBonusMatched: ${isBonusMatched}`); - switch (Number(matchCount)) { - case 6: - Console.print(`1등 당첨!`); - this.result["1등"]++; - break; - case 5: - if (isBonusMatched) { - Console.print(`2등 당첨!`); - this.result["2등"]++; - } else { - Console.print(`3등 당첨!`); - this.result["3등"]++; - } - break; - case 4: - Console.print(`4등 당첨!`); - this.result["4등"]++; - break; - case 3: - Console.print(`5등 당첨!`); - this.result["5등"]++; - break; - default: - break; - } + const rankMap = { + 6: "1등", + 5: isBonusMatched ? "2등" : "3등", + 4: "4등", + 3: "5등" + }; + + const rank = rankMap[matchCount]; + if (!rank) return; // 낙첨 + + this.result[rank]++; } + // 상금 결과 계산 getPriceResult() { const entries = Object.entries(this.result); // [ ["1등", 0], ["2등", 2], ...] const totalPrice = entries.reduce((acc, [key, value]) => { if (key === "winningPrice") return acc; - Console.print(`key: ${key}, value: ${value}`); - Console.print(`winningPriceMap[key]: ${LottoManager.winningPriceMap[key]}`); acc += LottoManager.winningPriceMap[key] * value; return acc; }, 0) this.result.winningPrice = Number(totalPrice); this.winningRate = (totalPrice / this.spentMoney) * 100; - Console.print(`총 당첨 금액은 ${totalPrice}원 입니다.`); } + // 게임 결과 출력 printGameResult() { Console.print("당첨 통계"); Console.print("---"); @@ -188,13 +174,5 @@ class LottoManager { Console.print(`6개 일치 (2,000,000,000원) - ${this.result["1등"]}개`); Console.print(`총 수익률은 ${this.winningRate.toFixed(2)}%입니다.`); } - /* - printLottos() { - for (const lotto of this.lottos) { - // Console.print(`[${lotto.getNumbers().join(", ")}]`); - } - } - */ - } export default LottoManager; \ No newline at end of file From 3cd11fede7553b77d8b28aa3ff14377de872bd39 Mon Sep 17 00:00:00 2001 From: Yuno Kim Date: Mon, 3 Nov 2025 23:31:32 +0900 Subject: [PATCH 13/13] =?UTF-8?q?test:=20npm=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=ED=86=B5=EA=B3=BC=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Lotto.js | 6 +++++- src/LottoManager.js | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Lotto.js b/src/Lotto.js index 314c1a60d..adf605982 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -6,7 +6,7 @@ class Lotto { constructor(numbers) { this.#validate(numbers); this.#numbers = numbers; - Console.print(this.#numbers); + Console.print(`[${this.#numbers.join(", ")}]`); // 구매한 로또 번호 출력은 누구 책임인가? 이게 잘못됐을지도? 그러면 매니저에서 받아서 프린트 } @@ -14,6 +14,10 @@ class Lotto { if (numbers.length !== 6) { throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); } + const numberSet = new Set(numbers); + if (numberSet.size !== numbers.length) { + throw new Error("[ERROR] 로또 번호는 중복될 수 없습니다."); + } } getNumbers() { diff --git a/src/LottoManager.js b/src/LottoManager.js index 83d7edab5..233745d05 100644 --- a/src/LottoManager.js +++ b/src/LottoManager.js @@ -17,7 +17,7 @@ class LottoManager { "5등": 0, "winningPrice": 0, } - + constructor() { this.lottos = []; this.spentMoney = 0; @@ -172,7 +172,7 @@ class LottoManager { Console.print(`5개 일치 (1,500,000원) - ${this.result["3등"]}개`); Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${this.result["2등"]}개`); Console.print(`6개 일치 (2,000,000,000원) - ${this.result["1등"]}개`); - Console.print(`총 수익률은 ${this.winningRate.toFixed(2)}%입니다.`); + Console.print(`총 수익률은 ${Number(this.winningRate.toFixed(2))}%입니다.`); } } export default LottoManager; \ No newline at end of file