From 957581b14133512420bc1653d7cca3b0a1c43b70 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 18:24:34 +0900 Subject: [PATCH 01/18] =?UTF-8?q?docs(README):=20=EA=B0=9C=EC=9A=94=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 15bb106b5..01ef50619 100644 --- a/README.md +++ b/README.md @@ -1 +1,45 @@ -# javascript-lotto-precourse +## 1️⃣ 과제 개요 + +**우아한 테크코스 프리코스 3주차 과제** + +**과제명 : 로또** + +**기간 : 10.28 ~ 11.03 (3주차)** + +**작성자 : 윤돌** + +
+ +## 2️⃣ 기능 목록 + +**(0) 기본 구조 세팅** + +**(1) 로또 구입 금액 입력 기능 구현** + +**(2) 구입 금액 검증 로직 구현** + +**(3) 로또 발행 기능 구현** + +**(4) Lotto 객체 생성 및 번호 검증 로직 구현** + +**(5) 발행된 로또 번호 출력 기능 구현** + +**(6) 당첨 번호 입력 기능 구현** + +**(7) 당첨 번호 검증 로직 구현** + +**(8) 보너스 번호 입력 기능 구현** + +**(9) 보너스 번호 검증 기능 구현** + +**(10) 규칙 및 상금 정의** + +**(11) 당첨 결과 계산 기능 구현** + +**(12) 결과 구현 및 출력 (결과 집계 및 수익률 계산)** + +**(13) 단위 테스트 작성** + +**(14) 통합 테스트 확인** + +
From 193be6a72afb6351986a9822773ee802d96edefe Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 18:28:45 +0900 Subject: [PATCH 02/18] =?UTF-8?q?chore:=20=EA=B8=B0=EB=B3=B8=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/{ => model}/Lotto.js | 0 src/model/LottoBundle.js | 0 src/model/Rank.js | 0 src/model/Result.js | 0 src/service/LottoJudge.js | 0 src/service/LottoMachine.js | 0 src/view/InputView.js | 0 src/view/OutputView.js | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename src/{ => model}/Lotto.js (100%) create mode 100644 src/model/LottoBundle.js create mode 100644 src/model/Rank.js create mode 100644 src/model/Result.js create mode 100644 src/service/LottoJudge.js create mode 100644 src/service/LottoMachine.js create mode 100644 src/view/InputView.js create mode 100644 src/view/OutputView.js diff --git a/src/Lotto.js b/src/model/Lotto.js similarity index 100% rename from src/Lotto.js rename to src/model/Lotto.js diff --git a/src/model/LottoBundle.js b/src/model/LottoBundle.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/model/Rank.js b/src/model/Rank.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/model/Result.js b/src/model/Result.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/service/LottoJudge.js b/src/service/LottoJudge.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/service/LottoMachine.js b/src/service/LottoMachine.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/view/InputView.js b/src/view/InputView.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/view/OutputView.js b/src/view/OutputView.js new file mode 100644 index 000000000..e69de29bb From 9f5fb8b0b4f71c16b4c7e37374693e4fd2815551 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 18:36:03 +0900 Subject: [PATCH 03/18] =?UTF-8?q?feat(view):=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EA=B5=AC=EC=9E=85=20=EA=B8=88=EC=95=A1=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - InputView에서 사용자로부터 구입 금액을 입력받는 기능 추가 --- src/App.js | 6 +++++- src/view/InputView.js | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 091aa0a5d..8e5465e3a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,9 @@ +import InputView from "./view/InputView.js"; + class App { - async run() {} + async run() { + const purchaseAmount = await InputView.readPurchaseAmount(); + } } export default App; diff --git a/src/view/InputView.js b/src/view/InputView.js index e69de29bb..d6f66e342 100644 --- a/src/view/InputView.js +++ b/src/view/InputView.js @@ -0,0 +1,13 @@ +import { Console } from "@woowacourse/mission-utils"; + +const InputView = { + async readPurchaseAmount() { + const purchaseAmount = await Console.readLineAsync( + "구입금액을 입력해 주세요.\n" + ); + + return purchaseAmount; + }, +}; + +export default InputView; From a51257978680f7fdc243aed923f639c521b26713 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 18:47:20 +0900 Subject: [PATCH 04/18] =?UTF-8?q?feat(util):=20=EA=B5=AC=EC=9E=85=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 검증을 위한 유틸 함수 객체인 Validator 구현 - 숫자가 아닐 경우, 0 이하일 경우, 1000단위가 아닐 경우 예외 처리 - readPurchaseAmount에서 받은 입력값 검증 - README 반영 --- README.md | 4 ++++ src/util/Validator.js | 21 +++++++++++++++++++++ src/view/InputView.js | 5 ++++- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/util/Validator.js diff --git a/README.md b/README.md index 01ef50619..ba4dc9ec4 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ **(2) 구입 금액 검증 로직 구현** +- 숫자가 아닌 경우 예외처리 +- 0보다 작거나 같을 경우 예외처리 +- 1000 단위로 떨어지지 않을 경우 예외처리 + **(3) 로또 발행 기능 구현** **(4) Lotto 객체 생성 및 번호 검증 로직 구현** diff --git a/src/util/Validator.js b/src/util/Validator.js new file mode 100644 index 000000000..ca9b0d3f3 --- /dev/null +++ b/src/util/Validator.js @@ -0,0 +1,21 @@ +const Validator = { + validatePurchaseAmount(input) { + const amount = Number(input); + + if (isNaN(amount)) { + throw new Error("[ERROR] 구입 금액은 숫자여야 합니다."); + } + + if (amount <= 0) { + throw new Error("[ERROR] 구입 금액은 0보다 커야 합니다."); + } + + if (amount % 1000 !== 0) { + throw new Error("[ERROR] 구입 금액은 1,000원 단위로 입력해야 합니다."); + } + + return amount; + }, +}; + +export default Validator; diff --git a/src/view/InputView.js b/src/view/InputView.js index d6f66e342..f812a73f2 100644 --- a/src/view/InputView.js +++ b/src/view/InputView.js @@ -1,4 +1,5 @@ import { Console } from "@woowacourse/mission-utils"; +import Validator from "../util/Validator.js"; const InputView = { async readPurchaseAmount() { @@ -6,7 +7,9 @@ const InputView = { "구입금액을 입력해 주세요.\n" ); - return purchaseAmount; + Validator.validatePurchaseAmount(purchaseAmount); + + return Number(purchaseAmount); }, }; From 11efb6793c2851f706638d25596826455fe9e15d Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 19:37:02 +0900 Subject: [PATCH 05/18] =?UTF-8?q?feat(service):=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EB=B0=9C=ED=96=89=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 구입 금액을 바탕으로 발행할 로또 개수를 계산 - 각 로또 인스턴스를 랜덤한 번호로 생성하는 LottoMachine 클래스 구현 - 발행된 로또 인스턴스를 LottoBundle에 저장하여 반환 --- src/App.js | 2 ++ src/service/LottoMachine.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/App.js b/src/App.js index 8e5465e3a..43a3f7998 100644 --- a/src/App.js +++ b/src/App.js @@ -1,8 +1,10 @@ +import LottoMachine from "./service/LottoMachine.js"; import InputView from "./view/InputView.js"; class App { async run() { const purchaseAmount = await InputView.readPurchaseAmount(); + const lottoMachine = new LottoMachine(purchaseAmount); } } diff --git a/src/service/LottoMachine.js b/src/service/LottoMachine.js index e69de29bb..01b2ba4ba 100644 --- a/src/service/LottoMachine.js +++ b/src/service/LottoMachine.js @@ -0,0 +1,32 @@ +import { MissionUtils } from "@woowacourse/mission-utils"; +import Lotto from "../model/Lotto.js"; + +class LottoMachine { + #lottoBundle; + + constructor(purchaseAmount) { + this.lottoCount = purchaseAmount / 1000; + this.#lottoBundle = this.#generateLottos(); + } + + #generateLottos() { + const lottoBundle = []; + for (let i = 0; i < this.lottoCount; i++) { + const numbers = this.#generateRandomNumbers(); + lottoBundle.push(new Lotto(numbers)); + } + + return lottoBundle; + } + + #generateRandomNumbers() { + const numbers = MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6); + return numbers.sort((a, b) => a - b); + } + + getLottos() { + return this.#lottoBundle; + } +} + +export default LottoMachine; From 293dfeb69b19477be107111714655034178da716 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 19:40:18 +0900 Subject: [PATCH 06/18] =?UTF-8?q?docs(README):=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 중복된 기능 목록 제거 후 새로운 클래스 연결 내용으로 수정 -(4) 저장 및 조회 가능한 LottoBundle 클래스 생성 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba4dc9ec4..7fe3845ba 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ **(3) 로또 발행 기능 구현** -**(4) Lotto 객체 생성 및 번호 검증 로직 구현** +**(4) 저장 및 조회 가능한 LottoBundle 클래스 생성** **(5) 발행된 로또 번호 출력 기능 구현** From 211b887b266873c9f6f74ecda94f023f3340cb33 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 19:48:04 +0900 Subject: [PATCH 07/18] =?UTF-8?q?feat(model):=20=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A1=B0=ED=9A=8C=20=EA=B0=80=EB=8A=A5=ED=95=9C=20?= =?UTF-8?q?LottoBundle=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 발행된 로또 인스턴스를 묶어 관리하는 LottoBundle 클래스 구현 - 개수 조회, 전체 조회, 순회 기능 추가 - 내부 로또 묶음 데이터를 #을 사용하여 보호 --- src/App.js | 2 ++ src/model/LottoBundle.js | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/App.js b/src/App.js index 43a3f7998..ae7436acd 100644 --- a/src/App.js +++ b/src/App.js @@ -1,3 +1,4 @@ +import LottoBundle from "./model/LottoBundle.js"; import LottoMachine from "./service/LottoMachine.js"; import InputView from "./view/InputView.js"; @@ -5,6 +6,7 @@ class App { async run() { const purchaseAmount = await InputView.readPurchaseAmount(); const lottoMachine = new LottoMachine(purchaseAmount); + const lottoBundle = new LottoBundle(lottoMachine.getLottos()); } } diff --git a/src/model/LottoBundle.js b/src/model/LottoBundle.js index e69de29bb..5e2019027 100644 --- a/src/model/LottoBundle.js +++ b/src/model/LottoBundle.js @@ -0,0 +1,21 @@ +class LottoBundle { + #lottoBundle; + + constructor(lottoBundle) { + this.#lottoBundle = lottoBundle; + } + + size() { + return this.#lottoBundle.length; + } + + getAll() { + return [...this.#lottoBundle]; + } + + forEach(callback) { + this.#lottoBundle.forEach(callback); + } +} + +export default LottoBundle; From d88bde13ca82a80ff76b83a292da345277c04a8c Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 20:00:18 +0900 Subject: [PATCH 08/18] =?UTF-8?q?feat(view):=20=EB=B0=9C=ED=96=89=EB=90=9C?= =?UTF-8?q?=20=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OutputView에 lottoBundle을 출력하는 printLottoBundle 메서드 구현 - 로또 개수 및 각 로또 번호 출력 - Lotto 클래스에 번호를 반환하는 getNumbers 메서드 추가 --- src/App.js | 3 +++ src/model/Lotto.js | 3 +++ src/view/OutputView.js | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/src/App.js b/src/App.js index ae7436acd..a789b9400 100644 --- a/src/App.js +++ b/src/App.js @@ -1,12 +1,15 @@ import LottoBundle from "./model/LottoBundle.js"; import LottoMachine from "./service/LottoMachine.js"; import InputView from "./view/InputView.js"; +import OutputView from "./view/OutputView.js"; class App { async run() { const purchaseAmount = await InputView.readPurchaseAmount(); const lottoMachine = new LottoMachine(purchaseAmount); const lottoBundle = new LottoBundle(lottoMachine.getLottos()); + + OutputView.printLottoBundle(lottoBundle); } } diff --git a/src/model/Lotto.js b/src/model/Lotto.js index cb0b1527e..a73c5c6c5 100644 --- a/src/model/Lotto.js +++ b/src/model/Lotto.js @@ -13,6 +13,9 @@ class Lotto { } // TODO: 추가 기능 구현 + getNumbers() { + return this.#numbers; + } } export default Lotto; diff --git a/src/view/OutputView.js b/src/view/OutputView.js index e69de29bb..06bf06c29 100644 --- a/src/view/OutputView.js +++ b/src/view/OutputView.js @@ -0,0 +1,19 @@ +import { Console } from "@woowacourse/mission-utils"; + +const OutputView = { + printLottoBundle(lottoBundle) { + this.printLineBreak(); + + Console.print(`${lottoBundle.size()}개를 구매했습니다.`); + + lottoBundle.forEach((lotto) => Console.print(lotto.getNumbers())); + + this.printLineBreak(); + }, + + printLineBreak() { + Console.print(""); + }, +}; + +export default OutputView; From da427db0cf238b0d0974da889e083f2029f3fae6 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 20:18:17 +0900 Subject: [PATCH 09/18] =?UTF-8?q?feat(view):=20=EB=8B=B9=EC=B2=A8=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - InputView에서 당첨 번호 입력 받는 readWinningNumbers() 구현 --- src/App.js | 2 ++ src/view/InputView.js | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/App.js b/src/App.js index a789b9400..11c851915 100644 --- a/src/App.js +++ b/src/App.js @@ -10,6 +10,8 @@ class App { const lottoBundle = new LottoBundle(lottoMachine.getLottos()); OutputView.printLottoBundle(lottoBundle); + + const winningNumbers = await InputView.readWinningNumbers(); } } diff --git a/src/view/InputView.js b/src/view/InputView.js index f812a73f2..7e060b26a 100644 --- a/src/view/InputView.js +++ b/src/view/InputView.js @@ -11,6 +11,17 @@ const InputView = { return Number(purchaseAmount); }, + + async readWinningNumbers() { + const inputNumbers = await Console.readLineAsync( + "당첨 번호를 입력해 주세요.\n" + ); + + const numbers = inputNumbers.split(","); + const winningNumbers = numbers.map((num) => Number(num.trim())); + + return winningNumbers; + }, }; export default InputView; From 66904008bd48ab701642c755a27d71a20fd98650 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 20:27:29 +0900 Subject: [PATCH 10/18] =?UTF-8?q?feat(util):=20=EB=8B=B9=EC=B2=A8=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Validator에서 당첨 번호를 검증하는 validateWinningNumbers() 구현 - 6개가 아닐 경우, 중복될 경우, 숫자가 아닐 경우, 1~45 사이가 아닐 경우 예외 처리 - readWinningNumbers에서 받은 입력값 검증 - README 예외 내용 추가 --- README.md | 5 +++++ src/util/Validator.js | 21 +++++++++++++++++++++ src/view/InputView.js | 2 ++ 3 files changed, 28 insertions(+) diff --git a/README.md b/README.md index 7fe3845ba..75ed2e749 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,11 @@ **(7) 당첨 번호 검증 로직 구현** +- 6개가 아닌 경우 예외처리 +- 중복될 경우 예외처리 +- 숫자가 아닐 경우 예외처리 +- 1~45 사이가 아닐 경우 예외처리 + **(8) 보너스 번호 입력 기능 구현** **(9) 보너스 번호 검증 기능 구현** diff --git a/src/util/Validator.js b/src/util/Validator.js index ca9b0d3f3..4129fbb8f 100644 --- a/src/util/Validator.js +++ b/src/util/Validator.js @@ -16,6 +16,27 @@ const Validator = { return amount; }, + + validateWinningNumbers(winningNumbers) { + if (winningNumbers.length !== 6) { + throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); + } + + const uniqueNumbers = new Set(winningNumbers); + if (uniqueNumbers.size !== winningNumbers.length) { + throw new Error("[ERROR] 로또 번호는 중복될 수 없습니다."); + } + + winningNumbers.forEach((num) => { + if (isNaN(num)) { + throw new Error("[ERROR] 로또 번호는 숫자만 입력해야 합니다."); + } + + if (num < 1 || num > 45) { + throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + } + }); + }, }; export default Validator; diff --git a/src/view/InputView.js b/src/view/InputView.js index 7e060b26a..0858aa139 100644 --- a/src/view/InputView.js +++ b/src/view/InputView.js @@ -20,6 +20,8 @@ const InputView = { const numbers = inputNumbers.split(","); const winningNumbers = numbers.map((num) => Number(num.trim())); + Validator.validateWinningNumbers(winningNumbers); + return winningNumbers; }, }; From eb8ff7965f1d7c3a3918e17efa9432866558504a Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 20:38:05 +0900 Subject: [PATCH 11/18] =?UTF-8?q?feat(view):=20=EB=B3=B4=EB=84=88=EC=8A=A4?= =?UTF-8?q?=20=EB=B2=88=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InputView에서 보너스 번호 입력 받는 readBonusNumber() 구현 --- src/App.js | 2 ++ src/view/InputView.js | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/App.js b/src/App.js index 11c851915..b0af8e529 100644 --- a/src/App.js +++ b/src/App.js @@ -12,6 +12,8 @@ class App { OutputView.printLottoBundle(lottoBundle); const winningNumbers = await InputView.readWinningNumbers(); + OutputView.printLineBreak(); + const bonusNumber = await InputView.readBonusNumber(); } } diff --git a/src/view/InputView.js b/src/view/InputView.js index 0858aa139..00ac56a37 100644 --- a/src/view/InputView.js +++ b/src/view/InputView.js @@ -24,6 +24,14 @@ const InputView = { return winningNumbers; }, + + async readBonusNumber() { + const bonusNumber = await Console.readLineAsync( + "보너스 번호를 입력해 주세요.\n" + ); + + return Number(bonusNumber); + }, }; export default InputView; From 6e0bdbefefd753e1ff25faefb4f2af4a4d3b9e42 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 20:43:49 +0900 Subject: [PATCH 12/18] =?UTF-8?q?feat(util):=20=EB=B3=B4=EB=84=88=EC=8A=A4?= =?UTF-8?q?=20=EB=B2=88=ED=98=B8=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Validator에서 보너스 번호를 검증하는 validateBonusNumber() 구현 - 숫자가 아닐 경우, 1~45 사이가 아닐 경우 예외 처리 - readBonusNumber에서 받은 입력값 검증 - README 예외 내용 추가 --- README.md | 3 +++ src/util/Validator.js | 12 ++++++++++++ src/view/InputView.js | 2 ++ 3 files changed, 17 insertions(+) diff --git a/README.md b/README.md index 75ed2e749..1768d3563 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,9 @@ **(9) 보너스 번호 검증 기능 구현** +- 숫자가 아닐 경우 예외처리 +- 1~45 사이가 아닐 경우 예외처리 + **(10) 규칙 및 상금 정의** **(11) 당첨 결과 계산 기능 구현** diff --git a/src/util/Validator.js b/src/util/Validator.js index 4129fbb8f..a792b6396 100644 --- a/src/util/Validator.js +++ b/src/util/Validator.js @@ -37,6 +37,18 @@ const Validator = { } }); }, + + validateBonusNumber(bonusNumber) { + const number = Number(bonusNumber); + + if (isNaN(number)) { + throw new Error("[ERROR] 보너스 번호는 숫자여야 합니다."); + } + + if (number < 1 || number > 45) { + throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + } + }, }; export default Validator; diff --git a/src/view/InputView.js b/src/view/InputView.js index 00ac56a37..87239581d 100644 --- a/src/view/InputView.js +++ b/src/view/InputView.js @@ -30,6 +30,8 @@ const InputView = { "보너스 번호를 입력해 주세요.\n" ); + Validator.validateBonusNumber(bonusNumber); + return Number(bonusNumber); }, }; From e3cb43470585bd43495566921446a471ee52f7f5 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 20:56:41 +0900 Subject: [PATCH 13/18] =?UTF-8?q?feat(model):=20=EA=B7=9C=EC=B9=99=20?= =?UTF-8?q?=EB=B0=8F=20=EC=83=81=EA=B8=88=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 일치 개수와 보너스 여부를 기반으로 등수와 상금을 반환하는 getRank() 구현 - 숫자 값을 하드코딩 하지 않고, 의미있는 이름 사용 --- src/model/Rank.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/model/Rank.js b/src/model/Rank.js index e69de29bb..40bfc147e 100644 --- a/src/model/Rank.js +++ b/src/model/Rank.js @@ -0,0 +1,30 @@ +export const RANKS = { + FIRST: 1, + SECOND: 2, + THIRD: 3, + FOURTH: 4, + FIFTH: 5, +}; + +export const PRIZES = { + [RANKS.FIRST]: 2000000000, + [RANKS.SECOND]: 30000000, + [RANKS.THIRD]: 1500000, + [RANKS.FOURTH]: 50000, + [RANKS.FIFTH]: 5000, +}; + +export function getRank(matchCount, hasBonus) { + if (matchCount === 6) + return { rank: RANKS.FIRST, prize: PRIZES[RANKS.FIRST] }; + if (matchCount === 5 && hasBonus) + return { rank: RANKS.SECOND, prize: PRIZES[RANKS.SECOND] }; + if (matchCount === 5) + return { rank: RANKS.THIRD, prize: PRIZES[RANKS.THIRD] }; + if (matchCount === 4) + return { rank: RANKS.FOURTH, prize: PRIZES[RANKS.FOURTH] }; + if (matchCount === 3) + return { rank: RANKS.FIFTH, prize: PRIZES[RANKS.FIFTH] }; + + return null; +} From eea03c0ff55a6eff3b94f9212458f09c67f5181e Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 21:07:51 +0900 Subject: [PATCH 14/18] =?UTF-8?q?feat(service):=20=EB=8B=B9=EC=B2=A8=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LottoJudge에서 당첨 번호, 보너스 번호, 로또 번호를 기반으로 결과를 반환하는 judge() 메소드 구현 - 일치 개수와 보너스 여부에 따라 getRank() 결과 반환 --- src/App.js | 3 +++ src/service/LottoJudge.js | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/App.js b/src/App.js index b0af8e529..4cb281617 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,5 @@ import LottoBundle from "./model/LottoBundle.js"; +import LottoJudge from "./service/LottoJudge.js"; import LottoMachine from "./service/LottoMachine.js"; import InputView from "./view/InputView.js"; import OutputView from "./view/OutputView.js"; @@ -14,6 +15,8 @@ class App { const winningNumbers = await InputView.readWinningNumbers(); OutputView.printLineBreak(); const bonusNumber = await InputView.readBonusNumber(); + + const lottoJudge = new LottoJudge(winningNumbers, bonusNumber); } } diff --git a/src/service/LottoJudge.js b/src/service/LottoJudge.js index e69de29bb..a2c7fa12c 100644 --- a/src/service/LottoJudge.js +++ b/src/service/LottoJudge.js @@ -0,0 +1,18 @@ +class LottoJudge { + constructor(winningNumbers, bonusNumber) { + this.winningNumbers = winningNumbers; + this.bonusNumber = bonusNumber; + } + + judge(lotto) { + const numbers = lotto.getNumbers(); + const matchCount = numbers.filter((num) => + this.winningNumbers.includes(num) + ).length; + const hasBonus = numbers.includes(this.bonusNumber); + + return getRank(matchCount, hasBonus); + } +} + +export default LottoJudge; From c3559b96416ff15810eb53b4e400aad1c6d17536 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 21:18:42 +0900 Subject: [PATCH 15/18] =?UTF-8?q?feat(model):=20=EA=B2=B0=EA=B3=BC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(=EA=B2=B0=EA=B3=BC=20=EC=A7=91=EA=B3=84?= =?UTF-8?q?=20=EB=B0=8F=20=EC=88=98=EC=9D=B5=EB=A5=A0=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 각 로또별 등수 결과를 집계하여 변수(rankCounts)에 저장 - 등수별 상금과 당첨 개수를 곱해 총 상금 계산 - 총 상금을 구입 금액으로 나누어 수익률 계산 - 결과 출력을 위한 getter 메서드 추가 --- README.md | 8 +++++--- src/model/Result.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1768d3563..9b3819182 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,12 @@ **(11) 당첨 결과 계산 기능 구현** -**(12) 결과 구현 및 출력 (결과 집계 및 수익률 계산)** +**(12) 결과 구현(결과 집계 및 수익률 계산)** -**(13) 단위 테스트 작성** +**(13) 결과 출력** -**(14) 통합 테스트 확인** +**(14) 단위 테스트 작성** + +**(15) 통합 테스트 확인**
diff --git a/src/model/Result.js b/src/model/Result.js index e69de29bb..1f7f5d135 100644 --- a/src/model/Result.js +++ b/src/model/Result.js @@ -0,0 +1,36 @@ +import { PRIZES } from "./Rank.js"; + +class Result { + constructor() { + this.rankCounts = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 }; + } + + addRank(rank) { + if (rank) this.rankCounts[rank.rank]++; + } + + calculate(lottoBundle, lottoJudge) { + lottoBundle.forEach((lotto) => { + const rank = lottoJudge.judge(lotto); + this.addRank(rank); + }); + } + + getTotalPrize() { + return Object.entries(this.rankCounts).reduce((total, [rank, count]) => { + const prize = PRIZES[rank] ?? 0; + return total + prize * count; + }, 0); + } + + getProfitRate(purchaseAmount) { + const totalPrize = this.getTotalPrize(); + return ((totalPrize / purchaseAmount) * 100).toFixed(1); + } + + getRankCounts() { + return this.rankCounts; + } +} + +export default Result; From 661fec12b430dc7a867feb2bf403cc854e74c0e4 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 21:42:25 +0900 Subject: [PATCH 16/18] =?UTF-8?q?feat(view):=20=EA=B2=B0=EA=B3=BC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OutputView에서 결과를 통합한 내용을 출력하는 printResult() 구현 - OutputView에서 수익률을 출력하는 printProfitRate() 구현 --- src/App.js | 9 +++++++++ src/service/LottoJudge.js | 2 ++ src/view/OutputView.js | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/src/App.js b/src/App.js index 4cb281617..c589682fe 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,5 @@ import LottoBundle from "./model/LottoBundle.js"; +import Result from "./model/Result.js"; import LottoJudge from "./service/LottoJudge.js"; import LottoMachine from "./service/LottoMachine.js"; import InputView from "./view/InputView.js"; @@ -17,6 +18,14 @@ class App { const bonusNumber = await InputView.readBonusNumber(); const lottoJudge = new LottoJudge(winningNumbers, bonusNumber); + const result = new Result(); + + result.calculate(lottoBundle, lottoJudge); + const rankCounts = result.getRankCounts(); + const profitRate = result.getProfitRate(purchaseAmount); + + OutputView.printResult(rankCounts); + OutputView.printProfitRate(profitRate); } } diff --git a/src/service/LottoJudge.js b/src/service/LottoJudge.js index a2c7fa12c..ea98ae510 100644 --- a/src/service/LottoJudge.js +++ b/src/service/LottoJudge.js @@ -1,3 +1,5 @@ +import { getRank } from "../model/Rank.js"; + class LottoJudge { constructor(winningNumbers, bonusNumber) { this.winningNumbers = winningNumbers; diff --git a/src/view/OutputView.js b/src/view/OutputView.js index 06bf06c29..72e4b4a5f 100644 --- a/src/view/OutputView.js +++ b/src/view/OutputView.js @@ -1,4 +1,5 @@ import { Console } from "@woowacourse/mission-utils"; +import { PRIZES } from "../model/Rank.js"; const OutputView = { printLottoBundle(lottoBundle) { @@ -11,6 +12,40 @@ const OutputView = { this.printLineBreak(); }, + printResult(rankCounts) { + this.printLineBreak(); + + Console.print("당첨 통계"); + Console.print("---"); + + Object.entries(rankCounts) + .sort(([a], [b]) => b - a) + .forEach(([rank, count]) => { + const prize = PRIZES[rank].toLocaleString("ko-KR"); + switch (Number(rank)) { + case 5: + Console.print(`3개 일치 (${prize}원) - ${count}개`); + break; + case 4: + Console.print(`4개 일치 (${prize}원) - ${count}개`); + break; + case 3: + Console.print(`5개 일치 (${prize}원) - ${count}개`); + break; + case 2: + Console.print(`5개 일치, 보너스 볼 일치 (${prize}원) - ${count}개`); + break; + case 1: + Console.print(`6개 일치 (${prize}원) - ${count}개`); + break; + } + }); + }, + + printProfitRate(profitRate) { + Console.print(`총 수익률은 ${profitRate}%입니다.`); + }, + printLineBreak() { Console.print(""); }, From 235da6f55ed9c84d21899f16d1b6527b11bafeda Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 22:20:48 +0900 Subject: [PATCH 17/18] =?UTF-8?q?fix:=20=ED=86=B5=ED=95=A9=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=ED=99=95=EC=9D=B8=20=EB=B0=8F=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 - 생성한 로또 번호 출력 과정에서 배열 반환이 아닌 배열 형태의 문자열을 반환하도록 수정 - Lotto 클래스의 파일 구조를 변경하는 과정에서 테스트 코드의 경로를 수정 - Lotto 단일 테스트를 통과하기 위해 클래스에서 예외 처리 추가 - 예외처리 시 단순히 Error만 던지는 것이 아닌 try-catch를 추가하여 Console 출력 추가 --- README.md | 4 +--- __tests__/LottoTest.js | 2 +- src/App.js | 33 +++++++++++++++++++-------------- src/model/Lotto.js | 15 +++++++++++++++ src/view/OutputView.js | 4 +++- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9b3819182..7748c3a5d 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,6 @@ **(13) 결과 출력** -**(14) 단위 테스트 작성** - -**(15) 통합 테스트 확인** +**(14) 통합 테스트 확인**
diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 409aaf69b..ea6ef8d4e 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -1,4 +1,4 @@ -import Lotto from "../src/Lotto"; +import Lotto from "../src/model/Lotto"; describe("로또 클래스 테스트", () => { test("로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.", () => { diff --git a/src/App.js b/src/App.js index c589682fe..3b4f69097 100644 --- a/src/App.js +++ b/src/App.js @@ -1,3 +1,4 @@ +import { Console } from "@woowacourse/mission-utils"; import LottoBundle from "./model/LottoBundle.js"; import Result from "./model/Result.js"; import LottoJudge from "./service/LottoJudge.js"; @@ -7,25 +8,29 @@ import OutputView from "./view/OutputView.js"; class App { async run() { - const purchaseAmount = await InputView.readPurchaseAmount(); - const lottoMachine = new LottoMachine(purchaseAmount); - const lottoBundle = new LottoBundle(lottoMachine.getLottos()); + try { + const purchaseAmount = await InputView.readPurchaseAmount(); + const lottoMachine = new LottoMachine(purchaseAmount); + const lottoBundle = new LottoBundle(lottoMachine.getLottos()); - OutputView.printLottoBundle(lottoBundle); + OutputView.printLottoBundle(lottoBundle); - const winningNumbers = await InputView.readWinningNumbers(); - OutputView.printLineBreak(); - const bonusNumber = await InputView.readBonusNumber(); + const winningNumbers = await InputView.readWinningNumbers(); + OutputView.printLineBreak(); + const bonusNumber = await InputView.readBonusNumber(); - const lottoJudge = new LottoJudge(winningNumbers, bonusNumber); - const result = new Result(); + const lottoJudge = new LottoJudge(winningNumbers, bonusNumber); + const result = new Result(); - result.calculate(lottoBundle, lottoJudge); - const rankCounts = result.getRankCounts(); - const profitRate = result.getProfitRate(purchaseAmount); + result.calculate(lottoBundle, lottoJudge); + const rankCounts = result.getRankCounts(); + const profitRate = result.getProfitRate(purchaseAmount); - OutputView.printResult(rankCounts); - OutputView.printProfitRate(profitRate); + OutputView.printResult(rankCounts); + OutputView.printProfitRate(profitRate); + } catch (error) { + Console.print(error.message); + } } } diff --git a/src/model/Lotto.js b/src/model/Lotto.js index a73c5c6c5..c1a5c9c84 100644 --- a/src/model/Lotto.js +++ b/src/model/Lotto.js @@ -10,6 +10,21 @@ class Lotto { if (numbers.length !== 6) { throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); } + + const uniqueNumbers = new Set(numbers); + if (uniqueNumbers.size !== numbers.length) { + throw new Error("[ERROR] 로또 번호는 중복될 수 없습니다."); + } + + numbers.forEach((num) => { + if (isNaN(num)) { + throw new Error("[ERROR] 로또 번호는 숫자만 입력해야 합니다."); + } + + if (num < 1 || num > 45) { + throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + } + }); } // TODO: 추가 기능 구현 diff --git a/src/view/OutputView.js b/src/view/OutputView.js index 72e4b4a5f..c0042bd64 100644 --- a/src/view/OutputView.js +++ b/src/view/OutputView.js @@ -7,7 +7,9 @@ const OutputView = { Console.print(`${lottoBundle.size()}개를 구매했습니다.`); - lottoBundle.forEach((lotto) => Console.print(lotto.getNumbers())); + lottoBundle.forEach((lotto) => + Console.print(`[${lotto.getNumbers().join(", ")}]`) + ); this.printLineBreak(); }, From 593999c8999e9975c5533263ff68e2014b657fd5 Mon Sep 17 00:00:00 2001 From: yundoll Date: Mon, 3 Nov 2025 23:00:06 +0900 Subject: [PATCH 18/18] =?UTF-8?q?test(=5F=5Ftests=5F=5F):=20=EB=8B=A8?= =?UTF-8?q?=EC=9D=BC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기능 목록에서 테스트가 필요한 기능들에 대한 테스트 코드를 구현 - 설정한 예외 내에서 테스트를 통과하는지 확인 --- README.md | 2 ++ __tests__/BonusNumberTest.js | 12 +++++++++++ __tests__/LottoJudgeTest.js | 7 ++++++ __tests__/LottoTest.js | 10 +++++++++ __tests__/PurchaseAmountTest.js | 17 +++++++++++++++ __tests__/WinningNumbersTest.js | 38 +++++++++++++++++++++++++++++++++ src/service/LottoJudge.js | 7 ++++++ 7 files changed, 93 insertions(+) create mode 100644 __tests__/BonusNumberTest.js create mode 100644 __tests__/LottoJudgeTest.js create mode 100644 __tests__/PurchaseAmountTest.js create mode 100644 __tests__/WinningNumbersTest.js diff --git a/README.md b/README.md index 7748c3a5d..22e99d8af 100644 --- a/README.md +++ b/README.md @@ -54,4 +54,6 @@ **(14) 통합 테스트 확인** +**(15) 단일 테스트 추가 및 확인** +
diff --git a/__tests__/BonusNumberTest.js b/__tests__/BonusNumberTest.js new file mode 100644 index 000000000..e49d0a618 --- /dev/null +++ b/__tests__/BonusNumberTest.js @@ -0,0 +1,12 @@ +import Validator from "../src/util/Validator"; + +describe("validateBonusNumber", () => { + test("숫자가 아니면 예외가 발생한다.", () => { + expect(() => Validator.validateBonusNumber("abc")).toThrow("[ERROR]"); + }); + + test("1 ~ 45 범위를 벗어나면 예외가 발생한다.", () => { + expect(() => Validator.validateBonusNumber("0")).toThrow("[ERROR]"); + expect(() => Validator.validateBonusNumber("46")).toThrow("[ERROR]"); + }); +}); diff --git a/__tests__/LottoJudgeTest.js b/__tests__/LottoJudgeTest.js new file mode 100644 index 000000000..a979a15a1 --- /dev/null +++ b/__tests__/LottoJudgeTest.js @@ -0,0 +1,7 @@ +import LottoJudge from "../src/service/LottoJudge"; + +describe("로또 판단하는 클래스 테스트", () => { + test("보너스 번호가 당첨 번호에 포함되어 있으면 에러를 던진다.", () => { + expect(() => new LottoJudge([1, 2, 3, 4, 5, 6], 6)).toThrow("[ERROR]"); + }); +}); diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index ea6ef8d4e..a1636dee2 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -15,4 +15,14 @@ describe("로또 클래스 테스트", () => { }); // TODO: 추가 기능 구현에 따른 테스트 코드 작성 + test("숫자가 아니면 예외가 발생한다.", () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5, NaN]); + }).toThrow("[ERROR]"); + }); + + test("1 ~ 45 범위를 벗어나면 예외가 발생한다.", () => { + expect(() => new Lotto([0, 2, 3, 4, 5, 6])).toThrow("[ERROR]"); + expect(() => new Lotto([1, 2, 3, 4, 5, 46])).toThrow("[ERROR]"); + }); }); diff --git a/__tests__/PurchaseAmountTest.js b/__tests__/PurchaseAmountTest.js new file mode 100644 index 000000000..2948c4e52 --- /dev/null +++ b/__tests__/PurchaseAmountTest.js @@ -0,0 +1,17 @@ +import Validator from "../src/util/Validator"; + +describe("구입 금액 검증 테스트", () => { + test("숫자가 아니면 예외가 발생한다.", () => { + expect(() => Validator.validatePurchaseAmount("abc")).toThrow("[ERROR]"); + }); + + test("0 이하면 예외가 발생한다.", () => { + expect(() => Validator.validatePurchaseAmount("0")).toThrow("[ERROR]"); + expect(() => Validator.validatePurchaseAmount("-1000")).toThrow("[ERROR]"); + }); + + test("1000 단위가 아니면 예외가 발생한다.", () => { + expect(() => Validator.validatePurchaseAmount("1500")).toThrow("[ERROR]"); + expect(() => Validator.validatePurchaseAmount("2999")).toThrow("[ERROR]"); + }); +}); diff --git a/__tests__/WinningNumbersTest.js b/__tests__/WinningNumbersTest.js new file mode 100644 index 000000000..d2050935b --- /dev/null +++ b/__tests__/WinningNumbersTest.js @@ -0,0 +1,38 @@ +import Validator from "../src/util/Validator"; + +describe("당첨 번호 검증 테스트", () => { + test("개수가 6개가 아니면 예외가 발생한다.", () => { + expect(() => + Validator.validateWinningNumbers([1, 2, 3, 4, 5, 6, 7]) + ).toThrow("[ERROR]"); + expect(() => Validator.validateWinningNumbers([1, 2, 3, 4, 5])).toThrow( + "[ERROR]" + ); + }); + + test("중복이 있으면 예외가 발생한다.", () => { + expect(() => Validator.validateWinningNumbers([1, 2, 3, 4, 5, 5])).toThrow( + "[ERROR]" + ); + }); + + test("숫자가 아니면 예외가 발생한다.", () => { + // 문자열 'a' 포함 + expect(() => + Validator.validateWinningNumbers(["a", 2, 3, 4, 5, 6]) + ).toThrow("[ERROR]"); + // NaN 직접 포함 + expect(() => + Validator.validateWinningNumbers([NaN, 2, 3, 4, 5, 6]) + ).toThrow("[ERROR]"); + }); + + test("1 ~ 45 범위를 벗어나면 예외가 발생한다.", () => { + expect(() => Validator.validateWinningNumbers([0, 2, 3, 4, 5, 6])).toThrow( + "[ERROR]" + ); + expect(() => Validator.validateWinningNumbers([1, 2, 3, 4, 5, 46])).toThrow( + "[ERROR]" + ); + }); +}); diff --git a/src/service/LottoJudge.js b/src/service/LottoJudge.js index ea98ae510..e202c2eb7 100644 --- a/src/service/LottoJudge.js +++ b/src/service/LottoJudge.js @@ -2,10 +2,17 @@ import { getRank } from "../model/Rank.js"; class LottoJudge { constructor(winningNumbers, bonusNumber) { + this.#validate(winningNumbers, bonusNumber); this.winningNumbers = winningNumbers; this.bonusNumber = bonusNumber; } + #validate(winningNumbers, bonusNumber) { + if (winningNumbers.includes(bonusNumber)) { + throw new Error("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."); + } + } + judge(lotto) { const numbers = lotto.getNumbers(); const matchCount = numbers.filter((num) =>