From 471fb2fe7d803cbf53910bf8d02a0037d7617e62 Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 16:31:34 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/controller/LottoController.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/main/java/lotto/controller/LottoController.java diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java new file mode 100644 index 0000000000..92ab476bf7 --- /dev/null +++ b/src/main/java/lotto/controller/LottoController.java @@ -0,0 +1,4 @@ +package lotto.controller; + +public class LottoController { +} From 0e872d2b2c369732eb5369985c7d1d84486d96ff Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 16:33:57 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20Budget=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/domain/Budget.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/lotto/domain/Budget.java diff --git a/src/main/java/lotto/domain/Budget.java b/src/main/java/lotto/domain/Budget.java new file mode 100644 index 0000000000..20da24eb1f --- /dev/null +++ b/src/main/java/lotto/domain/Budget.java @@ -0,0 +1,19 @@ +package lotto.domain; + +public class Budget { + private static final String NUMBER_FORMAT_EXCEPTION_MESSAGE = "[ERROR] 구입 금액은 숫자만 입력할 수 있습니다."; + private static final String DIVIDE_EXCEPTION_MESSAGE = "[ERROR] 구입 금액은 %d원 단위로 나누어 떨어져야합니다."; + private static final String MINIMUM_PRICE_EXCEPTION_MESSAGE = "[ERROR] 로또 구입 최소 금액은 %d원 입니다."; + private static final int LOTTO_UNIT_PRICE = 1000; + private static final int ZERO = 0; + private final int budget; + + private Budget(final int budget) { + this.budget = budget; + } + + public static Budget from(final String inputBudget) { + int budget = Integer.parseInt(inputBudget); + return new Budget(budget); + } +} From a3cebbed525305242b38e557038415c5cbce6bd2 Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 16:37:13 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20Budget=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/domain/Budget.java | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/lotto/domain/Budget.java b/src/main/java/lotto/domain/Budget.java index 20da24eb1f..cb7c083cd9 100644 --- a/src/main/java/lotto/domain/Budget.java +++ b/src/main/java/lotto/domain/Budget.java @@ -13,7 +13,36 @@ private Budget(final int budget) { } public static Budget from(final String inputBudget) { + validateNumeric(inputBudget); int budget = Integer.parseInt(inputBudget); return new Budget(budget); } + + private static void validateNumeric(final String inputBudget) { + try { + Integer.parseInt(inputBudget); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(NUMBER_FORMAT_EXCEPTION_MESSAGE, e); + } + } + + private static void validateDivideResultIsZero(final int inputBudget) { + if(inputBudget % LOTTO_UNIT_PRICE != ZERO) { + throw new IllegalArgumentException(String.format(DIVIDE_EXCEPTION_MESSAGE, LOTTO_UNIT_PRICE)); + } + } + + private static void validateLowerPrice(final int inputBudget) { + if(inputBudget < LOTTO_UNIT_PRICE) { + throw new IllegalArgumentException(String.format(MINIMUM_PRICE_EXCEPTION_MESSAGE, LOTTO_UNIT_PRICE)); + } + } + + public int getCountOfLottoLines() { + return budget / LOTTO_UNIT_PRICE; + } + + public int getBudget() { + return budget; + } } From 819e234b2f93309e39d7143cc222519d10ced773 Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 16:39:43 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=9D=BC?= =?UTF-8?q?=EA=B8=89=20=EC=BB=AC=EB=A0=89=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/Lotto.java | 42 +++++++++++++++++-- .../lotto/controller/LottoController.java | 16 +++++++ src/main/java/lotto/domain/Lottos.java | 21 ++++++++++ 3 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/main/java/lotto/domain/Lottos.java diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java index 519793d1f7..6c561d5260 100644 --- a/src/main/java/lotto/Lotto.java +++ b/src/main/java/lotto/Lotto.java @@ -1,20 +1,56 @@ package lotto; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; public class Lotto { private final List numbers; + private static final String SPLIT_CHAR = ", "; + private static final int LOTTO_SIZE = 6; + private static final int MAX_NUMBER = 45; + private static final int MIN_NUMBER = 1; + private static final String OUT_OF_RANGE_EXCEPTION_MESSAGE = "[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."; + private static final String DUPLICATION_EXCEPTION_MESSAGE = "[ERROR] 로또 번호는 중복없이 6개의 번호들로 구성되어야 합니다."; + private static final String LOTTO_SIZE_EXCEPTION_MESSAGE = "[ERROR] 로또는 6개의 숫자로 구성되어야 합니다."; public Lotto(List numbers) { validate(numbers); + validateRange(numbers); + validateDuplication(numbers); this.numbers = numbers; } private void validate(List numbers) { - if (numbers.size() != 6) { - throw new IllegalArgumentException(); + if (numbers.size() != LOTTO_SIZE) { + throw new IllegalArgumentException(LOTTO_SIZE_EXCEPTION_MESSAGE); } } - // TODO: 추가 기능 구현 + private void validateRange(List numbers) { + if (numbers.stream().anyMatch(number -> number < MIN_NUMBER || number > MAX_NUMBER)) { + throw new IllegalArgumentException(OUT_OF_RANGE_EXCEPTION_MESSAGE); + } + } + + private void validateDuplication(List numbers) { + if (numbers.stream().distinct().count() != numbers.size()) { + throw new IllegalArgumentException(DUPLICATION_EXCEPTION_MESSAGE); + } + } + + @Override + public String toString() { + return numbers.stream() + .sorted().map(Objects::toString) + .collect(Collectors.joining(SPLIT_CHAR)); + } + + public boolean isContain(int bonusNumber) { + return numbers.contains(bonusNumber); + } + + public List getNumbers() { + return numbers; + } } diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java index 92ab476bf7..3a0018afa7 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -1,4 +1,20 @@ package lotto.controller; +import lotto.domain.Budget; + public class LottoController { + private Budget budget; + + public void runMachine() { + buyLotto(); + } + + private void buyLotto() { + try { + + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + return buyLotto(); + } + } } diff --git a/src/main/java/lotto/domain/Lottos.java b/src/main/java/lotto/domain/Lottos.java new file mode 100644 index 0000000000..a5fcea2e33 --- /dev/null +++ b/src/main/java/lotto/domain/Lottos.java @@ -0,0 +1,21 @@ +package lotto.domain; + +import lotto.Lotto; + +import java.util.List; + +public class Lottos { + private final List lottos; + + private Lottos(final List lottos) { + this.lottos = lottos; + } + + public static Lottos from(List lottos) { + return new Lottos(lottos); + } + + public List getLottos() { + return lottos; + } +} From 010e7527cf13443847a9a546c57a5ed3318f2cbb Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 16:57:33 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=A0=84=EB=9E=B5=ED=8C=A8=ED=84=B4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/InputView.java | 14 +++++++ .../lotto/controller/LottoController.java | 17 ++++++-- .../strategy/LottoGenerateStrategy.java | 10 +++++ .../lotto/domain/strategy/LottoGenerator.java | 29 ++++++++++++++ .../strategy/UserLottoGenerateStrategy.java | 11 +++++ .../WinningLottoGenerateStrategy.java | 12 ++++++ src/main/java/lotto/util/LottoParser.java | 40 +++++++++++++++++++ 7 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 src/main/java/lotto/InputView.java create mode 100644 src/main/java/lotto/domain/strategy/LottoGenerateStrategy.java create mode 100644 src/main/java/lotto/domain/strategy/LottoGenerator.java create mode 100644 src/main/java/lotto/domain/strategy/UserLottoGenerateStrategy.java create mode 100644 src/main/java/lotto/domain/strategy/WinningLottoGenerateStrategy.java create mode 100644 src/main/java/lotto/util/LottoParser.java diff --git a/src/main/java/lotto/InputView.java b/src/main/java/lotto/InputView.java new file mode 100644 index 0000000000..112356c8d7 --- /dev/null +++ b/src/main/java/lotto/InputView.java @@ -0,0 +1,14 @@ +package lotto; + +import camp.nextstep.edu.missionutils.Console; + +public class InputView { + private static final String REQUIRE_BUDGET_MESSAGE = "구입금액을 입력해 주세요."; + private static final String REQUIRE_BONUS_MESSAGE = "\n보너스 번호를 입력해 주세요."; + private static final String REQUIRE_WINNING_NUMBERS_MESSAGE = "\n당첨 번호를 입력해 주세요."; + + public static String getBudgetInput() { + System.out.println(REQUIRE_BUDGET_MESSAGE); + return Console.readLine(); + } +} diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java index 3a0018afa7..347b2e4f15 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -1,20 +1,31 @@ package lotto.controller; +import lotto.InputView; import lotto.domain.Budget; +import lotto.domain.Lottos; +import lotto.domain.strategy.LottoGenerateStrategy; +import lotto.domain.strategy.LottoGenerator; +import lotto.domain.strategy.UserLottoGenerateStrategy; public class LottoController { private Budget budget; + private LottoGenerator lottoGenerator = new LottoGenerator(); public void runMachine() { - buyLotto(); + final Lottos userLottos = buyLotto(); } - private void buyLotto() { + private Lottos buyLotto() { try { - + budget = Budget.from(InputView.getBudgetInput()); + setLottoGeneratorStrategy(new UserLottoGenerateStrategy()); } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); return buyLotto(); } } + + public void setLottoGeneratorStrategy(LottoGenerateStrategy lottoGenerateStrategy) { + this.lottoGenerator.setLottoGenerateStrategy(lottoGenerateStrategy); + } } diff --git a/src/main/java/lotto/domain/strategy/LottoGenerateStrategy.java b/src/main/java/lotto/domain/strategy/LottoGenerateStrategy.java new file mode 100644 index 0000000000..a23d189f7d --- /dev/null +++ b/src/main/java/lotto/domain/strategy/LottoGenerateStrategy.java @@ -0,0 +1,10 @@ +package lotto.domain.strategy; + +import lotto.Lotto; + +public interface LottoGenerateStrategy { + int MIN_NUMBER = 1; + int MAX_NUMBER = 45; + int SIZE = 6; + Lotto generate(); +} diff --git a/src/main/java/lotto/domain/strategy/LottoGenerator.java b/src/main/java/lotto/domain/strategy/LottoGenerator.java new file mode 100644 index 0000000000..daa843feee --- /dev/null +++ b/src/main/java/lotto/domain/strategy/LottoGenerator.java @@ -0,0 +1,29 @@ +package lotto.domain.strategy; + +import lotto.Lotto; +import lotto.domain.Budget; +import lotto.domain.Lottos; + +import java.util.ArrayList; +import java.util.List; + +public class LottoGenerator { + private LottoGenerateStrategy lottoGenerateStrategy; + + public Lotto generateLotto() { + return lottoGenerateStrategy.generate(); + } + + public Lottos generateLottosByBudget(Budget budget) { + final int countOfLottoLine = budget.getCountOfLottoLines(); + final List lottos = new ArrayList<>(); + for (int i = 0; i < countOfLottoLine; i++) { + lottos.add(generateLotto()); + } + return Lottos.from(lottos); + } + + public void setLottoGenerateStrategy(LottoGenerateStrategy lottoGenerateStrategy) { + this.lottoGenerateStrategy = lottoGenerateStrategy; + } +} diff --git a/src/main/java/lotto/domain/strategy/UserLottoGenerateStrategy.java b/src/main/java/lotto/domain/strategy/UserLottoGenerateStrategy.java new file mode 100644 index 0000000000..769400a4e5 --- /dev/null +++ b/src/main/java/lotto/domain/strategy/UserLottoGenerateStrategy.java @@ -0,0 +1,11 @@ +package lotto.domain.strategy; + +import camp.nextstep.edu.missionutils.Randoms; +import lotto.Lotto; + +public class UserLottoGenerateStrategy implements LottoGenerateStrategy { + @Override + public Lotto generate() { + return new Lotto(Randoms.pickUniqueNumbersInRange(MIN_NUMBER, MAX_NUMBER, SIZE)); + } +} diff --git a/src/main/java/lotto/domain/strategy/WinningLottoGenerateStrategy.java b/src/main/java/lotto/domain/strategy/WinningLottoGenerateStrategy.java new file mode 100644 index 0000000000..837659b577 --- /dev/null +++ b/src/main/java/lotto/domain/strategy/WinningLottoGenerateStrategy.java @@ -0,0 +1,12 @@ +package lotto.domain.strategy; + +import camp.nextstep.edu.missionutils.Console; +import lotto.Lotto; +import lotto.util.LottoParser; + +public class WinningLottoGenerateStrategy implements LottoGenerateStrategy { + @Override + public Lotto generate() { + return new Lotto(LottoParser.parseWinningInputs(Console.readLine())); + } +} diff --git a/src/main/java/lotto/util/LottoParser.java b/src/main/java/lotto/util/LottoParser.java new file mode 100644 index 0000000000..ebed5d23c2 --- /dev/null +++ b/src/main/java/lotto/util/LottoParser.java @@ -0,0 +1,40 @@ +package lotto.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LottoParser { + private static final String SPLIT_CHAR = ","; + private static final int LOTTO_MIN_NUMBER = 1; + private static final int LOTTO_MAX_NUMBER = 45; + private static final String LOTTO_PARSE_ERROR_MESSAGE = "[ERROR] 로또 번호는 숫자만 입력할 수 있습니다."; + private static final String LOTTO_RANGE_ERROR_MESSAGE = "[ERROR] 로또 번호는 %d부터 %d까지의 수만 입력할 수 있습니다."; + + public static List parseWinningInputs(String input) { + List lottoNumbers = new ArrayList<>(); + Arrays.stream(input.split(SPLIT_CHAR)).forEach(digit -> { + int numberConvert = covertDigitToNumber(digit); + validateNumberRange(numberConvert); + lottoNumbers.add(numberConvert); + }); + return lottoNumbers; + } + + private static int covertDigitToNumber(String digit) { + try { + Integer.parseInt(digit); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(LOTTO_PARSE_ERROR_MESSAGE); + } + return Integer.parseInt(digit); + } + + private static void validateNumberRange(int number) { + if (number < LOTTO_MIN_NUMBER || number > LOTTO_MAX_NUMBER) { + throw new IllegalArgumentException( + String.format(LOTTO_RANGE_ERROR_MESSAGE, LOTTO_MIN_NUMBER, LOTTO_MAX_NUMBER)); + } + } +} + From 378484f74c8d50729c7fe00907c68f47ba73a30d Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 16:58:22 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/controller/LottoController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java index 347b2e4f15..a7b3200647 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -19,6 +19,8 @@ private Lottos buyLotto() { try { budget = Budget.from(InputView.getBudgetInput()); setLottoGeneratorStrategy(new UserLottoGenerateStrategy()); + Lottos userMultipleLottos = lottoGenerator.generateLottosByBudget(budget); + return userMultipleLottos; } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); return buyLotto(); From 28d7dc1668592e25b2d3c10deda7c95501961aa5 Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 17:03:42 +0900 Subject: [PATCH 07/11] t --- src/main/java/lotto/InputView.java | 9 +++++ .../lotto/controller/LottoController.java | 36 ++++++++++++++++++ src/main/java/lotto/domain/Bonus.java | 38 +++++++++++++++++++ src/main/java/lotto/domain/WinningLotto.java | 33 ++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 src/main/java/lotto/domain/Bonus.java create mode 100644 src/main/java/lotto/domain/WinningLotto.java diff --git a/src/main/java/lotto/InputView.java b/src/main/java/lotto/InputView.java index 112356c8d7..bb03ea8417 100644 --- a/src/main/java/lotto/InputView.java +++ b/src/main/java/lotto/InputView.java @@ -11,4 +11,13 @@ public static String getBudgetInput() { System.out.println(REQUIRE_BUDGET_MESSAGE); return Console.readLine(); } + public static String getBonusInput() { + System.out.println(REQUIRE_BONUS_MESSAGE); + return Console.readLine(); + } + + public static void printRequireWinningNumbersMessage() { + System.out.println(REQUIRE_WINNING_NUMBERS_MESSAGE); + } + } diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java index a7b3200647..634b256877 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -1,11 +1,15 @@ package lotto.controller; import lotto.InputView; +import lotto.Lotto; +import lotto.domain.Bonus; import lotto.domain.Budget; import lotto.domain.Lottos; +import lotto.domain.WinningLotto; import lotto.domain.strategy.LottoGenerateStrategy; import lotto.domain.strategy.LottoGenerator; import lotto.domain.strategy.UserLottoGenerateStrategy; +import lotto.domain.strategy.WinningLottoGenerateStrategy; public class LottoController { private Budget budget; @@ -13,6 +17,7 @@ public class LottoController { public void runMachine() { final Lottos userLottos = buyLotto(); + final WinningLotto winningLotto = drawLotto(); } private Lottos buyLotto() { @@ -27,6 +32,37 @@ private Lottos buyLotto() { } } + private WinningLotto drawLotto() { + try { + final Lotto lotto = getWinningLotto(); + final Bonus bonus = getBonus(); + return WinningLotto.of(lotto, bonus); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + return drawLotto(); + } + } + + private Lotto getWinningLotto() { + try { + InputView.printRequireWinningNumbersMessage(); + setLottoGeneratorStrategy(new WinningLottoGenerateStrategy()); + return lottoGenerator.generateLotto(); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + return getWinningLotto(); + } + } + + private Bonus getBonus(){ + try { + return Bonus.from(InputView.getBonusInput()); + } catch (IllegalArgumentException e){ + System.out.println(e.getMessage()); + return getBonus(); + } + } + public void setLottoGeneratorStrategy(LottoGenerateStrategy lottoGenerateStrategy) { this.lottoGenerator.setLottoGenerateStrategy(lottoGenerateStrategy); } diff --git a/src/main/java/lotto/domain/Bonus.java b/src/main/java/lotto/domain/Bonus.java new file mode 100644 index 0000000000..ed8ae8624e --- /dev/null +++ b/src/main/java/lotto/domain/Bonus.java @@ -0,0 +1,38 @@ +package lotto.domain; + +public class Bonus { + private final int bonus; + private static final String NUMBER_FORMAT_EXCEPTION_MESSAGE = "[ERROR] 보너스 번호는 숫자만 입력할 수 있습니다."; + private static final String NUMBER_PARSE_EXCEPTION_MESSAGE = "[ERROR] 보너스 번호는 1부터 45 사이의 숫자를 입력해야 합니다."; + private static final int MAX_NUMBER = 45; + private static final int MIN_NUMBER = 1; + + private Bonus(int bonus) { + validateOutOfRange(bonus); + this.bonus = bonus; + } + + public static Bonus from(String bonus) { + return new Bonus(convertBonusNumber(bonus)); + } + + private static int convertBonusNumber(String bonusNumber) { + try { + Integer.parseInt(bonusNumber); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(NUMBER_FORMAT_EXCEPTION_MESSAGE); + } + return Integer.parseInt(bonusNumber); + } + + public void validateOutOfRange(int bonus) { + if (bonus < MIN_NUMBER || bonus > MAX_NUMBER) { + throw new IllegalArgumentException(NUMBER_PARSE_EXCEPTION_MESSAGE); + } + } + + public int getBonus() { + return bonus; + } +} + diff --git a/src/main/java/lotto/domain/WinningLotto.java b/src/main/java/lotto/domain/WinningLotto.java new file mode 100644 index 0000000000..7f88a01bf3 --- /dev/null +++ b/src/main/java/lotto/domain/WinningLotto.java @@ -0,0 +1,33 @@ +package lotto.domain; + +import lotto.Lotto; + +public class WinningLotto { + private final Lotto lotto; + private final Bonus bonus; + private static final String BONUS_NUMBER_DUPLICATE_ERROR_MESSAGE = "[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다."; + + private WinningLotto(Lotto lotto, Bonus bonus) { + this.lotto = lotto; + this.bonus = bonus; + } + + public static WinningLotto of(Lotto lotto, Bonus bonus) { + validateBonusNumberDuplicate(lotto, bonus.getBonus()); + return new WinningLotto(lotto, bonus); + } + + private static void validateBonusNumberDuplicate(Lotto lotto, int bonusNumber) { + if (lotto.isContain(bonusNumber)) { + throw new IllegalArgumentException(BONUS_NUMBER_DUPLICATE_ERROR_MESSAGE); + } + } + + public Lotto getLotto() { + return lotto; + } + + public Bonus getBonus() { + return bonus; + } +} From 4e7f620ec2b8d323a12a2ccf1903c134d55852f6 Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 17:07:31 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20=ED=86=B5=EA=B2=8C=20=EB=82=B4?= =?UTF-8?q?=EB=A6=AC=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lotto/controller/LottoController.java | 13 +-- src/main/java/lotto/domain/WinningRank.java | 40 ++++++++++ .../java/lotto/domain/WinningStatistics.java | 80 +++++++++++++++++++ 3 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 src/main/java/lotto/domain/WinningRank.java create mode 100644 src/main/java/lotto/domain/WinningStatistics.java diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java index 634b256877..1447e5b1e3 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -2,10 +2,7 @@ import lotto.InputView; import lotto.Lotto; -import lotto.domain.Bonus; -import lotto.domain.Budget; -import lotto.domain.Lottos; -import lotto.domain.WinningLotto; +import lotto.domain.*; import lotto.domain.strategy.LottoGenerateStrategy; import lotto.domain.strategy.LottoGenerator; import lotto.domain.strategy.UserLottoGenerateStrategy; @@ -18,6 +15,8 @@ public class LottoController { public void runMachine() { final Lottos userLottos = buyLotto(); final WinningLotto winningLotto = drawLotto(); + final WinningStatistics winningStatistics = makeStatistics(userLottos, winningLotto); + OutputView.printWinningStaticstics(winningStatistics); } private Lottos buyLotto() { @@ -63,7 +62,11 @@ private Bonus getBonus(){ } } - public void setLottoGeneratorStrategy(LottoGenerateStrategy lottoGenerateStrategy) { + private WinningStatistics makeStatistics(final Lottos userLottos, final WinningLotto winningLotto) { + return WinningStatistics.of(userLottos, winningLotto, budget); + } + + public void setLottoGeneratorStrategy(final LottoGenerateStrategy lottoGenerateStrategy) { this.lottoGenerator.setLottoGenerateStrategy(lottoGenerateStrategy); } } diff --git a/src/main/java/lotto/domain/WinningRank.java b/src/main/java/lotto/domain/WinningRank.java new file mode 100644 index 0000000000..687843bc04 --- /dev/null +++ b/src/main/java/lotto/domain/WinningRank.java @@ -0,0 +1,40 @@ +package lotto.domain; + +import java.util.Arrays; + +public enum WinningRank { + FIRST(6, false, 2000000000, "6개 일치"), + SECOND(5, true, 30000000, "5개 일치, 보너스 볼 일치"), + THIRD(5, false, 1500000, "5개 일치"), + FOURTH(4, false, 50000, "4개 일치"), + FIFTH(3, false, 5000, "3개 일치"), + NOTHING(0, false, 0, ""); + + private final int match; + private final boolean isBonus; + private final int prize; + private final String message; + + WinningRank(int match, boolean isBonus, int prize, String message) { + this.match = match; + this.isBonus = isBonus; + this.prize = prize; + this.message = message; + } + + public static WinningRank from(int match, boolean isBonus) { + return Arrays.stream(WinningRank.values()) + .filter(rank -> rank.match == match) + .filter(rank -> rank.isBonus == isBonus) + .findAny() + .orElse(NOTHING); + } + + public int getPrize() { + return prize; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/lotto/domain/WinningStatistics.java b/src/main/java/lotto/domain/WinningStatistics.java new file mode 100644 index 0000000000..b52d45c86d --- /dev/null +++ b/src/main/java/lotto/domain/WinningStatistics.java @@ -0,0 +1,80 @@ +package lotto.domain; + +import lotto.Lotto; + +import java.math.BigDecimal; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +public class WinningStatistics { + private Map winningStatistics = new EnumMap<>(WinningRank.class); + private BigDecimal revenueRate = BigDecimal.ZERO; + + private WinningStatistics(Lottos userLottos, WinningLotto winningLotto, Budget budget) { + setWinningStatistics(userLottos, winningLotto); + setRevenueRate(budget); + } + + public static WinningStatistics of(Lottos userLottos, WinningLotto winningLotto, Budget budget) { + return new WinningStatistics(userLottos, winningLotto, budget); + } + + private void setWinningStatistics(Lottos userLottos, WinningLotto winningLotto) { + for (final Lotto userLotto : userLottos.getLottos()) { + final WinningRank winningResult = createWinningRank(userLotto.getNumbers(), winningLotto); + updateWinningStatistics(winningResult); + } + } + + private WinningRank createWinningRank(List userLottoNumbers, WinningLotto winningLotto) { + int matchesCount = getEachMatchesCount(userLottoNumbers, winningLotto.getLotto().getNumbers()); + boolean isBonus = getHasBonus(userLottoNumbers, winningLotto.getBonus()); + return WinningRank.from(matchesCount, isBonus); + } + + private int getEachMatchesCount(List userLottoNumbers, List winNumbers) { + return (int) userLottoNumbers.stream() + .filter(winNumbers::contains).count(); + } + + private void updateWinningStatistics(WinningRank winningRank) { + winningStatistics.put(winningRank, winningStatistics.getOrDefault(winningRank, 0) + 1); + } + + private boolean getHasBonus(List userLottoNumbers, Bonus bonus) { + return userLottoNumbers.contains(bonus.getBonus()); + } + + private void setRevenueRate(Budget budget) { + BigDecimal totalAmounts = getTotalAmounts(); + BigDecimal count = getBudget(budget); + this.revenueRate = calculateRevenueRate(totalAmounts, count); + } + + private BigDecimal getTotalAmounts() { + BigDecimal totalAmounts = BigDecimal.ZERO; + for (Map.Entry winningInfo : winningStatistics.entrySet()) { + BigDecimal amount = BigDecimal.valueOf(winningInfo.getKey().getPrize() * winningInfo.getValue()); + totalAmounts = totalAmounts.add(amount); + } + return totalAmounts; + } + + private BigDecimal getBudget(Budget budget) { + return new BigDecimal(budget.getBudget()); + } + + private BigDecimal calculateRevenueRate(BigDecimal totalAmounts, BigDecimal counts) { + BigDecimal rate = totalAmounts.divide(counts, 3, BigDecimal.ROUND_HALF_EVEN); + return rate.multiply(new BigDecimal("100")); + } + + public Map getWinningStatistics() { + return winningStatistics; + } + + public BigDecimal getRevenueRate() { + return revenueRate; + } +} From b6cb8ef3ba54de361be3d1087e9e5c9f0913bb5a Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 17:10:12 +0900 Subject: [PATCH 09/11] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lotto/controller/LottoController.java | 5 +- src/main/java/lotto/{ => domain}/Lotto.java | 2 +- src/main/java/lotto/domain/Lottos.java | 2 - src/main/java/lotto/domain/WinningLotto.java | 2 - .../java/lotto/domain/WinningStatistics.java | 2 - .../strategy/LottoGenerateStrategy.java | 2 +- .../lotto/domain/strategy/LottoGenerator.java | 2 +- .../strategy/UserLottoGenerateStrategy.java | 2 +- .../WinningLottoGenerateStrategy.java | 2 +- src/main/java/lotto/util/StringFormatter.java | 56 +++++++++++++++++++ src/main/java/lotto/{ => view}/InputView.java | 2 +- src/main/java/lotto/view/OutputView.java | 54 ++++++++++++++++++ src/test/java/lotto/LottoTest.java | 1 + 13 files changed, 120 insertions(+), 14 deletions(-) rename src/main/java/lotto/{ => domain}/Lotto.java (98%) create mode 100644 src/main/java/lotto/util/StringFormatter.java rename src/main/java/lotto/{ => view}/InputView.java (97%) 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 index 1447e5b1e3..46dfbf02df 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -1,12 +1,13 @@ package lotto.controller; -import lotto.InputView; -import lotto.Lotto; +import lotto.view.InputView; +import lotto.domain.Lotto; import lotto.domain.*; import lotto.domain.strategy.LottoGenerateStrategy; import lotto.domain.strategy.LottoGenerator; import lotto.domain.strategy.UserLottoGenerateStrategy; import lotto.domain.strategy.WinningLottoGenerateStrategy; +import lotto.view.OutputView; public class LottoController { private Budget budget; diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/domain/Lotto.java similarity index 98% rename from src/main/java/lotto/Lotto.java rename to src/main/java/lotto/domain/Lotto.java index 6c561d5260..09f44971f6 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; import java.util.Objects; diff --git a/src/main/java/lotto/domain/Lottos.java b/src/main/java/lotto/domain/Lottos.java index a5fcea2e33..426cd7775a 100644 --- a/src/main/java/lotto/domain/Lottos.java +++ b/src/main/java/lotto/domain/Lottos.java @@ -1,7 +1,5 @@ package lotto.domain; -import lotto.Lotto; - import java.util.List; public class Lottos { diff --git a/src/main/java/lotto/domain/WinningLotto.java b/src/main/java/lotto/domain/WinningLotto.java index 7f88a01bf3..f54af6ef96 100644 --- a/src/main/java/lotto/domain/WinningLotto.java +++ b/src/main/java/lotto/domain/WinningLotto.java @@ -1,7 +1,5 @@ package lotto.domain; -import lotto.Lotto; - public class WinningLotto { private final Lotto lotto; private final Bonus bonus; diff --git a/src/main/java/lotto/domain/WinningStatistics.java b/src/main/java/lotto/domain/WinningStatistics.java index b52d45c86d..b0654aa599 100644 --- a/src/main/java/lotto/domain/WinningStatistics.java +++ b/src/main/java/lotto/domain/WinningStatistics.java @@ -1,7 +1,5 @@ package lotto.domain; -import lotto.Lotto; - import java.math.BigDecimal; import java.util.EnumMap; import java.util.List; diff --git a/src/main/java/lotto/domain/strategy/LottoGenerateStrategy.java b/src/main/java/lotto/domain/strategy/LottoGenerateStrategy.java index a23d189f7d..2a0d0810e8 100644 --- a/src/main/java/lotto/domain/strategy/LottoGenerateStrategy.java +++ b/src/main/java/lotto/domain/strategy/LottoGenerateStrategy.java @@ -1,6 +1,6 @@ package lotto.domain.strategy; -import lotto.Lotto; +import lotto.domain.Lotto; public interface LottoGenerateStrategy { int MIN_NUMBER = 1; diff --git a/src/main/java/lotto/domain/strategy/LottoGenerator.java b/src/main/java/lotto/domain/strategy/LottoGenerator.java index daa843feee..8b83177a9f 100644 --- a/src/main/java/lotto/domain/strategy/LottoGenerator.java +++ b/src/main/java/lotto/domain/strategy/LottoGenerator.java @@ -1,6 +1,6 @@ package lotto.domain.strategy; -import lotto.Lotto; +import lotto.domain.Lotto; import lotto.domain.Budget; import lotto.domain.Lottos; diff --git a/src/main/java/lotto/domain/strategy/UserLottoGenerateStrategy.java b/src/main/java/lotto/domain/strategy/UserLottoGenerateStrategy.java index 769400a4e5..e570dde634 100644 --- a/src/main/java/lotto/domain/strategy/UserLottoGenerateStrategy.java +++ b/src/main/java/lotto/domain/strategy/UserLottoGenerateStrategy.java @@ -1,7 +1,7 @@ package lotto.domain.strategy; import camp.nextstep.edu.missionutils.Randoms; -import lotto.Lotto; +import lotto.domain.Lotto; public class UserLottoGenerateStrategy implements LottoGenerateStrategy { @Override diff --git a/src/main/java/lotto/domain/strategy/WinningLottoGenerateStrategy.java b/src/main/java/lotto/domain/strategy/WinningLottoGenerateStrategy.java index 837659b577..45e425ae21 100644 --- a/src/main/java/lotto/domain/strategy/WinningLottoGenerateStrategy.java +++ b/src/main/java/lotto/domain/strategy/WinningLottoGenerateStrategy.java @@ -1,7 +1,7 @@ package lotto.domain.strategy; import camp.nextstep.edu.missionutils.Console; -import lotto.Lotto; +import lotto.domain.Lotto; import lotto.util.LottoParser; public class WinningLottoGenerateStrategy implements LottoGenerateStrategy { diff --git a/src/main/java/lotto/util/StringFormatter.java b/src/main/java/lotto/util/StringFormatter.java new file mode 100644 index 0000000000..e5143055e2 --- /dev/null +++ b/src/main/java/lotto/util/StringFormatter.java @@ -0,0 +1,56 @@ +package lotto.util; + +import lotto.domain.WinningRank; + +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class StringFormatter { + public enum Format { + REWARD_RATE_FORMAT("#,##0.0"), + STATISTICS_RESULT_FORMAT("%s (%,d원) - %d개\n"); + + private final String format; + + Format(String format) { + this.format = format; + } + + public String toString() { + return this.format; + } + } + + public static String mapToWinningStatisticsToString(Map winningStatistics) { + StringBuilder result = new StringBuilder(); + addStatistics(winningStatistics, result); + return result.toString(); + } + + private static void addStatistics(Map winningStatistics, StringBuilder result) { + List winningResults = getBasicWinningResults(); + for (WinningRank winningResult : winningResults) { + result.append( + String.format(Format.STATISTICS_RESULT_FORMAT.toString(), + winningResult.getMessage(), + winningResult.getPrize(), + winningStatistics.getOrDefault(winningResult, 0))); + } + } + + private static List getBasicWinningResults() { + return Arrays.stream(WinningRank.values()) + .filter(rank -> rank != WinningRank.NOTHING) + .sorted(Comparator.naturalOrder()) + .collect(Collectors.toList()); + } + + public static String mapRewardRateToString(BigDecimal rewardDate) { + return new DecimalFormat(Format.REWARD_RATE_FORMAT.format).format(rewardDate); + } +} diff --git a/src/main/java/lotto/InputView.java b/src/main/java/lotto/view/InputView.java similarity index 97% rename from src/main/java/lotto/InputView.java rename to src/main/java/lotto/view/InputView.java index bb03ea8417..fbef7618c3 100644 --- a/src/main/java/lotto/InputView.java +++ b/src/main/java/lotto/view/InputView.java @@ -1,4 +1,4 @@ -package lotto; +package lotto.view; import camp.nextstep.edu.missionutils.Console; diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java new file mode 100644 index 0000000000..fd579b8124 --- /dev/null +++ b/src/main/java/lotto/view/OutputView.java @@ -0,0 +1,54 @@ +package lotto.view; + +import lotto.domain.Budget; +import lotto.domain.Lotto; +import lotto.domain.Lottos; +import lotto.domain.WinningStatistics; +import lotto.util.StringFormatter; + +import java.math.BigDecimal; + +public class OutputView { + private static final String COUNT_OF_USER_LOTTOS_MESSAGE = "\n%d개를 구매했습니다."; + + public static void printUserLottos(Lottos lottos, Budget budget) { + printCountOfUserLottos(budget); + printLottoNumbers(lottos); + } + + private static void printLottoNumbers(Lottos lottos) { + for (Lotto lotto : lottos.getLottos()) { + printEachLottoNumbers(lotto); + } + } + + private static void printEachLottoNumbers(Lotto lotto) { + System.out.println("[" + lotto.toString() + "]"); + } + + private static void printCountOfUserLottos(Budget budget) { + System.out.println(String.format(COUNT_OF_USER_LOTTOS_MESSAGE, budget.getCountOfLottoLines())); + } + + public static void printWinningStaticstics(WinningStatistics winningStatistics) { + printWinningStatisticsHeader(); + String resultStatistics = StringFormatter.mapToWinningStatisticsToString( + winningStatistics.getWinningStatistics()); + printWinningStaticstics(resultStatistics); + printRevenueRate(winningStatistics.getRevenueRate()); + } + + private static void printWinningStatisticsHeader() { + System.out.println("\n당첨 통계"); + System.out.println("---"); + } + + private static void printRevenueRate(BigDecimal revenueRate) { + String rate = StringFormatter.mapRewardRateToString(revenueRate); + System.out.println(String.format("총 수익률은 %s%%입니다.%n", rate)); + } + + public static void printWinningStaticstics(String resultStatistics) { + System.out.println(resultStatistics); + } +} diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/LottoTest.java index 0f3af0f6c4..d2bca39cc0 100644 --- a/src/test/java/lotto/LottoTest.java +++ b/src/test/java/lotto/LottoTest.java @@ -1,5 +1,6 @@ package lotto; +import lotto.domain.Lotto; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From b1f842fe7ffc72faf1f20bb60cb723a75a934a7c Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 17:10:48 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EA=B8=B0=20=EA=B0=80=EB=8F=99:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/Application.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index d190922ba4..7319a3c4ab 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,7 +1,10 @@ package lotto; +import lotto.controller.LottoController; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + final LottoController lottoController = new LottoController(); + lottoController.runMachine(); } } From 83b5f36d14f993ed7acf1db2978c17eb5630fdb1 Mon Sep 17 00:00:00 2001 From: msung99 Date: Tue, 1 Oct 2024 17:11:21 +0900 Subject: [PATCH 11/11] =?UTF-8?q?chore:=20final=20=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/controller/LottoController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java index 46dfbf02df..f1cfccf1c2 100644 --- a/src/main/java/lotto/controller/LottoController.java +++ b/src/main/java/lotto/controller/LottoController.java @@ -10,8 +10,8 @@ import lotto.view.OutputView; public class LottoController { + private final LottoGenerator lottoGenerator = new LottoGenerator(); private Budget budget; - private LottoGenerator lottoGenerator = new LottoGenerator(); public void runMachine() { final Lottos userLottos = buyLotto();