From c9a9008f2fa3a6dbba64bc6669ebbb5c346a6a86 Mon Sep 17 00:00:00 2001 From: ParkHyeonkyu <162525426+ParkHyeonkyu@users.noreply.github.com> Date: Fri, 21 Feb 2025 12:05:01 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:Lotto=20=ED=81=B4=EB=9E=98=EC=8A=A4=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 예외를 잡아 줄 Lotto.js와 LottoTest.js 코드 임시 작성 --- README.md | 14 ++++++++++++++ __tests__/LottoTest.js | 28 ++++++++++++++++++++++++++-- src/Lotto.js | 25 ++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 15bb106..3fadf7e 100644 --- a/README.md +++ b/README.md @@ -1 +1,15 @@ # javascript-lotto-precourse + +## 기능 구현 +1. 사용자로부터 로또 구입 금액을 입력한다. + 금액은 1000원 단위로 입력받으며 1000원으로 나누어 떨어지지 않으면 예외처리 +2. 구입 금액에 따른 로또 수량에 맞춰 랜덤으로 로또 번호가 6개 생성된다. + 로또 번호의 범위는 1~45이며, 중복되지 않는다. +3. 당첨 번호를 입력받는다. 번호는 쉼표(,)를 기준으로 구분한다. + 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑는다. +4. 사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 종료한다. + +## 예외 처리 +1. 당첨 번호가 6개가 아닌 경우 +2. 로또 번호의 범위가 벗어난 경우 +3. 로또 번호가 중복된 경우 diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 409aaf6..cdfefca 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -7,12 +7,36 @@ describe("로또 클래스 테스트", () => { }).toThrow("[ERROR]"); }); - // TODO: 테스트가 통과하도록 프로덕션 코드 구현 + test("로또 번호의 개수가 6개 미만이면 예외가 발생한다.", () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5]); + }).toThrow("[ERROR]"); + }); + test("로또 번호에 중복된 숫자가 있으면 예외가 발생한다.", () => { expect(() => { new Lotto([1, 2, 3, 4, 5, 5]); }).toThrow("[ERROR]"); }); - // TODO: 추가 기능 구현에 따른 테스트 코드 작성 + test("로또 번호가 1부터 45 사이의 숫자가 아니면 예외가 발생한다.", () => { + expect(() => { + new Lotto([0, 2, 3, 4, 5, 6]); + }).toThrow("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + + expect(() => { + new Lotto([1, 2, 3, 4, 5, 46]); + }).toThrow("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + }); + + test("정상적인 로또 번호가 입력되면 예외가 발생하지 않는다.", () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5, 6]); + }).not.toThrow(); + }); + + test("로또 번호가 오름차순으로 정렬된다.", () => { + const lotto = new Lotto([6, 5, 4, 3, 2, 1]); + expect(lotto.getNumbers()).toEqual([1, 2, 3, 4, 5, 6]); + }); }); diff --git a/src/Lotto.js b/src/Lotto.js index cb0b152..b261cb1 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -1,3 +1,5 @@ +import { Random } from "@woowacourse/mission-utils"; + class Lotto { #numbers; @@ -10,9 +12,30 @@ class Lotto { if (numbers.length !== 6) { throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); } + this.#checkNumberRange(numbers); + this.#checkDuplicates(numbers); + } + + #checkNumberRange(numbers) { + if (!numbers.every(num => num >= 1 && num <= 45)) { + throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + } + } + + #checkDuplicates(numbers) { + const uniqueNumbers = new Set(numbers); + if (uniqueNumbers.size !== 6) { + throw new Error("[ERROR] 로또 번호는 중복되지 않아야 합니다."); + } } - // TODO: 추가 기능 구현 + static generateRandomLotto() { + return new Lotto(Random.pickUniqueNumbersInRange(1, 45, 6)); + } + + getNumbers() { + return [...this.#numbers].sort((a, b) => a - b); + } } export default Lotto; From 8876f408e210fc153edaaa15861a6d0f38298d48 Mon Sep 17 00:00:00 2001 From: ParkHyeonkyu <162525426+ParkHyeonkyu@users.noreply.github.com> Date: Fri, 21 Feb 2025 12:38:28 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EA=B5=AC?= =?UTF-8?q?=EB=A7=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 입출력 구현으로 가격 구매 및 예외 처리 구현 --- src/App.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 091aa0a..723fac0 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,26 @@ +import { Console } from "@woowacourse/mission-utils" + class App { - async run() {} + async run() { + try { + const purchaseAmount = await this.getPurchaseAmount(); + const lottoCount = purchaseAmount / 1000; + + Console.print(`${lottoCount}개를 구매했습니다.`); + + } catch (error) { + Console.print(error.message); + } + } + async getPurchaseAmount() { + const input = await Console.readLineAsync(`구입 금액을 입력해주세요.\n`); + const amount = parseInt(input); + + if (isNaN(amount) || amount % 1000 !== 0) { + throw new Error("[ERROR] 천 원 단위로 입력해야 합니다."); + } + return amount; + } } export default App; From 05d8d6a42184e33042552a7e75d795aeae1720f4 Mon Sep 17 00:00:00 2001 From: ParkHyeonkyu <162525426+ParkHyeonkyu@users.noreply.github.com> Date: Fri, 21 Feb 2025 12:48:27 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EC=83=9D?= =?UTF-8?q?=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 Random을 활용한 로또 생성 구현 --- src/App.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 723fac0..ba0492d 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,5 @@ -import { Console } from "@woowacourse/mission-utils" +import { Console, Random } from "@woowacourse/mission-utils" +import Lotto from "./Lotto.js"; class App { async run() { @@ -6,7 +7,12 @@ class App { const purchaseAmount = await this.getPurchaseAmount(); const lottoCount = purchaseAmount / 1000; + const lottos = this.generateLottos(lottoCount); + Console.print(`${lottoCount}개를 구매했습니다.`); + lottos.forEach(lotto => { + Console.print(lotto.getNumbers()); + }); } catch (error) { Console.print(error.message); @@ -21,6 +27,15 @@ class App { } return amount; } + + generateLottos(lottoCount) { + const lottos = []; + for (let i = 0; i < lottoCount; i++) { + const numbers = Random.pickUniqueNumbersInRange(1,45,6); + lottos.push(new Lotto(numbers)); + } + return lottos; + } } export default App; From 9a5c6f35085da50d78b2d0181b14d9887f9dcd90 Mon Sep 17 00:00:00 2001 From: ParkHyeonkyu <162525426+ParkHyeonkyu@users.noreply.github.com> Date: Fri, 21 Feb 2025 15:13:59 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=EB=B2=88=ED=98=B8=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EA=B8=B0=EB=8A=A5=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 당첨 번호와 보너스 번호 입력기능 구현 --- src/App.js | 34 +++++++++++++++++++++++++++++++--- src/index.js | 2 +- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/App.js b/src/App.js index ba0492d..00789a3 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,4 @@ -import { Console, Random } from "@woowacourse/mission-utils" +import { Console } from "@woowacourse/mission-utils"; import Lotto from "./Lotto.js"; class App { @@ -14,10 +14,18 @@ class App { Console.print(lotto.getNumbers()); }); + const winningNumbers = await this.getWinningNumbers(); + const bonusNumber = await this.getBonusNumber(); + + // 당첨 번호 및 보너스 번호 출력 + Console.print(`당첨 번호: ${winningNumbers}`); + Console.print(`보너스 번호: ${bonusNumber}`); + } catch (error) { Console.print(error.message); } } + async getPurchaseAmount() { const input = await Console.readLineAsync(`구입 금액을 입력해주세요.\n`); const amount = parseInt(input); @@ -31,11 +39,31 @@ class App { generateLottos(lottoCount) { const lottos = []; for (let i = 0; i < lottoCount; i++) { - const numbers = Random.pickUniqueNumbersInRange(1,45,6); - lottos.push(new Lotto(numbers)); + const lotto = Lotto.generateRandomLotto(); + lottos.push(lotto); } return lottos; } + + async getWinningNumbers() { + const input = await Console.readLineAsync("당첨 번호를 입력해주세요. 번호는 쉼표(,)로 구분됩니다.\n"); + const numbers = input.split(",").map(num => parseInt(num.trim())); + + if (numbers.length !== 6 || numbers.some(num => num < 1 || num > 45 || isNaN(num))) { + throw new Error("[ERROR] 당첨 번호는 1부터 45 사이의 숫자 6개여야 합니다.\n"); + } + return numbers.sort((a, b) => a - b); + } + + async getBonusNumber() { + const input = await Console.readLineAsync("보너스 번호를 입력해주세요."); + const bonusNumber = parseInt(input); + + if (bonusNumber < 1 || bonusNumber > 45 || isNaN(bonusNumber)) { + throw new Error("[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."); + } + return bonusNumber; + } } export default App; diff --git a/src/index.js b/src/index.js index 02a1d38..100dd7d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ import App from "./App.js"; const app = new App(); -await app.run(); +await app.run(); \ No newline at end of file From e4c74fe401c593b764d4f0b937d21fd2a5fb471d Mon Sep 17 00:00:00 2001 From: ParkHyeonkyu <162525426+ParkHyeonkyu@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:21:18 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=EC=88=98=EC=9D=B5=EB=A5=A0=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit object를 활용한 수익률 계산 구현 --- __tests__/ApplicationTest.js | 26 ++++++-- src/App.js | 112 ++++++++++++++++++++++++++++------- src/Lotto.js | 13 ++++ 3 files changed, 125 insertions(+), 26 deletions(-) diff --git a/__tests__/ApplicationTest.js b/__tests__/ApplicationTest.js index 872380c..9b0e288 100644 --- a/__tests__/ApplicationTest.js +++ b/__tests__/ApplicationTest.js @@ -13,9 +13,9 @@ const mockQuestions = (inputs) => { const mockRandoms = (numbers) => { MissionUtils.Random.pickUniqueNumbersInRange = jest.fn(); - numbers.reduce((acc, number) => { - return acc.mockReturnValueOnce(number); - }, MissionUtils.Random.pickUniqueNumbersInRange); + numbers.forEach((number) => { + MissionUtils.Random.pickUniqueNumbersInRange.mockReturnValueOnce(number); + }); }; const getLogSpy = () => { @@ -51,7 +51,7 @@ describe("로또 테스트", () => { // given const logSpy = getLogSpy(); - mockRandoms([ + const expectedLottos = [ [8, 21, 23, 41, 42, 43], [3, 5, 11, 16, 32, 38], [7, 11, 16, 35, 36, 44], @@ -60,7 +60,9 @@ describe("로또 테스트", () => { [7, 11, 30, 40, 42, 43], [2, 13, 22, 32, 38, 45], [1, 3, 5, 14, 22, 45], - ]); + ]; + + mockRandoms(expectedLottos); mockQuestions(["8000", "1,2,3,4,5,6", "7"]); // when @@ -91,7 +93,19 @@ describe("로또 테스트", () => { }); }); - test("예외 테스트", async () => { + test("예외 테스트 - 잘못된 입력", async () => { await runException("1000j"); }); + + test("예외 테스트 - 1000원 단위로 입력하지 않음", async () => { + await runException("2000"); + }); + + test("예외 테스트 - 당첨 번호 잘못된 형식", async () => { + await runException("1,2,3,4,5,6,7"); + }); + + test("예외 테스트 - 보너스 번호 잘못된 형식", async () => { + await runException("46"); + }); }); diff --git a/src/App.js b/src/App.js index 00789a3..9d16e17 100644 --- a/src/App.js +++ b/src/App.js @@ -6,21 +6,14 @@ class App { try { const purchaseAmount = await this.getPurchaseAmount(); const lottoCount = purchaseAmount / 1000; - const lottos = this.generateLottos(lottoCount); - Console.print(`${lottoCount}개를 구매했습니다.`); - lottos.forEach(lotto => { - Console.print(lotto.getNumbers()); - }); + this.printLottoPurchaseDetails(lottoCount, lottos); const winningNumbers = await this.getWinningNumbers(); const bonusNumber = await this.getBonusNumber(); - // 당첨 번호 및 보너스 번호 출력 - Console.print(`당첨 번호: ${winningNumbers}`); - Console.print(`보너스 번호: ${bonusNumber}`); - + this.printResultsAndRevenueRate(lottos, winningNumbers, bonusNumber, purchaseAmount); } catch (error) { Console.print(error.message); } @@ -30,40 +23,119 @@ class App { const input = await Console.readLineAsync(`구입 금액을 입력해주세요.\n`); const amount = parseInt(input); + this.validatePurchaseAmount(amount); + + return amount; + } + + validatePurchaseAmount(amount) { if (isNaN(amount) || amount % 1000 !== 0) { throw new Error("[ERROR] 천 원 단위로 입력해야 합니다."); } - return amount; } generateLottos(lottoCount) { - const lottos = []; - for (let i = 0; i < lottoCount; i++) { - const lotto = Lotto.generateRandomLotto(); - lottos.push(lotto); - } - return lottos; + return Array.from({ length: lottoCount }, () => Lotto.generateRandomLotto()); + } + + printLottoPurchaseDetails(lottoCount, lottos) { + Console.print(`${lottoCount}개를 구매했습니다.`); + lottos.forEach(lotto => Console.print(lotto.getNumbers())); } async getWinningNumbers() { const input = await Console.readLineAsync("당첨 번호를 입력해주세요. 번호는 쉼표(,)로 구분됩니다.\n"); const numbers = input.split(",").map(num => parseInt(num.trim())); + this.validateWinningNumbers(numbers); + + return numbers.sort((a, b) => a - b); + } + + validateWinningNumbers(numbers) { if (numbers.length !== 6 || numbers.some(num => num < 1 || num > 45 || isNaN(num))) { throw new Error("[ERROR] 당첨 번호는 1부터 45 사이의 숫자 6개여야 합니다.\n"); } - return numbers.sort((a, b) => a - b); } async getBonusNumber() { - const input = await Console.readLineAsync("보너스 번호를 입력해주세요."); + const input = await Console.readLineAsync("보너스 번호를 입력해주세요.\n"); const bonusNumber = parseInt(input); + this.validateBonusNumber(bonusNumber); + + return bonusNumber; + } + + validateBonusNumber(bonusNumber) { if (bonusNumber < 1 || bonusNumber > 45 || isNaN(bonusNumber)) { throw new Error("[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."); } - return bonusNumber; + } + + calculateResult(lottos, winningNumbers, bonusNumber) { + const result = { + '6개 일치': 0, + '5개 일치 (보너스 볼 일치)': 0, + '5개 일치': 0, + '4개 일치': 0, + '3개 일치': 0 + }; + + lottos.forEach(lotto => { + const matchingNumbers = this.getMatchingCount(lotto.getNumbers(), winningNumbers); + this.updateResult(result, matchingNumbers, lotto.getNumbers(), bonusNumber); + }); + + return result; + } + + updateResult(result, matchingNumbers, lottoNumbers, bonusNumber) { + if (matchingNumbers === 6) result['6개 일치']++; + if (matchingNumbers === 5 && lottoNumbers.includes(bonusNumber)) result['5개 일치 (보너스 볼 일치)']++; + if (matchingNumbers === 5) result['5개 일치']++; + if (matchingNumbers === 4) result['4개 일치']++; + if (matchingNumbers === 3) result['3개 일치']++; + } + + getMatchingCount(lottoNumbers, winningNumbers) { + return lottoNumbers.filter(number => winningNumbers.includes(number)).length; + } + + printResultsAndRevenueRate(lottos, winningNumbers, bonusNumber, purchaseAmount) { + const result = this.calculateResult(lottos, winningNumbers, bonusNumber); + this.printResultDetails(result); + + const revenueRate = this.calculateRevenueRate(purchaseAmount, result); + Console.print(`총 수익률은 ${revenueRate}%입니다.`); + } + + printResultDetails(result) { + Console.print(`3개 일치 (5,000원) - ${result['3개 일치']}개`); + Console.print(`4개 일치 (50,000원) - ${result['4개 일치']}개`); + Console.print(`5개 일치 (1,500,000원) - ${result['5개 일치']}개`); + Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${result['5개 일치 (보너스 볼 일치)']}개`); + Console.print(`6개 일치 (2,000,000,000원) - ${result['6개 일치']}개`); + } + + calculateRevenueRate(purchaseAmount, result) { + const totalPrizeMoney = this.calculateTotalPrizeMoney(result); + const revenueRate = (totalPrizeMoney / purchaseAmount) * 100; + + return revenueRate.toFixed(1); + } + + calculateTotalPrizeMoney(result) { + const prizeMoney = { + '3개 일치': 5000, + '4개 일치': 50000, + '5개 일치': 1500000, + '5개 일치 (보너스 볼 일치)': 30000000, + '6개 일치': 2000000000 + }; + + return Object.entries(result).reduce((total, [key, value]) => total + value * prizeMoney[key], 0); } } -export default App; +export default App; \ No newline at end of file diff --git a/src/Lotto.js b/src/Lotto.js index b261cb1..97d796f 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -36,6 +36,19 @@ class Lotto { getNumbers() { return [...this.#numbers].sort((a, b) => a - b); } + + static validateWinningNumbers(numbers) { + if (numbers.length !== 6) { + throw new Error("[ERROR] 당첨 번호는 6개여야 합니다."); + } + return new Lotto(numbers); + } + + static validateBonusNumber(number) { + if (number < 1 || number > 45 || isNaN(number)) { + throw new Error("[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."); + } + } } export default Lotto; From d23eacb889760154bceff931216a7906ea60bc63 Mon Sep 17 00:00:00 2001 From: ParkHyeonkyu <162525426+ParkHyeonkyu@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:49:35 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20PrizeCheck=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 수익률을 계산해주는 PrizeCheck 클래스를 분리 --- README.md | 1 + src/App.js | 99 ++++++++++----------------------------------- src/PrizeChecker.js | 52 ++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 78 deletions(-) create mode 100644 src/PrizeChecker.js diff --git a/README.md b/README.md index 3fadf7e..2c3062e 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ 3. 당첨 번호를 입력받는다. 번호는 쉼표(,)를 기준으로 구분한다. 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑는다. 4. 사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 종료한다. + 수익률을 계산하는 PrizeCheck 클래스를 만들어 코드 분리를 시도해본다. ## 예외 처리 1. 당첨 번호가 6개가 아닌 경우 diff --git a/src/App.js b/src/App.js index 9d16e17..95415a8 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,6 @@ import { Console } from "@woowacourse/mission-utils"; import Lotto from "./Lotto.js"; +import PrizeChecker from "./PrizeChecker.js"; class App { async run() { @@ -13,18 +14,21 @@ class App { const winningNumbers = await this.getWinningNumbers(); const bonusNumber = await this.getBonusNumber(); - this.printResultsAndRevenueRate(lottos, winningNumbers, bonusNumber, purchaseAmount); + this.printResultsAndRevenueRate(purchaseAmount, lottos, winningNumbers, bonusNumber); } catch (error) { Console.print(error.message); } } + async getUserInput(message) { + const input = await Console.readLineAsync(message); + return input.trim(); + } + async getPurchaseAmount() { - const input = await Console.readLineAsync(`구입 금액을 입력해주세요.\n`); + const input = await this.getUserInput(`구입 금액을 입력해주세요.\n`); const amount = parseInt(input); - this.validatePurchaseAmount(amount); - return amount; } @@ -38,75 +42,33 @@ class App { return Array.from({ length: lottoCount }, () => Lotto.generateRandomLotto()); } - printLottoPurchaseDetails(lottoCount, lottos) { - Console.print(`${lottoCount}개를 구매했습니다.`); - lottos.forEach(lotto => Console.print(lotto.getNumbers())); - } - async getWinningNumbers() { - const input = await Console.readLineAsync("당첨 번호를 입력해주세요. 번호는 쉼표(,)로 구분됩니다.\n"); + const input = await this.getUserInput("당첨 번호를 입력해주세요. 번호는 쉼표(,)로 구분됩니다.\n"); const numbers = input.split(",").map(num => parseInt(num.trim())); - - this.validateWinningNumbers(numbers); - - return numbers.sort((a, b) => a - b); - } - - validateWinningNumbers(numbers) { - if (numbers.length !== 6 || numbers.some(num => num < 1 || num > 45 || isNaN(num))) { - throw new Error("[ERROR] 당첨 번호는 1부터 45 사이의 숫자 6개여야 합니다.\n"); - } + const winningLotto = Lotto.validateWinningNumbers(numbers); + return winningLotto.getNumbers(); } async getBonusNumber() { - const input = await Console.readLineAsync("보너스 번호를 입력해주세요.\n"); + const input = await this.getUserInput("보너스 번호를 입력해주세요.\n"); const bonusNumber = parseInt(input); - - this.validateBonusNumber(bonusNumber); - + Lotto.validateBonusNumber(bonusNumber); return bonusNumber; } - validateBonusNumber(bonusNumber) { - if (bonusNumber < 1 || bonusNumber > 45 || isNaN(bonusNumber)) { - throw new Error("[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."); - } - } - - calculateResult(lottos, winningNumbers, bonusNumber) { - const result = { - '6개 일치': 0, - '5개 일치 (보너스 볼 일치)': 0, - '5개 일치': 0, - '4개 일치': 0, - '3개 일치': 0 - }; - - lottos.forEach(lotto => { - const matchingNumbers = this.getMatchingCount(lotto.getNumbers(), winningNumbers); - this.updateResult(result, matchingNumbers, lotto.getNumbers(), bonusNumber); - }); - - return result; - } - - updateResult(result, matchingNumbers, lottoNumbers, bonusNumber) { - if (matchingNumbers === 6) result['6개 일치']++; - if (matchingNumbers === 5 && lottoNumbers.includes(bonusNumber)) result['5개 일치 (보너스 볼 일치)']++; - if (matchingNumbers === 5) result['5개 일치']++; - if (matchingNumbers === 4) result['4개 일치']++; - if (matchingNumbers === 3) result['3개 일치']++; + printLottoNumbers(lottos) { + lottos.forEach(lotto => Console.print(lotto.getNumbers())); } - getMatchingCount(lottoNumbers, winningNumbers) { - return lottoNumbers.filter(number => winningNumbers.includes(number)).length; + printLottoPurchaseDetails(lottoCount, lottos) { + Console.print(`${lottoCount}개를 구매했습니다.`); + this.printLottoNumbers(lottos); } - printResultsAndRevenueRate(lottos, winningNumbers, bonusNumber, purchaseAmount) { - const result = this.calculateResult(lottos, winningNumbers, bonusNumber); + printResultsAndRevenueRate(purchaseAmount, lottos, winningNumbers, bonusNumber) { + const result = PrizeChecker.checkResults(lottos, winningNumbers, bonusNumber); this.printResultDetails(result); - - const revenueRate = this.calculateRevenueRate(purchaseAmount, result); + const revenueRate = PrizeChecker.calculateRevenueRate(purchaseAmount, result); Console.print(`총 수익률은 ${revenueRate}%입니다.`); } @@ -117,25 +79,6 @@ class App { Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${result['5개 일치 (보너스 볼 일치)']}개`); Console.print(`6개 일치 (2,000,000,000원) - ${result['6개 일치']}개`); } - - calculateRevenueRate(purchaseAmount, result) { - const totalPrizeMoney = this.calculateTotalPrizeMoney(result); - const revenueRate = (totalPrizeMoney / purchaseAmount) * 100; - - return revenueRate.toFixed(1); - } - - calculateTotalPrizeMoney(result) { - const prizeMoney = { - '3개 일치': 5000, - '4개 일치': 50000, - '5개 일치': 1500000, - '5개 일치 (보너스 볼 일치)': 30000000, - '6개 일치': 2000000000 - }; - - return Object.entries(result).reduce((total, [key, value]) => total + value * prizeMoney[key], 0); - } } export default App; \ No newline at end of file diff --git a/src/PrizeChecker.js b/src/PrizeChecker.js new file mode 100644 index 0000000..f3995e0 --- /dev/null +++ b/src/PrizeChecker.js @@ -0,0 +1,52 @@ +//수익률 계산 +class PrizeChecker { + static checkResults(lottos, winningNumbers, bonusNumber) { + const result = { + '6개 일치': 0, + '5개 일치 (보너스 볼 일치)': 0, + '5개 일치': 0, + '4개 일치': 0, + '3개 일치': 0 + }; + + lottos.forEach(lotto => { + const matchingNumbers = this.getMatchingCount(lotto.getNumbers(), winningNumbers); + this.updateResult(result, matchingNumbers, lotto.getNumbers(), bonusNumber); + }); + + return result; + } + + static getMatchingCount(lottoNumbers, winningNumbers) { + return lottoNumbers.filter(number => winningNumbers.includes(number)).length; + } + + static updateResult(result, matchingNumbers, lottoNumbers, bonusNumber) { + if (matchingNumbers === 6) result['6개 일치']++; + if (matchingNumbers === 5 && lottoNumbers.includes(bonusNumber)) { + result['5개 일치 (보너스 볼 일치)']++; + } + if (matchingNumbers === 5) result['5개 일치']++; + if (matchingNumbers === 4) result['4개 일치']++; + if (matchingNumbers === 3) result['3개 일치']++; + } + + static calculateRevenueRate(purchaseAmount, result) { + const totalPrizeMoney = this.calculateTotalPrizeMoney(result); + return ((totalPrizeMoney / purchaseAmount) * 100).toFixed(1); + } + + static calculateTotalPrizeMoney(result) { + const prizeMoney = { + '3개 일치': 5000, + '4개 일치': 50000, + '5개 일치': 1500000, + '5개 일치 (보너스 볼 일치)': 30000000, + '6개 일치': 2000000000 + }; + + return Object.entries(result).reduce((total, [key, value]) => total + value * prizeMoney[key], 0); + } + } + + export default PrizeChecker; \ No newline at end of file From 262a4909af07d37e9fa2ae2b56236fde7a5eb72d Mon Sep 17 00:00:00 2001 From: ParkHyeonkyu <162525426+ParkHyeonkyu@users.noreply.github.com> Date: Fri, 21 Feb 2025 16:59:55 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=20=ED=95=A8=EC=88=98=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 중복되는 함수를 하나로 합침 --- src/App.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/App.js b/src/App.js index 95415a8..013e281 100644 --- a/src/App.js +++ b/src/App.js @@ -56,14 +56,10 @@ class App { return bonusNumber; } - printLottoNumbers(lottos) { - lottos.forEach(lotto => Console.print(lotto.getNumbers())); - } - printLottoPurchaseDetails(lottoCount, lottos) { Console.print(`${lottoCount}개를 구매했습니다.`); - this.printLottoNumbers(lottos); - } + lottos.forEach(lotto => Console.print(`[${lotto.getNumbers().join(", ")}]`)); + } printResultsAndRevenueRate(purchaseAmount, lottos, winningNumbers, bonusNumber) { const result = PrizeChecker.checkResults(lottos, winningNumbers, bonusNumber);