From d3d2b79898b2a67e28229109ee649d10cf955676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 20:29:04 +0900 Subject: [PATCH 01/13] docs: write README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 프로젝트 개요, 프로세스 흐름, 구현할 기능 목록을 ./README.md에 작성 --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 15bb106b5..8a0b130cd 100644 --- a/README.md +++ b/README.md @@ -1 +1,31 @@ # javascript-lotto-precourse +## 프로젝트 개요 +- 사용자로부터 입력받은 구매 금액만큼 로또를 발행하여, 사용자가 입력한 당첨 번호 및 보너스 번호를 바탕으로 로또의 총 당첨 내역 및 수익률을 출력하는 프로젝트 +## 서비스 프로세스 흐름 +1. 사용자로부터 로또 구입 금액을 입력 받는다. +2. 그 금액만큼 로또를 발행한다. +3. 당첨 번호를 입력 받는다. +4. 보너스 번호를 입력 받는다. +5. 각 로또를 순회하며 당첨 내역을 기록한다. +6. 기록된 당첨 내역을 바탕으로 당첨 통계 및 수익률을 출력한다. +## 구현할 기능 목록 +- [ ] 메인 함수(`App.run()`) +- [ ] `Lotto` 메서드 + - `validate` 메서드 내용 확장 + - [ ] 당첨 번호, 보너스 번호를 인자로 받아 비교 후 등수를 반환하는 메서드 (calculateRank) +- [ ] 로또 구입 금액을 입력받는 함수 (setupLottoBudget) + - 예외 케이스 1) 사용자가 정수를 입력하지 않는 경우 + - 예외 케이스 2) 입력 받은 금액이 1,000원 단위로 나누어 떨어지지 않는 경우 +- [ ] 중복되지 않는 숫자 6개를 생성해 로또를 발행하는 함수 (createLotto) +- [ ] 입력된 금액만큼 복권을 발행하는 함수 (purchaseLotto) +- [ ] 당첨 번호를 입력받는 함수 (setupWinningNum) + - 예외 케이스 1) 사용자가 입력한 값을 쉼표 기준으로 구분했을 때, 원소 개수가 6개가 아닌 경우 + - 예외 케이스 2) 원소 중 정수가 아닌 값이 있는 경우 + - 예외 케이스 3) 원소 중 1 ~ 45 범위를 벗어난 값이 있는 경우 + - 예외 케이스 4) 당첨 번호 중 중복되는 값이 있는 경우 +- [ ] 보너스 번호를 입력받는 함수(setupBonusNum) + - 예외 케이스 1) 정수가 아닌 값을 입력받은 경우 + - 예외 케이스 2) 입력받은 값이 1 ~ 45 범위를 벗어난 경우 + - 예외 케이스 3) 당첨 번호 중 보너스 번호와 중복되는 값이 있는 경우 +- [ ] 구매한 로또들의 당첨 내역을 기록하는 함수 (checkLotteriesResult) +- [ ] 기록된 당첨 내역을 바탕으로 수익률을 계산하고 이들을 출력하는 함수(calculateProfit) \ No newline at end of file From bb4313b77237f4e404bd05472e3297833b59094c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 20:32:08 +0900 Subject: [PATCH 02/13] feat: add new method setupLottoBudget() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로또 구입 금액을 입력받는 함수 setupLottoBudget 추가 - 입력 받은 값이 정수가 아니거나, 1000 미만 또는 1000 단위가 아닐 경우 에러 - 정상적인 경우 Number 형으로 변환한 금액 반환 --- src/App.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/App.js b/src/App.js index 091aa0a5d..7f1b21ba5 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,21 @@ +import { Console, Random } from "@woowacourse/mission-utils"; +import Lotto from "./Lotto"; + + class App { async run() {} } +async function setupLottoBudget() { + let input = await Console.readLineAsync("구입 금액을 입력해 주세요."); + if (!Number.isInteger(input)) { + throw new Error("[ERROR] 구입 금액은 정수여야 합니다."); + } + input = Number(input); + if (input <= 0 || input % 1000 !== 0) { + throw new Error("[ERROR] 구입 금액은 1,000원 단위여야 합니다."); + } + return input; +} + export default App; From c9958903b65586813d3bfd1b865807bcc7cdc85b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 20:36:24 +0900 Subject: [PATCH 03/13] feat: add new method createLotto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1~45 사이 랜덤 숫자 6개로 Lotto 인스턴스를 생성하는 함수 - Random.pickUniqueNumberInRange를 사용해 랜덤 숫자 생성하며, Array.sort()를 통해 오름차순으로 정렬한 뒤 Lotto 생성자에 전달 --- src/App.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/App.js b/src/App.js index 7f1b21ba5..c3d3078b1 100644 --- a/src/App.js +++ b/src/App.js @@ -18,4 +18,8 @@ async function setupLottoBudget() { return input; } +function createLotto() { + return new Lotto(Random.pickUniqueNumberInRange(1, 45, 6).sort((a, b) => a - b)); +} + export default App; From 420601bb185ca609c5e89971903f35f10888ea84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 21:11:11 +0900 Subject: [PATCH 04/13] feat: add new method purchaseLotto and Lotto.toString MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 구입 금액만큼 복권을 발행하는 purchaseLotto와 Lotto의 번호를 출력 폼에 맞춘 문자열로 반환하는 Lotto.toString() 메서드 추가 - purchaseLotto는 (입력받은 금액 / 1000) 만큼 createLotto를 반복 호출해 Lotto 인스턴스를 생성한 뒤 배열에 담아 반환 - Lotto.toString은 Lotto의 번호(#numbers)를 규격에 맞춘 문자열 형태로 반환 --- src/App.js | 11 +++++++++++ src/Lotto.js | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index c3d3078b1..a4efff45d 100644 --- a/src/App.js +++ b/src/App.js @@ -22,4 +22,15 @@ function createLotto() { return new Lotto(Random.pickUniqueNumberInRange(1, 45, 6).sort((a, b) => a - b)); } +function purchaseLotto(budget) { + const quantity = budget / 1000; + Console.print(`${quantity}개를 구매했습니다.`); + const lotteries = new Array(quantity); + for (let i = 0; i < quantity; i++) { + lotteries[i] = createLotto(); + Console.print(lotteries[i].toString()); + } + return lotteries; +} + export default App; diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e..9c07ac541 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -12,7 +12,9 @@ class Lotto { } } - // TODO: 추가 기능 구현 + toString() { + return `[${this.#numbers.join(", ")}]`; + } } export default Lotto; From 36c344683f91e982c55b46987cf498108ab61b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 21:44:15 +0900 Subject: [PATCH 05/13] feat: add new method setupWinningNum, validateWinningNum, checkDuplicationWinningNum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 쉼표로 구분되는 6개의 당첨 번호를 입력 받아 이를 검증 후 배열로 반환하는 setupWinningNum 함수 추가 - 당첨 번호 검증에 필요한 validateWinningNum, checkDuplicationWinningNum 함수 추가 - validateWinningNum 함수는 각 당첨 번호가 1 ~ 45 사이의 정수인지 검사 - checkDuplicationWinningNum 함수는 당첨 번호 중 중복이 있는지 검사 --- src/App.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/App.js b/src/App.js index a4efff45d..dacb7163a 100644 --- a/src/App.js +++ b/src/App.js @@ -33,4 +33,37 @@ function purchaseLotto(budget) { return lotteries; } +async function setupWinningNum() { + const winningNumbers = await Console.readLineAsync("당첨 번호를 입력해 주세요.").split(","); + if (winningNumbers.length !== 6) { + throw new Error("[ERROR] 당첨 번호는 쉼표를 기준으로 구분되는 6개의 문자여야 합니다."); + } + for (let i = 0, len = winningNumbers.length; i < len; i++) { + winningNumbers[i] = validateWinningNum(winningNumbers[i]); + } + checkDuplicationWinningNum(winningNumbers); + return winningNumbers; +} + +function validateWinningNum(number) { + if (Number.isNaN(number)) { + throw new Error("[ERROR] 당첨 번호는 정수여야 합니다."); + } + number = Number(number); + if (number < 0 || number > 45) { + throw new Error("[ERROR] 당첨 번호는 1 ~ 45 사이의 정수여야 합니다."); + } + return number; +} + +function checkDuplicationWinningNum(array) { + const v = new Array(46).fill(false); + for (const number of array) { + if (v[number]) { + throw new Error("[ERROR] 당첨 번호는 중복될 수 없습니다."); + } + v[number] = true; + } +} + export default App; From 94c4316699513f636b64eba70224ed5568c9fe21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 21:52:17 +0900 Subject: [PATCH 06/13] feat: add new method setupBonusNum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 보너스 번호를 입력받는 함수 setupBonusNum 추가 - 입력 받은 값이 정수가 아니거나, 1 ~ 45 구간 사이의 값이 아닐 경우 에러 - 인자로 받은 당첨 번호들(winningNumbers)과 보너스 번호 간 중복이 발생할 경우 에러 --- src/App.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/App.js b/src/App.js index dacb7163a..6700841b0 100644 --- a/src/App.js +++ b/src/App.js @@ -66,4 +66,16 @@ function checkDuplicationWinningNum(array) { } } +async function setupBonusNum(winningNumbers) { + let bonusNumber = await Console.readLineAsync("보너스 번호를 입력해 주세요."); + if (Number.isNaN(bonusNumber)) { + throw new Error("[ERROR] 보너스 번호는 정수여야 합니다."); + } + bonusNumber = validateWinningNum(bonusNumber); + if (winningNumbers.indexOf(bonusNumber) >= 0) { + throw new Error("[ERROR] 당첨 번호와 보너스 번호는 중복될 수 없습니다."); + } + return bonusNumber; +} + export default App; From 856e72fe974c2b949bdc6d8cba54e5ae7cbf8d08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 22:26:34 +0900 Subject: [PATCH 07/13] feat: add new method checkLotteriesResult, calculateRank, Lotto.checkWinningStatus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 구매한 로또들의 당첨 내역을 기록하는 함수 checkLotteriesResult 추가 - 이를 위해 당첨 등수를 계산하는 함수 calculateRank, 맞은 번호 개수 및 보너스 번호 적중 여부를 반환하는 함수 Lotto.checkWinningStatus를 추가 - calculateRank는 당첨 번호 개수 및 보너스 번호 적중 여부를 인자로 받아, 당첨 등수를 반환 - Lotto.checkWinningStatus는 당첨 번호와 보너스 번호를 인자로 받아 일치하는 당첨 번호 개수 및 보너스 번호 일치 여부를 반환 --- src/App.js | 25 +++++++++++++++++++++++++ src/Lotto.js | 18 ++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/App.js b/src/App.js index 6700841b0..25795e6f9 100644 --- a/src/App.js +++ b/src/App.js @@ -78,4 +78,29 @@ async function setupBonusNum(winningNumbers) { return bonusNumber; } +function checkLotteriesResult(lotteries, winningNumbers, bonusNumber) { + const rankCount = new Array(6).fill(0); + for (const lotto of lotteries) { + const [matchedNumberCount, isBonusNumberExist] = lotto.checkWinningStatus(winningNumbers, bonusNumber); + const rank = calculateRank(matchedNumberCount, isBonusNumberExist); + rankCount[rank]++; + } + return rankCount; +} + +function calculateRank(matchedNumberCount, isBonusNumberExist) { + switch (matchedNumberCount) { + case 3: + return 5; + case 4: + return 4; + case 5: + if (isBonusNumberExist) return 2; + return 3; + case 6: + return 1; + } + return 6; +}; + export default App; diff --git a/src/Lotto.js b/src/Lotto.js index 9c07ac541..7bcfe1636 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -15,6 +15,24 @@ class Lotto { toString() { return `[${this.#numbers.join(", ")}]`; } + + checkWinningStatus(winningNumbers, bonusNumber) { + let matchedNumberCount = 0; + let isBonusNumberExist = false; + let winningNumIdx = 0; + for (const number of this.#numbers) { + if (number === winningNumbers[winningNumIdx]) { + matchedNumberCount++; + } else if (number === bonusNumber) { + isBonusNumberExist = true; + } + while (winningNumIdx < winningNumbers.length && number > winningNumbers[winningNumIdx]) { + winningNumIdx++; + } + if (winningNumIdx === winningNumbers.length) break; + } + return [matchedNumberCount, isBonusNumberExist]; + } } export default Lotto; From 7c9c53246b2b24acc9dada6c2f2ab9875b51bb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 22:43:43 +0900 Subject: [PATCH 08/13] feat: add new method calculateProfit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기록된 당첨 내역을 바탕으로 수익률을 계산하고 이들을 출력하는 함수 calculateProfit() 추가 - 복권 구입 금액과 등수 별 당첨 횟수가 기록된 배열을 인자로 받음 - 각 등수에 당첨된 복권 개수를 출력하고, 총 이익에 누계 - 이후 총 이익을 복권 구입 금액으로 나눈 위 소수점 둘째자리에서 반올림하여 수익률로 출력 --- src/App.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 25795e6f9..8364bea75 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,8 @@ import { Console, Random } from "@woowacourse/mission-utils"; import Lotto from "./Lotto"; +const WINNER_PRIZE = [0, 2_000_000_000, 30_000_000, 1_500_000, 50_000, 5_000]; + class App { async run() {} @@ -100,7 +102,26 @@ function calculateRank(matchedNumberCount, isBonusNumberExist) { case 6: return 1; } - return 6; + return 0; }; +function calculateProfit(budget, rankCount) { + let totalProfit = 0; + let profitRate = 0; + Console.print("당첨 통계"); + Console.print("------"); + Console.print(`3개 일치 (5,000원) - ${rankCount[5]}개`); + totalProfit += WINNER_PRIZE[5] * rankCount[5]; + Console.print(`4개 일치 (50,000원) - ${rankCount[4]}개`); + totalProfit += WINNER_PRIZE[4] * rankCount[5]; + Console.print(`5개 일치 (1,500,000원) - ${rankCount[3]}개`); + totalProfit += WINNER_PRIZE[3] * rankCount[5]; + Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${rankCount[2]}개`); + totalProfit += WINNER_PRIZE[2] * rankCount[5]; + Console.print(`6개 일치 (2,000,000,000원) - ${rankCount[1]}개`); + totalProfit += WINNER_PRIZE[1] * rankCount[5]; + profitRate = (totalProfit / budget).toFixed(1); + Console.print(`총 수익률은 ${profitRate}%입니다.`); +} + export default App; From 74658e1242770a94ae532f9d22a8d2b0feceda12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 22:50:55 +0900 Subject: [PATCH 09/13] feat: write App.run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 서비스 프로세스에 맞춰 각 함수를 호출하는 메서드 App.run() 작성 - 또한, Lotto 파일의 확장자를 명시해 import 오류 수정 --- src/App.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/App.js b/src/App.js index 8364bea75..247c7ada2 100644 --- a/src/App.js +++ b/src/App.js @@ -1,11 +1,18 @@ import { Console, Random } from "@woowacourse/mission-utils"; -import Lotto from "./Lotto"; +import Lotto from "./Lotto.js"; const WINNER_PRIZE = [0, 2_000_000_000, 30_000_000, 1_500_000, 50_000, 5_000]; class App { - async run() {} + async run() { + const budget = await setupLottoBudget(); + const lotteries = purchaseLotto(budget); + const winningNumbers = await setupWinningNum(); + const bonusNumber = await setupBonusNum(); + const rankCount = checkLotteriesResult(lotteries, winningNumbers, bonusNumber); + calculateProfit(budget, rankCount); + } } async function setupLottoBudget() { From 48c83ad050f67617bf7c1d8ff48ec670ff41dbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 23:17:40 +0900 Subject: [PATCH 10/13] fix: modify Lotto.checkWinningStatus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lotto.checkWinningStatus 메서드의 동작 방식을 일부 수정 - bonusNumber와 일치하는지 먼저 확인 후, winningNumbers[winningNumIdx] 와 일치하는지 확인하도록 수정 - 또한, winningNumbers[winningNumIdx]와 일치하는지 확인할 때 일치한다면 winningNumIdx도 증가시키도록 수정 --- src/Lotto.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Lotto.js b/src/Lotto.js index 7bcfe1636..2e006e7de 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -21,15 +21,18 @@ class Lotto { let isBonusNumberExist = false; let winningNumIdx = 0; for (const number of this.#numbers) { - if (number === winningNumbers[winningNumIdx]) { + if (number === bonusNumber) { + isBonusNumberExist = true; + continue; + } + if (winningNumIdx < winningNumbers.length && number === winningNumbers[winningNumIdx]) { matchedNumberCount++; - } else if (number === bonusNumber) { - isBonusNumberExist = true; + winningNumIdx++; + continue; } while (winningNumIdx < winningNumbers.length && number > winningNumbers[winningNumIdx]) { winningNumIdx++; } - if (winningNumIdx === winningNumbers.length) break; } return [matchedNumberCount, isBonusNumberExist]; } From bbbe56afebc861fc92004cd7186fb3e780ffc9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 23:21:47 +0900 Subject: [PATCH 11/13] fix: modify App.run(), add linebreaks, fix wrong Method Name and call, change validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit App 내부의 함수들의 세부 사항 일부 수정 - Console.readLineAsync()를 호출하는 함수들에 대해, 인자로 넘기는 문자열에 줄바꿈 문자(\n)추가 - 입력 값이 정수인지 판별하는 식 수정 - Random.pickUniqueNumbersInRange 호출하는 부분 함수 이름 틀린 것 수정 - await Console.readLineAsync()문 뒤에 split()을 바로 호출하던 것 수정 - setupBonusNum에 당첨 번호들(winningNumbers) 넘기지 않던것 수정 --- src/App.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/App.js b/src/App.js index 247c7ada2..413a64912 100644 --- a/src/App.js +++ b/src/App.js @@ -9,15 +9,15 @@ class App { const budget = await setupLottoBudget(); const lotteries = purchaseLotto(budget); const winningNumbers = await setupWinningNum(); - const bonusNumber = await setupBonusNum(); + const bonusNumber = await setupBonusNum(winningNumbers); const rankCount = checkLotteriesResult(lotteries, winningNumbers, bonusNumber); calculateProfit(budget, rankCount); } } async function setupLottoBudget() { - let input = await Console.readLineAsync("구입 금액을 입력해 주세요."); - if (!Number.isInteger(input)) { + let input = await Console.readLineAsync("구입 금액을 입력해 주세요.\n"); + if (Number.isNaN(input) || Number.isNaN(Number(input))) { throw new Error("[ERROR] 구입 금액은 정수여야 합니다."); } input = Number(input); @@ -28,12 +28,12 @@ async function setupLottoBudget() { } function createLotto() { - return new Lotto(Random.pickUniqueNumberInRange(1, 45, 6).sort((a, b) => a - b)); + return new Lotto(Random.pickUniqueNumbersInRange(1, 45, 6).sort((a, b) => a - b)); } function purchaseLotto(budget) { const quantity = budget / 1000; - Console.print(`${quantity}개를 구매했습니다.`); + Console.print(`${quantity}개를 구매했습니다.\n`); const lotteries = new Array(quantity); for (let i = 0; i < quantity; i++) { lotteries[i] = createLotto(); @@ -43,7 +43,8 @@ function purchaseLotto(budget) { } async function setupWinningNum() { - const winningNumbers = await Console.readLineAsync("당첨 번호를 입력해 주세요.").split(","); + let winningNumbers = await Console.readLineAsync("당첨 번호를 입력해 주세요.\n"); + winningNumbers = winningNumbers.split(","); if (winningNumbers.length !== 6) { throw new Error("[ERROR] 당첨 번호는 쉼표를 기준으로 구분되는 6개의 문자여야 합니다."); } @@ -55,7 +56,7 @@ async function setupWinningNum() { } function validateWinningNum(number) { - if (Number.isNaN(number)) { + if (Number.isNaN(input) || Number.isNaN(Number(winningNumbers))) { throw new Error("[ERROR] 당첨 번호는 정수여야 합니다."); } number = Number(number); @@ -76,8 +77,8 @@ function checkDuplicationWinningNum(array) { } async function setupBonusNum(winningNumbers) { - let bonusNumber = await Console.readLineAsync("보너스 번호를 입력해 주세요."); - if (Number.isNaN(bonusNumber)) { + let bonusNumber = await Console.readLineAsync("보너스 번호를 입력해 주세요.\n"); + if (Number.isNaN(input) || Number.isNaN(Number(winningNumbers))) { throw new Error("[ERROR] 보너스 번호는 정수여야 합니다."); } bonusNumber = validateWinningNum(bonusNumber); From b1f2194f53b8faa85b16895858db719a2754cf48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 23:49:22 +0900 Subject: [PATCH 12/13] fix: modify Lotto.checkWinningStatus, Lotto.validate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit checkWinningStatus의 당첨 번호 개수 카운팅 로직을 수정하고, validate의 검증 과정을 추가 - Array.filter, Array.includes를 사용해 당첨 번호와 보너스 번호가 있는지 파악하도록 수정 - 로또 번호가 정수인지, 중복된 수가 있는지도 검사하도록 수정 --- src/Lotto.js | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/Lotto.js b/src/Lotto.js index 2e006e7de..c5817d612 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -10,6 +10,16 @@ class Lotto { if (numbers.length !== 6) { throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); } + const v = new Array(46).fill(false); + for (const number of numbers) { + if (Number.isNaN(number) || Number.isNaN(Number(number))) { + throw new Error("[ERROR] 로또 번호는 정수여야 합니다."); + } + if (v[number]) { + throw new Error("[ERROR] 로또 번호는 중복될 수 없습니다."); + } + v[number] = true; + } } toString() { @@ -19,21 +29,8 @@ class Lotto { checkWinningStatus(winningNumbers, bonusNumber) { let matchedNumberCount = 0; let isBonusNumberExist = false; - let winningNumIdx = 0; - for (const number of this.#numbers) { - if (number === bonusNumber) { - isBonusNumberExist = true; - continue; - } - if (winningNumIdx < winningNumbers.length && number === winningNumbers[winningNumIdx]) { - matchedNumberCount++; - winningNumIdx++; - continue; - } - while (winningNumIdx < winningNumbers.length && number > winningNumbers[winningNumIdx]) { - winningNumIdx++; - } - } + matchedNumberCount = this.#numbers.filter(num => winningNumbers.includes(num)).length; + isBonusNumberExist = this.#numbers.includes(bonusNumber); return [matchedNumberCount, isBonusNumberExist]; } } From 413a3db905186cbcdc1777fce5af9a76b8ee15e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EA=B7=9C=EC=98=81?= Date: Mon, 3 Nov 2025 23:51:37 +0900 Subject: [PATCH 13/13] fix: modify linebreak prints, validate NaN logic, calculateProfit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 줄바꿈 출력 수정, 정수인지 판별하는 로직 수정, calculateProfit에서 누적 이익 계산시 RankCount의 잘못된 위치를 참조하던 것과 수익률 계산식 수정 --- src/App.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/App.js b/src/App.js index 413a64912..bc2221de0 100644 --- a/src/App.js +++ b/src/App.js @@ -24,6 +24,7 @@ async function setupLottoBudget() { if (input <= 0 || input % 1000 !== 0) { throw new Error("[ERROR] 구입 금액은 1,000원 단위여야 합니다."); } + Console.print(""); return input; } @@ -39,6 +40,7 @@ function purchaseLotto(budget) { lotteries[i] = createLotto(); Console.print(lotteries[i].toString()); } + Console.print(""); return lotteries; } @@ -52,11 +54,13 @@ async function setupWinningNum() { winningNumbers[i] = validateWinningNum(winningNumbers[i]); } checkDuplicationWinningNum(winningNumbers); + + Console.print(""); return winningNumbers; } function validateWinningNum(number) { - if (Number.isNaN(input) || Number.isNaN(Number(winningNumbers))) { + if (Number.isNaN(number) || Number.isNaN(Number(number))) { throw new Error("[ERROR] 당첨 번호는 정수여야 합니다."); } number = Number(number); @@ -78,13 +82,15 @@ function checkDuplicationWinningNum(array) { async function setupBonusNum(winningNumbers) { let bonusNumber = await Console.readLineAsync("보너스 번호를 입력해 주세요.\n"); - if (Number.isNaN(input) || Number.isNaN(Number(winningNumbers))) { + if (Number.isNaN(bonusNumber) || Number.isNaN(Number(bonusNumber))) { throw new Error("[ERROR] 보너스 번호는 정수여야 합니다."); } bonusNumber = validateWinningNum(bonusNumber); if (winningNumbers.indexOf(bonusNumber) >= 0) { throw new Error("[ERROR] 당첨 번호와 보너스 번호는 중복될 수 없습니다."); } + + Console.print(""); return bonusNumber; } @@ -121,14 +127,14 @@ function calculateProfit(budget, rankCount) { Console.print(`3개 일치 (5,000원) - ${rankCount[5]}개`); totalProfit += WINNER_PRIZE[5] * rankCount[5]; Console.print(`4개 일치 (50,000원) - ${rankCount[4]}개`); - totalProfit += WINNER_PRIZE[4] * rankCount[5]; + totalProfit += WINNER_PRIZE[4] * rankCount[4]; Console.print(`5개 일치 (1,500,000원) - ${rankCount[3]}개`); - totalProfit += WINNER_PRIZE[3] * rankCount[5]; + totalProfit += WINNER_PRIZE[3] * rankCount[3]; Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${rankCount[2]}개`); - totalProfit += WINNER_PRIZE[2] * rankCount[5]; + totalProfit += WINNER_PRIZE[2] * rankCount[2]; Console.print(`6개 일치 (2,000,000,000원) - ${rankCount[1]}개`); - totalProfit += WINNER_PRIZE[1] * rankCount[5]; - profitRate = (totalProfit / budget).toFixed(1); + totalProfit += WINNER_PRIZE[1] * rankCount[1]; + profitRate = (totalProfit / budget * 100).toFixed(1); Console.print(`총 수익률은 ${profitRate}%입니다.`); }