From 5ddf201d3e233f8591696bde2c6d60ad8ef37d78 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:07:35 +0900 Subject: [PATCH 01/19] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=20=EC=A0=84=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..47564e5b55 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,54 @@ +로또 게임 기능 목록 +-------------------- +
+ +- 로또 구입 금액 입력받기 + - 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. +
+ +- 로또 발행 + - 구입 금액에 해당하는 만큼 로또를 발행한다 + - 로또 1장의 가격은 1000원이다 +
+ +- 구매한 로또 수량 및 번호 출력 + - 로또 번호는 오름차순으로 정렬하여 보여준다. +
+ +- 당첨 번호를 입력 받는다 + - 번호는 쉼표(,)를 기준으로 구분한다. +- 보너스 번호를 입력 받는다 +
+ +- 잘못된 입력에 대한 예외처리 (각 입력마다) + - 사용자가 잘못된 값을 입력할 경우 throw문을 사용해 예외를 발생시킨다. 그런 다음, "[ERROR]"로 시작하는 에러 메시지를 출력하고 해당 부분부터 입력을 다시 받는다. +
+ +- 당첨 번호 추첨 + - 1~45범위의 중복되지 않는 6개의 숫자를 뽑는다 + - 보너스 번호를 뽑는다 +
+ +- 당첨금 계산 + - 당첨은 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원 +
+ +- 당첨 내역 출력 + - 일치한 번호 개수, 당첨금, 로또 개수 + 3개 일치 (5,000원) - ?개 + 4개 일치 (50,000원) - ?개 + 5개 일치 (1,500,000원) - ?개 + 5개 일치, 보너스 볼 일치 (30,000,000원) - ?개 + 6개 일치 (2,000,000,000원) - ?개 +
+ +- 수익률 계산 + - 수익률은 소수점 둘째 자리에서 반올림한다 +
+ +- 수익률 출력 From 299d6318bdffce36e62fb384a7ff36cbf09d4971 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:49:20 +0900 Subject: [PATCH 02/19] =?UTF-8?q?feat:=20=EA=B5=AC=EC=9E=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EC=9E=85=EB=A0=A5=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index c38b30d5b2..efbda63b4f 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,14 @@ +import { MissionUtils } from "@woowacourse/mission-utils"; +import Lotto from "./Lotto.js"; class App { - async play() {} + // 구입 금액 입력받기 + async inputMoney() { + const money = await MissionUtils.Console.readLineAsync("구입금액을 입력해 주세요.\n"); + if (money % 1000 !== 0) { + throw new Error("[ERROR] 1000원 단위로 입력해 주세요."); + } + return money; + } } export default App; From 9c40731d22a34b8dca98dcba9bba1fe486bd1df8 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:49:39 +0900 Subject: [PATCH 03/19] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=B0=9C?= =?UTF-8?q?=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/App.js b/src/App.js index efbda63b4f..adec9ce4b7 100644 --- a/src/App.js +++ b/src/App.js @@ -9,6 +9,16 @@ class App { } return money; } + // 로또 발행 + publishLotto(money) { + const lottoCount = money / 1000; + const lottos = []; + for (let i = 0; i < lottoCount; i++) { + const randomNumbers = MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6) + lottos.push(randomNumbers); + } + return lottos; + } } export default App; From c7308f18033757a8daf1c1863031112ced20c5fb Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:49:55 +0900 Subject: [PATCH 04/19] =?UTF-8?q?feat:=20=EA=B5=AC=EB=A7=A4=ED=95=9C=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EC=88=98=EB=9F=89=20=EB=B0=8F=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/App.js b/src/App.js index adec9ce4b7..ec387652e6 100644 --- a/src/App.js +++ b/src/App.js @@ -19,6 +19,13 @@ class App { } return lottos; } + // 구매한 로또 수량 및 번호 출력 + printLottos(lottos) { + MissionUtils.Console.print(`\n${lottos.length}개를 구매했습니다.`); + for (let i=0; i Date: Wed, 8 Nov 2023 19:32:54 +0900 Subject: [PATCH 05/19] =?UTF-8?q?feat:=20=EB=8B=B9=EC=B2=A8=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=9E=85=EB=A0=A5=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/App.js b/src/App.js index ec387652e6..f2e72f7735 100644 --- a/src/App.js +++ b/src/App.js @@ -22,9 +22,16 @@ class App { // 구매한 로또 수량 및 번호 출력 printLottos(lottos) { MissionUtils.Console.print(`\n${lottos.length}개를 구매했습니다.`); - for (let i=0; i Number(number.trim())); + return numbers; + } } } From b2e1fea2e03ba52778b28bb4935b2c0cfe39f648 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:33:07 +0900 Subject: [PATCH 06/19] =?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=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/App.js b/src/App.js index f2e72f7735..b36ff6de52 100644 --- a/src/App.js +++ b/src/App.js @@ -32,6 +32,16 @@ class App { .map((number) => Number(number.trim())); return numbers; } + + // 보너스 번호 입력받기 + async inputBonusNumber() { + const inputString = await MissionUtils.Console.readLineAsync( + "보너스 번호를 입력해주세요.\n" + ); + const bonusNumber = Number(inputString.trim()); + return bonusNumber; + } + } } From bcb55e3ee6c528671deed9eb00d860a8cd4f66f8 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:33:35 +0900 Subject: [PATCH 07/19] =?UTF-8?q?feat:=20=EA=B0=9C=EB=B3=84=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B2=B0=EA=B3=BC=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/App.js b/src/App.js index b36ff6de52..39b9fad1f3 100644 --- a/src/App.js +++ b/src/App.js @@ -42,6 +42,36 @@ class App { return bonusNumber; } + // 로또 하나에 대한 결과(등수) 계산 + + // 일치하는 번호 개수 + countMatchingNumbers(lotto, winningNumbers) { + let count = 0; + lotto.forEach((number) => { + if (winningNumbers.includes(number)) { + count++; + } + }); + return count; + } + // 등수 계산 + computeRank(lotto, winningNumbers, bonusNumber) { + const count = this.countMatchingNumbers(lotto, winningNumbers); + switch (count) { + case 6: + return "1등"; + case 5: + if (winningNumbers.includes(bonusNumber)) { + return "2등"; + } else return "3등"; + case 4: + return "4등"; + case 3: + return "5등"; + default: + return "꽝"; + } + } } } From 4bd1085809b9007b432a17d136606d794dc87613 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:35:25 +0900 Subject: [PATCH 08/19] =?UTF-8?q?feat:=20=EC=B4=9D=20=EB=8B=B9=EC=B2=A8=20?= =?UTF-8?q?=EB=82=B4=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 --- src/App.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/App.js b/src/App.js index 39b9fad1f3..fd8fa279ed 100644 --- a/src/App.js +++ b/src/App.js @@ -72,6 +72,28 @@ class App { return "꽝"; } } + + // 총 당첨 내역 출력 + // 결과 합산 + computeTotalResult(lottos, winningNumbers, bonusNubmer) { + const result = { "1등": 0, "2등": 0, "3등": 0, "4등": 0, "5등": 0, "꽝": 0}; + for (const lotto of lottos) { + const rank = this.computeRank(lotto, winningNumbers, bonusNubmer); + result[rank]++; + } + return result; + } + + // 출력 + printResult(result) { + MissionUtils.Console.print(` +당첨 통계\n--- +3개 일치 (5,000원) - ${result["5등"]}개 +4개 일치 (50,000원) - ${result["4등"]}개 +5개 일치 (1,500,000원) - ${result["3등"]}개 +5개 일치, 보너스 볼 일치 (30,000,000원) - ${result["2등"]}개 +6개 일치 (2,000,000,000원) - ${result["1등"]}개`); + } } } From ae1227ab1982cfa29425046cb122fbab2161dbe5 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 20:08:19 +0900 Subject: [PATCH 09/19] =?UTF-8?q?feat:=20=EC=88=98=EC=9D=B5=EB=A5=A0=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EB=B0=8F=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/App.js b/src/App.js index fd8fa279ed..e31870c476 100644 --- a/src/App.js +++ b/src/App.js @@ -94,6 +94,18 @@ class App { 5개 일치, 보너스 볼 일치 (30,000,000원) - ${result["2등"]}개 6개 일치 (2,000,000,000원) - ${result["1등"]}개`); } + + // 수익률 계산 + + computeProfit(result,money){ + const totalPrize = result["5등"]*5000 + result["4등"]*50000 + result["3등"]*1500000 + result["2등"]*30000000 + result["1등"]*2000000000; + const profit = (totalPrize/money*100).toFixed(1); + return profit; + } + + printProfit(profit){ + MissionUtils.Console.print(`총 수익률은 ${profit}%입니다.`); + } } } From 1aaae94f87b4661667057be6a2401c5fc3a2a109 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:04:10 +0900 Subject: [PATCH 10/19] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20-=20=EC=9E=85=EB=A0=A5=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20?= =?UTF-8?q?=ED=95=A8=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 78 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/src/App.js b/src/App.js index e31870c476..8b3eeedd1e 100644 --- a/src/App.js +++ b/src/App.js @@ -3,12 +3,27 @@ import Lotto from "./Lotto.js"; class App { // 구입 금액 입력받기 async inputMoney() { - const money = await MissionUtils.Console.readLineAsync("구입금액을 입력해 주세요.\n"); - if (money % 1000 !== 0) { - throw new Error("[ERROR] 1000원 단위로 입력해 주세요."); + let money; + let isValidated = false; + while (!isValidated) { + const inputString = await MissionUtils.Console.readLineAsync( + "구입금액을 입력해 주세요.\n" + ); + money = Number(inputString.trim()); + isValidated = this.validateMoney(money); } return money; } + + // 예외처리 + validateMoney(money) { + if (isNaN(money)) { + MissionUtils.Console.print("[ERROR] 숫자만 입력해주세요.\n"); + } else if (money % 1000 !== 0) { + MissionUtils.Console.print("[ERROR] 1000원 단위로 입력해주세요.\n"); + } else return true; + } + // 로또 발행 publishLotto(money) { const lottoCount = money / 1000; @@ -24,22 +39,55 @@ class App { MissionUtils.Console.print(`\n${lottos.length}개를 구매했습니다.`); // 당첨 번호 입력받기 async inputNumbers() { - const inputString = await MissionUtils.Console.readLineAsync( - "당첨 번호를 입력해주세요.\n" - ); - const numbers = inputString - .split(",") - .map((number) => Number(number.trim())); - return numbers; + let numbers; + let isValidated = false; + while (!isValidated) { + const inputString = await MissionUtils.Console.readLineAsync( + "\n당첨 번호를 입력해주세요.\n" + ); + numbers = inputString.split(",").map((number) => Number(number.trim())); + isValidated = this.validateNumbers(numbers); + } + this.winningNumbers = numbers; + } + + // 당첨 번호 예외처리 + validateNumbers(numbers) { + if (numbers.length !== 6) { + MissionUtils.Console.print("[ERROR] 6개의 숫자를 입력해주세요.\n"); + } else if (numbers.some((number) => isNaN(number))) { + MissionUtils.Console.print("[ERROR] 숫자만 입력해주세요.\n"); + } else if (numbers.some((number) => number < 1 || number > 45)) { + MissionUtils.Console.print("[ERROR] 1~45 사이의 숫자를 입력해주세요.\n"); + } else if (new Set(numbers).size !== 6) { + MissionUtils.Console.print("[ERROR] 중복된 숫자를 입력할 수 없습니다.\n"); + } else return true; } // 보너스 번호 입력받기 async inputBonusNumber() { - const inputString = await MissionUtils.Console.readLineAsync( - "보너스 번호를 입력해주세요.\n" - ); - const bonusNumber = Number(inputString.trim()); - return bonusNumber; + let bonusNumber; + let isValidated = false; + while (!isValidated) { + const inputString = await MissionUtils.Console.readLineAsync( + "\n보너스 번호를 입력해주세요.\n" + ); + bonusNumber = Number(inputString.trim()); + isValidated = this.validateBonusNumber(bonusNumber); + } + this.bonusNumber = bonusNumber; + } + + validateBonusNumber(bonusNumber) { + const winningNumbers = this.winningNumbers; + if (isNaN(bonusNumber)) { + MissionUtils.Console.print("[ERROR] 숫자만 입력해주세요.\n"); + } else if (bonusNumber < 1 || bonusNumber > 45) { + MissionUtils.Console.print("[ERROR] 1~45 사이의 숫자를 입력해주세요.\n"); + } else if (winningNumbers.includes(bonusNumber)) { + MissionUtils.Console.print("[ERROR] 당첨 번호와 중복될 수 없습니다.\n"); + } + else return true; } // 로또 하나에 대한 결과(등수) 계산 From 1ce7ac58ef05599fa2008ca541283a20bb7697c3 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:07:18 +0900 Subject: [PATCH 11/19] style: code formatting --- src/App.js | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/App.js b/src/App.js index 8b3eeedd1e..c5966db300 100644 --- a/src/App.js +++ b/src/App.js @@ -29,7 +29,11 @@ class App { const lottoCount = money / 1000; const lottos = []; for (let i = 0; i < lottoCount; i++) { - const randomNumbers = MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6) + const randomNumbers = MissionUtils.Random.pickUniqueNumbersInRange( + 1, + 45, + 6 + ); lottos.push(randomNumbers); } return lottos; @@ -123,8 +127,8 @@ class App { // 총 당첨 내역 출력 // 결과 합산 - computeTotalResult(lottos, winningNumbers, bonusNubmer) { - const result = { "1등": 0, "2등": 0, "3등": 0, "4등": 0, "5등": 0, "꽝": 0}; + computeTotalResult(lottos) { + const result = { "1등": 0, "2등": 0, "3등": 0, "4등": 0, "5등": 0, 꽝: 0 }; for (const lotto of lottos) { const rank = this.computeRank(lotto, winningNumbers, bonusNubmer); result[rank]++; @@ -144,14 +148,19 @@ class App { } // 수익률 계산 - - computeProfit(result,money){ - const totalPrize = result["5등"]*5000 + result["4등"]*50000 + result["3등"]*1500000 + result["2등"]*30000000 + result["1등"]*2000000000; - const profit = (totalPrize/money*100).toFixed(1); - return profit; + + computeProfit(result, money) { + const totalPrize = + result["5등"] * 5000 + + result["4등"] * 50000 + + result["3등"] * 1500000 + + result["2등"] * 30000000 + + result["1등"] * 2000000000; + const profit = ((totalPrize / money) * 100).toFixed(1); + return profit; } - - printProfit(profit){ + + printProfit(profit) { MissionUtils.Console.print(`총 수익률은 ${profit}%입니다.`); } } From f0d1277bf2bd1e1841be36aa6d470b22054d33a7 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:09:47 +0900 Subject: [PATCH 12/19] =?UTF-8?q?refactor:=20=EB=B0=98=EB=B3=B5=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EB=90=98=EB=8A=94=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20=EB=A9=A4=EB=B2=84=20=EB=B3=80=EC=88=98?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/App.js b/src/App.js index c5966db300..0525b0604b 100644 --- a/src/App.js +++ b/src/App.js @@ -1,7 +1,11 @@ import { MissionUtils } from "@woowacourse/mission-utils"; import Lotto from "./Lotto.js"; class App { - // 구입 금액 입력받기 + constructor() { + this.winningNumbers = []; + this.bonusNumber = 0; + } + async inputMoney() { let money; let isValidated = false; @@ -94,26 +98,23 @@ class App { else return true; } - // 로또 하나에 대한 결과(등수) 계산 - - // 일치하는 번호 개수 - countMatchingNumbers(lotto, winningNumbers) { + countMatchingNumbers(lotto) { let count = 0; lotto.forEach((number) => { - if (winningNumbers.includes(number)) { + if (this.winningNumbers.includes(number)) { count++; } }); return count; } - // 등수 계산 - computeRank(lotto, winningNumbers, bonusNumber) { - const count = this.countMatchingNumbers(lotto, winningNumbers); + + computeRank(lotto) { + const count = this.countMatchingNumbers(lotto, this.winningNumbers); switch (count) { case 6: return "1등"; case 5: - if (winningNumbers.includes(bonusNumber)) { + if (this.winningNumbers.includes(this.bonusNumber)) { return "2등"; } else return "3등"; case 4: @@ -130,7 +131,11 @@ class App { computeTotalResult(lottos) { const result = { "1등": 0, "2등": 0, "3등": 0, "4등": 0, "5등": 0, 꽝: 0 }; for (const lotto of lottos) { - const rank = this.computeRank(lotto, winningNumbers, bonusNubmer); + const rank = this.computeRank( + lotto, + this.winningNumbers, + this.bonusNumber + ); result[rank]++; } return result; From 5884b5781b75ea446c6b592320d6e6f8e4aa5720 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:10:12 +0900 Subject: [PATCH 13/19] =?UTF-8?q?feat:=20play=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/App.js b/src/App.js index 0525b0604b..5a056bc38d 100644 --- a/src/App.js +++ b/src/App.js @@ -168,6 +168,21 @@ class App { printProfit(profit) { MissionUtils.Console.print(`총 수익률은 ${profit}%입니다.`); } + + async play() { + const money = await this.inputMoney(); + const lottos = this.publishLotto(money); + this.printLottos(lottos); + await this.inputNumbers(); + await this.inputBonusNumber(); + const result = this.computeTotalResult( + lottos, + this.winningNumbers, + this.mber + ); + this.printResult(result); + const profit = this.computeProfit(result, money); + this.printProfit(profit); } } From d8ae5726c95e8439d4823db37d97662ec1313851 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:11:01 +0900 Subject: [PATCH 14/19] style: code formatting --- src/App.js | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/App.js b/src/App.js index 5a056bc38d..67afd78c71 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,6 @@ import { MissionUtils } from "@woowacourse/mission-utils"; import Lotto from "./Lotto.js"; + class App { constructor() { this.winningNumbers = []; @@ -19,7 +20,6 @@ class App { return money; } - // 예외처리 validateMoney(money) { if (isNaN(money)) { MissionUtils.Console.print("[ERROR] 숫자만 입력해주세요.\n"); @@ -28,7 +28,6 @@ class App { } else return true; } - // 로또 발행 publishLotto(money) { const lottoCount = money / 1000; const lottos = []; @@ -42,10 +41,14 @@ class App { } return lottos; } - // 구매한 로또 수량 및 번호 출력 + printLottos(lottos) { MissionUtils.Console.print(`\n${lottos.length}개를 구매했습니다.`); - // 당첨 번호 입력받기 + for (const lotto of lottos) { + MissionUtils.Console.print(`[${lotto.join(", ")}]`); + } + } + async inputNumbers() { let numbers; let isValidated = false; @@ -59,7 +62,6 @@ class App { this.winningNumbers = numbers; } - // 당첨 번호 예외처리 validateNumbers(numbers) { if (numbers.length !== 6) { MissionUtils.Console.print("[ERROR] 6개의 숫자를 입력해주세요.\n"); @@ -72,7 +74,6 @@ class App { } else return true; } - // 보너스 번호 입력받기 async inputBonusNumber() { let bonusNumber; let isValidated = false; @@ -94,8 +95,7 @@ class App { MissionUtils.Console.print("[ERROR] 1~45 사이의 숫자를 입력해주세요.\n"); } else if (winningNumbers.includes(bonusNumber)) { MissionUtils.Console.print("[ERROR] 당첨 번호와 중복될 수 없습니다.\n"); - } - else return true; + } else return true; } countMatchingNumbers(lotto) { @@ -126,8 +126,6 @@ class App { } } - // 총 당첨 내역 출력 - // 결과 합산 computeTotalResult(lottos) { const result = { "1등": 0, "2등": 0, "3등": 0, "4등": 0, "5등": 0, 꽝: 0 }; for (const lotto of lottos) { @@ -141,7 +139,6 @@ class App { return result; } - // 출력 printResult(result) { MissionUtils.Console.print(` 당첨 통계\n--- @@ -152,8 +149,6 @@ class App { 6개 일치 (2,000,000,000원) - ${result["1등"]}개`); } - // 수익률 계산 - computeProfit(result, money) { const totalPrize = result["5등"] * 5000 + From 37095aa8f96f211dbd13d4ef86ff3db6af17cfcc Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:11:37 +0900 Subject: [PATCH 15/19] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/README.md b/docs/README.md index 47564e5b55..243458ecad 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,34 +3,33 @@
- 로또 구입 금액 입력받기 - - 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. + - 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다
- 로또 발행 - 구입 금액에 해당하는 만큼 로또를 발행한다 + - 1~45범위의 중복되지 않는 6개의 숫자를 뽑는다 - 로또 1장의 가격은 1000원이다
- 구매한 로또 수량 및 번호 출력 - - 로또 번호는 오름차순으로 정렬하여 보여준다. + - 로또 번호는 오름차순으로 정렬하여 보여준다
- 당첨 번호를 입력 받는다 + - 1~45범위의 중복되지 않는 6개의 숫자를 입력받는다 - 번호는 쉼표(,)를 기준으로 구분한다. - 보너스 번호를 입력 받는다 + - 보너스 번호는 당첨 번호와 중복될 수 없다
- 잘못된 입력에 대한 예외처리 (각 입력마다) - 사용자가 잘못된 값을 입력할 경우 throw문을 사용해 예외를 발생시킨다. 그런 다음, "[ERROR]"로 시작하는 에러 메시지를 출력하고 해당 부분부터 입력을 다시 받는다.
-- 당첨 번호 추첨 - - 1~45범위의 중복되지 않는 6개의 숫자를 뽑는다 - - 보너스 번호를 뽑는다 -
- -- 당첨금 계산 - - 당첨은 1등부터 5등까지 있다. 당첨 기준과 금액은 아래와 같다. +- 로또 하나에 대한 결과(등수) 계산 + - 당첨은 1등부터 5등까지 있다. 당첨 기준과 금액은 아래와 같다 + - 5개가 일치할 시 틀린 1개가 보너스 번호와 일치하는지 확인하여 2등과 3등을 나눈다 1등: 6개 번호 일치 / 2,000,000,000원 2등: 5개 번호 + 보너스 번호 일치 / 30,000,000원 3등: 5개 번호 일치 / 1,500,000원 @@ -38,11 +37,12 @@ 5등: 3개 번호 일치 / 5,000원
-- 당첨 내역 출력 - - 일치한 번호 개수, 당첨금, 로또 개수 +- 총 당첨 내역 출력 + - 각 로또의 결과를 합산한다 + - 아래와 같은 형식으로 출력한다 3개 일치 (5,000원) - ?개 4개 일치 (50,000원) - ?개 - 5개 일치 (1,500,000원) - ?개 + 5개 일치 (1,500,000원) - ?개 5개 일치, 보너스 볼 일치 (30,000,000원) - ?개 6개 일치 (2,000,000,000원) - ?개
From d06d7395af27837cbf3920b73364dcbfce3a9fa6 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:19:00 +0900 Subject: [PATCH 16/19] =?UTF-8?q?fix:=202=EB=93=B1=20=ED=8C=90=EB=8B=A8=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App.js b/src/App.js index 67afd78c71..a2f041bfb0 100644 --- a/src/App.js +++ b/src/App.js @@ -93,7 +93,7 @@ class App { MissionUtils.Console.print("[ERROR] 숫자만 입력해주세요.\n"); } else if (bonusNumber < 1 || bonusNumber > 45) { MissionUtils.Console.print("[ERROR] 1~45 사이의 숫자를 입력해주세요.\n"); - } else if (winningNumbers.includes(bonusNumber)) { + } else if (this.winningNumbers.includes(bonusNumber)) { MissionUtils.Console.print("[ERROR] 당첨 번호와 중복될 수 없습니다.\n"); } else return true; } @@ -114,7 +114,7 @@ class App { case 6: return "1등"; case 5: - if (this.winningNumbers.includes(this.bonusNumber)) { + if (lotto.includes(this.bonusNumber)) { return "2등"; } else return "3등"; case 4: From 21fa15873577bdce78ee946afceacc7bf494ebe4 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:20:54 +0900 Subject: [PATCH 17/19] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/App.js b/src/App.js index a2f041bfb0..b71e3e5979 100644 --- a/src/App.js +++ b/src/App.js @@ -88,7 +88,6 @@ class App { } validateBonusNumber(bonusNumber) { - const winningNumbers = this.winningNumbers; if (isNaN(bonusNumber)) { MissionUtils.Console.print("[ERROR] 숫자만 입력해주세요.\n"); } else if (bonusNumber < 1 || bonusNumber > 45) { @@ -129,11 +128,7 @@ class App { computeTotalResult(lottos) { const result = { "1등": 0, "2등": 0, "3등": 0, "4등": 0, "5등": 0, 꽝: 0 }; for (const lotto of lottos) { - const rank = this.computeRank( - lotto, - this.winningNumbers, - this.bonusNumber - ); + const rank = this.computeRank(lotto); result[rank]++; } return result; @@ -170,11 +165,7 @@ class App { this.printLottos(lottos); await this.inputNumbers(); await this.inputBonusNumber(); - const result = this.computeTotalResult( - lottos, - this.winningNumbers, - this.mber - ); + const result = this.computeTotalResult(lottos); this.printResult(result); const profit = this.computeProfit(result, money); this.printProfit(profit); From 6f7362df74bd1926f885c783430c2cb746641d30 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:50:51 +0900 Subject: [PATCH 18/19] =?UTF-8?q?refactor:=20Lotto=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=ED=99=9C=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 19 ++++++++++++------- src/Lotto.js | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/App.js b/src/App.js index b71e3e5979..8a5af334da 100644 --- a/src/App.js +++ b/src/App.js @@ -37,7 +37,13 @@ class App { 45, 6 ); - lottos.push(randomNumbers); + try { + const lotto = new Lotto(randomNumbers); + lottos.push(lotto); + } catch (error) { + MissionUtils.Console.print(error.message); + i--; + } } return lottos; } @@ -45,7 +51,7 @@ class App { printLottos(lottos) { MissionUtils.Console.print(`\n${lottos.length}개를 구매했습니다.`); for (const lotto of lottos) { - MissionUtils.Console.print(`[${lotto.join(", ")}]`); + MissionUtils.Console.print(lotto.toString()); } } @@ -99,7 +105,7 @@ class App { countMatchingNumbers(lotto) { let count = 0; - lotto.forEach((number) => { + lotto.getNumbers().forEach((number) => { if (this.winningNumbers.includes(number)) { count++; } @@ -108,14 +114,13 @@ class App { } computeRank(lotto) { - const count = this.countMatchingNumbers(lotto, this.winningNumbers); + const count = this.countMatchingNumbers(lotto); + const isBonusMatched = lotto.hasNumber(this.bonusNumber); switch (count) { case 6: return "1등"; case 5: - if (lotto.includes(this.bonusNumber)) { - return "2등"; - } else return "3등"; + return isBonusMatched ? "2등" : "3등"; case 4: return "4등"; case 3: diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e9..1e6e61c3bd 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -10,8 +10,25 @@ class Lotto { if (numbers.length !== 6) { throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); } + if (new Set(numbers).size !== 6) { + throw new Error("[ERROR] 중복된 숫자가 있습니다."); + } + if (numbers.some(num => num < 1 || num > 45)) { + throw new Error("[ERROR] 번호는 1과 45 사이여야 합니다."); + } + } + + getNumbers() { + return this.#numbers; } + hasNumber(number) { + return this.#numbers.includes(number); + } + + toString() { + return `[${this.#numbers.join(", ")}]`; + } // TODO: 추가 기능 구현 } From 5ba0b1fdf2eea01b86447b8197cf4efc7d13e5a1 Mon Sep 17 00:00:00 2001 From: Eunhak Lee <112919689+Ag-crane@users.noreply.github.com> Date: Wed, 8 Nov 2023 23:58:01 +0900 Subject: [PATCH 19/19] =?UTF-8?q?test:=20=EB=8B=A8=EC=9C=84=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=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 | 81 ++++++++++++++++++++++++++++++++++++++++-- src/App.js | 5 ++- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 97bd457659..070344468e 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -1,4 +1,5 @@ import Lotto from "../src/Lotto.js"; +import App from "../src/App.js"; describe("로또 클래스 테스트", () => { test("로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.", () => { @@ -7,12 +8,88 @@ describe("로또 클래스 테스트", () => { }).toThrow("[ERROR]"); }); - // TODO: 이 테스트가 통과할 수 있게 구현 코드 작성 test("로또 번호에 중복된 숫자가 있으면 예외가 발생한다.", () => { expect(() => { new Lotto([1, 2, 3, 4, 5, 5]); }).toThrow("[ERROR]"); }); - // 아래에 추가 테스트 작성 가능 + test("로또 번호에 1보다 작은 숫자가 있으면 예외가 발생한다.", () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5, 0]); + }).toThrow("[ERROR]"); + }); + + test("로또 번호에 45보다 큰 숫자가 있으면 예외가 발생한다.", () => { + expect(() => { + new Lotto([1, 2, 3, 4, 5, 46]); + }).toThrow("[ERROR]"); + }); + + test("hasNumber 테스트",()=>{ + const lotto = new Lotto([1,2,3,4,5,6]); + expect(lotto.hasNumber(1)).toEqual(true); + expect(lotto.hasNumber(7)).toEqual(false); + }) }); + +describe("App.js 메서드 단위 테스트",()=>{ + test("constructor 테스트",()=>{ + const app = new App(); + expect(app.winningNumbers).toEqual([]); + expect(app.bonusNumber).toEqual(0); + }) + test("validateMoney 테스트",()=>{ + const app = new App(); + expect(app.validateMoney(1000)).toEqual(true); + expect(app.validateMoney(1001)).toEqual(undefined); + expect(app.validateMoney(0)).toEqual(undefined); + expect(app.validateMoney(-1)).toEqual(undefined); + }) + test("publishLotto 테스트",()=>{ + const app = new App(); + const lottos = app.publishLotto(1000); + expect(lottos.length).toEqual(1); + expect(lottos[0].getNumbers().length).toEqual(6); + }) + test("validateNumbers 테스트",()=>{ + const app = new App(); + expect(app.validateNumbers([1,2,3,4,5,6])).toEqual(true); + expect(app.validateNumbers([1,2,3,4,5,5])).toEqual(undefined); + expect(app.validateNumbers([1,2,3,4,5,0])).toEqual(undefined); + expect(app.validateNumbers([1,2,3,4,5,46])).toEqual(undefined); + }) + test("validateBonusNumber 테스트",()=>{ + const app = new App(); + app.winningNumbers = [1,2,3,4,5,6]; + expect(app.validateBonusNumber(7)).toEqual(true); + expect(app.validateBonusNumber(6)).toEqual(undefined); + expect(app.validateBonusNumber(0)).toEqual(undefined); + expect(app.validateBonusNumber(46)).toEqual(undefined); + }) + test("countMatchingNumbers 테스트",()=>{ + const app = new App(); + app.winningNumbers = [1,2,3,4,5,6]; + const lotto = new Lotto([1,2,3,4,5,6]); + expect(app.countMatchingNumbers(lotto)).toEqual(6); + app.winningNumbers = [1,2,3,4,5,7]; + expect(app.countMatchingNumbers(lotto)).toEqual(5); + }) + test("computeRank 테스트",()=>{ + const app = new App(); + app.bonusNumber = 7; + const lotto = new Lotto([1,2,3,4,5,6]); + app.winningNumbers = [1,2,3,4,5,6]; + expect(app.computeRank(lotto)).toEqual("1등"); + // app.winningNumbers = [1,2,3,4,5,7]; + // expect(app.computeRank(lotto)).toEqual("2등"); + app.winningNumbers = [1,2,3,4,5,8]; + expect(app.computeRank(lotto)).toEqual("3등"); + app.winningNumbers = [1,2,3,4,7,8]; + expect(app.computeRank(lotto)).toEqual("4등"); + app.winningNumbers = [1,2,3,7,8,9]; + expect(app.computeRank(lotto)).toEqual("5등"); + app.winningNumbers = [1,2,7,8,9,10]; + expect(app.computeRank(lotto)).toEqual("꽝"); + }); +}) diff --git a/src/App.js b/src/App.js index 8a5af334da..4214ffb105 100644 --- a/src/App.js +++ b/src/App.js @@ -23,7 +23,10 @@ class App { validateMoney(money) { if (isNaN(money)) { MissionUtils.Console.print("[ERROR] 숫자만 입력해주세요.\n"); - } else if (money % 1000 !== 0) { + }else if(money < 1000){ + MissionUtils.Console.print("[ERROR] 최소 1000 이상을 입력해야 합니다.\n"); + } + else if (money % 1000 !== 0) { MissionUtils.Console.print("[ERROR] 1000원 단위로 입력해주세요.\n"); } else return true; }