diff --git a/.gitignore b/.gitignore index 573e847..09f21d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/ .gradle/ build/ +out \ No newline at end of file diff --git a/README.md b/README.md index 7c9722c..6e5ab37 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,60 @@ 총 수익률은 0.35입니다.(기준이 1이기 때문에 결과적으로 손해라는 의미임) ``` +# 🚀 로또 2단계 - 수동 구매 + +## 기능 요구사항 +- 현재 로또 생성기는 자동 생성 기능만 제공한다. 사용자가 수동으로 추첨 번호를 입력할 수 있도록 해야 한다. +- 입력한 금액, 자동 생성 숫자, 수동 생성 번호를 입력하도록 해야 한다. + +## 프로그래밍 요구사항 +- 예외가 발생하는 부분에 대해 자바 Exception을 적용해 예외처리한다. +- 사용자가 입력한 값에 대한 예외 처리를 철저히 한다. + +### 실행 결과 +``` +구입금액을 입력해 주세요. +14000 + +수동으로 구매할 로또 수를 입력해 주세요. +3 + +수동으로 구매할 번호를 입력해 주세요. +8, 21, 23, 41, 42, 43 +3, 5, 11, 16, 32, 38 +7, 11, 16, 35, 36, 44 + +수동으로 3장, 자동으로 11개를 구매했습니다. +[8, 21, 23, 41, 42, 43] +[3, 5, 11, 16, 32, 38] +[7, 11, 16, 35, 36, 44] +[1, 8, 11, 31, 41, 42] +[13, 14, 16, 38, 42, 45] +[7, 11, 30, 40, 42, 43] +[2, 13, 22, 32, 38, 45] +[23, 25, 33, 36, 39, 41] +[1, 3, 5, 14, 22, 45] +[5, 9, 38, 41, 43, 44] +[2, 8, 9, 18, 19, 21] +[13, 14, 18, 21, 23, 35] +[17, 21, 29, 37, 42, 45] +[3, 8, 27, 30, 35, 44] + +지난 주 당첨 번호를 입력해 주세요. +1, 2, 3, 4, 5, 6 +보너스 볼을 입력해 주세요. +7 + +당첨 통계 +--------- +3개 일치 (5000원)- 1개 +4개 일치 (50000원)- 0개 +5개 일치 (1500000원)- 0개 +5개 일치, 보너스 볼 일치(30000000원) - 0개 +6개 일치 (2000000000원)- 0개 +총 수익률은 0.35입니다.(기준이 1이기 때문에 결과적으로 손해라는 의미임) +``` + ## 프로그래밍 요구사항 - indent(인덴트, 들여쓰기) depth를 2단계에서 1단계로 줄여라. - depth의 경우 if문을 사용하는 경우 1단계의 depth가 증가한다. if문 안에 while문을 사용한다면 depth가 2단계가 된다. @@ -54,3 +108,26 @@ - 로또 자동 생성은 Collections.shuffle() 메소드 활용한다. - Collections.sort() 메소드를 활용해 정렬 가능하다. - ArrayList의 contains() 메소드를 활용하면 어떤 값이 존재하는지 유무를 판단할 수 있다. + +## 구현 할 기능 +- [X] 구입 금액을 입력 받는다. +- [X] 수동으로 구매할 수를 입력 받는다. +- [X] 수동으로 구매할 번호를 입력 받는다. +- [X] 구입 금액에 따라 수동, 자동으로 각각 몇개씩 구매 했는지 알려준다. +- [X] 1 - 45 사이의 랜덤한 6개의 숫자 리스트를 구입 개수만큼 만들어 준다. +- [X] 지난 주 당첨 번호를 입력 받는다. +- [X] 보너스 볼을 입력 받는다. +- [X] 일치 여부를 확인 후 당첨 통계를 출력한다. +- [X] 당첨 금액을 계산한다. +- [X] 수익률을 계산한다. + +## 예외 목록 +- 구매 금액 + - [X] 1000원 미만의 금액이 입력될 경우 + +- 로또 번호 + - [X] 1 - 45 범위의 입력이 아닐 경우 + - [X] 6개 중 중복된 숫자가 있을 경우 + - [X] 6개 아닌 수의 입력이 있을 경우 + - [X] 보너스 볼이 1개가 아닐 경우 + - [ ] 보너스 볼이 6개의 숫자와 중복될 경우 \ No newline at end of file diff --git a/out/production/classes/LottoApplication.class b/out/production/classes/LottoApplication.class new file mode 100644 index 0000000..89cf858 Binary files /dev/null and b/out/production/classes/LottoApplication.class differ diff --git a/out/production/classes/domain/Lotto.class b/out/production/classes/domain/Lotto.class new file mode 100644 index 0000000..4d1137e Binary files /dev/null and b/out/production/classes/domain/Lotto.class differ diff --git a/out/production/classes/domain/LottoCount.class b/out/production/classes/domain/LottoCount.class new file mode 100644 index 0000000..42d05b1 Binary files /dev/null and b/out/production/classes/domain/LottoCount.class differ diff --git a/out/production/classes/domain/LottoNumber.class b/out/production/classes/domain/LottoNumber.class new file mode 100644 index 0000000..233e81b Binary files /dev/null and b/out/production/classes/domain/LottoNumber.class differ diff --git a/out/production/classes/domain/LottoRank.class b/out/production/classes/domain/LottoRank.class new file mode 100644 index 0000000..a5925df Binary files /dev/null and b/out/production/classes/domain/LottoRank.class differ diff --git a/out/production/classes/domain/LottoResult.class b/out/production/classes/domain/LottoResult.class new file mode 100644 index 0000000..1f4adcf Binary files /dev/null and b/out/production/classes/domain/LottoResult.class differ diff --git a/out/production/classes/domain/Lottos.class b/out/production/classes/domain/Lottos.class new file mode 100644 index 0000000..dc6fbaa Binary files /dev/null and b/out/production/classes/domain/Lottos.class differ diff --git a/out/production/classes/domain/MatchCount.class b/out/production/classes/domain/MatchCount.class new file mode 100644 index 0000000..e7cf8ab Binary files /dev/null and b/out/production/classes/domain/MatchCount.class differ diff --git a/out/production/classes/domain/Money.class b/out/production/classes/domain/Money.class new file mode 100644 index 0000000..da4bef6 Binary files /dev/null and b/out/production/classes/domain/Money.class differ diff --git a/out/production/classes/domain/ProfitResult.class b/out/production/classes/domain/ProfitResult.class new file mode 100644 index 0000000..1d6cea6 Binary files /dev/null and b/out/production/classes/domain/ProfitResult.class differ diff --git a/out/production/classes/domain/WinningLotto.class b/out/production/classes/domain/WinningLotto.class new file mode 100644 index 0000000..dbc747d Binary files /dev/null and b/out/production/classes/domain/WinningLotto.class differ diff --git a/out/production/classes/ui/Printer.class b/out/production/classes/ui/Printer.class new file mode 100644 index 0000000..63aeab2 Binary files /dev/null and b/out/production/classes/ui/Printer.class differ diff --git a/out/production/classes/ui/Receiver.class b/out/production/classes/ui/Receiver.class new file mode 100644 index 0000000..cf40142 Binary files /dev/null and b/out/production/classes/ui/Receiver.class differ diff --git a/out/test/classes/LottoCountTest.class b/out/test/classes/LottoCountTest.class new file mode 100644 index 0000000..c9710a4 Binary files /dev/null and b/out/test/classes/LottoCountTest.class differ diff --git a/out/test/classes/LottoRankTest.class b/out/test/classes/LottoRankTest.class new file mode 100644 index 0000000..99957c1 Binary files /dev/null and b/out/test/classes/LottoRankTest.class differ diff --git a/out/test/classes/LottoResultTest.class b/out/test/classes/LottoResultTest.class new file mode 100644 index 0000000..1ca6fc2 Binary files /dev/null and b/out/test/classes/LottoResultTest.class differ diff --git a/out/test/classes/LottoTest.class b/out/test/classes/LottoTest.class new file mode 100644 index 0000000..0ad1cc9 Binary files /dev/null and b/out/test/classes/LottoTest.class differ diff --git a/out/test/classes/LottosTest.class b/out/test/classes/LottosTest.class new file mode 100644 index 0000000..a5f52ac Binary files /dev/null and b/out/test/classes/LottosTest.class differ diff --git a/out/test/classes/MatchCountTest.class b/out/test/classes/MatchCountTest.class new file mode 100644 index 0000000..81b7500 Binary files /dev/null and b/out/test/classes/MatchCountTest.class differ diff --git a/out/test/classes/MoneyTest.class b/out/test/classes/MoneyTest.class new file mode 100644 index 0000000..24bbd21 Binary files /dev/null and b/out/test/classes/MoneyTest.class differ diff --git a/out/test/classes/ProfitResultTest.class b/out/test/classes/ProfitResultTest.class new file mode 100644 index 0000000..a0fd87a Binary files /dev/null and b/out/test/classes/ProfitResultTest.class differ diff --git a/out/test/classes/WinningLottoTest.class b/out/test/classes/WinningLottoTest.class new file mode 100644 index 0000000..2007f4f Binary files /dev/null and b/out/test/classes/WinningLottoTest.class differ diff --git a/src/main/java/LottoApplication.java b/src/main/java/LottoApplication.java new file mode 100644 index 0000000..9a24df0 --- /dev/null +++ b/src/main/java/LottoApplication.java @@ -0,0 +1,54 @@ +import java.util.ArrayList; +import java.util.List; +import domain.LottoNumber; +import domain.Lotto; +import domain.LottoCount; +import domain.Lottos; +import domain.Money; +import domain.ProfitResult; +import domain.WinningLotto; +import ui.Receiver; +import ui.Printer; + +public class LottoApplication { + + Printer printer = new Printer(); + Receiver receiver = new Receiver(); + + public static void main(String[] args) { + LottoApplication app = new LottoApplication(); + app.start(); + } + + private void start() { + LottoCount count = getCountByMoney(); + List manualLottoNumbers = getManualLottoNumbers(count); + printer.printNumberOfLottoTickets(count); + Lottos lottos = Lottos.createLottos(manualLottoNumbers, count); + printer.printLottos(lottos); + WinningLotto winningLotto = getWinningLotto(); + ProfitResult result = winningLotto.getResult(lottos); + printer.printLottoProfit(result); + printer.printIsLottoProfit(result.isProfit()); + } + + private List getManualLottoNumbers(LottoCount count) { + List manualLottoNumbers = new ArrayList<>(); + if (count.hasManualLottoCount()) { + manualLottoNumbers.addAll(receiver.receiveManualLottoNumbers(count)); + } + return manualLottoNumbers; + } + + private LottoCount getCountByMoney() { + int inputMoney = receiver.receiveMoney(); + Money money = new Money(inputMoney); + return money.getLottoCount(receiver.receiveManualNumberOfLottoTickets()); + } + + private WinningLotto getWinningLotto() { + Lotto winningLotto = Lotto.of(receiver.receiveWinningLottoNumbers()); + LottoNumber bonusBall = LottoNumber.of(receiver.receiveBonusBall()); + return new WinningLotto(winningLotto, bonusBall); + } +} \ No newline at end of file diff --git a/src/main/java/domain/Lotto.java b/src/main/java/domain/Lotto.java new file mode 100644 index 0000000..07db74e --- /dev/null +++ b/src/main/java/domain/Lotto.java @@ -0,0 +1,65 @@ +package domain; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class Lotto { + + private static final String LOTTO_NUMBER_COUNT_EXCEPTION_MESSAGE = "6개를 입력해주세요"; + private static final String DELIMITER = ", "; + private static final int NUMBER_COUNT_ZERO = 0; + private static final int NUMBER_COUNT = 6; + + private final Set balls; + + private Lotto(Set balls) { + validateBallCount(balls); + this.balls = Collections.unmodifiableSet(new HashSet<>(balls)); + } + + private void validateBallCount(Set balls) { + if (balls.size() != NUMBER_COUNT) { + throw new IllegalArgumentException(LOTTO_NUMBER_COUNT_EXCEPTION_MESSAGE); + } + } + + public static Lotto of(String rawLotto) { + String[] numbers = rawLotto.split(DELIMITER); + Set balls = new HashSet<>(); + for (String number : numbers) { + balls.add(LottoNumber.of(Integer.parseInt(number))); + } + return new Lotto(balls); + } + + public static Lotto newAutoLotto() { + List balls = LottoNumber.getBalls(); + Collections.shuffle(balls); + Set randomBalls = new HashSet<>(balls.subList(NUMBER_COUNT_ZERO, NUMBER_COUNT)); + return new Lotto(randomBalls); + } + + public static boolean moreThanBallCount(int matchCount) { + return matchCount > NUMBER_COUNT; + } + + public boolean contains(LottoNumber ball) { + return balls.contains(ball); + } + + public int countCommonBalls(Lotto lotto) { + Set sameBalls = new HashSet<>(balls); + sameBalls.retainAll(lotto.balls); + return sameBalls.size(); + } + + public List getLotto() { + List ballsData = balls.stream() + .map(LottoNumber::toString) + .collect(Collectors.toList()); + return Collections.unmodifiableList(ballsData); + } +} \ No newline at end of file diff --git a/src/main/java/domain/LottoCount.java b/src/main/java/domain/LottoCount.java new file mode 100644 index 0000000..e6b5580 --- /dev/null +++ b/src/main/java/domain/LottoCount.java @@ -0,0 +1,52 @@ +package domain; + +import java.util.Objects; + +public class LottoCount { + private static final int MINIMUM_MANUAL_LOTTO_COUNT = 0; + private final int manualLottoCount; + private final int lottoCount; + + public LottoCount(int lottoCount) { + this(lottoCount, MINIMUM_MANUAL_LOTTO_COUNT); + } + + public LottoCount(int lottoCount, int manualLottoCount) { + this.lottoCount = lottoCount; + this.manualLottoCount = manualLottoCount; + } + + public boolean hasManualLottoCount() { + return manualLottoCount != 0; + } + + public Money getBuyMoney(int lottoPrice) { + return new Money(lottoCount * lottoPrice); + } + + public int getAutoLottoCount() { + return lottoCount - manualLottoCount; + } + + public int getManualLottoCount() { + return manualLottoCount; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LottoCount that = (LottoCount) o; + return manualLottoCount == that.manualLottoCount && + lottoCount == that.lottoCount; + } + + @Override + public int hashCode() { + return Objects.hash(manualLottoCount, lottoCount); + } +} \ No newline at end of file diff --git a/src/main/java/domain/LottoNumber.java b/src/main/java/domain/LottoNumber.java new file mode 100644 index 0000000..e77cdde --- /dev/null +++ b/src/main/java/domain/LottoNumber.java @@ -0,0 +1,69 @@ +package domain; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class LottoNumber implements Comparable { + + private static final int MINIMUM_LOTTO_NUMBER = 1; + private static final int MAXIMUM_LOTTO_NUMBER = 45; + private static final String PRINT_IF_NUMBER_IS_INVALID_NUMBER = "유효한 로또 번호가 아닙니다."; + private static final Map MAPPING_BALL = new HashMap<>(); + + private final int number; + + static { + DisposeBall(); + } + + private static void DisposeBall() { + for (int ballNumber = MINIMUM_LOTTO_NUMBER; ballNumber <= MAXIMUM_LOTTO_NUMBER; ballNumber++) { + MAPPING_BALL.put(ballNumber, new LottoNumber(ballNumber)); + } + } + + private LottoNumber(int number) { + this.number = number; + } + + public static LottoNumber of(int number) { + if (MAPPING_BALL.containsKey(number)) { + return MAPPING_BALL.get(number); + } + throw new IllegalArgumentException(PRINT_IF_NUMBER_IS_INVALID_NUMBER); + } + + public static List getBalls() { + return new ArrayList<>(MAPPING_BALL.values()); + } + + @Override + public String toString() { + return Integer.toString(number); + } + + @Override + public int compareTo(LottoNumber o) { + return Integer.compare(number, o.number); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LottoNumber ball = (LottoNumber) o; + return number == ball.number; + } + + @Override + public int hashCode() { + return Objects.hash(number); + } +} \ No newline at end of file diff --git a/src/main/java/domain/LottoRank.java b/src/main/java/domain/LottoRank.java new file mode 100644 index 0000000..630c5e0 --- /dev/null +++ b/src/main/java/domain/LottoRank.java @@ -0,0 +1,60 @@ +package domain; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public enum LottoRank { + THREE_MATCH(new MatchCount(3), false, new Money(5_000)), + FOUR_MATCH(new MatchCount(4), false, new Money(50_000)), + FIVE_MATCH(new MatchCount(5), false, new Money(1_500_000)), + FIVE_MATCH_WITH_BONUS_BALL(new MatchCount(5), true, new Money(30_000_000)), + SIX_MATCH(new MatchCount(6), false, new Money(2_000_000_000)); + + private static final String THERE_IS_NON_RANK_EXCEPTION_MESSAGE = "꽝!"; + + private final MatchCount matchCount; + private final boolean bonusMatch; + private final Money money; + + LottoRank(MatchCount matchCount, boolean bonusMatch, Money money) { + this.matchCount = matchCount; + this.bonusMatch = bonusMatch; + this.money = money; + } + + public static LottoRank getRank(int matchCount, boolean bonusMatch) { + List lottoRanks = Arrays.stream(values()) + .filter(lottoRank -> lottoRank.matchCount.getMatchCount() == matchCount) + .sorted() + .collect(Collectors.toList()); + return getRankWithBonus(lottoRanks, bonusMatch); + } + + private static LottoRank getRankWithBonus(List lottoRanks, boolean bonusMatch) { + if (lottoRanks.size() == 1) { + return lottoRanks.get(0); + } + return lottoRanks.stream() + .filter(lottoRank -> lottoRank.bonusMatch == bonusMatch) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(THERE_IS_NON_RANK_EXCEPTION_MESSAGE)); + } + + public static boolean isMatchedCount(int matchCount) { + return Arrays.stream(values()) + .anyMatch(rank -> rank.matchCount.getMatchCount() == matchCount); + } + + public long getTotal(int count) { + return this.money.multiply(count); + } + + public int getMatchCount() { + return this.matchCount.getMatchCount(); + } + + public int getMoney() { + return this.money.getMoney(); + } +} diff --git a/src/main/java/domain/LottoResult.java b/src/main/java/domain/LottoResult.java new file mode 100644 index 0000000..303e6b1 --- /dev/null +++ b/src/main/java/domain/LottoResult.java @@ -0,0 +1,25 @@ +package domain; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +public class LottoResult { + + private final Map rankResult; + + public LottoResult(Map rankResult) { + this.rankResult = Collections.unmodifiableMap(rankResult); + } + + public long calculateTotalPrize() { + Set lottoRanks = rankResult.keySet(); + return lottoRanks.stream() + .mapToLong(lottoRank -> lottoRank.getTotal(rankResult.get(lottoRank))) + .sum(); + } + + public Map getRankResult() { + return rankResult; + } +} diff --git a/src/main/java/domain/Lottos.java b/src/main/java/domain/Lottos.java new file mode 100644 index 0000000..a61f2fc --- /dev/null +++ b/src/main/java/domain/Lottos.java @@ -0,0 +1,49 @@ +package domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +public class Lottos implements Iterable { + + private final List lottos; + private final LottoCount lottoCount; + + private Lottos(List lottos, LottoCount lottoCount) { + this.lottos = Collections.unmodifiableList(new ArrayList<>(lottos)); + this.lottoCount = lottoCount; + } + + public static Lottos createLottos(List manualLotto, LottoCount count) { + List lottos = new ArrayList<>(); + lottos.addAll(createManualLottos(manualLotto, count)); + lottos.addAll(createRandomLottos(count)); + return new Lottos(lottos, count); + } + + private static List createManualLottos(List manualLotto, LottoCount count) { + return manualLotto.stream() + .map(Lotto::of) + .collect(Collectors.toList()); + } + + private static List createRandomLottos(LottoCount count) { + List lottos = new ArrayList<>(); + int lottoCount = count.getAutoLottoCount(); + for (int i = 0; i < lottoCount; i++) { + lottos.add(Lotto.newAutoLotto()); + } + return lottos; + } + + public LottoCount getCount() { + return lottoCount; + } + + @Override + public Iterator iterator() { + return lottos.iterator(); + } +} \ No newline at end of file diff --git a/src/main/java/domain/MatchCount.java b/src/main/java/domain/MatchCount.java new file mode 100644 index 0000000..0dfec95 --- /dev/null +++ b/src/main/java/domain/MatchCount.java @@ -0,0 +1,39 @@ +package domain; + +import java.util.Objects; + +public class MatchCount { + + private static final int MINIMUM_MATCH_COUNT = 1; + private static final String INVALID_MATCH_COUNT_EXCEPTION_MESSAGE = "유효하지 않는 일치 갯수입니다."; + + private final int matchCount; + + public MatchCount(int matchCount) { + if (matchCount < MINIMUM_MATCH_COUNT || Lotto.moreThanBallCount(matchCount)) { + throw new IllegalArgumentException(INVALID_MATCH_COUNT_EXCEPTION_MESSAGE); + } + this.matchCount = matchCount; + } + + public int getMatchCount() { + return matchCount; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MatchCount that = (MatchCount) o; + return matchCount == that.matchCount; + } + + @Override + public int hashCode() { + return Objects.hash(matchCount); + } +} \ No newline at end of file diff --git a/src/main/java/domain/Money.java b/src/main/java/domain/Money.java new file mode 100644 index 0000000..2afa19b --- /dev/null +++ b/src/main/java/domain/Money.java @@ -0,0 +1,55 @@ +package domain; + +import java.util.Objects; + +public class Money { + + private static final int ONE_LOTTO_PRICE = 1000; + private static final String MONEY_EXCEPTION_MESSAGE = String.format("로또 구매를 위한 최소 금액은 %d원 입니다.", ONE_LOTTO_PRICE); + + private final int money; + + public Money(int money) { + validatePositive(money); + this.money = money; + } + + private void validatePositive(int money) { + if (money < ONE_LOTTO_PRICE) { + throw new IllegalArgumentException(MONEY_EXCEPTION_MESSAGE); + } + } + + public static Money getMoney(LottoCount lottoCount) { + return lottoCount.getBuyMoney(ONE_LOTTO_PRICE); + } + + public LottoCount getLottoCount(int manualLottoCount) { + return new LottoCount(money / ONE_LOTTO_PRICE, manualLottoCount); + } + + public int multiply(int count) { + return money * count; + } + + public int getMoney() { + return money; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Money money1 = (Money) o; + return money == money1.money; + } + + @Override + public int hashCode() { + return Objects.hash(money); + } +} diff --git a/src/main/java/domain/ProfitResult.java b/src/main/java/domain/ProfitResult.java new file mode 100644 index 0000000..3315fa7 --- /dev/null +++ b/src/main/java/domain/ProfitResult.java @@ -0,0 +1,32 @@ +package domain; + +import java.util.Map; + +public class ProfitResult { + private static final int PROFIT_THRESHOLD = 1; + + private final LottoResult lottoResult; + private final LottoCount count; + + public ProfitResult(LottoResult lottoResult, LottoCount count) { + this.lottoResult = lottoResult; + this.count = count; + } + + public float getProfitRate() { + float totalPrize = lottoResult.calculateTotalPrize(); + Money money = Money.getMoney(count); + return totalPrize / money.getMoney(); + } + + public boolean isProfit() { + if (getProfitRate() < PROFIT_THRESHOLD) { + return false; + } + return true; + } + + public Map getLottoResult() { + return lottoResult.getRankResult(); + } +} \ No newline at end of file diff --git a/src/main/java/domain/WinningLotto.java b/src/main/java/domain/WinningLotto.java new file mode 100644 index 0000000..1743059 --- /dev/null +++ b/src/main/java/domain/WinningLotto.java @@ -0,0 +1,54 @@ +package domain; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class WinningLotto { + + private static final String PRINT_IF_BONUSBALL_SAME_WITH_WINNING_NUMBER = "보너스 볼은 당첨 번호 6개와 중복 될 수 없습니다."; + + private final Lotto winningLotto; + private final LottoNumber bonusBall; + + public WinningLotto(Lotto winningLotto, LottoNumber bonusBall) { + validateCheckBonusBallSameWithWinningNumber(winningLotto, bonusBall); + this.winningLotto = winningLotto; + this.bonusBall = bonusBall; + } + + private void validateCheckBonusBallSameWithWinningNumber(Lotto winningLotto, LottoNumber bonusBall) { + if (winningLotto.contains(bonusBall)) { + throw new IllegalArgumentException(PRINT_IF_BONUSBALL_SAME_WITH_WINNING_NUMBER); + } + } + + public ProfitResult getResult(Lottos lottos) { + Map result = getInitialResult(); + for (Lotto lotto : lottos) { + putLottoRankResult(result, lotto); + } + return new ProfitResult(new LottoResult(result), lottos.getCount()); + } + + private void putLottoRankResult(Map result, Lotto lotto) { + int matchCount = lotto.countCommonBalls(winningLotto); + if (!LottoRank.isMatchedCount(matchCount)) { + return; + } + LottoRank rank = getLottoRank(lotto, matchCount); + result.put(rank, result.get(rank) + 1); + } + + private LottoRank getLottoRank(Lotto lotto, int matchCount) { + LottoRank rank = LottoRank.getRank(matchCount, lotto.contains(bonusBall)); + return rank; + } + + private Map getInitialResult() { + Map result = new LinkedHashMap<>(); + for (LottoRank lottoRank : LottoRank.values()) { + result.put(lottoRank, 0); + } + return result; + } +} \ No newline at end of file diff --git a/src/main/java/empty.txt b/src/main/java/empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/ui/Printer.java b/src/main/java/ui/Printer.java new file mode 100644 index 0000000..10d94db --- /dev/null +++ b/src/main/java/ui/Printer.java @@ -0,0 +1,54 @@ +package ui; + +import domain.*; + +import java.util.Map; + +public class Printer { + + private static final String PRINT_NUMBER_OF_LOTTO_TICKETS_MESSAGE = "\n수동으로 %d장, 자동으로 %d개를 구매했습니다.\n"; + private static final String PRINT_LOTTO_PROFIT_MESSAGE = "총 수익률은 %.2f입니다."; + private static final String PRINT_WINNING_STATISTICS_MESSAGE = "\n당첨 통계"; + private static final String PRINTER_DIVIDER = "---------"; + private static final String PRINT_LOTTO_MATCHED_LOTTO_RESULT_MESSAGE = "%d개 일치"; + private static final String PRINT_BONUS_BALL_MATCHED_MESSAGE = ", 보너스 볼 일치"; + private static final String PRINT_PRICE_WITH_MATCHED_NUMBER_OF_LOTTOS = " (%d원) - %d개\n"; + private static final String PRINT_PROFIT_LOSS_MESSAGE = "(기준이 1이기 때문에 결과적으로 손해라는 의미임)"; + + public Printer(){ + } + + public void printNumberOfLottoTickets(LottoCount count) { + System.out.print(String.format(PRINT_NUMBER_OF_LOTTO_TICKETS_MESSAGE, count.getManualLottoCount(), count.getAutoLottoCount())); + } + + public void printLottos(Lottos lottos) { + for(Lotto lotto : lottos) { + System.out.println(lotto.getLotto()); + } + } + + public void printLottoProfit(ProfitResult profitResult) { + System.out.println(PRINT_WINNING_STATISTICS_MESSAGE); + System.out.println(PRINTER_DIVIDER); + Map lottoResult = profitResult.getLottoResult(); + for (LottoRank lottoRank : lottoResult.keySet()) { + printLottoMatchedResult(lottoRank, lottoResult.get(lottoRank)); + } + System.out.print(String.format(PRINT_LOTTO_PROFIT_MESSAGE, profitResult.getProfitRate())); + } + + public void printLottoMatchedResult(LottoRank lottoRank, Integer count) { + System.out.print(String.format(PRINT_LOTTO_MATCHED_LOTTO_RESULT_MESSAGE, lottoRank.getMatchCount())); + if (lottoRank == LottoRank.FIVE_MATCH_WITH_BONUS_BALL) { + System.out.print(PRINT_BONUS_BALL_MATCHED_MESSAGE); + } + System.out.print(String.format(PRINT_PRICE_WITH_MATCHED_NUMBER_OF_LOTTOS, lottoRank.getMoney(), count)); + } + + public void printIsLottoProfit(boolean isProfit) { + if(!isProfit) { + System.out.println(PRINT_PROFIT_LOSS_MESSAGE); + } + } +} diff --git a/src/main/java/ui/Receiver.java b/src/main/java/ui/Receiver.java new file mode 100644 index 0000000..c24b295 --- /dev/null +++ b/src/main/java/ui/Receiver.java @@ -0,0 +1,53 @@ +package ui; + +import domain.LottoCount; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class Receiver { + + private static final String REQUEST_MONEY_MESSAGE = "구입금액을 입력해 주세요."; + private static final String RECEIVE_MANUAL_NUMBER_OF_LOTTO_TICKETS_MESSAGE = "\n수동으로 구매할 로또 수를 입력해 주세요."; + private static final String RECEIVE_MANUAL_LOTTO_NUMBERS = "\n수동으로 구매할 번호를 입력해 주세요."; + private static final String RECEIVE_WINNING_LOTTO_NUMBERS_MESSAGE = "\n지난 주 당첨 번호를 입력해 주세요."; + private static final String RECEIVE_BONUS_BALL_MESSAGE = "보너스 볼을 입력해주세요."; + + private static final Scanner SCANNER = new Scanner(System.in); + + public Receiver() { + } + + public int receiveMoney() { + System.out.println(REQUEST_MONEY_MESSAGE); + return SCANNER.nextInt(); + } + + public int receiveManualNumberOfLottoTickets() { + System.out.println(RECEIVE_MANUAL_NUMBER_OF_LOTTO_TICKETS_MESSAGE); + int manualLottoCount = SCANNER.nextInt(); + SCANNER.nextLine(); + return manualLottoCount; + } + + public List receiveManualLottoNumbers(LottoCount lottoCount) { + System.out.println(RECEIVE_MANUAL_LOTTO_NUMBERS); + List manualLottoNumbers = new ArrayList<>(); + int manualLottoCount = lottoCount.getManualLottoCount(); + for (int i =0; i < manualLottoCount; i++){ + manualLottoNumbers.add(SCANNER.nextLine()); + } + return manualLottoNumbers; + } + + public String receiveWinningLottoNumbers() { + System.out.println(RECEIVE_WINNING_LOTTO_NUMBERS_MESSAGE); + return SCANNER.nextLine(); + } + + public int receiveBonusBall() { + System.out.println(RECEIVE_BONUS_BALL_MESSAGE); + return SCANNER.nextInt(); + } +} diff --git a/src/test/java/LottoCountTest.java b/src/test/java/LottoCountTest.java new file mode 100644 index 0000000..2386899 --- /dev/null +++ b/src/test/java/LottoCountTest.java @@ -0,0 +1,12 @@ +import domain.LottoCount; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class LottoCountTest { + @Test + void 자동로또의_수는_전체_수에서_수동로또의_수를_뺀_것과_같다 () { + LottoCount count = new LottoCount(100, 43); + assertThat(count.getAutoLottoCount()).isEqualTo(57); + } +} diff --git a/src/test/java/LottoRankTest.java b/src/test/java/LottoRankTest.java new file mode 100644 index 0000000..be71558 --- /dev/null +++ b/src/test/java/LottoRankTest.java @@ -0,0 +1,21 @@ +import domain.LottoRank; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class LottoRankTest { + @Test + void 맞은_개수와_등수_확인한다 () { + assertThat(LottoRank.getRank(3, false)).isEqualTo(LottoRank.THREE_MATCH); + assertThat(LottoRank.getRank(3, true)).isEqualTo(LottoRank.THREE_MATCH); + + assertThat(LottoRank.getRank(4, false)).isEqualTo(LottoRank.FOUR_MATCH); + assertThat(LottoRank.getRank(4, true)).isEqualTo(LottoRank.FOUR_MATCH); + + assertThat(LottoRank.getRank(5, false)).isEqualTo(LottoRank.FIVE_MATCH); + assertThat(LottoRank.getRank(5, true)).isEqualTo(LottoRank.FIVE_MATCH_WITH_BONUS_BALL); + + assertThat(LottoRank.getRank(6, false)).isEqualTo(LottoRank.SIX_MATCH); + assertThat(LottoRank.getRank(6, true)).isEqualTo(LottoRank.SIX_MATCH); + } +} diff --git a/src/test/java/LottoResultTest.java b/src/test/java/LottoResultTest.java new file mode 100644 index 0000000..2481e78 --- /dev/null +++ b/src/test/java/LottoResultTest.java @@ -0,0 +1,22 @@ +import domain.LottoRank; +import domain.LottoResult; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class LottoResultTest { + @Test + void 전체_이익은_각_로또의_돈과_같다() { + Map rankResult = new HashMap<>(); + rankResult.put(LottoRank.SIX_MATCH, 1); + rankResult.put(LottoRank.FIVE_MATCH_WITH_BONUS_BALL, 3); + rankResult.put(LottoRank.THREE_MATCH, 4); + + LottoResult result = new LottoResult(rankResult); + + assertThat(result.calculateTotalPrize()).isEqualTo(2_000_000_000L + 30_000_000 * 3 + 5_000 * 4); + } +} diff --git a/src/test/java/LottoTest.java b/src/test/java/LottoTest.java new file mode 100644 index 0000000..4056e81 --- /dev/null +++ b/src/test/java/LottoTest.java @@ -0,0 +1,21 @@ +import domain.Lotto; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class LottoTest { + @Test + void getLotto() { + Lotto lotto = Lotto.of("1, 2, 3, 4, 5, 6"); + List lottoData = lotto.getLotto(); + + assertThat((lottoData).contains("1")); + assertThat((lottoData).contains("2")); + assertThat((lottoData).contains("3")); + assertThat((lottoData).contains("4")); + assertThat((lottoData).contains("5")); + assertThat((lottoData).contains("6")); + } +} diff --git a/src/test/java/WinningLottoTest.java b/src/test/java/WinningLottoTest.java new file mode 100644 index 0000000..df30930 --- /dev/null +++ b/src/test/java/WinningLottoTest.java @@ -0,0 +1,20 @@ +import domain.*; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +public class WinningLottoTest { + + @Test + void 당첨번호가_로또번호_6개랑_같을_때_예외_메시지_출력() { + Lotto lotto = Lotto.of("1, 2, 3, 4, 5, 6"); + LottoNumber lottoNumber = LottoNumber.of(1); + + assertThatThrownBy(() -> new WinningLotto(lotto, lottoNumber)) + .isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/src/test/java/empty.txt b/src/test/java/empty.txt deleted file mode 100644 index e69de29..0000000