From ab94f83a7992725177f4b615510e830978cb70ad Mon Sep 17 00:00:00 2001 From: rtaeho Date: Mon, 18 Mar 2024 16:24:57 +0900 Subject: [PATCH 1/3] =?UTF-8?q?docs=20:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=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 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/README.md b/docs/README.md index e69de29..db2de15 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,18 @@ +- [ ] 구입 금액 입력 + - [ ] 1000원 단위인지 검사하는 기능 +- [ ] 당첨 번호 입력 + - [ ] 1 ~ 45 사이인지 검사하는 기능 + - [ ] 중복 여부 검사하는 기능 + - [ ] 쉼표로 구분하는 기능 +- [ ] 보너스 번호 입력 + - [ ] 1 ~ 45 사이인지 검사하는 기능 + - [ ] 당첨 번호와의 중복 여부 검사하는 기능 +- [ ] 발행한 로또 출력 + - [ ] 1 ~ 45 사이의 중복되지 않는 숫자 6개를 뽑는 기능 + - [ ] 오름차순으로 만드는 기능 +- [ ] 당첨 내역 출력 + - [ ] 당첨 번호와 발행한 로또를 비교하는 기능 + - [ ] 당첨된를 등수 저장하는 기능 +- [ ] 수익률 출력 + - [ ] 수익금 계산하는 기능 + - [ ] 소수점 둘째 자리에서 반올림하는 기능 \ No newline at end of file From 5261048a9a58f72da344640ad5b1611756b7b358 Mon Sep 17 00:00:00 2001 From: rtaeho Date: Sat, 23 Mar 2024 21:06:44 +0900 Subject: [PATCH 2/3] =?UTF-8?q?~=EC=97=B4=EA=B1=B0=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=EC=88=9C=EC=84=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lotto/controller/LottoController.java | 8 +++ src/main/java/lotto/{ => domain}/Lotto.java | 6 +- .../java/lotto/domain/LottoGenerator.java | 45 ++++++++++++ src/main/java/lotto/domain/Lottos.java | 14 ++++ .../java/lotto/domain/WinningDetails.java | 41 +++++++++++ src/main/java/lotto/domain/WinningLotto.java | 70 +++++++++++++++++++ src/main/java/lotto/domain/WinningRank.java | 51 ++++++++++++++ src/main/java/lotto/view/InputView.java | 43 ++++++++++++ src/main/java/lotto/view/OutputView.java | 19 +++++ src/test/java/lotto/LottoTest.java | 2 + 10 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 src/main/java/lotto/controller/LottoController.java rename src/main/java/lotto/{ => domain}/Lotto.java (80%) create mode 100644 src/main/java/lotto/domain/LottoGenerator.java create mode 100644 src/main/java/lotto/domain/Lottos.java create mode 100644 src/main/java/lotto/domain/WinningDetails.java create mode 100644 src/main/java/lotto/domain/WinningLotto.java create mode 100644 src/main/java/lotto/domain/WinningRank.java create mode 100644 src/main/java/lotto/view/InputView.java create mode 100644 src/main/java/lotto/view/OutputView.java diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java new file mode 100644 index 0000000..03a611e --- /dev/null +++ b/src/main/java/lotto/controller/LottoController.java @@ -0,0 +1,8 @@ +package lotto.controller; + +public class LottoController { + + public void lottoStart() { + + } +} \ No newline at end of file diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/domain/Lotto.java similarity index 80% rename from src/main/java/lotto/Lotto.java rename to src/main/java/lotto/domain/Lotto.java index 519793d..1356b09 100644 --- a/src/main/java/lotto/Lotto.java +++ b/src/main/java/lotto/domain/Lotto.java @@ -1,4 +1,4 @@ -package lotto; +package lotto.domain; import java.util.List; @@ -15,6 +15,8 @@ private void validate(List numbers) { throw new IllegalArgumentException(); } } - + public List getNumbers() { + return numbers; + } // TODO: 추가 기능 구현 } diff --git a/src/main/java/lotto/domain/LottoGenerator.java b/src/main/java/lotto/domain/LottoGenerator.java new file mode 100644 index 0000000..1a453dc --- /dev/null +++ b/src/main/java/lotto/domain/LottoGenerator.java @@ -0,0 +1,45 @@ +package lotto.domain; + +import org.kokodak.Randoms; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class LottoGenerator { + private static final int LOTTO_PRICE = 1_000; + private static final int LOTTO_NUMBER_LOWER_LIMIT = 1; + private static final int LOTTO_NUMBER_UPPER_LIMIT = 45; + private static final int LOTTO_NUMBER_QUANTITY = 6; + private static final String MONEY_SHOULD_BE_DIVIDED_BY_ONE_THOUSAND = "[ERROR] 구입금액은 1,000원으로 나누어 떨어져야 합니다."; + // static 변수로 생성 + private List lottos = new ArrayList<>(); + private int lottoQuantity; + + public LottoGenerator(int money) { + validateMoney(money); + lottoQuantity = money / LOTTO_PRICE; + } + + private void validateMoney(int money) { + if (money % 1000 != 0) { + throw new IllegalArgumentException(MONEY_SHOULD_BE_DIVIDED_BY_ONE_THOUSAND); + } + } + + public List generateLottos() { // 로또들을 담을 객체 반환 + for (int i = 0; i < lottoQuantity; i++) { + Lotto lotto = generateLotto(); + lottos.add(lotto); + } + return lottos; + } + + private Lotto generateLotto() { + List randomNumbers = Randoms.pickUniqueNumbersInRange(LOTTO_NUMBER_LOWER_LIMIT, LOTTO_NUMBER_UPPER_LIMIT, LOTTO_NUMBER_QUANTITY); + // 범위 내에서 로또 번호 생성 + randomNumbers.sort(Comparator.naturalOrder()); // 오름차순 정렬 + return new Lotto(randomNumbers); // 생성한 로또 반환 + } + +} diff --git a/src/main/java/lotto/domain/Lottos.java b/src/main/java/lotto/domain/Lottos.java new file mode 100644 index 0000000..7d8920e --- /dev/null +++ b/src/main/java/lotto/domain/Lottos.java @@ -0,0 +1,14 @@ +package lotto.domain; + +import java.util.List; + +public class Lottos { + private List lottos; + + public Lottos(List lottos) { + this.lottos = lottos; + } + public List getLottos() { + return lottos; + } +} diff --git a/src/main/java/lotto/domain/WinningDetails.java b/src/main/java/lotto/domain/WinningDetails.java new file mode 100644 index 0000000..817beca --- /dev/null +++ b/src/main/java/lotto/domain/WinningDetails.java @@ -0,0 +1,41 @@ +package lotto.domain; + +import java.util.List; +import java.util.Map; + +public class WinningDetails { + public static Map getWinningDetails(Lottos lottos, WinningLotto winningLotto) { + Map winningDetails = WinningRank.generateWinningDetails(); + for (Lotto lotto : lottos.getLottos()) { + int matchingCount = compareNumbersWithWinningNumbers(lotto, winningLotto); + boolean containsBonusNumber = compareNumbersWithBonusNumber(lotto, winningLotto, matchingCount); + WinningRank winningRank = WinningRank.findWinningRank(matchingCount, containsBonusNumber); + winningDetails.replace(winningRank, winningDetails.get(winningRank) + 1); + } + return winningDetails; + } + + private static int compareNumbersWithWinningNumbers(Lotto lotto, WinningLotto winningLotto) { + List numbers = lotto.getNumbers(); + List winningNumbers = winningLotto.getWinningNumbers(); + return (int) numbers.stream() + .filter(winningNumbers::contains) + .count(); + } + + private static boolean compareNumbersWithBonusNumber(Lotto lotto, WinningLotto winningLotto, int matchingCount) { + if (matchingCount != 5) return false; + List numbers = lotto.getNumbers(); + int bonusNumber = winningLotto.getBonusNumber(); + return numbers.contains(bonusNumber); + } + + public static double getLottoYield(Map winningDetails, int money) { + long winningAmount = winningDetails.entrySet().stream() + .filter(entry -> entry.getValue() != 0) + .mapToLong(entry -> (long) entry.getKey().getWinningPrice() * entry.getValue()) + .sum(); + double lottoYield = 100 + (winningAmount - money) / money * 100; + return Math.round(lottoYield * 100) / 100.0; + } +} diff --git a/src/main/java/lotto/domain/WinningLotto.java b/src/main/java/lotto/domain/WinningLotto.java new file mode 100644 index 0000000..3bd955d --- /dev/null +++ b/src/main/java/lotto/domain/WinningLotto.java @@ -0,0 +1,70 @@ +package lotto.domain; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class WinningLotto { + private static final String WINNING_NUMBERS_ARE_BETWEEN_ONE_AND_FORTY_FIVE = "[ERROR] 당첨 번호는 1부터 45 사이의 숫자여야 합니다."; + private static final String WINNING_NUMBERS_MUST_BE_SIX_DIFFERENT_NUMBERS = "[ERROR] 당첨 번호는 서로 다른 6개의 수여야 합니다."; + private static final String BONUS_NUMBER_IS_BETWEEN_ONE_AND_FORTY_FIVE = "[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."; + private static final String WINNING_NUMBERS_CONTAIN_BONUS_NUMBER = "[ERROR] 당첨 번호와 보너스 번호가 중복됩니다."; + + private final List winningNumbers; + private final int bonusNumber; + + public WinningLotto(List winningNumbers, int bonusNumber) { + validateWinningNumbers(winningNumbers); + validateBonusNumber(bonusNumber); + validateDuplicate(winningNumbers, bonusNumber); + this.winningNumbers = winningNumbers; + this.bonusNumber = bonusNumber; + } + + private void validateWinningNumbers(List winningNumbers) { + if (!isSixDifferentNumbers(winningNumbers)) { + throw new IllegalArgumentException(WINNING_NUMBERS_MUST_BE_SIX_DIFFERENT_NUMBERS); + } + if (!isBetweenOneAndFortyFive(winningNumbers)) { + throw new IllegalArgumentException(WINNING_NUMBERS_ARE_BETWEEN_ONE_AND_FORTY_FIVE); + } + } + + private boolean isBetweenOneAndFortyFive(List winningNumbers) { + for (int winningNumber : winningNumbers) { + if (winningNumber < 1 || winningNumber > 45) { + return false; + } + } + return true; + } + + private boolean isSixDifferentNumbers(List winningNumbers) { + Set duplicateChecker = new HashSet<>(winningNumbers); + return duplicateChecker.size() == 6; + } + + private void validateBonusNumber(int bonusNumber) { + if (!isBetweenOneAndFortyFive(bonusNumber)) { + throw new IllegalArgumentException(BONUS_NUMBER_IS_BETWEEN_ONE_AND_FORTY_FIVE); + } + } + + private boolean isBetweenOneAndFortyFive(int bonusNumber) { + return bonusNumber >= 1 && bonusNumber <= 45; + } + + private void validateDuplicate(List winningNumbers, int bonusNumber) { + if (winningNumbers.contains(bonusNumber)) { + throw new IllegalArgumentException(WINNING_NUMBERS_CONTAIN_BONUS_NUMBER); + } + } + + public List getWinningNumbers() { + return winningNumbers; + } + + public int getBonusNumber() { + return bonusNumber; + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/WinningRank.java b/src/main/java/lotto/domain/WinningRank.java new file mode 100644 index 0000000..fdb7952 --- /dev/null +++ b/src/main/java/lotto/domain/WinningRank.java @@ -0,0 +1,51 @@ +package lotto.domain; + +import java.util.Arrays; +import java.util.EnumMap; +import java.util.Map; + +public enum WinningRank { + LAST_PLACE(0, false, 0), + FIFTH_PLACE(3, false, 5_000), + FOURTH_PLACE(4, false, 50_000), + THIRD_PLACE(5, false, 1_500_000), + SECOND_PLACE(5, true, 30_000_000), + FIRST_PLACE(6, false, 2_000_000_000); + + private static final int INITIAL_VALUE = 0; + private final int matchingCount; + private final boolean containsBonusNumber; + private final int winningPrice; + + WinningRank(int matchingCount, boolean containsBonusNumber, int winningPrice) { + this.matchingCount = matchingCount; + this.containsBonusNumber = containsBonusNumber; + this.winningPrice = winningPrice; + } + + public static WinningRank findWinningRank(int matchingCount, boolean containsBonusNumber) { + return Arrays.stream(values()) + .filter(winningRank -> winningRank.matchingCount == matchingCount) + .filter(winningRank -> winningRank.containsBonusNumber == containsBonusNumber) + .findFirst() + .orElse(WinningRank.LAST_PLACE); + } + + public static Map generateWinningDetails() { + Map winningDetails = new EnumMap<>(WinningRank.class); + Arrays.stream(values()).forEach(winningRank -> winningDetails.put(winningRank, INITIAL_VALUE)); + return winningDetails; + } + + public int getMatchingCount() { + return matchingCount; + } + + public boolean getContainsBonusNumber() { + return containsBonusNumber; + } + + public int getWinningPrice() { + return winningPrice; + } +} \ No newline at end of file diff --git a/src/main/java/lotto/view/InputView.java b/src/main/java/lotto/view/InputView.java new file mode 100644 index 0000000..9f191ca --- /dev/null +++ b/src/main/java/lotto/view/InputView.java @@ -0,0 +1,43 @@ +package lotto.view; + +import org.kokodak.Console; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class InputView { + private static final String PURCHASE_AMOUNT_MESSAGE = "구입금액을 입력해 주세요."; + private static final String LOTTO_NUMBER_MESSAGE = "당첨 번호를 입력해 주세요."; + private static final String LOTTO_BONUS_NUMBER_MESSAGE = "보너스 번호를 입력해 주세요."; + private static final String NOT_NUMBER = "[ERROR] 숫자가 아닌 값이 입력됐습니다."; + + public int getPurchaseAmount() { + System.out.println(PURCHASE_AMOUNT_MESSAGE); + try { + return Integer.parseInt(Console.readLine()); + } catch (NumberFormatException numberFormatException) { + throw new IllegalArgumentException(NOT_NUMBER); + } + } + + public List getLottoNumber() { + System.out.println(LOTTO_NUMBER_MESSAGE); + try { + return Arrays.stream(Console.readLine().split(",")) + .map(Integer::parseInt) + .collect(Collectors.toList()); + } catch (NumberFormatException numberFormatException) { + throw new IllegalArgumentException(NOT_NUMBER); + } + } + + public int getLottoBonusNumber() { + System.out.println(LOTTO_BONUS_NUMBER_MESSAGE); + try { + return Integer.parseInt(Console.readLine()); + } catch (NumberFormatException numberFormatException) { + throw new IllegalArgumentException(NOT_NUMBER); + } + } +} \ No newline at end of file diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java new file mode 100644 index 0000000..4051d8b --- /dev/null +++ b/src/main/java/lotto/view/OutputView.java @@ -0,0 +1,19 @@ +package lotto.view; + +import lotto.domain.Lotto; +import lotto.domain.Lottos; + +public class OutputView { + + private static final String HOW_MANY_LOTTO_USER_PURCHASED_MESSAGE = "개를 구매했습니다."; + + public static void printHowManyLottoUserPurchased(int lottoQuantity) { + System.out.println(lottoQuantity + HOW_MANY_LOTTO_USER_PURCHASED_MESSAGE); + } + + public static void printLottos(Lottos lottos) { + for (Lotto lotto : lottos.getLottos()) { + System.out.println(lotto.toString()); + } + } +} \ No newline at end of file diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/LottoTest.java index 14ed50f..8f9a149 100644 --- a/src/test/java/lotto/LottoTest.java +++ b/src/test/java/lotto/LottoTest.java @@ -3,6 +3,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.List; + +import lotto.domain.Lotto; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From 752234139cb031ea036d2214bf017a0ad6e7abf7 Mon Sep 17 00:00:00 2001 From: rtaeho Date: Sun, 24 Mar 2024 18:55:26 +0900 Subject: [PATCH 3/3] =?UTF-8?q?test=20=EC=A0=9C=EC=99=B8=ED=95=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/Application.java | 4 ++ .../lotto/controller/LottoController.java | 30 +++++++++- src/main/java/lotto/domain/Lotto.java | 16 +++++- .../java/lotto/domain/LottoGenerator.java | 20 +++++-- src/main/java/lotto/domain/WinningLotto.java | 9 ++- src/main/java/lotto/domain/WinningRank.java | 11 ---- ...ingDetails.java => WinningStatistics.java} | 33 ++++++++--- src/main/java/lotto/view/InputView.java | 9 +-- src/main/java/lotto/view/OutputView.java | 56 +++++++++++++++++-- 9 files changed, 150 insertions(+), 38 deletions(-) rename src/main/java/lotto/domain/{WinningDetails.java => WinningStatistics.java} (56%) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index d190922..a0862b0 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,7 +1,11 @@ package lotto; +import lotto.controller.LottoController; + public class Application { public static void main(String[] args) { // TODO: 프로그램 구현 + LottoController lottoController = new LottoController(); + lottoController.lottoStart(); } } diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java index 03a611e..93bdddf 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -1,8 +1,36 @@ package lotto.controller; +import lotto.domain.*; +import lotto.view.InputView; +import lotto.view.OutputView; + +import java.util.Map; + public class LottoController { public void lottoStart() { + try { + int purchaseAmount = InputView.getPurchaseAmount(); + LottoGenerator lottoGenerator = new LottoGenerator(purchaseAmount); + Lottos lottos = new Lottos(lottoGenerator.generateLottos()); + printLottosInformation(lottoGenerator, lottos); + WinningLotto winningLotto = new WinningLotto(InputView.getLottoNumber(), InputView.getLottoBonusNumber()); + Map winningDetails = WinningStatistics.getWinningDetails(lottos, winningLotto); + printWinningInformation(winningDetails, purchaseAmount); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + + private void printLottosInformation(LottoGenerator lottoGenerator, Lottos lottos) { + OutputView.printHowManyLottoUserPurchased(lottoGenerator.getLottoQuantity()); + OutputView.printLottos(lottos); + } + private void printWinningInformation(Map winningDetails, int purchaseAmount) { + OutputView.printWinningStatistics(); + OutputView.printWinningDetails(winningDetails); + long winningAmount = WinningStatistics.getWinningAmount(winningDetails); + OutputView.printLottoYield(WinningStatistics.getLottoYield(winningAmount, purchaseAmount)); } -} \ No newline at end of file +} diff --git a/src/main/java/lotto/domain/Lotto.java b/src/main/java/lotto/domain/Lotto.java index 1356b09..f1f9a25 100644 --- a/src/main/java/lotto/domain/Lotto.java +++ b/src/main/java/lotto/domain/Lotto.java @@ -1,6 +1,8 @@ package lotto.domain; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class Lotto { private final List numbers; @@ -9,14 +11,24 @@ public Lotto(List numbers) { validate(numbers); this.numbers = numbers; } + // TODO: 추가 기능 구현 private void validate(List numbers) { - if (numbers.size() != 6) { + if (!isSizeSix(numbers) || isDuplicate(numbers)) { throw new IllegalArgumentException(); } } + + private boolean isSizeSix(List numbers) { + return numbers.size() == 6; + } + + private boolean isDuplicate(List numbers) { + Set duplicateChecker = new HashSet<>(numbers); + return duplicateChecker.size() != 6; + } + public List getNumbers() { return numbers; } - // TODO: 추가 기능 구현 } diff --git a/src/main/java/lotto/domain/LottoGenerator.java b/src/main/java/lotto/domain/LottoGenerator.java index 1a453dc..fb842d0 100644 --- a/src/main/java/lotto/domain/LottoGenerator.java +++ b/src/main/java/lotto/domain/LottoGenerator.java @@ -11,10 +11,11 @@ public class LottoGenerator { private static final int LOTTO_NUMBER_LOWER_LIMIT = 1; private static final int LOTTO_NUMBER_UPPER_LIMIT = 45; private static final int LOTTO_NUMBER_QUANTITY = 6; - private static final String MONEY_SHOULD_BE_DIVIDED_BY_ONE_THOUSAND = "[ERROR] 구입금액은 1,000원으로 나누어 떨어져야 합니다."; + private static final int ZERO = 0; + private static final String MONEY_SHOULD_BE_DIVIDED_BY_ONE_THOUSAND = "[ERROR] 구입 금액은 1,000원 단위로만 받을 수 있습니다."; // static 변수로 생성 - private List lottos = new ArrayList<>(); - private int lottoQuantity; + private final List lottos = new ArrayList<>(); + private final int lottoQuantity; public LottoGenerator(int money) { validateMoney(money); @@ -22,11 +23,19 @@ public LottoGenerator(int money) { } private void validateMoney(int money) { - if (money % 1000 != 0) { + if (money % LOTTO_PRICE != ZERO) { throw new IllegalArgumentException(MONEY_SHOULD_BE_DIVIDED_BY_ONE_THOUSAND); } } + private boolean isZeroOrNegativeNumber(int money) { + return money <= ZERO; + } + + private boolean isDividedByOneThousand(int money) { + return money % LOTTO_PRICE == ZERO; + } + public List generateLottos() { // 로또들을 담을 객체 반환 for (int i = 0; i < lottoQuantity; i++) { Lotto lotto = generateLotto(); @@ -42,4 +51,7 @@ private Lotto generateLotto() { return new Lotto(randomNumbers); // 생성한 로또 반환 } + public int getLottoQuantity() { + return lottoQuantity; + } } diff --git a/src/main/java/lotto/domain/WinningLotto.java b/src/main/java/lotto/domain/WinningLotto.java index 3bd955d..3ab2ea1 100644 --- a/src/main/java/lotto/domain/WinningLotto.java +++ b/src/main/java/lotto/domain/WinningLotto.java @@ -9,6 +9,9 @@ public class WinningLotto { private static final String WINNING_NUMBERS_MUST_BE_SIX_DIFFERENT_NUMBERS = "[ERROR] 당첨 번호는 서로 다른 6개의 수여야 합니다."; private static final String BONUS_NUMBER_IS_BETWEEN_ONE_AND_FORTY_FIVE = "[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다."; private static final String WINNING_NUMBERS_CONTAIN_BONUS_NUMBER = "[ERROR] 당첨 번호와 보너스 번호가 중복됩니다."; + private static final int LOTTO_NUMBER_LOWER_LIMIT = 1; + private static final int LOTTO_NUMBER_UPPER_LIMIT = 45; + private static final int LOTTO_NUMBERS_SIZE = 6; private final List winningNumbers; private final int bonusNumber; @@ -32,7 +35,7 @@ private void validateWinningNumbers(List winningNumbers) { private boolean isBetweenOneAndFortyFive(List winningNumbers) { for (int winningNumber : winningNumbers) { - if (winningNumber < 1 || winningNumber > 45) { + if (winningNumber < LOTTO_NUMBER_LOWER_LIMIT || winningNumber > LOTTO_NUMBER_UPPER_LIMIT) { return false; } } @@ -41,7 +44,7 @@ private boolean isBetweenOneAndFortyFive(List winningNumbers) { private boolean isSixDifferentNumbers(List winningNumbers) { Set duplicateChecker = new HashSet<>(winningNumbers); - return duplicateChecker.size() == 6; + return duplicateChecker.size() == LOTTO_NUMBERS_SIZE; } private void validateBonusNumber(int bonusNumber) { @@ -51,7 +54,7 @@ private void validateBonusNumber(int bonusNumber) { } private boolean isBetweenOneAndFortyFive(int bonusNumber) { - return bonusNumber >= 1 && bonusNumber <= 45; + return bonusNumber >= LOTTO_NUMBER_LOWER_LIMIT && bonusNumber <= LOTTO_NUMBER_UPPER_LIMIT; } private void validateDuplicate(List winningNumbers, int bonusNumber) { diff --git a/src/main/java/lotto/domain/WinningRank.java b/src/main/java/lotto/domain/WinningRank.java index fdb7952..2e49034 100644 --- a/src/main/java/lotto/domain/WinningRank.java +++ b/src/main/java/lotto/domain/WinningRank.java @@ -12,7 +12,6 @@ public enum WinningRank { SECOND_PLACE(5, true, 30_000_000), FIRST_PLACE(6, false, 2_000_000_000); - private static final int INITIAL_VALUE = 0; private final int matchingCount; private final boolean containsBonusNumber; private final int winningPrice; @@ -31,20 +30,10 @@ public static WinningRank findWinningRank(int matchingCount, boolean containsBon .orElse(WinningRank.LAST_PLACE); } - public static Map generateWinningDetails() { - Map winningDetails = new EnumMap<>(WinningRank.class); - Arrays.stream(values()).forEach(winningRank -> winningDetails.put(winningRank, INITIAL_VALUE)); - return winningDetails; - } - public int getMatchingCount() { return matchingCount; } - public boolean getContainsBonusNumber() { - return containsBonusNumber; - } - public int getWinningPrice() { return winningPrice; } diff --git a/src/main/java/lotto/domain/WinningDetails.java b/src/main/java/lotto/domain/WinningStatistics.java similarity index 56% rename from src/main/java/lotto/domain/WinningDetails.java rename to src/main/java/lotto/domain/WinningStatistics.java index 817beca..746e651 100644 --- a/src/main/java/lotto/domain/WinningDetails.java +++ b/src/main/java/lotto/domain/WinningStatistics.java @@ -1,11 +1,17 @@ package lotto.domain; +import java.util.Arrays; +import java.util.EnumMap; import java.util.List; import java.util.Map; -public class WinningDetails { +public class WinningStatistics { + private static final int AT_LEAST_THIRD_PLACE = 5; + private static final int PERCENTAGE = 100; + private static final int INITIAL_VALUE = 0; + public static Map getWinningDetails(Lottos lottos, WinningLotto winningLotto) { - Map winningDetails = WinningRank.generateWinningDetails(); + Map winningDetails = generateWinningDetails(); for (Lotto lotto : lottos.getLottos()) { int matchingCount = compareNumbersWithWinningNumbers(lotto, winningLotto); boolean containsBonusNumber = compareNumbersWithBonusNumber(lotto, winningLotto, matchingCount); @@ -15,6 +21,12 @@ public static Map getWinningDetails(Lottos lottos, Winning return winningDetails; } + public static Map generateWinningDetails() { + Map winningDetails = new EnumMap<>(WinningRank.class); + Arrays.stream(WinningRank.values()).forEach(winningRank -> winningDetails.put(winningRank, INITIAL_VALUE)); + return winningDetails; + } + private static int compareNumbersWithWinningNumbers(Lotto lotto, WinningLotto winningLotto) { List numbers = lotto.getNumbers(); List winningNumbers = winningLotto.getWinningNumbers(); @@ -24,18 +36,23 @@ private static int compareNumbersWithWinningNumbers(Lotto lotto, WinningLotto wi } private static boolean compareNumbersWithBonusNumber(Lotto lotto, WinningLotto winningLotto, int matchingCount) { - if (matchingCount != 5) return false; + if (matchingCount != AT_LEAST_THIRD_PLACE) { + return false; + } List numbers = lotto.getNumbers(); int bonusNumber = winningLotto.getBonusNumber(); return numbers.contains(bonusNumber); } - public static double getLottoYield(Map winningDetails, int money) { - long winningAmount = winningDetails.entrySet().stream() - .filter(entry -> entry.getValue() != 0) + public static long getWinningAmount(Map winningDetails) { + return winningDetails.entrySet().stream() .mapToLong(entry -> (long) entry.getKey().getWinningPrice() * entry.getValue()) .sum(); - double lottoYield = 100 + (winningAmount - money) / money * 100; - return Math.round(lottoYield * 100) / 100.0; } + + public static double getLottoYield(long winningAmount, int money) { + double lottoYield = PERCENTAGE + (double) (winningAmount - money) / money * PERCENTAGE; + return Math.round(lottoYield * 10) / 10.0; + } + } diff --git a/src/main/java/lotto/view/InputView.java b/src/main/java/lotto/view/InputView.java index 9f191ca..329e2fa 100644 --- a/src/main/java/lotto/view/InputView.java +++ b/src/main/java/lotto/view/InputView.java @@ -11,8 +11,9 @@ public class InputView { private static final String LOTTO_NUMBER_MESSAGE = "당첨 번호를 입력해 주세요."; private static final String LOTTO_BONUS_NUMBER_MESSAGE = "보너스 번호를 입력해 주세요."; private static final String NOT_NUMBER = "[ERROR] 숫자가 아닌 값이 입력됐습니다."; + private static final String SEPARATOR_VALUE = ","; - public int getPurchaseAmount() { + public static int getPurchaseAmount() { System.out.println(PURCHASE_AMOUNT_MESSAGE); try { return Integer.parseInt(Console.readLine()); @@ -21,10 +22,10 @@ public int getPurchaseAmount() { } } - public List getLottoNumber() { + public static List getLottoNumber() { System.out.println(LOTTO_NUMBER_MESSAGE); try { - return Arrays.stream(Console.readLine().split(",")) + return Arrays.stream(Console.readLine().split(SEPARATOR_VALUE)) .map(Integer::parseInt) .collect(Collectors.toList()); } catch (NumberFormatException numberFormatException) { @@ -32,7 +33,7 @@ public List getLottoNumber() { } } - public int getLottoBonusNumber() { + public static int getLottoBonusNumber() { System.out.println(LOTTO_BONUS_NUMBER_MESSAGE); try { return Integer.parseInt(Console.readLine()); diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java index 4051d8b..1651d1e 100644 --- a/src/main/java/lotto/view/OutputView.java +++ b/src/main/java/lotto/view/OutputView.java @@ -2,18 +2,64 @@ import lotto.domain.Lotto; import lotto.domain.Lottos; +import lotto.domain.WinningRank; + +import java.text.DecimalFormat; +import java.util.Map; public class OutputView { - private static final String HOW_MANY_LOTTO_USER_PURCHASED_MESSAGE = "개를 구매했습니다."; + private static final String HOW_MANY_LOTTO_USER_PURCHASED_MESSAGE = "%d개를 구매했습니다.\n"; + private static final String WINNING_STATISTICS_MESSAGE = "당첨 통계\n---"; + private static final String WINNING_DETAILS_MESSAGE = "%d개 일치 (%s원) - %d개\n"; + private static final String WINNING_DETAILS_WITH_BONUS_MESSAGE = "%d개 일치, 보너스 볼 일치 (%s원) - %d개\n"; + private static final String LOTTO_YIELD_MESSAGE = "총 수익률은 %.1f%%입니다.\n"; + private static final String SEPARATOR_PATTERN = "###,###"; public static void printHowManyLottoUserPurchased(int lottoQuantity) { - System.out.println(lottoQuantity + HOW_MANY_LOTTO_USER_PURCHASED_MESSAGE); + System.out.printf(HOW_MANY_LOTTO_USER_PURCHASED_MESSAGE, lottoQuantity); } public static void printLottos(Lottos lottos) { - for (Lotto lotto : lottos.getLottos()) { - System.out.println(lotto.toString()); - } + lottos.getLottos().stream() + .forEach(lotto -> System.out.println(lotto.getNumbers().toString())); + } + + public static void printWinningStatistics() { + System.out.println(WINNING_STATISTICS_MESSAGE); + } + + public static void printWinningDetails(Map winningDetails) { + winningDetails.entrySet().stream() + .filter(entry -> entry.getKey() != WinningRank.LAST_PLACE) + .forEach(entry -> { + if (entry.getKey() == WinningRank.SECOND_PLACE) { + printWinningDetailsWithBonus(entry); + } + printWinningDetailsWithoutBonus(entry); + }); + } + + private static void printWinningDetailsWithBonus(Map.Entry entry) { + System.out.printf(WINNING_DETAILS_WITH_BONUS_MESSAGE, + entry.getKey().getMatchingCount(), + getFormattingPrice(entry.getKey().getWinningPrice()), + entry.getValue()); + } + + private static void printWinningDetailsWithoutBonus(Map.Entry entry) { + System.out.printf(WINNING_DETAILS_MESSAGE, + entry.getKey().getMatchingCount(), + getFormattingPrice(entry.getKey().getWinningPrice()), + entry.getValue()); + } + + private static String getFormattingPrice(int winningPrice) { + DecimalFormat df = new DecimalFormat(SEPARATOR_PATTERN); + return df.format(winningPrice); + } + + public static void printLottoYield(double lottoYield) { + System.out.printf(LOTTO_YIELD_MESSAGE, lottoYield); } } \ No newline at end of file