From e3a0d6bd8cbe47d820fa2341ffc8f0460dda2e22 Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 11:40:50 +0900 Subject: [PATCH 01/14] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..6a2a3c4b4e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,31 @@ +# 기능 목록 정리 + +## 입력 +### 로또 구입 금액 +- [ ] 로또 구입 금액을 입력받는다. +- [ ] (예외) 숫자가 아닌 경우 +- [ ] (예외) 1,000 단위로 나누어 떨어지지 않는 경우 + +### 당첨 번호 +- [ ] 쉼표(,)를 기준으로 당첨 번호를 입력받는다. +- [ ] (예외) 각 번호의 숫자 범위가 1~45에 포함되지 않는 경우 +- [ ] (예외) 번호가 중복되는 경우 + +### 보너스 번호 +- [ ] 보너스 번호를 입력받는다 +- [ ] (예외) 숫자가 아닌 경우 + +## 출력 +- [ ] 발행한 로또 수량 및 번호를 오름차순으로 출력한다. +- [ ] 당첨 내역을 출력한다. +- [ ] 수익률은 소수점 둘째 자리에서 반올림한다. +- [ ] 예외 상황 시 에러 분구 출력 + +## 진행 +- [ ] 구입 금액 입력 +- [ ] 로또 구입 금액에 해당하는 만큼 로또 발행 +- [ ] 구매 확인 문구 출력 +- [ ] 당첨 번호 입력 +- [ ] 보너스 번호 입력 +- [ ] 사용자가 구매한 로또 번호와 당첨 번호를 비교 +- [ ] 당첨 내역 및 수익률 출력 \ No newline at end of file From 48fdd9ee3bd17502f86a61df153bf7be8d2757be Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 16:44:25 +0900 Subject: [PATCH 02/14] =?UTF-8?q?test:=20=EA=B5=AC=EC=9E=85=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EC=9E=85=EB=A0=A5=20=EC=98=88=EC=99=B8=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/InputMoneyTest.js | 49 +++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 __tests__/InputMoneyTest.js diff --git a/__tests__/InputMoneyTest.js b/__tests__/InputMoneyTest.js new file mode 100644 index 0000000000..b6838a0cfe --- /dev/null +++ b/__tests__/InputMoneyTest.js @@ -0,0 +1,49 @@ +import App from "../src/App.js"; +import { MissionUtils } from "@woowacourse/mission-utils"; + +const mockQuestions = (inputs) => { + MissionUtils.Console.readLineAsync = jest.fn(); + + MissionUtils.Console.readLineAsync.mockImplementation(() => { + const input = inputs.shift(); + + return Promise.resolve(input); + }); +}; +describe("구입금액 테스트", () => { + test("구입금액이 숫자가 아니면 예외가 발생한다.", async () => { + // given + mockQuestions(['천원']); + + // when + const app = new App(); + + // then + await expect(app.play()).rejects.toThrow("[ERROR]"); + }); + + // TODO: 이 테스트가 통과할 수 있게 구현 코드 작성 + test("구입금액이 1000원 단위로 나누어 떨어지지 않으면 예외가 발생한다.", async () => { + // given + mockQuestions(['8888']); + + // when + const app = new App(); + + // then + await expect(app.play()).rejects.toThrow("[ERROR]"); + }); + + test("구입금액이 0원인 경우 예외가 발생한다.", async () => { + // given + mockQuestions(['0']); + + // when + const app = new App(); + + // then + await expect(app.play()).rejects.toThrow("[ERROR]"); + }); + + // 아래에 추가 테스트 작성 가능 +}); \ No newline at end of file From eda7e4eb4c9b1bf91ea45e2e5561f61992adea31 Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 16:45:05 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feat:=20=EA=B5=AC=EC=9E=85=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 8 +++++--- src/App.js | 11 ++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/README.md b/docs/README.md index 6a2a3c4b4e..089c584729 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,9 +2,11 @@ ## 입력 ### 로또 구입 금액 -- [ ] 로또 구입 금액을 입력받는다. -- [ ] (예외) 숫자가 아닌 경우 -- [ ] (예외) 1,000 단위로 나누어 떨어지지 않는 경우 +- [x] 로또 구입 금액을 입력받는다. +- [x] (예외) 숫자가 아닌 경우 +- [x] (예외) 1,000 단위로 나누어 떨어지지 않는 경우 +- [x] (예외) 0원인 경우 + ### 당첨 번호 - [ ] 쉼표(,)를 기준으로 당첨 번호를 입력받는다. diff --git a/src/App.js b/src/App.js index c38b30d5b2..93079176cd 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,14 @@ +import { MissionUtils } from "@woowacourse/mission-utils"; + class App { - async play() {} + async play() { + const money = await MissionUtils.Console.readLineAsync('구입금액을 입력해 주세요.\n'); + + // 예외처리 + if (isNaN(money)) throw new Error("[ERROR] 구입금액은 숫자여야 합니다."); + if (parseInt(money / 1000) !== money / 1000) throw new Error("[ERROR] 구입금액은 1000원 단위여야 합니다."); + if (money == 0) throw new Error("[ERROR] 구입금액은 0원 이상이어야 합니다."); + } } export default App; From f38bfe311f2c53145c99ca227598c78d7d7b5115 Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 18:25:12 +0900 Subject: [PATCH 04/14] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EA=B5=AC?= =?UTF-8?q?=EC=9E=85=EA=B8=88=EC=95=A1=EC=97=90=20=ED=95=B4=EB=8B=B9?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A7=8C=ED=81=BC=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EB=B0=9C=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 6 +++--- src/App.js | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 089c584729..18b6b72908 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,14 +18,14 @@ - [ ] (예외) 숫자가 아닌 경우 ## 출력 -- [ ] 발행한 로또 수량 및 번호를 오름차순으로 출력한다. +- [x] 발행한 로또 수량 및 번호를 오름차순으로 출력한다. - [ ] 당첨 내역을 출력한다. - [ ] 수익률은 소수점 둘째 자리에서 반올림한다. - [ ] 예외 상황 시 에러 분구 출력 ## 진행 -- [ ] 구입 금액 입력 -- [ ] 로또 구입 금액에 해당하는 만큼 로또 발행 +- [x] 구입 금액 입력 +- [x] 로또 구입 금액에 해당하는 만큼 로또 발행 - [ ] 구매 확인 문구 출력 - [ ] 당첨 번호 입력 - [ ] 보너스 번호 입력 diff --git a/src/App.js b/src/App.js index 93079176cd..9e75a5492c 100644 --- a/src/App.js +++ b/src/App.js @@ -8,6 +8,16 @@ class App { if (isNaN(money)) throw new Error("[ERROR] 구입금액은 숫자여야 합니다."); if (parseInt(money / 1000) !== money / 1000) throw new Error("[ERROR] 구입금액은 1000원 단위여야 합니다."); if (money == 0) throw new Error("[ERROR] 구입금액은 0원 이상이어야 합니다."); + + // 구입금액에 해당하는 만큼 로또 발행 + let count = money / 1000; + MissionUtils.Console.print(`${count}개를 구매했습니다.`); + const lottoList = []; + while(count--) { + lottoList.push(MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6).sort((a, b) => a - b)); + } + + console.log(lottoList); } } From 1d4936101aabc9f51658b99b7eb978dec0885b62 Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 18:38:05 +0900 Subject: [PATCH 05/14] =?UTF-8?q?test:=20=EB=A1=9C=EB=98=90=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=EC=98=88=EC=99=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/LottoTest.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 97bd457659..00ed3188f2 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -14,5 +14,17 @@ describe("로또 클래스 테스트", () => { }).toThrow("[ERROR]"); }); + test("로또 번호에 숫자가 아닌 값이 있으면 예외가 발생한다.", () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5, 'a']); + }).toThrow("[ERROR]"); + }); + + test("로또 번호에 1~45 이외의 숫자가 있으면 예외가 발생한다..", () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5, 50]); + }).toThrow("[ERROR]"); + }); + // 아래에 추가 테스트 작성 가능 }); From b8359d5af0681ab3ebcc1ce27c79b409ce90dccc Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 18:39:13 +0900 Subject: [PATCH 06/14] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=8B=B9?= =?UTF-8?q?=EC=B2=A8=20=EB=B2=88=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 11 ++++++----- src/App.js | 6 +++++- src/Lotto.js | 5 +++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 18b6b72908..3789b7a91b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,9 +9,11 @@ ### 당첨 번호 -- [ ] 쉼표(,)를 기준으로 당첨 번호를 입력받는다. -- [ ] (예외) 각 번호의 숫자 범위가 1~45에 포함되지 않는 경우 -- [ ] (예외) 번호가 중복되는 경우 +- [x] 쉼표(,)를 기준으로 당첨 번호를 입력받는다. +- [x] (예외) 숫자가 아닌 경우 +- [x] (예외) 각 번호의 숫자 범위가 1~45에 포함되지 않는 경우 +- [x] (예외) 번호가 중복되는 경우 +- [x] (예외) 번호가 6개가 아닌 경우 ### 보너스 번호 - [ ] 보너스 번호를 입력받는다 @@ -26,8 +28,7 @@ ## 진행 - [x] 구입 금액 입력 - [x] 로또 구입 금액에 해당하는 만큼 로또 발행 -- [ ] 구매 확인 문구 출력 -- [ ] 당첨 번호 입력 +- [x] 당첨 번호 입력 - [ ] 보너스 번호 입력 - [ ] 사용자가 구매한 로또 번호와 당첨 번호를 비교 - [ ] 당첨 내역 및 수익률 출력 \ No newline at end of file diff --git a/src/App.js b/src/App.js index 9e75a5492c..c288b3ad14 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,5 @@ import { MissionUtils } from "@woowacourse/mission-utils"; +import Lotto from './Lotto.js'; class App { async play() { @@ -16,8 +17,11 @@ class App { while(count--) { lottoList.push(MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6).sort((a, b) => a - b)); } + MissionUtils.Console.print(lottoList); - console.log(lottoList); + // 당첨 번호 입력 + const win = await MissionUtils.Console.readLineAsync('당첨 번호를 입력해 주세요.\n'); + const lotto = new Lotto(win.split(',')); } } diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e9..985482344d 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -7,6 +7,11 @@ class Lotto { } #validate(numbers) { + [...numbers].map((v, idx) => { + if (isNaN(parseInt(v))) throw new Error("[ERROR] 로또 번호는 숫자여야 합니다."); + if (1 > v || v > 45) throw new Error("[ERROR] 로또 번호는 1~45 사이여야 합니다."); + if (numbers.indexOf(v) !== idx) throw new Error("[ERROR] 로또 번호는 중복될 수 없습니다"); + }) if (numbers.length !== 6) { throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); } From 28409adfbedcecba5844ed2158bfd79ac2cf58c8 Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 21:33:30 +0900 Subject: [PATCH 07/14] =?UTF-8?q?test:=20=EB=B3=B4=EB=84=88=EC=8A=A4=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/BonusTest.js | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 __tests__/BonusTest.js diff --git a/__tests__/BonusTest.js b/__tests__/BonusTest.js new file mode 100644 index 0000000000..1f3b1600e1 --- /dev/null +++ b/__tests__/BonusTest.js @@ -0,0 +1,49 @@ +import App from "../src/App.js"; +import { MissionUtils } from "@woowacourse/mission-utils"; + +const mockQuestions = (inputs) => { + MissionUtils.Console.readLineAsync = jest.fn(); + + MissionUtils.Console.readLineAsync.mockImplementation(() => { + const input = inputs.shift(); + + return Promise.resolve(input); + }); +}; + +describe("보너스 번호 입력 테스트", () => { + test("보너스 번호가 숫자가 아니면 예외가 발생한다.", async () => { + // given + mockQuestions(["8000", "1,2,3,4,5,6", "one"]); + + // when + const app = new App(); + + // then + await expect(app.play()).rejects.toThrow("[ERROR]"); + }); + + test("보너스 번호가 1~45 범위를 벗어나면 예외가 발생한다.", async () => { + // given + mockQuestions(["8000", "1,2,3,4,5,6", "50"]); + + // when + const app = new App(); + + // then + await expect(app.play()).rejects.toThrow("[ERROR]"); + }); + + test("보너스 번호가 당첨 번호와 중복될 경우 예외가 발생한다.", async () => { + // given + mockQuestions(["8000", "1,2,3,4,5,6", "1"]); + + // when + const app = new App(); + + // then + await expect(app.play()).rejects.toThrow("[ERROR]"); + }); + + // 아래에 추가 테스트 작성 가능 +}); \ No newline at end of file From a1eb49ec78f981aebdfde195b54b5b703079ada0 Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 21:34:35 +0900 Subject: [PATCH 08/14] =?UTF-8?q?feat:=20=EB=B3=B4=EB=84=88=EC=8A=A4=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 9 ++++++--- src/App.js | 6 ++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 3789b7a91b..b94968e6fe 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,8 +16,11 @@ - [x] (예외) 번호가 6개가 아닌 경우 ### 보너스 번호 -- [ ] 보너스 번호를 입력받는다 -- [ ] (예외) 숫자가 아닌 경우 +- [x] 보너스 번호를 입력받는다 +- [x] (예외) 숫자가 아닌 경우 +- [x] (예외) 숫자 범위가 1~45에 포함되지 않는 경우 +- [x] (예외) 당첨 번호와 중복되는 경우 + ## 출력 - [x] 발행한 로또 수량 및 번호를 오름차순으로 출력한다. @@ -29,6 +32,6 @@ - [x] 구입 금액 입력 - [x] 로또 구입 금액에 해당하는 만큼 로또 발행 - [x] 당첨 번호 입력 -- [ ] 보너스 번호 입력 +- [x] 보너스 번호 입력 - [ ] 사용자가 구매한 로또 번호와 당첨 번호를 비교 - [ ] 당첨 내역 및 수익률 출력 \ No newline at end of file diff --git a/src/App.js b/src/App.js index c288b3ad14..07da3f97cd 100644 --- a/src/App.js +++ b/src/App.js @@ -22,6 +22,12 @@ class App { // 당첨 번호 입력 const win = await MissionUtils.Console.readLineAsync('당첨 번호를 입력해 주세요.\n'); const lotto = new Lotto(win.split(',')); + + // 보너스 번호 입력 + const bonus = await MissionUtils.Console.readLineAsync('보너스 번호를 입력해 주세요.\n'); + if (isNaN(parseInt(bonus))) throw new Error("[ERROR] 보너스 번호는 숫자여야 합니다."); + if (1 > bonus || bonus > 45) throw new Error("[ERROR] 보너스 번호는 1~45 사이여야 합니다."); + if (win.includes(bonus)) throw new Error("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."); } } From ed892925bfef6afbca97ba7962cf835a78b38a9b Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 22:27:04 +0900 Subject: [PATCH 09/14] =?UTF-8?q?test:=20=EB=A1=9C=EB=98=90=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EC=9D=98=20=EB=8B=B9=EC=B2=A8=20=ED=86=B5?= =?UTF-8?q?=EA=B3=84=20=ED=95=A8=EC=88=98=EC=97=90=20=EB=8C=80=ED=95=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/LottoTest.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 00ed3188f2..4f7fe3f0ac 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -1,3 +1,4 @@ +import App from '../src/App.js'; import Lotto from "../src/Lotto.js"; describe("로또 클래스 테스트", () => { @@ -24,7 +25,25 @@ describe("로또 클래스 테스트", () => { expect(() => { new Lotto([1, 2, 3, 4, 5, 50]); }).toThrow("[ERROR]"); - }); + }) + + test("당첨 통계 테스트1", async () => { + const lotto = new Lotto([1, 2, 3, 4, 5, 6]); - // 아래에 추가 테스트 작성 가능 + expect( + lotto.stats( + [ + [7, 8, 9, 10, 11, 12], // 0 + [6, 7, 8, 9, 10 , 11, 12], // 1 + [5, 6, 7, 8, 9, 10], // 2 + [4, 5, 6, 7, 8, 9], // 3 + [3, 4, 5, 6, 7, 8], // 4 + [2, 3, 4, 5, 6, 7], // 5 + bonus + [2, 3, 4, 5, 6, 8], // 5 + [1, 2, 3, 4, 5, 6], // 6 + ], + 7 + ) + ).toEqual([1, 1, 1, 1, 1]); + }) }); From 003a643102462a3cc61256b418b14bc944051e7b Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 22:28:39 +0900 Subject: [PATCH 10/14] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=EA=B5=AC=EB=A7=A4=ED=95=9C=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=EC=99=80=20=EB=8B=B9=EC=B2=A8=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=EB=A5=BC=20=EB=B9=84=EA=B5=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 3 +-- src/App.js | 5 ++++- src/Lotto.js | 17 ++++++++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/README.md b/docs/README.md index b94968e6fe..a7be03ed17 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,12 +26,11 @@ - [x] 발행한 로또 수량 및 번호를 오름차순으로 출력한다. - [ ] 당첨 내역을 출력한다. - [ ] 수익률은 소수점 둘째 자리에서 반올림한다. -- [ ] 예외 상황 시 에러 분구 출력 ## 진행 - [x] 구입 금액 입력 - [x] 로또 구입 금액에 해당하는 만큼 로또 발행 - [x] 당첨 번호 입력 - [x] 보너스 번호 입력 -- [ ] 사용자가 구매한 로또 번호와 당첨 번호를 비교 +- [x] 사용자가 구매한 로또 번호와 당첨 번호를 비교 - [ ] 당첨 내역 및 수익률 출력 \ No newline at end of file diff --git a/src/App.js b/src/App.js index 07da3f97cd..7673786c3b 100644 --- a/src/App.js +++ b/src/App.js @@ -21,13 +21,16 @@ class App { // 당첨 번호 입력 const win = await MissionUtils.Console.readLineAsync('당첨 번호를 입력해 주세요.\n'); - const lotto = new Lotto(win.split(',')); + const lotto = new Lotto(win.split(',').map(v=>Number(v))); // 보너스 번호 입력 const bonus = await MissionUtils.Console.readLineAsync('보너스 번호를 입력해 주세요.\n'); if (isNaN(parseInt(bonus))) throw new Error("[ERROR] 보너스 번호는 숫자여야 합니다."); if (1 > bonus || bonus > 45) throw new Error("[ERROR] 보너스 번호는 1~45 사이여야 합니다."); if (win.includes(bonus)) throw new Error("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."); + + console.log(lotto.stats(lottoList, bonus)); + } } diff --git a/src/Lotto.js b/src/Lotto.js index 985482344d..e7f0dc0fcc 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -17,7 +17,22 @@ class Lotto { } } - // TODO: 추가 기능 구현 + stats(lottoList, bonus) { + const result = [0, 0, 0, 0, 0]; + lottoList.forEach((lotto) => { + switch(new Set([...lotto, ...this.#numbers]).size) { + case(9): result[0]++; break; + case(8): result[1]++; break; + case(7): { + if (lotto.includes(bonus)) result[3]++; + else result[2]++; + break; + } + case(6): result[4]++; break; + } + }) + return result; + } } export default Lotto; From 681ed7729f9a3de296f26ebf77061a30143a6df9 Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 23:10:02 +0900 Subject: [PATCH 11/14] =?UTF-8?q?feat:=20=EB=8B=B9=EC=B2=A8=20=EB=82=B4?= =?UTF-8?q?=EC=97=AD=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/App.js | 26 ++++++++++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index a7be03ed17..24e58e566d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -24,7 +24,7 @@ ## 출력 - [x] 발행한 로또 수량 및 번호를 오름차순으로 출력한다. -- [ ] 당첨 내역을 출력한다. +- [x] 당첨 내역을 출력한다. - [ ] 수익률은 소수점 둘째 자리에서 반올림한다. ## 진행 diff --git a/src/App.js b/src/App.js index 7673786c3b..71c6b579a1 100644 --- a/src/App.js +++ b/src/App.js @@ -2,13 +2,30 @@ import { MissionUtils } from "@woowacourse/mission-utils"; import Lotto from './Lotto.js'; class App { + + printResult = (result) => { + MissionUtils.Console.print('당첨 통계'); + MissionUtils.Console.print('---'); + + MissionUtils.Console.print(`3개 일치 (5,000원) - ${result[0]}개`); + MissionUtils.Console.print(`4개 일치 (50,000원) - ${result[1]}개`); + MissionUtils.Console.print(`5개 일치 (1,500,000원) - ${result[2]}개`); + MissionUtils.Console.print(`5개 일치, 보너스 볼 일치 (30,000,000원) - ${result[3]}개`); + MissionUtils.Console.print(`6개 일치 (2,000,000,000원) - ${result[4]}개`); + } + async play() { const money = await MissionUtils.Console.readLineAsync('구입금액을 입력해 주세요.\n'); // 예외처리 - if (isNaN(money)) throw new Error("[ERROR] 구입금액은 숫자여야 합니다."); - if (parseInt(money / 1000) !== money / 1000) throw new Error("[ERROR] 구입금액은 1000원 단위여야 합니다."); - if (money == 0) throw new Error("[ERROR] 구입금액은 0원 이상이어야 합니다."); + try{ + if (isNaN(money)) throw new Error("[ERROR] 구입금액은 숫자여야 합니다."); + if (parseInt(money / 1000) !== money / 1000) throw new Error("[ERROR] 구입금액은 1000원 단위여야 합니다."); + if (money == 0) throw new Error("[ERROR] 구입금액은 0원 이상이어야 합니다."); + } catch(error) { + console.log(error); + MissionUtils.Console.print(error.message); + } // 구입금액에 해당하는 만큼 로또 발행 let count = money / 1000; @@ -29,7 +46,8 @@ class App { if (1 > bonus || bonus > 45) throw new Error("[ERROR] 보너스 번호는 1~45 사이여야 합니다."); if (win.includes(bonus)) throw new Error("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."); - console.log(lotto.stats(lottoList, bonus)); + const result = lotto.stats(lottoList, bonus); + this.printResult(result); } } From 6662600061bc9e80296c4fb6650cfeed6e23cb7a Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 23:24:33 +0900 Subject: [PATCH 12/14] =?UTF-8?q?refactor:=20=EC=9E=98=EB=AA=BB=EB=90=9C?= =?UTF-8?q?=20=EA=B0=92=EC=9D=84=20=EC=9E=85=EB=A0=A5=ED=95=9C=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0,=20=EC=97=90=EB=9F=AC=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EC=B6=9C=EB=A0=A5=ED=95=98=EA=B3=A0=20=ED=95=B4?= =?UTF-8?q?=EB=8B=B9=20=EB=B6=80=EB=B6=84=EB=B6=80=ED=84=B0=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EC=9D=84=20=EB=8B=A4=EC=8B=9C=20=EB=B0=9B=EB=8A=94?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/App.js | 52 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/docs/README.md b/docs/README.md index 24e58e566d..28d44cbf1b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,7 +6,7 @@ - [x] (예외) 숫자가 아닌 경우 - [x] (예외) 1,000 단위로 나누어 떨어지지 않는 경우 - [x] (예외) 0원인 경우 - +- [x] 잘못된 값을 입력한 경우, 에러 메시지를 출력하고 해당 부분부터 입력을 다시 받는다. ### 당첨 번호 - [x] 쉼표(,)를 기준으로 당첨 번호를 입력받는다. diff --git a/src/App.js b/src/App.js index 71c6b579a1..6cc453863f 100644 --- a/src/App.js +++ b/src/App.js @@ -14,22 +14,40 @@ class App { MissionUtils.Console.print(`6개 일치 (2,000,000,000원) - ${result[4]}개`); } - async play() { - const money = await MissionUtils.Console.readLineAsync('구입금액을 입력해 주세요.\n'); - - // 예외처리 - try{ - if (isNaN(money)) throw new Error("[ERROR] 구입금액은 숫자여야 합니다."); - if (parseInt(money / 1000) !== money / 1000) throw new Error("[ERROR] 구입금액은 1000원 단위여야 합니다."); - if (money == 0) throw new Error("[ERROR] 구입금액은 0원 이상이어야 합니다."); - } catch(error) { - console.log(error); - MissionUtils.Console.print(error.message); + calculateLottoCount = async () => { + while(true) { + try { + const money = await MissionUtils.Console.readLineAsync('구입금액을 입력해 주세요.\n'); + + if (isNaN(money)) throw new Error("[ERROR] 구입금액은 숫자여야 합니다."); + if (parseInt(money / 1000) !== money / 1000) throw new Error("[ERROR] 구입금액은 1000원 단위여야 합니다."); + if (money == 0) throw new Error("[ERROR] 구입금액은 0원 이상이어야 합니다."); + + const count = money / 1000; + MissionUtils.Console.print(`${count}개를 구매했습니다.`); + return count; + } catch(error) { + MissionUtils.Console.print(error.message); + } + } + } + + inputBonus = async (win) => { + while(true) { + try { + const bonus = await MissionUtils.Console.readLineAsync('보너스 번호를 입력해 주세요.\n'); + if (isNaN(parseInt(bonus))) throw new Error("[ERROR] 보너스 번호는 숫자여야 합니다."); + if (1 > bonus || bonus > 45) throw new Error("[ERROR] 보너스 번호는 1~45 사이여야 합니다."); + if (win.includes(bonus)) throw new Error("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."); + return bonus; + } catch(error) { + MissionUtils.Console.print(error.message); + } } + } + async play() { + let count = await this.calculateLottoCount(); - // 구입금액에 해당하는 만큼 로또 발행 - let count = money / 1000; - MissionUtils.Console.print(`${count}개를 구매했습니다.`); const lottoList = []; while(count--) { lottoList.push(MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6).sort((a, b) => a - b)); @@ -41,14 +59,10 @@ class App { const lotto = new Lotto(win.split(',').map(v=>Number(v))); // 보너스 번호 입력 - const bonus = await MissionUtils.Console.readLineAsync('보너스 번호를 입력해 주세요.\n'); - if (isNaN(parseInt(bonus))) throw new Error("[ERROR] 보너스 번호는 숫자여야 합니다."); - if (1 > bonus || bonus > 45) throw new Error("[ERROR] 보너스 번호는 1~45 사이여야 합니다."); - if (win.includes(bonus)) throw new Error("[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."); + const bonus = await this.inputBonus(win); const result = lotto.stats(lottoList, bonus); this.printResult(result); - } } From 5ccf6dd40fd13a05b1d4dd2d641384ceee935ce2 Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 23:34:28 +0900 Subject: [PATCH 13/14] =?UTF-8?q?refactor:=20=ED=95=A8=EC=88=98=EB=A1=9C?= =?UTF-8?q?=20=EB=A6=AC=ED=8E=99=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/App.js b/src/App.js index 6cc453863f..c9a6793360 100644 --- a/src/App.js +++ b/src/App.js @@ -45,6 +45,13 @@ class App { } } } + + printLottoNumbers = (lottoList) => { + lottoList.forEach((lottoNumbers) => { + MissionUtils.Console.print(`[${lottoNumbers.join(', ')}]`); + }); + } + async play() { let count = await this.calculateLottoCount(); @@ -52,13 +59,11 @@ class App { while(count--) { lottoList.push(MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6).sort((a, b) => a - b)); } - MissionUtils.Console.print(lottoList); + this.printLottoNumbers(lottoList); - // 당첨 번호 입력 const win = await MissionUtils.Console.readLineAsync('당첨 번호를 입력해 주세요.\n'); const lotto = new Lotto(win.split(',').map(v=>Number(v))); - // 보너스 번호 입력 const bonus = await this.inputBonus(win); const result = lotto.stats(lottoList, bonus); From e4bcde395a859a4a6f17e8bb286f8c6c8b4925d4 Mon Sep 17 00:00:00 2001 From: KangYunJi Date: Wed, 8 Nov 2023 23:51:54 +0900 Subject: [PATCH 14/14] =?UTF-8?q?feat:=20=EC=88=98=EC=9D=B5=EB=A5=A0=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=ED=95=98=EC=97=AC=20=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/BonusTest.js | 49 ------------------------------------- __tests__/InputMoneyTest.js | 49 ------------------------------------- docs/README.md | 2 +- src/App.js | 26 ++++++++++++++++---- 4 files changed, 22 insertions(+), 104 deletions(-) delete mode 100644 __tests__/BonusTest.js delete mode 100644 __tests__/InputMoneyTest.js diff --git a/__tests__/BonusTest.js b/__tests__/BonusTest.js deleted file mode 100644 index 1f3b1600e1..0000000000 --- a/__tests__/BonusTest.js +++ /dev/null @@ -1,49 +0,0 @@ -import App from "../src/App.js"; -import { MissionUtils } from "@woowacourse/mission-utils"; - -const mockQuestions = (inputs) => { - MissionUtils.Console.readLineAsync = jest.fn(); - - MissionUtils.Console.readLineAsync.mockImplementation(() => { - const input = inputs.shift(); - - return Promise.resolve(input); - }); -}; - -describe("보너스 번호 입력 테스트", () => { - test("보너스 번호가 숫자가 아니면 예외가 발생한다.", async () => { - // given - mockQuestions(["8000", "1,2,3,4,5,6", "one"]); - - // when - const app = new App(); - - // then - await expect(app.play()).rejects.toThrow("[ERROR]"); - }); - - test("보너스 번호가 1~45 범위를 벗어나면 예외가 발생한다.", async () => { - // given - mockQuestions(["8000", "1,2,3,4,5,6", "50"]); - - // when - const app = new App(); - - // then - await expect(app.play()).rejects.toThrow("[ERROR]"); - }); - - test("보너스 번호가 당첨 번호와 중복될 경우 예외가 발생한다.", async () => { - // given - mockQuestions(["8000", "1,2,3,4,5,6", "1"]); - - // when - const app = new App(); - - // then - await expect(app.play()).rejects.toThrow("[ERROR]"); - }); - - // 아래에 추가 테스트 작성 가능 -}); \ No newline at end of file diff --git a/__tests__/InputMoneyTest.js b/__tests__/InputMoneyTest.js deleted file mode 100644 index b6838a0cfe..0000000000 --- a/__tests__/InputMoneyTest.js +++ /dev/null @@ -1,49 +0,0 @@ -import App from "../src/App.js"; -import { MissionUtils } from "@woowacourse/mission-utils"; - -const mockQuestions = (inputs) => { - MissionUtils.Console.readLineAsync = jest.fn(); - - MissionUtils.Console.readLineAsync.mockImplementation(() => { - const input = inputs.shift(); - - return Promise.resolve(input); - }); -}; -describe("구입금액 테스트", () => { - test("구입금액이 숫자가 아니면 예외가 발생한다.", async () => { - // given - mockQuestions(['천원']); - - // when - const app = new App(); - - // then - await expect(app.play()).rejects.toThrow("[ERROR]"); - }); - - // TODO: 이 테스트가 통과할 수 있게 구현 코드 작성 - test("구입금액이 1000원 단위로 나누어 떨어지지 않으면 예외가 발생한다.", async () => { - // given - mockQuestions(['8888']); - - // when - const app = new App(); - - // then - await expect(app.play()).rejects.toThrow("[ERROR]"); - }); - - test("구입금액이 0원인 경우 예외가 발생한다.", async () => { - // given - mockQuestions(['0']); - - // when - const app = new App(); - - // then - await expect(app.play()).rejects.toThrow("[ERROR]"); - }); - - // 아래에 추가 테스트 작성 가능 -}); \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 28d44cbf1b..496c3d6f1c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -33,4 +33,4 @@ - [x] 당첨 번호 입력 - [x] 보너스 번호 입력 - [x] 사용자가 구매한 로또 번호와 당첨 번호를 비교 -- [ ] 당첨 내역 및 수익률 출력 \ No newline at end of file +- [x] 당첨 내역 및 수익률 출력 \ No newline at end of file diff --git a/src/App.js b/src/App.js index c9a6793360..a012ea5bd1 100644 --- a/src/App.js +++ b/src/App.js @@ -52,22 +52,38 @@ class App { }); } - async play() { - let count = await this.calculateLottoCount(); + calculateTotalPrize = (stats) => { + let total = 0; + total += stats[0] * 5000; + total += stats[1] * 50000; + total += stats[2] * 1500000; + total += stats[3] * 30000000; + total += stats[4] * 2000000000; + return total; + } + earningsRate = (stats, count) => { + const totalPrize = this.calculateTotalPrize(stats); + return (totalPrize / (count * 1000) * 100).toFixed(1); + } + createLotto = (count) => { const lottoList = []; while(count--) { lottoList.push(MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6).sort((a, b) => a - b)); } + return lottoList; + } + + async play() { + let count = await this.calculateLottoCount(); + const lottoList = this.createLotto(count); this.printLottoNumbers(lottoList); - const win = await MissionUtils.Console.readLineAsync('당첨 번호를 입력해 주세요.\n'); const lotto = new Lotto(win.split(',').map(v=>Number(v))); - const bonus = await this.inputBonus(win); - const result = lotto.stats(lottoList, bonus); this.printResult(result); + MissionUtils.Console.print(`총 수익률은 ${this.earningsRate(result, count)}%입니다.`); } }