From fd81ecc9a2733d82fb576a40c7e81c57c2b6c6d6 Mon Sep 17 00:00:00 2001 From: LocKey Date: Mon, 30 Sep 2024 13:40:13 +0900 Subject: [PATCH 1/9] =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20r?= =?UTF-8?q?eadme=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 | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/README.md b/docs/README.md index e69de29bb2..1a8bd48056 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,24 @@ +# 기능 목록 ++ 각 기능에 대한 예외사항과 핸들링도 기재 + +- [ ] 게임 관리 - GameManager class + - [ ] 게임 시작 - start() +- [ ] 로또 게임 구현 - LottoGame class + - [ ] 6개의 숫자 생성 **(Computer)** - generateLottoNumber() + - [ ] 로또 구입 금액 입력 받기 **(Me)** - receiveUserMoneyInput() + - [ ] **예외사항** : 1000원으로 나누어 떨어지지 않는 경우 -> `IllegalArgumentException` + - [ ] 당첨 번호 입력 받기 **(Me)** - receiveUserNumberInput() + - [ ] **예외사항** : 쉼표를 기준으로 구분하지 않은 경우 -> `IllegalArgumentException` + - [ ] **예외사항** : 로또 번호의 숫자 범위 밖의 경우 (1 ~ 45) -> `IllegalArgumentException` + - [ ] **예외사항** : 숫자가 중복되는 경우 -> `IllegalArgumentException` + - [ ] 보너스 번호 입력 받기 **(Me)** - receiveUserBonusInput() + - [ ] **예외사항** : 로또 번호의 숫자 범위 밖의 경우 (1 ~ 45) -> `IllegalArgumentException` + - [ ] **예외사항** : 숫자가 중복되는 경우 -> `IllegalArgumentException` + - [ ] 발행한 로또 수량 및 번호를 오름차순으로 출력 - issuanceLotto() + - [ ] 당첨 내역 출력 - printWinningDetails() + - [ ] 수익률 계산 (소수점 둘째 자리 반올림) - calculateRateOfProfit() + +------- + +* 당첨 번호와 보너스 번호를 입력하는 기능을 분리하는게 좋을까? + * 가독성을 위해 분리하는 방향으로 선택 \ No newline at end of file From 7ed040af3221b699864dd08e1cced65f047a0872 Mon Sep 17 00:00:00 2001 From: LocKey Date: Tue, 1 Oct 2024 03:06:44 +0900 Subject: [PATCH 2/9] =?UTF-8?q?=EA=B0=81=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/Application.java | 3 +- src/main/java/lotto/GameManager.java | 33 ++++++++++ src/main/java/lotto/Lotto.java | 14 +++- src/main/java/lotto/LottoInputView.java | 82 ++++++++++++++++++++++++ src/main/java/lotto/LottoOutputView.java | 29 +++++++++ src/main/java/lotto/LottoRank.java | 37 +++++++++++ src/main/java/lotto/LottoResult.java | 28 ++++++++ src/main/java/lotto/LottoService.java | 36 +++++++++++ 8 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 src/main/java/lotto/GameManager.java create mode 100644 src/main/java/lotto/LottoInputView.java create mode 100644 src/main/java/lotto/LottoOutputView.java create mode 100644 src/main/java/lotto/LottoRank.java create mode 100644 src/main/java/lotto/LottoResult.java create mode 100644 src/main/java/lotto/LottoService.java diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index d190922ba4..8504405f83 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -2,6 +2,7 @@ public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + GameManager gameManager = new GameManager(); + gameManager.start(); } } diff --git a/src/main/java/lotto/GameManager.java b/src/main/java/lotto/GameManager.java new file mode 100644 index 0000000000..60fe1bd2f8 --- /dev/null +++ b/src/main/java/lotto/GameManager.java @@ -0,0 +1,33 @@ +package lotto; + +import java.util.List; + +public class GameManager { + private final LottoInputView lottoInputView; + private final LottoService lottoService; + private final LottoOutputView lottoOutputView; + + public GameManager() { + this.lottoService = new LottoService(); + this.lottoOutputView = new LottoOutputView(); + this.lottoInputView = new LottoInputView(); + } + + /** + * 게임 시작 + */ + public void start() { + int money = lottoInputView.receiveUserMoneyInput(); + List lottoList = lottoService.generateLottoNumber(money / 1000); + lottoOutputView.printLotto(lottoList); + + List winningNumbers = lottoInputView.receiveWinningNumberInput(); + int bonusNumber = lottoInputView.receiveBonusNumberInput(winningNumbers); + + LottoResult result = lottoService.checkWinningResult(lottoList, winningNumbers, bonusNumber); + lottoOutputView.printWinningStatistics(result); + + double profitRate = lottoService.calculateProfitRate(money, result); + lottoOutputView.printProfitRate(profitRate); + } +} diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java index 519793d1f7..a312200bc5 100644 --- a/src/main/java/lotto/Lotto.java +++ b/src/main/java/lotto/Lotto.java @@ -16,5 +16,17 @@ private void validate(List numbers) { } } - // TODO: 추가 기능 구현 + /** + * + */ + public boolean contains(int number) { + return numbers.contains(number); + } + + /** + * + */ + public int matchCount(List winningNumbers) { + return (int) numbers.stream().filter(winningNumbers::contains).count(); //numbers에 있는 int를 loop 돌려서 winningNumbers에 포함되어있다면 개수를 셈 + } } diff --git a/src/main/java/lotto/LottoInputView.java b/src/main/java/lotto/LottoInputView.java new file mode 100644 index 0000000000..eef669d2a5 --- /dev/null +++ b/src/main/java/lotto/LottoInputView.java @@ -0,0 +1,82 @@ +package lotto; + +import camp.nextstep.edu.missionutils.Console; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class LottoInputView { + + /** + * 로또 구입 금액 입력 받기 + */ + public int receiveUserMoneyInput() { + System.out.println("구입금액을 입력해 주세요."); + String input = Console.readLine(); + validateMoneyInput(input); + return Integer.parseInt(input); + } + + private void validateMoneyInput(String input) { + try { + int money = Integer.parseInt(input); + if (money % 1000 != 0) { + throw new IllegalArgumentException("[ERROR] 구입 금액은 1,000원 단위여야 합니다."); + } + } catch (NumberFormatException e) { //숫자가 아닐 경우 + throw new IllegalArgumentException("[ERROR] 올바른 숫자를 입력하세요."); + } + } + + /** + * 당첨 번호 입력 받기 + */ + public List receiveWinningNumberInput() { + System.out.println("당첨 번호를 입력해 주세요."); + String input = Console.readLine(); + List numbers = parseNumbers(input); + validateNumbers(numbers); + return numbers; + } + + private void validateNumbers(List numbers) { + if (numbers.size() != 6) { + throw new IllegalArgumentException("[ERROR] 당첨 번호는 6개여야 합니다."); + } + if (numbers.stream().distinct().count() != 6) { + throw new IllegalArgumentException("[ERROR] 당첨 번호에 중복된 숫자가 있습니다."); + } + if (numbers.stream().anyMatch(n -> n < 1 || n > 45)) { + throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + } + } + + /** + * 입력 정수 리스트로 변환 + */ + private List parseNumbers(String input) { + return Arrays.stream(input.split(",")) + .map(String::trim) //스페이스 제거 + .map(Integer::parseInt) //정수 변환 + .collect(Collectors.toList()); + } + + + public int receiveBonusNumberInput(List winningList) { + System.out.println("보너스 번호를 입력해 주세요."); + String input = Console.readLine(); + int result = Integer.parseInt(input); + validateBonusNumber(result, winningList); + return result; + } + + private void validateBonusNumber(int bonusNumber, List winningList) { + if (bonusNumber < 1 || bonusNumber > 45) { + throw new IllegalArgumentException("[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."); + } + if (winningList.contains(bonusNumber)) { + throw new IllegalArgumentException("[ERROR] 당첨 번호에 중복된 숫자가 있습니다."); + } + } +} diff --git a/src/main/java/lotto/LottoOutputView.java b/src/main/java/lotto/LottoOutputView.java new file mode 100644 index 0000000000..6ec9e3287a --- /dev/null +++ b/src/main/java/lotto/LottoOutputView.java @@ -0,0 +1,29 @@ +package lotto; + +import java.util.List; + +public class LottoOutputView { + + public void printLotto(List lottoList) { + System.out.println(lottoList.size() + "개를 구매했습니다."); + for(Lotto lotto : lottoList) { + System.out.println(lotto); + } + System.out.println(); + } + + public void printWinningStatistics(LottoResult result) { + System.out.println("당첨 통계"); + System.out.println("---"); + for (LottoRank lottoRank : LottoRank.values()) { + if (lottoRank != LottoRank.NONE) { + //println (X) print(X) printf(O) + System.out.printf("%s - %d개\n", lottoRank.getDescription(), result.getCountForRank(lottoRank)); + } + } + } + + public void printProfitRate(double profitRate) { + System.out.printf("총 수익률은 %.1f%%입니다.\n", profitRate); + } +} diff --git a/src/main/java/lotto/LottoRank.java b/src/main/java/lotto/LottoRank.java new file mode 100644 index 0000000000..3204bf96ba --- /dev/null +++ b/src/main/java/lotto/LottoRank.java @@ -0,0 +1,37 @@ +package lotto; + +public enum LottoRank { + FIRST(6, 2_000_000_000, "6개 일치 (2,000,000,000원)"), + SECOND(5, 30_000_000, "5개 일치, 보너스 볼 일치 (30,000,000원)"), + THIRD(5, 1_500_000, "5개 일치 (1,500,000원)"), + FOURTH(4, 50_000, "4개 일치 (50,000원)"), + FIFTH(3, 5_000, "3개 일치 (5,000원)"), + NONE(0, 0, ""); + + private final int matchCount; + private final int prize; + private final String description; + + LottoRank(int matchCount, int prize, String description) { + this.matchCount = matchCount; + this.prize = prize; + this.description = description; + } + + public static LottoRank getRank(int matchCount, boolean bonusMatch) { + if (matchCount == 6) return FIRST; + else if (matchCount == 5 && bonusMatch) return SECOND; + else if (matchCount == 5) return THIRD; + else if (matchCount == 4) return FOURTH; + else if (matchCount == 3) return FIFTH; + return NONE; + } + + public String getDescription() { + return description; + } + + public long getPrize() { + return prize; + } +} diff --git a/src/main/java/lotto/LottoResult.java b/src/main/java/lotto/LottoResult.java new file mode 100644 index 0000000000..41b910c210 --- /dev/null +++ b/src/main/java/lotto/LottoResult.java @@ -0,0 +1,28 @@ +package lotto; + +import java.util.HashMap; + +public class LottoResult { + private final HashMap rankCounts; + + public LottoResult() { + this.rankCounts = new HashMap(); + for (LottoRank lottoRank : LottoRank.values()) { + rankCounts.put(lottoRank, 0); + } + } + + public void addResult(LottoRank rank) { + rankCounts.put(rank, rankCounts.get(rank) + 1); //현재 랭크 갯수보다 하나 업 + } + + public int getCountForRank(LottoRank lottoRank) { + return rankCounts.get(lottoRank); + } + + public long getTotalPrize() { + return rankCounts.entrySet().stream() + .mapToLong(entry -> entry.getKey().getPrize() * entry.getValue()) + .sum(); + } +} diff --git a/src/main/java/lotto/LottoService.java b/src/main/java/lotto/LottoService.java new file mode 100644 index 0000000000..553606df91 --- /dev/null +++ b/src/main/java/lotto/LottoService.java @@ -0,0 +1,36 @@ +package lotto; + +import camp.nextstep.edu.missionutils.Randoms; + +import java.util.ArrayList; +import java.util.List; + +public class LottoService { + + /** + * 6개의 숫자 생성 + */ + public List generateLottoNumber(int count) { + List result = new ArrayList<>(); + for(int i = 0; i < count; i++) { + List numbers = Randoms.pickUniqueNumbersInRange(1, 45, 6); + result.add(new Lotto(numbers)); + } + return result; + } + + public LottoResult checkWinningResult(List lottoList, List winningNumbers, int bonusNumber) { + LottoResult result = new LottoResult(); + for (Lotto lotto : lottoList) { + int matchCount = lotto.matchCount(winningNumbers); + boolean bonusMatch = lotto.contains(bonusNumber); + result.addResult(LottoRank.getRank(matchCount, bonusMatch)); + } + return result; + } + + public double calculateProfitRate(int money, LottoResult result) { + long totalPrize = result.getTotalPrize(); + return (totalPrize * 100.0) / money; + } +} From bf9e5e107bf276401b57995719f260d40e30070d Mon Sep 17 00:00:00 2001 From: LocKey Date: Sat, 5 Oct 2024 01:22:50 +0900 Subject: [PATCH 3/9] =?UTF-8?q?fix:=20input=EA=B3=BC=20output=EC=9D=98=20?= =?UTF-8?q?=EC=97=AD=ED=95=A0=EC=9D=84=20=EC=A0=95=ED=99=95=ED=9E=88=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/GameManager.java | 7 +++++-- src/main/java/lotto/Lotto.java | 7 +++++++ src/main/java/lotto/LottoOutputView.java | 17 +++++++--------- src/main/java/lotto/LottoResult.java | 26 ++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/main/java/lotto/GameManager.java b/src/main/java/lotto/GameManager.java index 60fe1bd2f8..08d96e83d3 100644 --- a/src/main/java/lotto/GameManager.java +++ b/src/main/java/lotto/GameManager.java @@ -1,6 +1,7 @@ package lotto; import java.util.List; +import java.util.stream.Collectors; public class GameManager { private final LottoInputView lottoInputView; @@ -19,13 +20,15 @@ public GameManager() { public void start() { int money = lottoInputView.receiveUserMoneyInput(); List lottoList = lottoService.generateLottoNumber(money / 1000); - lottoOutputView.printLotto(lottoList); + lottoOutputView.printLotto(lottoList.size(), lottoList.stream() + .map(Lotto::getNumbers) + .collect(Collectors.toList())); List winningNumbers = lottoInputView.receiveWinningNumberInput(); int bonusNumber = lottoInputView.receiveBonusNumberInput(winningNumbers); LottoResult result = lottoService.checkWinningResult(lottoList, winningNumbers, bonusNumber); - lottoOutputView.printWinningStatistics(result); + lottoOutputView.printWinningStatistics(result.getRankDescriptions(), result.getRankCounts()); double profitRate = lottoService.calculateProfitRate(money, result); lottoOutputView.printProfitRate(profitRate); diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java index a312200bc5..8667b1d4b1 100644 --- a/src/main/java/lotto/Lotto.java +++ b/src/main/java/lotto/Lotto.java @@ -29,4 +29,11 @@ public boolean contains(int number) { public int matchCount(List winningNumbers) { return (int) numbers.stream().filter(winningNumbers::contains).count(); //numbers에 있는 int를 loop 돌려서 winningNumbers에 포함되어있다면 개수를 셈 } + + /** + * 로또 번호 리스트 반환 + */ + public List getNumbers() { + return numbers; + } } diff --git a/src/main/java/lotto/LottoOutputView.java b/src/main/java/lotto/LottoOutputView.java index 6ec9e3287a..5658b64080 100644 --- a/src/main/java/lotto/LottoOutputView.java +++ b/src/main/java/lotto/LottoOutputView.java @@ -4,22 +4,19 @@ public class LottoOutputView { - public void printLotto(List lottoList) { - System.out.println(lottoList.size() + "개를 구매했습니다."); - for(Lotto lotto : lottoList) { - System.out.println(lotto); + public void printLotto(int numberOfLotto, List> lottoNumbersList) { + System.out.println(numberOfLotto + "개를 구매했습니다."); + for (List lottoNumbers : lottoNumbersList) { + System.out.println(lottoNumbers); } System.out.println(); } - public void printWinningStatistics(LottoResult result) { + public void printWinningStatistics(List rankDescriptions, List rankCounts) { System.out.println("당첨 통계"); System.out.println("---"); - for (LottoRank lottoRank : LottoRank.values()) { - if (lottoRank != LottoRank.NONE) { - //println (X) print(X) printf(O) - System.out.printf("%s - %d개\n", lottoRank.getDescription(), result.getCountForRank(lottoRank)); - } + for (int i = 0; i < rankDescriptions.size(); i++) { + System.out.printf("%s - %d개\n", rankDescriptions.get(i), rankCounts.get(i)); } } diff --git a/src/main/java/lotto/LottoResult.java b/src/main/java/lotto/LottoResult.java index 41b910c210..a59b6a7773 100644 --- a/src/main/java/lotto/LottoResult.java +++ b/src/main/java/lotto/LottoResult.java @@ -1,6 +1,10 @@ package lotto; +import java.util.Comparator; import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; public class LottoResult { private final HashMap rankCounts; @@ -25,4 +29,26 @@ public long getTotalPrize() { .mapToLong(entry -> entry.getKey().getPrize() * entry.getValue()) .sum(); } + + /** + * 랭크 설명 리스트를 LottoRank의 역순서대로 반환 + */ + public List getRankDescriptions() { + return rankCounts.keySet().stream() + .filter(rank -> rank != LottoRank.NONE) // NONE 랭크 제외 + .sorted((r1, r2) -> r2.ordinal() - r1.ordinal()) // 역순 정렬 (ordinal 값을 기준으로) + .map(LottoRank::getDescription) // 각 랭크의 설명 문자열 추출 + .collect(Collectors.toList()); + } + + /** + * 각 랭크의 개수를 LottoRank의 역순서대로 리스트로 반환 + */ + public List getRankCounts() { + return rankCounts.entrySet().stream() + .filter(entry -> entry.getKey() != LottoRank.NONE) // NONE 랭크 제외 + .sorted((entry1, entry2) -> entry2.getKey().ordinal() - entry1.getKey().ordinal()) // 역순 정렬 (ordinal 값을 기준으로) + .map(Map.Entry::getValue) // 각 랭크의 개수만 추출 + .collect(Collectors.toList()); + } } From a36a901beb7aa625d540e80d61cae4958693ba8c Mon Sep 17 00:00:00 2001 From: LocKey Date: Sat, 5 Oct 2024 02:09:34 +0900 Subject: [PATCH 4/9] =?UTF-8?q?fix:=20validate=EC=99=80=20parser=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20=EB=B7=B0=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/LottoInputView.java | 45 +++------------------- src/main/java/lotto/LottoParser.java | 22 +++++++++++ src/main/java/lotto/LottoValidator.java | 51 +++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 40 deletions(-) create mode 100644 src/main/java/lotto/LottoParser.java create mode 100644 src/main/java/lotto/LottoValidator.java diff --git a/src/main/java/lotto/LottoInputView.java b/src/main/java/lotto/LottoInputView.java index eef669d2a5..03f31eb989 100644 --- a/src/main/java/lotto/LottoInputView.java +++ b/src/main/java/lotto/LottoInputView.java @@ -6,6 +6,9 @@ import java.util.List; import java.util.stream.Collectors; +import static lotto.LottoParser.parseNumbers; +import static lotto.LottoValidator.*; + public class LottoInputView { /** @@ -18,17 +21,6 @@ public int receiveUserMoneyInput() { return Integer.parseInt(input); } - private void validateMoneyInput(String input) { - try { - int money = Integer.parseInt(input); - if (money % 1000 != 0) { - throw new IllegalArgumentException("[ERROR] 구입 금액은 1,000원 단위여야 합니다."); - } - } catch (NumberFormatException e) { //숫자가 아닐 경우 - throw new IllegalArgumentException("[ERROR] 올바른 숫자를 입력하세요."); - } - } - /** * 당첨 번호 입력 받기 */ @@ -40,29 +32,9 @@ public List receiveWinningNumberInput() { return numbers; } - private void validateNumbers(List numbers) { - if (numbers.size() != 6) { - throw new IllegalArgumentException("[ERROR] 당첨 번호는 6개여야 합니다."); - } - if (numbers.stream().distinct().count() != 6) { - throw new IllegalArgumentException("[ERROR] 당첨 번호에 중복된 숫자가 있습니다."); - } - if (numbers.stream().anyMatch(n -> n < 1 || n > 45)) { - throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); - } - } - /** - * 입력 정수 리스트로 변환 + * 보너스 번호 입력 받기 */ - private List parseNumbers(String input) { - return Arrays.stream(input.split(",")) - .map(String::trim) //스페이스 제거 - .map(Integer::parseInt) //정수 변환 - .collect(Collectors.toList()); - } - - public int receiveBonusNumberInput(List winningList) { System.out.println("보너스 번호를 입력해 주세요."); String input = Console.readLine(); @@ -71,12 +43,5 @@ public int receiveBonusNumberInput(List winningList) { return result; } - private void validateBonusNumber(int bonusNumber, List winningList) { - if (bonusNumber < 1 || bonusNumber > 45) { - throw new IllegalArgumentException("[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."); - } - if (winningList.contains(bonusNumber)) { - throw new IllegalArgumentException("[ERROR] 당첨 번호에 중복된 숫자가 있습니다."); - } - } + } diff --git a/src/main/java/lotto/LottoParser.java b/src/main/java/lotto/LottoParser.java new file mode 100644 index 0000000000..105276bf0a --- /dev/null +++ b/src/main/java/lotto/LottoParser.java @@ -0,0 +1,22 @@ +package lotto; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class LottoParser { + + + private LottoParser() { + } + + /** + * 입력 정수 리스트로 변환 + */ + public static List parseNumbers(String input) { + return Arrays.stream(input.split(",")) + .map(String::trim) //스페이스 제거 + .map(Integer::parseInt) //정수 변환 + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/lotto/LottoValidator.java b/src/main/java/lotto/LottoValidator.java new file mode 100644 index 0000000000..892717a656 --- /dev/null +++ b/src/main/java/lotto/LottoValidator.java @@ -0,0 +1,51 @@ +package lotto; + +import java.util.List; + +public class LottoValidator { + + private LottoValidator() { + // 객체 생성 방지 + } + + /** + * 구입 금액 검증 + */ + public static void validateMoneyInput(String input) { + try { + int money = Integer.parseInt(input); + if (money % 1000 != 0) { + throw new IllegalArgumentException("[ERROR] 구입 금액은 1,000원 단위여야 합니다."); + } + } catch (NumberFormatException e) { //숫자가 아닐 경우 + throw new IllegalArgumentException("[ERROR] 올바른 숫자를 입력하세요."); + } + } + + /** + * 로또 번호 리스트 검증 + */ + public static void validateNumbers(List numbers) { + if (numbers.size() != 6) { + throw new IllegalArgumentException("[ERROR] 당첨 번호는 6개여야 합니다."); + } + if (numbers.stream().distinct().count() != 6) { + throw new IllegalArgumentException("[ERROR] 당첨 번호에 중복된 숫자가 있습니다."); + } + if (numbers.stream().anyMatch(n -> n < 1 || n > 45)) { + throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); + } + } + + /** + * 보너스 번호 검증 + */ + public static void validateBonusNumber(int bonusNumber, List winningList) { + if (bonusNumber < 1 || bonusNumber > 45) { + throw new IllegalArgumentException("[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."); + } + if (winningList.contains(bonusNumber)) { + throw new IllegalArgumentException("[ERROR] 당첨 번호에 중복된 숫자가 있습니다."); + } + } +} From 84914ca42cf3e538c45e7f5f9325e89fa310a32f Mon Sep 17 00:00:00 2001 From: LocKey Date: Sun, 6 Oct 2024 02:18:57 +0900 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20MVC=20=ED=8C=A8=ED=84=B4=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EA=B2=8C=20=ED=8C=8C=EC=9D=BC=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/Application.java | 6 ++++-- .../GameController.java} | 15 ++++++++++----- .../LottoController.java} | 7 +++++-- src/main/java/lotto/{ => model}/Lotto.java | 2 +- src/main/java/lotto/{ => model}/LottoRank.java | 2 +- src/main/java/lotto/{ => model}/LottoResult.java | 3 +-- src/main/java/lotto/{ => util}/LottoParser.java | 2 +- .../java/lotto/{ => util}/LottoValidator.java | 2 +- .../java/lotto/{ => view}/LottoInputView.java | 8 +++----- .../java/lotto/{ => view}/LottoOutputView.java | 2 +- 10 files changed, 28 insertions(+), 21 deletions(-) rename src/main/java/lotto/{GameManager.java => controller/GameController.java} (78%) rename src/main/java/lotto/{LottoService.java => controller/LottoController.java} (88%) rename src/main/java/lotto/{ => model}/Lotto.java (97%) rename src/main/java/lotto/{ => model}/LottoRank.java (98%) rename src/main/java/lotto/{ => model}/LottoResult.java (97%) rename src/main/java/lotto/{ => util}/LottoParser.java (96%) rename src/main/java/lotto/{ => util}/LottoValidator.java (98%) rename src/main/java/lotto/{ => view}/LottoInputView.java (87%) rename src/main/java/lotto/{ => view}/LottoOutputView.java (97%) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index 8504405f83..932744f713 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,8 +1,10 @@ package lotto; +import lotto.controller.GameController; + public class Application { public static void main(String[] args) { - GameManager gameManager = new GameManager(); - gameManager.start(); + GameController gameController = new GameController(); + gameController.start(); } } diff --git a/src/main/java/lotto/GameManager.java b/src/main/java/lotto/controller/GameController.java similarity index 78% rename from src/main/java/lotto/GameManager.java rename to src/main/java/lotto/controller/GameController.java index 08d96e83d3..bfec8e593a 100644 --- a/src/main/java/lotto/GameManager.java +++ b/src/main/java/lotto/controller/GameController.java @@ -1,15 +1,20 @@ -package lotto; +package lotto.controller; + +import lotto.view.LottoInputView; +import lotto.view.LottoOutputView; +import lotto.model.Lotto; +import lotto.model.LottoResult; import java.util.List; import java.util.stream.Collectors; -public class GameManager { +public class GameController { private final LottoInputView lottoInputView; - private final LottoService lottoService; + private final LottoController lottoService; private final LottoOutputView lottoOutputView; - public GameManager() { - this.lottoService = new LottoService(); + public GameController() { + this.lottoService = new LottoController(); this.lottoOutputView = new LottoOutputView(); this.lottoInputView = new LottoInputView(); } diff --git a/src/main/java/lotto/LottoService.java b/src/main/java/lotto/controller/LottoController.java similarity index 88% rename from src/main/java/lotto/LottoService.java rename to src/main/java/lotto/controller/LottoController.java index 553606df91..5a986b9213 100644 --- a/src/main/java/lotto/LottoService.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -1,11 +1,14 @@ -package lotto; +package lotto.controller; import camp.nextstep.edu.missionutils.Randoms; +import lotto.model.Lotto; +import lotto.model.LottoRank; +import lotto.model.LottoResult; import java.util.ArrayList; import java.util.List; -public class LottoService { +public class LottoController { /** * 6개의 숫자 생성 diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/model/Lotto.java similarity index 97% rename from src/main/java/lotto/Lotto.java rename to src/main/java/lotto/model/Lotto.java index 8667b1d4b1..c42f681abd 100644 --- a/src/main/java/lotto/Lotto.java +++ b/src/main/java/lotto/model/Lotto.java @@ -1,4 +1,4 @@ -package lotto; +package lotto.model; import java.util.List; diff --git a/src/main/java/lotto/LottoRank.java b/src/main/java/lotto/model/LottoRank.java similarity index 98% rename from src/main/java/lotto/LottoRank.java rename to src/main/java/lotto/model/LottoRank.java index 3204bf96ba..a57defd979 100644 --- a/src/main/java/lotto/LottoRank.java +++ b/src/main/java/lotto/model/LottoRank.java @@ -1,4 +1,4 @@ -package lotto; +package lotto.model; public enum LottoRank { FIRST(6, 2_000_000_000, "6개 일치 (2,000,000,000원)"), diff --git a/src/main/java/lotto/LottoResult.java b/src/main/java/lotto/model/LottoResult.java similarity index 97% rename from src/main/java/lotto/LottoResult.java rename to src/main/java/lotto/model/LottoResult.java index a59b6a7773..e46a522590 100644 --- a/src/main/java/lotto/LottoResult.java +++ b/src/main/java/lotto/model/LottoResult.java @@ -1,6 +1,5 @@ -package lotto; +package lotto.model; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; diff --git a/src/main/java/lotto/LottoParser.java b/src/main/java/lotto/util/LottoParser.java similarity index 96% rename from src/main/java/lotto/LottoParser.java rename to src/main/java/lotto/util/LottoParser.java index 105276bf0a..8776a70ac8 100644 --- a/src/main/java/lotto/LottoParser.java +++ b/src/main/java/lotto/util/LottoParser.java @@ -1,4 +1,4 @@ -package lotto; +package lotto.util; import java.util.Arrays; import java.util.List; diff --git a/src/main/java/lotto/LottoValidator.java b/src/main/java/lotto/util/LottoValidator.java similarity index 98% rename from src/main/java/lotto/LottoValidator.java rename to src/main/java/lotto/util/LottoValidator.java index 892717a656..8d33c708da 100644 --- a/src/main/java/lotto/LottoValidator.java +++ b/src/main/java/lotto/util/LottoValidator.java @@ -1,4 +1,4 @@ -package lotto; +package lotto.util; import java.util.List; diff --git a/src/main/java/lotto/LottoInputView.java b/src/main/java/lotto/view/LottoInputView.java similarity index 87% rename from src/main/java/lotto/LottoInputView.java rename to src/main/java/lotto/view/LottoInputView.java index 03f31eb989..09a05efafe 100644 --- a/src/main/java/lotto/LottoInputView.java +++ b/src/main/java/lotto/view/LottoInputView.java @@ -1,13 +1,11 @@ -package lotto; +package lotto.view; import camp.nextstep.edu.missionutils.Console; -import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; -import static lotto.LottoParser.parseNumbers; -import static lotto.LottoValidator.*; +import static lotto.util.LottoParser.parseNumbers; +import static lotto.util.LottoValidator.*; public class LottoInputView { diff --git a/src/main/java/lotto/LottoOutputView.java b/src/main/java/lotto/view/LottoOutputView.java similarity index 97% rename from src/main/java/lotto/LottoOutputView.java rename to src/main/java/lotto/view/LottoOutputView.java index 5658b64080..792c2b7316 100644 --- a/src/main/java/lotto/LottoOutputView.java +++ b/src/main/java/lotto/view/LottoOutputView.java @@ -1,4 +1,4 @@ -package lotto; +package lotto.view; import java.util.List; From 041f2723e084a1f7bf7c02f04e9ae915e662158f Mon Sep 17 00:00:00 2001 From: LocKey Date: Sun, 6 Oct 2024 02:35:31 +0900 Subject: [PATCH 6/9] =?UTF-8?q?fix:=20if-else=20=EA=B5=AC=EB=AC=B8?= =?UTF-8?q?=EC=9D=84=20stream=20api=EB=A5=BC=20=EC=8D=A8=EC=84=9C=20?= =?UTF-8?q?=EC=B6=95=EC=95=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/model/LottoRank.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/lotto/model/LottoRank.java b/src/main/java/lotto/model/LottoRank.java index a57defd979..4380011090 100644 --- a/src/main/java/lotto/model/LottoRank.java +++ b/src/main/java/lotto/model/LottoRank.java @@ -1,5 +1,7 @@ package lotto.model; +import java.util.Arrays; + public enum LottoRank { FIRST(6, 2_000_000_000, "6개 일치 (2,000,000,000원)"), SECOND(5, 30_000_000, "5개 일치, 보너스 볼 일치 (30,000,000원)"), @@ -18,13 +20,12 @@ public enum LottoRank { this.description = description; } - public static LottoRank getRank(int matchCount, boolean bonusMatch) { - if (matchCount == 6) return FIRST; - else if (matchCount == 5 && bonusMatch) return SECOND; - else if (matchCount == 5) return THIRD; - else if (matchCount == 4) return FOURTH; - else if (matchCount == 3) return FIFTH; - return NONE; + public static LottoRank getRank(int count, boolean bonusMatch) { + return Arrays.stream(values()) //모든 LottoRank 값을 스트림으로 변환 + .filter(rank -> rank.matchCount == count) + .filter(rank -> rank != SECOND || (rank == SECOND && bonusMatch)) + .findFirst() + .orElse(NONE); } public String getDescription() { From a33f8fb6bf5df76df92179fadc8b2a15b292a382 Mon Sep 17 00:00:00 2001 From: LocKey Date: Sun, 6 Oct 2024 03:06:29 +0900 Subject: [PATCH 7/9] =?UTF-8?q?fix:=20magic=20number=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=20&=20=ED=95=A8=EC=88=98=20=EC=84=A4=EB=AA=85=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EB=8B=AC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/lotto/controller/GameController.java | 3 ++- .../lotto/controller/LottoController.java | 19 +++++++++++++++---- src/main/java/lotto/model/Lotto.java | 14 +++++--------- src/main/java/lotto/model/LottoRank.java | 2 +- src/main/java/lotto/model/LottoResult.java | 15 ++++++++++++--- src/main/java/lotto/util/LottoValidator.java | 15 ++++++++++----- 6 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/main/java/lotto/controller/GameController.java b/src/main/java/lotto/controller/GameController.java index bfec8e593a..53ef7503dc 100644 --- a/src/main/java/lotto/controller/GameController.java +++ b/src/main/java/lotto/controller/GameController.java @@ -12,6 +12,7 @@ public class GameController { private final LottoInputView lottoInputView; private final LottoController lottoService; private final LottoOutputView lottoOutputView; + private static final int LOTTO_PRICE = 1000; public GameController() { this.lottoService = new LottoController(); @@ -24,7 +25,7 @@ public GameController() { */ public void start() { int money = lottoInputView.receiveUserMoneyInput(); - List lottoList = lottoService.generateLottoNumber(money / 1000); + List lottoList = lottoService.generateLottoNumber(money / LOTTO_PRICE); lottoOutputView.printLotto(lottoList.size(), lottoList.stream() .map(Lotto::getNumbers) .collect(Collectors.toList())); diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java index 5a986b9213..1515dcc942 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -10,30 +10,41 @@ public class LottoController { + private static final int LOTTO_MIN_NUMBER = 1; // 로또 번호의 최소값 + private static final int LOTTO_MAX_NUMBER = 45; // 로또 번호의 최대값 + private static final int LOTTO_NUMBER_COUNT = 6; // 로또 번호의 개수 + private static final double PERCENTAGE_CONVERSION = 100.0; // 수익률 계산 비율 + /** - * 6개의 숫자 생성 + * 로또 번호 생성 */ public List generateLottoNumber(int count) { List result = new ArrayList<>(); for(int i = 0; i < count; i++) { - List numbers = Randoms.pickUniqueNumbersInRange(1, 45, 6); + List numbers = Randoms.pickUniqueNumbersInRange(LOTTO_MIN_NUMBER, LOTTO_MAX_NUMBER, LOTTO_NUMBER_COUNT); result.add(new Lotto(numbers)); } return result; } + /** + * 당첨 결과 확인 + */ public LottoResult checkWinningResult(List lottoList, List winningNumbers, int bonusNumber) { LottoResult result = new LottoResult(); for (Lotto lotto : lottoList) { int matchCount = lotto.matchCount(winningNumbers); boolean bonusMatch = lotto.contains(bonusNumber); - result.addResult(LottoRank.getRank(matchCount, bonusMatch)); + result.addResult(LottoRank.findMatchingRank(matchCount, bonusMatch)); } return result; } + /** + * 수익률 계산 + */ public double calculateProfitRate(int money, LottoResult result) { long totalPrize = result.getTotalPrize(); - return (totalPrize * 100.0) / money; + return (totalPrize * PERCENTAGE_CONVERSION) / money; } } diff --git a/src/main/java/lotto/model/Lotto.java b/src/main/java/lotto/model/Lotto.java index c42f681abd..fec5ecec78 100644 --- a/src/main/java/lotto/model/Lotto.java +++ b/src/main/java/lotto/model/Lotto.java @@ -2,29 +2,25 @@ import java.util.List; +import static lotto.util.LottoValidator.validateNumbers; + public class Lotto { private final List numbers; public Lotto(List numbers) { - validate(numbers); + validateNumbers(numbers); this.numbers = numbers; } - private void validate(List numbers) { - if (numbers.size() != 6) { - throw new IllegalArgumentException(); - } - } - /** - * + * 특정 번호가 로또 번호 리스트에 포함되어 있는지 확인 */ public boolean contains(int number) { return numbers.contains(number); } /** - * + * 당첨 번호 리스트와 로또 번호 리스트의 일치 개수를 반환 */ public int matchCount(List winningNumbers) { return (int) numbers.stream().filter(winningNumbers::contains).count(); //numbers에 있는 int를 loop 돌려서 winningNumbers에 포함되어있다면 개수를 셈 diff --git a/src/main/java/lotto/model/LottoRank.java b/src/main/java/lotto/model/LottoRank.java index 4380011090..2fae9d1784 100644 --- a/src/main/java/lotto/model/LottoRank.java +++ b/src/main/java/lotto/model/LottoRank.java @@ -20,7 +20,7 @@ public enum LottoRank { this.description = description; } - public static LottoRank getRank(int count, boolean bonusMatch) { + public static LottoRank findMatchingRank(int count, boolean bonusMatch) { return Arrays.stream(values()) //모든 LottoRank 값을 스트림으로 변환 .filter(rank -> rank.matchCount == count) .filter(rank -> rank != SECOND || (rank == SECOND && bonusMatch)) diff --git a/src/main/java/lotto/model/LottoResult.java b/src/main/java/lotto/model/LottoResult.java index e46a522590..552787eae1 100644 --- a/src/main/java/lotto/model/LottoResult.java +++ b/src/main/java/lotto/model/LottoResult.java @@ -9,20 +9,29 @@ public class LottoResult { private final HashMap rankCounts; public LottoResult() { - this.rankCounts = new HashMap(); + this.rankCounts = new HashMap<>(); for (LottoRank lottoRank : LottoRank.values()) { rankCounts.put(lottoRank, 0); } } + /** + * 당첨 결과를 추가 + */ public void addResult(LottoRank rank) { rankCounts.put(rank, rankCounts.get(rank) + 1); //현재 랭크 갯수보다 하나 업 } + /** + * 특정 랭크의 당첨 개수 반환 + */ public int getCountForRank(LottoRank lottoRank) { return rankCounts.get(lottoRank); } + /** + * 전체 상금 합계 반환 + */ public long getTotalPrize() { return rankCounts.entrySet().stream() .mapToLong(entry -> entry.getKey().getPrize() * entry.getValue()) @@ -30,7 +39,7 @@ public long getTotalPrize() { } /** - * 랭크 설명 리스트를 LottoRank의 역순서대로 반환 + * 랭크 설명을 역순으로 반환 */ public List getRankDescriptions() { return rankCounts.keySet().stream() @@ -41,7 +50,7 @@ public List getRankDescriptions() { } /** - * 각 랭크의 개수를 LottoRank의 역순서대로 리스트로 반환 + * 각 랭크의 당첨 개수를 역순으로 반환 */ public List getRankCounts() { return rankCounts.entrySet().stream() diff --git a/src/main/java/lotto/util/LottoValidator.java b/src/main/java/lotto/util/LottoValidator.java index 8d33c708da..c0908c0b4b 100644 --- a/src/main/java/lotto/util/LottoValidator.java +++ b/src/main/java/lotto/util/LottoValidator.java @@ -4,6 +4,11 @@ public class LottoValidator { + private static final int LOTTO_MIN_NUMBER = 1; // 로또 번호의 최소값 + private static final int LOTTO_MAX_NUMBER = 45; // 로또 번호의 최대값 + private static final int LOTTO_NUMBER_COUNT = 6; // 로또 번호의 개수 + private static final int LOTTO_PRICE_UNIT = 1000; // 로또 구입 금액 단위 + private LottoValidator() { // 객체 생성 방지 } @@ -14,7 +19,7 @@ private LottoValidator() { public static void validateMoneyInput(String input) { try { int money = Integer.parseInt(input); - if (money % 1000 != 0) { + if (money % LOTTO_PRICE_UNIT != 0) { throw new IllegalArgumentException("[ERROR] 구입 금액은 1,000원 단위여야 합니다."); } } catch (NumberFormatException e) { //숫자가 아닐 경우 @@ -26,13 +31,13 @@ public static void validateMoneyInput(String input) { * 로또 번호 리스트 검증 */ public static void validateNumbers(List numbers) { - if (numbers.size() != 6) { + if (numbers.size() != LOTTO_NUMBER_COUNT) { throw new IllegalArgumentException("[ERROR] 당첨 번호는 6개여야 합니다."); } - if (numbers.stream().distinct().count() != 6) { + if (numbers.stream().distinct().count() != LOTTO_NUMBER_COUNT) { throw new IllegalArgumentException("[ERROR] 당첨 번호에 중복된 숫자가 있습니다."); } - if (numbers.stream().anyMatch(n -> n < 1 || n > 45)) { + if (numbers.stream().anyMatch(n -> n < LOTTO_MIN_NUMBER || n > LOTTO_MAX_NUMBER)) { throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."); } } @@ -41,7 +46,7 @@ public static void validateNumbers(List numbers) { * 보너스 번호 검증 */ public static void validateBonusNumber(int bonusNumber, List winningList) { - if (bonusNumber < 1 || bonusNumber > 45) { + if (bonusNumber < LOTTO_MIN_NUMBER || bonusNumber > LOTTO_MAX_NUMBER) { throw new IllegalArgumentException("[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."); } if (winningList.contains(bonusNumber)) { From 1724cd317995866d41ef3bc30e0c53ca1d5b37a3 Mon Sep 17 00:00:00 2001 From: LocKey Date: Sun, 6 Oct 2024 13:12:26 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20printf,=20println=EC=9D=98=20?= =?UTF-8?q?=EC=B0=A8=EC=9D=B4=20=EC=95=8C=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/view/LottoOutputView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/lotto/view/LottoOutputView.java b/src/main/java/lotto/view/LottoOutputView.java index 792c2b7316..9378dc7842 100644 --- a/src/main/java/lotto/view/LottoOutputView.java +++ b/src/main/java/lotto/view/LottoOutputView.java @@ -16,7 +16,8 @@ public void printWinningStatistics(List rankDescriptions, List System.out.println("당첨 통계"); System.out.println("---"); for (int i = 0; i < rankDescriptions.size(); i++) { - System.out.printf("%s - %d개\n", rankDescriptions.get(i), rankCounts.get(i)); +// System.out.printf("%s - %d개\n", rankDescriptions.get(i), rankCounts.get(i)); + System.out.println(rankDescriptions.get(i) + " - " + rankCounts.get(i) + "개"); } } From 3dba30e7f20a17f98915ded917d7aa830f8dd136 Mon Sep 17 00:00:00 2001 From: LocKey Date: Sun, 6 Oct 2024 13:44:25 +0900 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=EA=B8=B0=EB=8A=A5=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=20=EC=82=AC=ED=95=AD=20=EB=AA=A9=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 61 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/docs/README.md b/docs/README.md index 1a8bd48056..69dd513bf6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,22 +1,51 @@ # 기능 목록 + 각 기능에 대한 예외사항과 핸들링도 기재 ++ MVC 패턴을 사용 -- [ ] 게임 관리 - GameManager class - - [ ] 게임 시작 - start() -- [ ] 로또 게임 구현 - LottoGame class - - [ ] 6개의 숫자 생성 **(Computer)** - generateLottoNumber() - - [ ] 로또 구입 금액 입력 받기 **(Me)** - receiveUserMoneyInput() - - [ ] **예외사항** : 1000원으로 나누어 떨어지지 않는 경우 -> `IllegalArgumentException` - - [ ] 당첨 번호 입력 받기 **(Me)** - receiveUserNumberInput() - - [ ] **예외사항** : 쉼표를 기준으로 구분하지 않은 경우 -> `IllegalArgumentException` - - [ ] **예외사항** : 로또 번호의 숫자 범위 밖의 경우 (1 ~ 45) -> `IllegalArgumentException` - - [ ] **예외사항** : 숫자가 중복되는 경우 -> `IllegalArgumentException` - - [ ] 보너스 번호 입력 받기 **(Me)** - receiveUserBonusInput() - - [ ] **예외사항** : 로또 번호의 숫자 범위 밖의 경우 (1 ~ 45) -> `IllegalArgumentException` - - [ ] **예외사항** : 숫자가 중복되는 경우 -> `IllegalArgumentException` - - [ ] 발행한 로또 수량 및 번호를 오름차순으로 출력 - issuanceLotto() - - [ ] 당첨 내역 출력 - printWinningDetails() - - [ ] 수익률 계산 (소수점 둘째 자리 반올림) - calculateRateOfProfit() +- model 패키지 + - [x] 로또 번호 관리 - Lotto class + - [x] 특정 번호가 로또 번호 리스트에 포함되어 있는지 확인 - contains() + - [x] 당첨 번호 리스트와 로또 번호 리스트의 일치 개수를 반환 - matchCount() + - [x] 로또 번호 리스트 반환 - getNumbers() + - [x] 로또 당첨 등수 관리 - LottoRank class + - [x] 일치하는 등수를 찾음 - findMatchingRank() + - [x] 등수의 설명을 반환 - getDescription() + - [x] 등수의 상금을 반환 - getPrize() + - [x] 로또 당첨 결과 관리 - LottoResult class + - [x] 당첨 결과를 추가 - addResult() + - [x] 전체 상금 합계 반환 - calculateTotalPrize() + - [x] 랭크 설명을 역순으로 반환 - reverseRankDescriptions() + - [x] 각 랭크의 당첨 개수를 역순으로 반환 - reverseRankCounts() +- view 패키지 + - [x] 사용자 입력 처리 - LottoInputView class + - [x] 로또 구입 금액 입력 받기 - receiveUserMoneyInput() + - 예외사항 : 구입 금액이 1,000원 단위가 아닌 경우 ➔ IllegalArgumentException + - 예외사항 : 입력이 숫자가 아닌 경우 ➔ IllegalArgumentException + - [x] 당첨 번호 입력 받기 - receiveWinningNumberInput() + - 예외사항 : 당첨번호가 6개가 아닌 경우 ➔ IllegalArgumentException + - 예외사항 : 당첨번호에 중복된 숫자가 있는 경우 ➔ IllegalArgumentException + - 예외사항 : 로또번호가 1부터 45 사이가 아닌 경우 ➔ IllegalArgumentException + - [x] 보너스 번호 입력 받기 - receiveBonusNumberInput() + - 예외사항 : 당첨번호에 중복된 숫자가 있는 경우 ➔ IllegalArgumentException + - 예외사항 : 로또번호가 1부터 45 사이가 아닌 경우 ➔ IllegalArgumentException + - [x] 결과 출력 - LottoOutputView class + - [x] 로또 번호 목록 출력 - printLotto() + - [x] 당첨 통계 출력 - printWinningStatistics() + - [x] 총 수익률 출력 - printProfitRate() +- controller 패키지 + - [x] 로또게임 구현 - GameController class + - [x] 게임 시작 - start() + - [x] 로또 게임 로직 처리 - LottoController class + - [x] 로또 번호 생성 - generateLottoNumber() + - [x] 당첨 결과 확인 - checkWinningResult() + - [x] 수익률 계산 - calculateProfitRate() +- util 패키지 + - [x] 입력 변환 유틸리티 - LottoParser class + - [x] 입력 정수 리스트로 변환 - parseNumbers() + - [x] 입력 검증 유틸리티 - LottoValidator class + - [x] 구입 금액 검증 - validateMoneyInput() + - [x] 로또 번호 리스트 검증 - validateNumbers() + - [x] 보너스 번호 검증 - validateBonusNumber() -------