diff --git a/README.md b/README.md index 15bb106b5..348267dfd 100644 --- a/README.md +++ b/README.md @@ -1 +1,233 @@ # javascript-lotto-precourse + +--- + +## 기능 요구 사항 + +#### 간단한 로또 발매기 구현 + +- 로또 번호의 숫자 범위 1~45 +- 1개의 로또를 발행할 때 중복되지 않는 숫자 6개를 뽑는다. +- 당첨 번호 추첨 시 중복되지 않는 수자 6개와 보너스 번호 1개를 뽑는다. (총 7개) +- 당첨은 1등부터 5등까지 + - 1등 : 6개 번호 일치 (2,000,000,000원) + - 2등 : 5개 번호 + 보너스 번호 일치 (30,000,000원) + - 3등 : 5개 번호 일치 (1,500,000원) + - 4등 : 4개 번호 일치 (50,000원) + - 5등 : 3개 번호 일치 (5,000원) +- 로또 구입 금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 한다. +- 로또 1장 당 1,000원 +- 당첨번호와 보너스 번호를 입력 받는다. +- 사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 로또 게임을 종료한다. +- 사용자가 잘못된 값을 입력할 경우 "ERROR"로 시작하는 메시지와 함께 `Error`를 발생시키고 출력한 다음 해당 지점부터 다시 입력을 받는다. + +#### 입출력 요구사항 + +##### 입력 + +- 로또 구입 금액 +- 금액 단위 1,000 +- 1,000원으로 나누어 떨어지지 않는 경우 예외 처리 + +``` +14000 +``` + +- 당첨 번호 입력, 번호는 쉼표(,) 기준으로 구분 + +``` +1,2,3,4,5,6 +``` + +- 보너스 번호 입력 + +``` +7 +``` + +##### 출력 + +- 발행산 로또 수량 및 번호 출력 +- 로또 번호는 오름차순 정렬 + +``` +8개를 구매했습니다. +[8, 21, 23, 41, 42, 43] +[3, 5, 11, 16, 32, 38] +[7, 11, 16, 35, 36, 44] +[1, 8, 11, 31, 41, 42] +[13, 14, 16, 38, 42, 45] +[7, 11, 30, 40, 42, 43] +[2, 13, 22, 32, 38, 45] +[1, 3, 5, 14, 22, 45] +``` + +- 당첨 내역 출력 + +``` +3개 일치 (5,000원) - 1개 +4개 일치 (50,000원) - 0개 +5개 일치 (1,500,000원) - 0개 +5개 일치, 보너스 볼 일치 (30,000,000원) - 0개 +6개 일치 (2,000,000,000원) - 0개 +``` + +- 수익률은 소수점 둘째자리에서 반올림 (Ex. 100.0%, 51.5%, 1,000,000.0%) + +``` +총 수익률은 62.5% 입니다. +``` + +- 예외 상황 시 에러 문구 출력. 단, 에러 문구는 "[ERROR]"로 시작해야한다. + +``` +[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다. +``` + +##### 실행 결과 예시 + +``` +구입금액을 입력해 주세요. +8000 + +8개를 구매했습니다. +[8, 21, 23, 41, 42, 43] +[3, 5, 11, 16, 32, 38] +[7, 11, 16, 35, 36, 44] +[1, 8, 11, 31, 41, 42] +[13, 14, 16, 38, 42, 45] +[7, 11, 30, 40, 42, 43] +[2, 13, 22, 32, 38, 45] +[1, 3, 5, 14, 22, 45] + +당첨 번호를 입력해 주세요. +1,2,3,4,5,6 + +보너스 번호를 입력해 주세요. +7 + +당첨 통계 +--- +3개 일치 (5,000원) - 1개 +4개 일치 (50,000원) - 0개 +5개 일치 (1,500,000원) - 0개 +5개 일치, 보너스 볼 일치 (30,000,000원) - 0개 +6개 일치 (2,000,000,000원) - 0개 +총 수익률은 62.5%입니다. +``` + +## 프로그래밍 요구사항 2 + +- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다. + - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. + - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. +- 3항 연산자를 쓰지 않는다. +- 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라. +- Jest를 이용하여 정리한 기능 목록이 정상적으로 작동하는지 테스트 코드로 확인한다. + - 테스트 도구 사용법이 익숙하지 않다면 아래 문서를 참고하여 학습한 후 테스트를 구현한다. + +## 프로그래밍 요구사항 3 + +- 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다. + - 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다. +- else를 지양한다. + - 때로는 if/else, when문을 사용하는 것이 더 깔끔해 보일 수 있다. 어느 경우에 쓰는 것이 적절할지 스스로 고민해 본다. + - 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다. +- 구현한 기능에 대한 단위 테스트를 작성한다. 단, UI(System.out, System.in, Scanner) 로직은 제외한다. + - 단위 테스트 작성이 익숙하지 않다면 LottoTest를 참고하여 학습한 후 테스트를 작성한다. + +#### 라이브러리 + +- @woowacourse/mission-utils에서 제공하는 Random 및 Console API를 사용하여 구현해야 한다. + - Random 값 추출은 Random. pickUniqueNumbersInRange()를 활용한다. + - 사용자의 값을 입력 및 출력하려면 Console.readLineAsync()와 Console.print()를 활용한다. + +###### 사용 예시 + +- 1에서 45 사이의 중복되지 않은 정수 6개 반환 + +```Javascript +MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6); +``` + +#### Lotto 클래스 + +- 제공된 `Lotto` 클래스를 사용하여 구현해야 한다. +- `Lotto`에 `numbers` 이외의 필드(인스턴스 변수)를 추가할 수 없다. +- `numbers`의 접근 제어자인 `#`은 변경할 수 없다. +- `Lotto`의 패키지를 변경할 수 있다. + +```javascript +class Lotto { + #numbers; + constructor(numbers) { + this.#validate(numbers); + this.#numbers = numbers; + } + + #validate(numbers) { + if (numbers.length !== 6) { + throw new Error('[ERROR] 로또 번호는 6개여야 합니다.'); + } + } + //TODO: 추가 기능 구현 +} +``` + +## 💻 구현 기능 목록 + +#### 입력 + +- 로또 구매 금액 +- 당첨 번호 6개 (쉼표 구분) +- 보너스 번호 1개 + +#### 입력 검증 + +###### 구매 금액 확인 + +- 숫자 확인, 아닌 경우 예외 처리 +- 1,000원 단위 확인, 아닌 경우 예외 처리 + +###### 당첨 번호 확인 + +- 숫자 범위 확인 (1~45) +- 예외 처리 ❌ + - 입력값이 없는 경우 (빈 배열) + - 숫자가 아닌 경우 + - 숫자 6개 보다 적거나 많은 경우 +- 6개 숫자의 중복 여부 확인 + +###### 보너스 번호 확인 + +- 숫자 범위 확인 (1~45) +- 예외 처리 ❌ + - 입력값이 없는 경우 + - 숫자가 아닌 경우 + - 번호가 2개 이상일 경우 + +###### ❓ + +``` +- 당첨 번호 추첨 시 당첨 번호와 보너스 번호는 중복되지 않아야하는데, 입력값도 그래야 하나? + - 그럴 경우 당첨번호와 보너스 번호의 중복 여부 추가 검증 +- 당첨 번호 6개와 보너스 번호 중복 여부 확인, 중복일 경우 예외 처리 +``` + +#### 로또 로직 + +- 무작위로 로또 번호 6개 출력 (`Random.pickUniqueNumbersInRange()`) +- 보너스 번호 출력 (`Random.pickNumberInRange(n,m)`) +- 입력받은 번호와 발행된 번호 비교 +- 당첨 여부 확인 로직 +- 수익률 계산 로직 + +#### 출력 + +- 구입 금액 +- 구매 내역 (갯수, 해당 로또 당첨 번호) +- 입력한 당첨 번호 +- 보너스 입력 번호 +- 당첨 통계 + - 5등부터 1등 순으로 당첨 여부 확인 내역 + - 총 수익률 (소수점 둘째 자리에서 반올림) diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 409aaf69b..b992f3ee1 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -1,18 +1,71 @@ -import Lotto from "../src/Lotto"; +import Lotto from '../src/Lotto'; -describe("로또 클래스 테스트", () => { - test("로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.", () => { +describe('로또 클래스 테스트', () => { + test('로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.', () => { expect(() => { new Lotto([1, 2, 3, 4, 5, 6, 7]); - }).toThrow("[ERROR]"); + }).toThrow('[ERROR]'); }); // TODO: 테스트가 통과하도록 프로덕션 코드 구현 - test("로또 번호에 중복된 숫자가 있으면 예외가 발생한다.", () => { + test('로또 번호에 중복된 숫자가 있으면 예외가 발생한다.', () => { expect(() => { new Lotto([1, 2, 3, 4, 5, 5]); - }).toThrow("[ERROR]"); + }).toThrow('[ERROR]'); + }); + + test('로또 번호의 개수가 6개보다 적으면 예외가 발생한다.', () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5]); + }).toThrow('[ERROR]'); + }); + + test('로또 번호에 중복된 숫자가 있으면 예외가 발생한다.', () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5, 5]); + }).toThrow('[ERROR]'); + }); + + test('로또 번호에 숫자가 아닌 값이 있으면 예외가 발생한다.', () => { + expect(() => { + new Lotto([1, 2, 'a', 4, 5, 6]); + }).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]'); + }); + + test('로또 번호에 음수나 소수가 포함되면 예외가 발생한다.', () => { + expect(() => { + new Lotto([-1, 2, 3, 4, 5, 6]); + }).toThrow('[ERROR]'); + expect(() => { + new Lotto([1.5, 2, 3, 4, 5, 6]); + }).toThrow('[ERROR]'); }); // TODO: 추가 기능 구현에 따른 테스트 코드 작성 + + test('유효한 6개의 번호로 생성된 경우 예외가 발생하지 않는다.', () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5, 6]); + }).not.toThrow(); + }); + + test('로또 번호는 오름차순으로 정렬되어 저장된다.', () => { + const lotto = new Lotto([6, 1, 3, 5, 2, 4]); + expect(lotto.getNumbers()).toEqual([1, 2, 3, 4, 5, 6]); + }); + + test('당첨 번호와 일치하는 개수를 반환한다.', () => { + const lotto = new Lotto([1, 2, 3, 4, 5, 6]); + const winningNumbers = [1, 3, 5, 7, 9, 11]; + expect(lotto.countMatchingNumbers(winningNumbers)).toBe(3); + }); }); diff --git a/src/App.js b/src/App.js index 091aa0a5d..17c319a04 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,26 @@ +import LottoGame from './LottoGame.js'; +import InputView from './views/InputView.js'; +import OutputView from './views/OutputView.js'; + class App { - async run() {} + async run() { + try { + const money = await InputView.readPurchaseAmount(); + const game = new LottoGame(money); + + OutputView.printLottoTickets(game.getTickets()); + + const winningNumbers = await InputView.readWinningNumbers(); + const bonuseNumber = await InputView.readBonusNumber(); + + const results = game.checkResult(winningNumbers, bonuseNumber); + const profitRate = game.calculateProfitRate(); + + OutputView.printStatistics(results, profitRate); + } catch (error) { + OutputView.printError(error.message); + } + } } export default App; diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e..59061570f 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -1,18 +1,29 @@ +import Validator from './utils/Validator.js'; + class Lotto { #numbers; constructor(numbers) { - this.#validate(numbers); - this.#numbers = numbers; + Validator.validateWinningNumbers(numbers); + this.#numbers = [...numbers].sort((a, b) => a - b); } - #validate(numbers) { - if (numbers.length !== 6) { - throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); - } - } + // #validate(numbers) { + + // } // TODO: 추가 기능 구현 + countMatchingNumbers(winningNumbers) { + return this.#numbers.filter((num) => winningNumbers.includes(num)).length; + } + + matchBonusNumber(bonusNumber) { + return this.#numbers.includes(bonusNumber); + } + + getNumbers() { + return [...this.#numbers]; + } } export default Lotto; diff --git a/src/LottoGame.js b/src/LottoGame.js new file mode 100644 index 000000000..7c086774f --- /dev/null +++ b/src/LottoGame.js @@ -0,0 +1,84 @@ +import { Random } from '@woowacourse/mission-utils'; +import { + LOTTO_NUMBER_COUNT, + LOTTO_NUMBER_MAX, + LOTTO_NUMBER_MIN, + LOTTO_PRICE, + PRIZE_TABLE, +} from './constants/lotto.js'; +import { ERROR } from './constants/messages.js'; +import Lotto from './Lotto.js'; + +class LottoGame { + #money; + + #tickets; + + #results; + + constructor(money) { + LottoGame.#validateMoney(money); + this.#money = Number(money); + this.#tickets = this.#generateTickets(); + this.#results = {}; + } + + static #validateMoney(money) { + const num = Number(money); + if (!Number.isInteger(num) || num <= 0 || num % LOTTO_PRICE !== 0) { + throw new Error(ERROR.INVALID_MONEY_1000); + } + } + + #calculateTicketCount() { + return this.#money / LOTTO_PRICE; + } + + #generateTickets() { + const count = this.#calculateTicketCount(); + const tickets = []; + + for (let i = 0; i < count; i += 1) { + const numbers = Random.pickUniqueNumbersInRange( + LOTTO_NUMBER_MIN, + LOTTO_NUMBER_MAX, + LOTTO_NUMBER_COUNT, + ); + tickets.push(new Lotto(numbers)); + } + return tickets; + } + + checkResult(winningNumbers, bonusNumber) { + const results = { 3: 0, 4: 0, 5: 0, 5.5: 0, 6: 0 }; + + this.#tickets.forEach((ticket) => { + const matchCount = ticket.countMatchingNumbers(winningNumbers); + const hasBonus = ticket.matchBonusNumber(bonusNumber); + + if (matchCount === 5 && hasBonus) { + results[5.5] += 1; + } else if (matchCount >= 3) { + results[matchCount] += 1; + } + }); + this.#results = results; + return results; + } + + calculateProfitRate() { + const totalPrize = Object.entries(this.#results).reduce( + (sum, [match, count]) => sum + PRIZE_TABLE[match] * count, + 0, + ); + + const rate = (totalPrize / this.#money) * 100; + return Number(rate.toFixed(2)); + } + + getTickets() { + return [...this.#tickets]; + } +} + +export default LottoGame; diff --git a/src/constants/lotto.js b/src/constants/lotto.js new file mode 100644 index 000000000..110388f06 --- /dev/null +++ b/src/constants/lotto.js @@ -0,0 +1,12 @@ +export const LOTTO_NUMBER_COUNT = 6; +export const LOTTO_PRICE = 1000; +export const LOTTO_NUMBER_MIN = 1; +export const LOTTO_NUMBER_MAX = 45; + +export const PRIZE_TABLE = { + 3: 5000, + 4: 50000, + 5: 1500000, + 5.5: 30000000, + 6: 2000000000, +}; diff --git a/src/constants/messages.js b/src/constants/messages.js new file mode 100644 index 000000000..fdcc2dcc1 --- /dev/null +++ b/src/constants/messages.js @@ -0,0 +1,11 @@ +export const ERROR_PREFIX = '[ERROR]'; + +export const ERROR = { + INVALID_ISNAN: `${ERROR_PREFIX} 입력값은 숫자여야 합니다.`, + INVALID_POSITIVE_NUMBER: `${ERROR_PREFIX} 숫자는 양의 정수만 입력할 수 있습니다.`, + INVALID_MONEY_1000: `${ERROR_PREFIX} 구입 금액은 1,000원 단위의 숫자여야 합니다.`, + INVALID_WINNING_NUMBERS_6: `${ERROR_PREFIX} 당첨 번호는 6개의 숫자여야 합니다.`, + INVALID_NUMBER_OUT_OF_RANGE: `${ERROR_PREFIX} 번호는 1~45 사이의 숫자여야 합니다.`, + INVALID_BONUS_NUMBER_ONE: `${ERROR_PREFIX} 보너스 번호는 1개여야 합니다.`, + INVALID_NUMBER_DUPLICATE: `${ERROR_PREFIX} 번호는 중복될 수 없습니다.`, +}; diff --git a/src/tests/Validator.test.js b/src/tests/Validator.test.js new file mode 100644 index 000000000..9f8901286 --- /dev/null +++ b/src/tests/Validator.test.js @@ -0,0 +1,106 @@ +import Validator from '../utils/Validator.js'; +import { ERROR } from '../constants/messages.js'; + +describe('Validator 테스트', () => { + describe('validateWinningNumbers', () => { + test('배열이 아닌 값이 들어오면 예외가 발생한다.', () => { + expect(() => { + Validator.validateWinningNumbers('1,2,3,4,5,6'); + }).toThrow(ERROR.INVALID_WINNING_NUMBERS_6); + }); + + test('당첨 번호가 6개가 아니면 예외가 발생한다.', () => { + expect(() => { + Validator.validateWinningNumbers([1, 2, 3, 4, 5]); + }).toThrow(ERROR.INVALID_WINNING_NUMBERS_6); + }); + + test('숫자가 아닌 값이 하나라도 있으면 예외가 발생한다.', () => { + expect(() => { + Validator.validateWinningNumbers([1, 'a', 3, 4, 5, 6]); + }).toThrow(ERROR.INVALID_ISNAN); + }); + + test('0이 포함되면 양의 정수 예외가 발생한다.', () => { + expect(() => { + Validator.validateWinningNumbers([0, 2, 3, 4, 5, 6]); + }).toThrow(ERROR.INVALID_POSITIVE_NUMBER); + }); + + test('1~45 범위를 벗어나면 범위 예외가 발생한다.', () => { + expect(() => { + Validator.validateWinningNumbers([1, 2, 3, 4, 5, 46]); + }).toThrow(ERROR.INVALID_NUMBER_OUT_OF_RANGE); + }); + + test('중복된 번호가 있으면 예외가 발생한다.', () => { + expect(() => { + Validator.validateWinningNumbers([1, 2, 3, 4, 5, 5]); + }).toThrow(ERROR.INVALID_NUMBER_DUPLICATE); + }); + + test('정상적인 6개 번호면 예외가 발생하지 않는다.', () => { + expect(() => { + Validator.validateWinningNumbers([1, 2, 3, 4, 5, 6]); + }).not.toThrow(); + }); + }); + + describe('validateMoney', () => { + test('숫자가 아니거나 양의 정수가 아니면 예외가 발생한다.', () => { + expect(() => { + Validator.validateMoney('abc'); + }).toThrow(ERROR.INVALID_POSITIVE_NUMBER); + + expect(() => { + Validator.validateMoney(0); + }).toThrow(ERROR.INVALID_POSITIVE_NUMBER); + }); + + test('1,000원 단위가 아니면 예외가 발생한다.', () => { + expect(() => { + Validator.validateMoney(1500); + }).toThrow(ERROR.INVALID_MONEY_1000); + }); + + test('정상 금액은 통과한다.', () => { + expect(() => { + Validator.validateMoney(3000); + }).not.toThrow(); + }); + }); + + describe('validateBonusNumber', () => { + const winningNums = [1, 2, 3, 4, 5, 6]; + + test('보너스 번호가 숫자가 아니면 예외가 발생한다.', () => { + expect(() => { + Validator.validateBonusNumber(winningNums, 'a'); + }).toThrow(ERROR.INVALID_ISNAN); + }); + + test('보너스 번호가 0이면 양의 정수 예외가 발생한다.', () => { + expect(() => { + Validator.validateBonusNumber(winningNums, 0); + }).toThrow(ERROR.INVALID_POSITIVE_NUMBER); + }); + + test('보너스 번호가 46이면 범위 초과 예외가 발생한다.', () => { + expect(() => { + Validator.validateBonusNumber(winningNums, 46); + }).toThrow(ERROR.INVALID_NUMBER_OUT_OF_RANGE); + }); + + test('보너스 번호가 당첨 번호와 중복되면 예외가 발생한다.', () => { + expect(() => { + Validator.validateBonusNumber(winningNums, 3); + }).toThrow(ERROR.INVALID_BONUS_NUMBER_DUPLICATE); + }); + + test('정상적인 보너스 번호면 통과한다.', () => { + expect(() => { + Validator.validateBonusNumber(winningNums, 10); + }).not.toThrow(); + }); + }); +}); diff --git a/src/utils/Validator.js b/src/utils/Validator.js new file mode 100644 index 000000000..5911d1a23 --- /dev/null +++ b/src/utils/Validator.js @@ -0,0 +1,65 @@ +import { LOTTO_NUMBER_MAX, LOTTO_NUMBER_MIN } from '../constants/lotto.js'; +import { ERROR } from '../constants/messages.js'; + +const Validator = { + validatePositiveInteger(value) { + const num = Number(value); + if (!Number.isInteger(num) || num <= 0) { + throw new Error(ERROR.INVALID_POSITIVE_NUMBER); + } + }, + + validateMoney(money) { + const num = Number(money); + this.validatePositiveInteger(num); + if (num % 1000 !== 0) { + throw new Error(ERROR.INVALID_MONEY_1000); + } + }, + + validateWinningNumbers(numbers) { + if (numbers.length !== 6) { + throw new Error(ERROR.INVALID_WINNING_NUMBERS_6); + } + + const hasNonNumber = numbers.some((num) => Number.isNaN(Number(num))); + if (hasNonNumber) { + throw new Error(ERROR.INVALID_ISNAN); + } + + numbers.forEach((num) => this.validatePositiveInteger(num)); + + const hasOutOfRangeNumber = numbers.some( + (num) => Number(num) < LOTTO_NUMBER_MIN || Number(num) > LOTTO_NUMBER_MAX, + ); + if (hasOutOfRangeNumber) { + throw new Error(ERROR.INVALID_NUMBER_OUT_OF_RANGE); + } + + const unique = new Set(numbers.map(Number)); + if (unique.size !== numbers.length) { + throw new Error(ERROR.INVALID_NUMBER_DUPLICATE); + } + }, + + validateBonusNumber(winningNums, bonusNum) { + const num = Number(bonusNum); + + if (Number.isNaN(num)) { + throw new Error(ERROR.INVALID_ISNAN); + } + + this.validatePositiveInteger(num); + + if (Number(num) < LOTTO_NUMBER_MIN || Number(num) > LOTTO_NUMBER_MAX) { + throw new Error(ERROR.INVALID_NUMBER_OUT_OF_RANGE); + } + + const isDuplicate = winningNums.map(Number).includes(num); + if (isDuplicate) { + throw new Error(ERROR.INVALID_NUMBER_DUPLICATE); + } + }, +}; + +export default Validator; diff --git a/src/views/InputView.js b/src/views/InputView.js new file mode 100644 index 000000000..95da0089f --- /dev/null +++ b/src/views/InputView.js @@ -0,0 +1,20 @@ +import { Console } from '@woowacourse/mission-utils'; + +const InputView = { + async readPurchaseAmount() { + const input = await Console.readLineAsync('구입 금액을 입력해 주세요. \n'); + return Number(input); + }, + + async readWinningNumbers() { + const input = await Console.readLineAsync('당첨 번호를 입력해주세요. \n'); + return input.split(',').map((num) => Number(num.trim())); + }, + + async readBonusNumber() { + const input = await Console.readLineAsync('보너스 번호를 입력해주세요. \n'); + return Number(input.trim()); + }, +}; + +export default InputView; diff --git a/src/views/OutputView.js b/src/views/OutputView.js new file mode 100644 index 000000000..366e12543 --- /dev/null +++ b/src/views/OutputView.js @@ -0,0 +1,29 @@ +import { Console } from '@woowacourse/mission-utils'; + +const OutputView = { + printLottoTickets(tickets) { + Console.print(`\n${tickets.length}개를 구매했습니다.`); + tickets.forEach((ticket) => { + const numbers = ticket.getNumbers().join(', '); + Console.print(`[${numbers}]`); + }); + }, + + printStatistics(results, profitRate) { + Console.print('\n당첨 통계\n---'); + Console.print(`3개 일치 (5,000원) - ${results[3]}개`); + Console.print(`4개 일치 (50,000원) - ${results[4]}개`); + Console.print(`5개 일치 (1,500,000원) - ${results[5]}개`); + Console.print( + `5개 일치, 보너스 볼 일치 (30,000,000원) - ${results[5.5]}개`, + ); + Console.print(`6개 일치 (2,000,000,000원) - ${results[6]}개`); + Console.print(`총 수익률은 ${profitRate}%입니다.`); + }, + + printError(message) { + Console.print(message); + }, +}; + +export default OutputView;