From 64dd46a7364d93a097db1257397b2d3d6a9ba447 Mon Sep 17 00:00:00 2001 From: sunkiteo-o Date: Mon, 4 Nov 2024 18:36:31 +0900 Subject: [PATCH 1/5] =?UTF-8?q?docs:=20README.md=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 15bb106b5..23aeccbc2 100644 --- a/README.md +++ b/README.md @@ -1 +1,24 @@ # javascript-lotto-precourse + +우아한 테크코스 3주차 + +# 기능 요구 사항 + +- 1. 사용자 입력 +- [] 로또 구입 금액을 입력받는다. + - [] 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. +- [] 당첨 번호를 쉼표(,)를 기준으로 구분하여 입력 받는다. +- [] 보너스 번호를 입력 받는다. + +- 2. 로또 실행 +- [] 로또 번호의 숫자 범위는 1~45까지이다. +- [] 로또 범위의 숫자 범위 내에서 중복되지 않는 6개의 숫자를 뽑는다. +- [] 보너스 번호 1개의 숫자를 뽑는다. +- [] 구입 금액에 해당하는 만큼 로또를 발행한다. + +- 3. 출력 +- [] 발행한 로또 수량 및 번호를 출력한다. +- [] 로또 번호는 오름차순으로 정렬하여 보여준다. +- [] 당첨 내역을 출력한다. +- [] 수익률을 계산하여 출력한다. 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%) +- [] 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다. From c5ac953f88c2f8ae8c12b6cee44c8010844151f0 Mon Sep 17 00:00:00 2001 From: sunkiteo-o Date: Mon, 4 Nov 2024 18:37:45 +0900 Subject: [PATCH 2/5] =?UTF-8?q?docs:=20README.md=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 23aeccbc2..cf5ebad2a 100644 --- a/README.md +++ b/README.md @@ -4,21 +4,24 @@ # 기능 요구 사항 -- 1. 사용자 입력 -- [] 로또 구입 금액을 입력받는다. - - [] 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. -- [] 당첨 번호를 쉼표(,)를 기준으로 구분하여 입력 받는다. -- [] 보너스 번호를 입력 받는다. - -- 2. 로또 실행 -- [] 로또 번호의 숫자 범위는 1~45까지이다. -- [] 로또 범위의 숫자 범위 내에서 중복되지 않는 6개의 숫자를 뽑는다. -- [] 보너스 번호 1개의 숫자를 뽑는다. -- [] 구입 금액에 해당하는 만큼 로또를 발행한다. - -- 3. 출력 -- [] 발행한 로또 수량 및 번호를 출력한다. -- [] 로또 번호는 오름차순으로 정렬하여 보여준다. -- [] 당첨 내역을 출력한다. -- [] 수익률을 계산하여 출력한다. 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%) -- [] 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다. +## 1. 사용자 입력 + +- 로또 구입 금액을 입력받는다. + - 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. +- 당첨 번호를 쉼표(,)를 기준으로 구분하여 입력 받는다. +- [x] 보너스 번호를 입력 받는다. + +## 2. 로또 실행 + +- 로또 번호의 숫자 범위는 1~45까지이다. +- 로또 범위의 숫자 범위 내에서 중복되지 않는 6개의 숫자를 뽑는다. +- 보너스 번호 1개의 숫자를 뽑는다. +- 구입 금액에 해당하는 만큼 로또를 발행한다. + +## 3. 출력 + +- 발행한 로또 수량 및 번호를 출력한다. +- 로또 번호는 오름차순으로 정렬하여 보여준다. +- 당첨 내역을 출력한다. +- 수익률을 계산하여 출력한다. 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%) +- 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다. From e966c5148be6c740ca3ed761e477169f89f87f9b Mon Sep 17 00:00:00 2001 From: sunkiteo-o Date: Mon, 4 Nov 2024 18:39:11 +0900 Subject: [PATCH 3/5] =?UTF-8?q?docs:=20README.md=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cf5ebad2a..83721cc36 100644 --- a/README.md +++ b/README.md @@ -2,23 +2,23 @@ 우아한 테크코스 3주차 -# 기능 요구 사항 +## 기능 요구 사항 -## 1. 사용자 입력 +### 1. 사용자 입력 - 로또 구입 금액을 입력받는다. - 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. - 당첨 번호를 쉼표(,)를 기준으로 구분하여 입력 받는다. -- [x] 보너스 번호를 입력 받는다. +- [ ] 보너스 번호를 입력 받는다. -## 2. 로또 실행 +### 2. 로또 실행 - 로또 번호의 숫자 범위는 1~45까지이다. - 로또 범위의 숫자 범위 내에서 중복되지 않는 6개의 숫자를 뽑는다. - 보너스 번호 1개의 숫자를 뽑는다. - 구입 금액에 해당하는 만큼 로또를 발행한다. -## 3. 출력 +### 3. 출력 - 발행한 로또 수량 및 번호를 출력한다. - 로또 번호는 오름차순으로 정렬하여 보여준다. From 975a5137a4f9756a73ce40873c8a61dc238ec466 Mon Sep 17 00:00:00 2001 From: sunkiteo-o Date: Mon, 4 Nov 2024 18:40:27 +0900 Subject: [PATCH 4/5] =?UTF-8?q?docs:=20README.md=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 83721cc36..a6fa6fb94 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,22 @@ ### 1. 사용자 입력 -- 로또 구입 금액을 입력받는다. - - 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. -- 당첨 번호를 쉼표(,)를 기준으로 구분하여 입력 받는다. +- [ ] 로또 구입 금액을 입력받는다. + - [ ] 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. +- [ ] 당첨 번호를 쉼표(,)를 기준으로 구분하여 입력 받는다. - [ ] 보너스 번호를 입력 받는다. ### 2. 로또 실행 -- 로또 번호의 숫자 범위는 1~45까지이다. -- 로또 범위의 숫자 범위 내에서 중복되지 않는 6개의 숫자를 뽑는다. -- 보너스 번호 1개의 숫자를 뽑는다. -- 구입 금액에 해당하는 만큼 로또를 발행한다. +- [ ] 로또 번호의 숫자 범위는 1~45까지이다. +- [ ] 로또 범위의 숫자 범위 내에서 중복되지 않는 6개의 숫자를 뽑는다. +- [ ] 보너스 번호 1개의 숫자를 뽑는다. +- [ ] 구입 금액에 해당하는 만큼 로또를 발행한다. ### 3. 출력 -- 발행한 로또 수량 및 번호를 출력한다. -- 로또 번호는 오름차순으로 정렬하여 보여준다. -- 당첨 내역을 출력한다. -- 수익률을 계산하여 출력한다. 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%) -- 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다. +- [ ] 발행한 로또 수량 및 번호를 출력한다. +- [ ] 로또 번호는 오름차순으로 정렬하여 보여준다. +- [ ] 당첨 내역을 출력한다. +- [ ] 수익률을 계산하여 출력한다. 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%) +- [ ] 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다. From f2462952cb4ba0f4190aecec99254dc954a8b70d Mon Sep 17 00:00:00 2001 From: sunkiteo-o Date: Mon, 4 Nov 2024 23:43:46 +0900 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=EA=B8=B0=EB=8A=A5=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 20 ++++---- src/App.js | 6 ++- src/Constant.js | 16 +++++++ src/InputHandler.js | 14 ++++++ src/Lotto.js | 15 +++++- src/LottoProgram.js | 109 +++++++++++++++++++++++++++++++++++++++++++ src/OutputHandler.js | 12 +++++ src/Validation.js | 5 ++ 8 files changed, 185 insertions(+), 12 deletions(-) create mode 100644 src/Constant.js create mode 100644 src/InputHandler.js create mode 100644 src/LottoProgram.js create mode 100644 src/OutputHandler.js create mode 100644 src/Validation.js diff --git a/README.md b/README.md index a6fa6fb94..1becf96b0 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,22 @@ ### 1. 사용자 입력 -- [ ] 로또 구입 금액을 입력받는다. +- [x] 로또 구입 금액을 입력받는다. - [ ] 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. -- [ ] 당첨 번호를 쉼표(,)를 기준으로 구분하여 입력 받는다. -- [ ] 보너스 번호를 입력 받는다. +- [x] 당첨 번호를 쉼표(,)를 기준으로 구분하여 입력 받는다. +- [x] 보너스 번호를 입력 받는다. ### 2. 로또 실행 -- [ ] 로또 번호의 숫자 범위는 1~45까지이다. +- [x] 로또 번호의 숫자 범위는 1~45까지이다. - [ ] 로또 범위의 숫자 범위 내에서 중복되지 않는 6개의 숫자를 뽑는다. -- [ ] 보너스 번호 1개의 숫자를 뽑는다. -- [ ] 구입 금액에 해당하는 만큼 로또를 발행한다. +- [x] 보너스 번호 1개의 숫자를 뽑는다. +- [x] 구입 금액에 해당하는 만큼 로또를 발행한다. ### 3. 출력 -- [ ] 발행한 로또 수량 및 번호를 출력한다. -- [ ] 로또 번호는 오름차순으로 정렬하여 보여준다. -- [ ] 당첨 내역을 출력한다. -- [ ] 수익률을 계산하여 출력한다. 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%) +- [x] 발행한 로또 수량 및 번호를 출력한다. +- [x] 로또 번호는 오름차순으로 정렬하여 보여준다. +- [x] 당첨 내역을 출력한다. +- [x] 수익률을 계산하여 출력한다. 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%) - [ ] 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다. diff --git a/src/App.js b/src/App.js index 091aa0a5d..322a45d93 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,9 @@ +import { startLotto } from "./LottoProgram.js"; + class App { - async run() {} + async run() { + await startLotto(); + } } export default App; diff --git a/src/Constant.js b/src/Constant.js new file mode 100644 index 000000000..94f9706cd --- /dev/null +++ b/src/Constant.js @@ -0,0 +1,16 @@ +export const PROGRAM_MESSAGES = { + PRICE_PROMPT: "구입금액을 입력해 주세요.", + TRY_NUM_PROMPT: "개를 구매했습니다.", + WINNING_NUMBER_PROMPT: "\n" + "당첨 번호를 입력해 주세요.", + BONUS_NUMBER_PROMPT: "\n" + "보너스 번호를 입력해 주세요.", +}; + +export const STATICS_MESSAGE = { + RESULT_MESSAGE: "\n" + "당첨 통계" + "\n" + "---" + "\n", + THREE_MATCHES: "3개 일치 (5,000원) - ", + FOUR_MATCHES: "4개 일치 (50,000원) - ", + FIVE_MATCHES: "5개 일치 (1,500,000원) - ", + BONUS_MATCHES: "5개 일치, 보너스 볼 일치 (30,000,000원) - ", + SIX_MATCHES: "6개 일치 (2,000,000,000원) - ", + RATE_OF_RETURN: (rate) => `총 수익률은 ${rate}%입니다.`, +}; diff --git a/src/InputHandler.js b/src/InputHandler.js new file mode 100644 index 000000000..12a9420f4 --- /dev/null +++ b/src/InputHandler.js @@ -0,0 +1,14 @@ +import { Console } from "@woowacourse/mission-utils"; + +class InputHandler { + static async input(message) { + const price = await this.#readInput(message + "\n"); + return price; + } + + static #readInput(message) { + return Console.readLineAsync(message); + } +} + +export default InputHandler; diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e..d31ae3b5c 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -1,3 +1,5 @@ +import OutputHandler from "./OutputHandler.js"; + class Lotto { #numbers; @@ -13,6 +15,17 @@ class Lotto { } // TODO: 추가 기능 구현 -} + // 로또 출력 함수 + displayNumbers() { + OutputHandler.output("[" + this.#numbers.join(", ") + "]"); + } + + countMatchNumber(winningNumbers) { + const matchNum = this.#numbers.filter((num) => + winningNumbers.includes(num) + ); + return matchNum.length; + } +} export default Lotto; diff --git a/src/LottoProgram.js b/src/LottoProgram.js new file mode 100644 index 000000000..443ace7e7 --- /dev/null +++ b/src/LottoProgram.js @@ -0,0 +1,109 @@ +import InputHandler from "./InputHandler.js"; +import OutputHandler from "./OutputHandler.js"; +import { PROGRAM_MESSAGES, STATICS_MESSAGE } from "./Constant.js"; +import { validatePrice } from "./Validation.js"; +import { MissionUtils } from "@woowacourse/mission-utils"; + +import Lotto from "./Lotto.js"; + +export const startLotto = async () => { + //로또 구입 금액을 입력받는다. + const price = await InputHandler.input(PROGRAM_MESSAGES.PRICE_PROMPT); + const tryNum = price / 1000; + // 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. + validatePrice(tryNum); + + // 로또 몇장인지 출력 + OutputHandler.output("\n" + tryNum + PROGRAM_MESSAGES.TRY_NUM_PROMPT); + //tryNum 만큼의 로또를 발행 + const lottoNumbers = getLottoNumbers(tryNum); + + // 당첨 번호를 쉼표(,)를 기준으로 구분하여 입력 받는다. + let winningNumbers = await InputHandler.input( + PROGRAM_MESSAGES.WINNING_NUMBER_PROMPT + ); + winningNumbers = winningNumbers.split(",").map((num) => num.trim()); + + //로또 번호 검증 ( 6개인지 ) + const validateLotto = new Lotto(winningNumbers); + + //보너스 번호 입력 + const bonusNumber = await InputHandler.input( + PROGRAM_MESSAGES.BONUS_NUMBER_PROMPT + ); + + //당첨통계 + OutputHandler.output(STATICS_MESSAGE.RESULT_MESSAGE); + getStatics(lottoNumbers, winningNumbers, bonusNumber, price); +}; + +export const getLottoNumbers = (tryNum) => { + const lottoNumbersArray = []; + for (let i = 0; i < tryNum; i++) { + const numbers = MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6); + //오름차순 정렬 + const lotto = new Lotto(numbers.sort((a, b) => a - b)); + lotto.displayNumbers(); + lottoNumbersArray.push(lotto); + } + return lottoNumbersArray; +}; + +export const getStatics = ( + lottoNumbers, + winningNumbers, + bonusNumber, + price +) => { + const result = { + threeMatches: 0, + fourMatches: 0, + fiveMatches: 0, + fiveBonusMatches: 0, + sixMatches: 0, + }; + let income = 0; + let rate = 0; + lottoNumbers.forEach((num) => { + const matchCount = num.countMatchNumber(winningNumbers); + + if (matchCount === 3) { + result.threeMatches += 1; + income += 5000; + } else if (matchCount === 4) { + result.fourMatches += 1; + income += 50000; + } else if (matchCount === 5) { + if (num.numbers.includes(bonusNumber)) { + result.fiveBonusMatches += 1; + income += 30000000; + } else { + result.fiveMatches += 1; + income += 1500000; + } + } else if (matchCount === 6) { + result.sixMatches += 1; + income += 2000000000; + } + }); + + OutputHandler.output( + `${STATICS_MESSAGE.THREE_MATCHES} ${result.threeMatches}개` + ); + OutputHandler.output( + `${STATICS_MESSAGE.FOUR_MATCHES} ${result.fourMatches}개` + ); + OutputHandler.output( + `${STATICS_MESSAGE.FIVE_MATCHES} ${result.fiveMatches}개` + ); + OutputHandler.output( + `${STATICS_MESSAGE.BONUS_MATCHES} ${result.fiveBonusMatches}개` + ); + OutputHandler.output(`${STATICS_MESSAGE.SIX_MATCHES} ${result.sixMatches}개`); + + if (income !== 0) { + rate = (income / price) * 100; + } + + OutputHandler.output(STATICS_MESSAGE.RATE_OF_RETURN(rate.toFixed(2))); +}; diff --git a/src/OutputHandler.js b/src/OutputHandler.js new file mode 100644 index 000000000..6b3bf8217 --- /dev/null +++ b/src/OutputHandler.js @@ -0,0 +1,12 @@ +import { Console } from "@woowacourse/mission-utils"; + +class OutputHandler { + static async output(message) { + Console.print(message); + } + static async staticOutput(matchNum, winners, message) { + Console.print(matchNum + message + winners); + } +} + +export default OutputHandler; diff --git a/src/Validation.js b/src/Validation.js new file mode 100644 index 000000000..9b1c51628 --- /dev/null +++ b/src/Validation.js @@ -0,0 +1,5 @@ +export const validatePrice = (try_num) => { + if (!Number.isInteger(try_num)) { + throw Error("[ERROR] 입력 금액이 1,000원 단위가 아닙니다."); + } +};