diff --git a/README.md b/README.md index 15bb106b5..3103de9eb 100644 --- a/README.md +++ b/README.md @@ -1 +1,59 @@ -# javascript-lotto-precourse +# 로또 발매기 + +간단한 로또 발매기 +구매한 로또의 금액과 당첨된 로또의 금액을 비교하여 수익률을 알려주는 프로그램 + +## 실행 결과 + +### 입력 + +``` plaintext + 구입금액을 입력해 주세요. + 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%입니다. +``` + +## 구현할 기능 +- [x] 입력 받기 + - [x] 로또 구매할 금액 입력 + - [x] 1000원으로 나누어 떨어지지 않는 경우 ERROR + - [x] 당첨 번호 입력 + - [x] 예외 처리 + - [x] ','로 구분 안되는 값 + - [x] 숫자가 아닌 값 + - [x] 중복된 값 + - [x] 보너스 번호 입력 + - [x] 예외 처리 + - [x] 숫자가 아닌 값 + - [x] 입력 당첨 번호와 중복된 값 + +- [ ] 로또 발행하기 + - [x] 구매한 로또만큼 번호 발행 + - [x] 발행한 로또 출력 + - [x] 발행한 로또 당첨 처리 + - [x] 당첨 내역 출력 + - [x] 수익률 출력 diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 409aaf69b..22a9ad58f 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -1,4 +1,4 @@ -import Lotto from "../src/Lotto"; +import Lotto from "../src/Lotto.js"; describe("로또 클래스 테스트", () => { test("로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.", () => { diff --git a/src/App.js b/src/App.js index 091aa0a5d..9a2b85a55 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,39 @@ +import Customer from "./model/Customer.js"; +import Lotto from "./Lotto.js"; +import LottoChecker from "./model/LottoChecker.js"; +import InputView from "./view/InputView.js"; + class App { - async run() {} + async run() { + const input = new InputView(); + const customer = new Customer(); + const lottoChecker = new LottoChecker(); + + + // 로또 구매 및 출력 + const purchaseAmount = await input.readPurchaseAmount(); + customer.purchaseLotto(purchaseAmount); + customer.getLottoNumberList(); + + // 생성한 번호 출력 + customer.lottoNumbersPrint(); + + const winningNumbers = await input.readWinningNumbers(); + const lotto = new Lotto(winningNumbers); + const validWinningNumbers = lotto.getNumbers(); + const bonusNumber = await input.readBonusNumber(); + + lottoChecker.setWinningAndBonusNumbers(validWinningNumbers, bonusNumber); + customer.getLottoResults(lottoChecker); + + customer.calculateProfit(); + customer.lottoResultPrint(); + + + + + + } } export default App; diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e..f054e8c08 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -10,9 +10,20 @@ class Lotto { if (numbers.length !== 6) { throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); } + + if (new Set(numbers).size !== numbers.length) { + throw new Error("[ERROR] 로또 당첨 번호는 중복된 값을 가질 수 없습니다."); + } + + if (numbers.some((number) => number < 1 || number > 45)) { + throw new Error("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + } + } + + getNumbers() { + return this.#numbers; } - // TODO: 추가 기능 구현 } export default Lotto; diff --git a/src/View/InputView.js b/src/View/InputView.js new file mode 100644 index 000000000..994af50cc --- /dev/null +++ b/src/View/InputView.js @@ -0,0 +1,28 @@ +import { Console } from "@woowacourse/mission-utils"; + +export default class InputView { + + async readPurchaseAmount() { + const purchaseAmountStr = await Console.readLineAsync("구입금액을 입력해 주세요.\n"); + const purchaseAmount = Number(purchaseAmountStr); + return purchaseAmount; + } + + async readWinningNumbers() { + const winningNumbers = await Console.readLineAsync("당첨 번호를 입력해 주세요.\n"); + const winningNumbersArr = this.splitNumbers(winningNumbers); + return winningNumbersArr; + } + + async readBonusNumber() { + let bonusNumber = await Console.readLineAsync("보너스 번호를 입력해 주세요.\n"); + bonusNumber = Number(bonusNumber.trim()); + return bonusNumber; + } + + splitNumbers(winningNumbers) { + const numbersArray = winningNumbers.split(',').map(number => Number(number.trim())); + return numbersArray; + } + +} \ No newline at end of file diff --git a/src/View/outputView.js b/src/View/outputView.js new file mode 100644 index 000000000..4be72301e --- /dev/null +++ b/src/View/outputView.js @@ -0,0 +1,6 @@ +import { Console } from "@woowacourse/mission-utils"; + +export default class outputView { + + static +} \ No newline at end of file diff --git a/src/model/Customer.js b/src/model/Customer.js new file mode 100644 index 000000000..2552c7561 --- /dev/null +++ b/src/model/Customer.js @@ -0,0 +1,61 @@ +import Lotto from "../Lotto.js"; +import LottoChecker from "./LottoChecker.js"; +import { Console } from "@woowacourse/mission-utils"; + +export default class Customer { + #purchaseAmount; + #lottoNumbersList = []; + #lottoRankResults = [0, 0, 0, 0, 0, 0]; // index = 결과 등수 + #lottoCount; + #profitRate; + #profit = 0; + + #valid(purchaseAmount) { + if (purchaseAmount % 1000 !== 0) + throw new Error("[ERROR] 구매금액은 1000원 단위이어야합니다."); + } + + purchaseLotto(purchaseAmount) { + this.#valid(purchaseAmount); + this.#purchaseAmount = purchaseAmount; + this.#lottoCount = purchaseAmount/1000; + } + + getLottoNumberList() { + Array.from({ length: this.#lottoCount }).forEach(() => { + const lottoNumbers = LottoChecker.generateLottoNumbers(); + this.#lottoNumbersList.push(lottoNumbers); + }) + } + + getLottoResults(lottoChecker) { + this.#lottoNumbersList.forEach(lottoNumbers => { + const rank = lottoChecker.getLottoRank(lottoNumbers); + this.#lottoRankResults[rank] += 1; + }) + } + + lottoNumbersPrint() { + Console.print(`${this.#lottoCount}개를 구매했습니다.\n`); + this.#lottoNumbersList.forEach((lottoNumbers) => { + Console.print(`${lottoNumbers}\n`); + }) + } + + calculateProfit() { + const prizeAmounts = [0, 2000000000, 30000000, 1500000, 50000, 5000]; + + this.#lottoRankResults.forEach((count, rank) => { + this.#profit += count * prizeAmounts[rank]; + }); + + this.#profitRate = Math.round((this.#profit / this.#purchaseAmount) * 10000) / 100; + } + + lottoResultPrint() { + Console.print("당첨 통계\n---\n"); + Console.print(`3개 일치 (5,000원) - ${this.#lottoRankResults[5]}개\n4개 일치 (50,000원) - ${this.#lottoRankResults[4]}개\n5개 일치 (1,500,000원) - ${this.#lottoRankResults[3]}개\n5개 일치, 보너스 볼 일치 (30,000,000원) - ${this.#lottoRankResults[2]}개\n6개 일치 (2,000,000,000원) - ${this.#lottoRankResults[1]}개\n총 수익률은 ${this.#profitRate}%입니다.\n + `) + } + +} \ No newline at end of file diff --git a/src/model/LottoChecker.js b/src/model/LottoChecker.js new file mode 100644 index 000000000..5ebb4a8c7 --- /dev/null +++ b/src/model/LottoChecker.js @@ -0,0 +1,34 @@ +import { Random } from "@woowacourse/mission-utils"; + +export default class LottoChecker { + #winningNumbers=[]; + #bonusNumber; + + setWinningAndBonusNumbers(winningNumbers, bonusNumber) { + this.#winningNumbers = winningNumbers; + this.#bonusNumber = bonusNumber; + } + + static generateLottoNumbers() { + const lottoNumbers = Random.pickUniqueNumbersInRange(1, 45, 6); + return lottoNumbers; + } + + // return : 로또 등수 + getLottoRank(LottoNumbers) { + const winningCount = LottoNumbers.filter(number => this.#winningNumbers.includes(number)) + const actions = { + 3: () => {return 5}, + 4: () => {return 4}, + 5: () => { + if (LottoNumbers.includes(this.#bonusNumber)) + return 2; + return 3; + }, + 6: () => { return 1; }, + default: () => { return 0;} + } + const rank = (actions[winningCount.length] || actions.default)(); + return rank; + } +} \ No newline at end of file