diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 000000000..8d0bff680 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,37 @@ +import domain.*; +import view.InputView; +import view.ResultView; + +import java.util.List; + + +public class Application { + public static void main(String[] args) { + LottoGenerator lottoGenerator = new LottoGenerator(); + LottoResult lottoResult = new LottoResult(); + WinningRate winningRate = new WinningRate(); + + int purchasePrice = InputView.inputPrice(); + PurchaseAmount purchaseAmount = PurchaseAmount.from(purchasePrice); + + int lottoCount = purchaseAmount.calculateCount(); + int passiveCount = InputView.inputPassiveCount(); + int autoCount = lottoCount - passiveCount; + + List> passiveLotto = InputView.inputPassiveLotto(passiveCount); + List> autoLotto = lottoGenerator.lottoLists(autoCount); + + passiveLotto.addAll(autoLotto); + ResultView.printPurchase(passiveLotto, passiveCount, autoCount); + + List wins = InputView.inputWinning(); + int bonusBall = InputView.inputBonusBall(); + List counts = lottoResult.calculateCounts(passiveLotto, wins, bonusBall); + + int winPrice = winningRate.calculateWinPrice(counts); + double rate = winningRate.calculateRate(winPrice, purchasePrice); + + ResultView.printResult(counts, rate); + } +} + diff --git a/src/main/java/domain/Lotto.java b/src/main/java/domain/Lotto.java new file mode 100644 index 000000000..e51b15551 --- /dev/null +++ b/src/main/java/domain/Lotto.java @@ -0,0 +1,36 @@ +package domain; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class Lotto { + private final List numbers; + + private Lotto(List numbers) { + this.numbers = numbers; + } + + public static Lotto from(List numbers) { + validateCount(numbers); + validateDuplicate(numbers); + return new Lotto(numbers); + } + + private static void validateCount(List numbers) { + if(numbers.size() != 6) { + throw new IllegalArgumentException(); + } + } + + private static void validateDuplicate(List numbers) { + Set set = new HashSet<>(numbers); + if (set.size() != numbers.size()) { + throw new IllegalArgumentException(); + } + } + + + + +} diff --git a/src/main/java/domain/LottoGenerator.java b/src/main/java/domain/LottoGenerator.java new file mode 100644 index 000000000..14b035168 --- /dev/null +++ b/src/main/java/domain/LottoGenerator.java @@ -0,0 +1,53 @@ +package domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class LottoGenerator { + private static List lottoList() { + List lotto = new ArrayList<>(); + + for (int i = 0; i < 45; i++) { + lotto.add(i+1); + } + return lotto; + } + + private void lottoShuffle(List lotto) { + Collections.shuffle(lotto); + } + + private List lottoPick(List lotto) { + List lottoSix = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + lottoSix.add(LottoNumber.from(lotto.get(i))); + } + + return lottoSix; + } + + private void lottoSort(List lotto) { + Collections.sort(lotto); + } + + public List run() { + List lottoList = lottoList(); + + lottoShuffle(lottoList); + List lotto = lottoPick(lottoList); + lottoSort(lotto); + + return lotto; + } + + public List> lottoLists(int count) { + List> lottos = new ArrayList<>(); + for (int i = 0; i < count; i++) { + lottos.add(run()); + } + return lottos; + } + + +} diff --git a/src/main/java/domain/LottoNumber.java b/src/main/java/domain/LottoNumber.java new file mode 100644 index 000000000..ed4bfc670 --- /dev/null +++ b/src/main/java/domain/LottoNumber.java @@ -0,0 +1,52 @@ +package domain; + +import java.util.Objects; + +public class LottoNumber implements Comparable{ + private final int number; + + private LottoNumber(int number) { + this.number = number; + } + + public int getNumber() { + return number; + } + + public static LottoNumber from(int number) { + validate(number); + return new LottoNumber(number); + } + + private static final int MIN = 1; + private static final int MAX = 45; + + private static void validate(int number) { + if (number < MIN || number > MAX) { + throw new IllegalArgumentException(); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + LottoNumber that = (LottoNumber) o; + return number == that.number; + } + + @Override + public int hashCode() { + return Objects.hashCode(number); + } + + @Override + public int compareTo(LottoNumber o) { + return Integer.compare(number, o.number); + } + + @Override + public String toString() { + return String.valueOf(number); + } +} diff --git a/src/main/java/domain/LottoResult.java b/src/main/java/domain/LottoResult.java new file mode 100644 index 000000000..731d3a468 --- /dev/null +++ b/src/main/java/domain/LottoResult.java @@ -0,0 +1,37 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; + +public class LottoResult { + + private boolean containsWinningNumber(List lottoList, int win) { + return lottoList.contains(LottoNumber.from(win)); + } + + private int resultCounting(List lottoList, int win, int count) { + if (containsWinningNumber(lottoList, win)) { + count++; + } + return count; + } + + private int checkingWinningNumbers(List lottoList, List wins, int bonusBall) { + int count = 0; + for (int win : wins) { + count = resultCounting(lottoList, win, count); + } + + if (count == 5 && containsWinningNumber(lottoList, bonusBall)) return 7; + return count; + } + + public List calculateCounts(List> lottos, List wins, int bonusBall) { + List counts = new ArrayList<>(); + + for (List lotto : lottos) { + counts.add(checkingWinningNumbers(lotto, wins, bonusBall)); + } + return counts; + } +} diff --git a/src/main/java/domain/PurchaseAmount.java b/src/main/java/domain/PurchaseAmount.java new file mode 100644 index 000000000..acf89d274 --- /dev/null +++ b/src/main/java/domain/PurchaseAmount.java @@ -0,0 +1,31 @@ +package domain; + +public class PurchaseAmount { + private final int amount; + + private PurchaseAmount(int amount) { + validate(amount); + this.amount = amount; + } + + public static PurchaseAmount from(int amount) { + return new PurchaseAmount(amount); + } + + private static void validate(int amount) { + if (amount < 1000) { + throw new IllegalArgumentException(); + } + if (amount % 1000 != 0) { + throw new IllegalArgumentException(); + } + } + + public int getAmount() { + return amount; + } + + public int calculateCount() { + return amount / 1000; + } +} diff --git a/src/main/java/domain/WinningPrize.java b/src/main/java/domain/WinningPrize.java new file mode 100644 index 000000000..73821fc79 --- /dev/null +++ b/src/main/java/domain/WinningPrize.java @@ -0,0 +1,25 @@ +package domain; + +public enum WinningPrize { + THREE(3, 5000), + FOUR(4, 50000), + FIVE(5, 1500000), + BONUS(7, 30000000), + SIX(6, 2000000000); + + private final int goal; + private final int prize; + + WinningPrize(int goal, int prize) { + this.goal = goal; + this.prize = prize; + } + + public int getGoal() { + return goal; + } + + public int getPrize() { + return prize; + } +} diff --git a/src/main/java/domain/WinningRate.java b/src/main/java/domain/WinningRate.java new file mode 100644 index 000000000..8729f1329 --- /dev/null +++ b/src/main/java/domain/WinningRate.java @@ -0,0 +1,47 @@ +package domain; + +import java.util.List; + +public class WinningRate { + + public int calculateWinPrice(List counts) { + return threeWin(counts) + fourWin(counts) + fiveWin(counts) + secondWin(counts) + sixWin(counts); + } + + private int threeWin(List counts) { + return countGoal(counts, WinningPrize.THREE.getGoal()) * WinningPrize.THREE.getPrize(); + } + + private int fourWin(List counts) { + return countGoal(counts, WinningPrize.FOUR.getGoal()) + * WinningPrize.FOUR.getPrize(); + } + + private int fiveWin(List counts) { + return countGoal(counts, WinningPrize.FIVE.getGoal()) + * WinningPrize.FIVE.getPrize(); + } + + private int secondWin(List counts) { + return countGoal(counts, WinningPrize.BONUS.getGoal()) + * WinningPrize.BONUS.getPrize(); + } + + private int sixWin(List counts) { + return countGoal(counts, WinningPrize.SIX.getGoal()) + * WinningPrize.SIX.getPrize(); + } + + private int countGoal(List counts, int goal) { + int count = 0; + + for (int i = 0; i < counts.size(); i++) { + if (goal == counts.get(i)) count++; + } + return count; + } + + public double calculateRate(int winPrice, int purchasePrice) { + return (double) winPrice / purchasePrice; + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 000000000..79d04049c --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,69 @@ +package view; + +import domain.LottoNumber; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class InputView { + + private static Scanner scanner = new Scanner(System.in); + + public static int inputPrice() { + + System.out.println("구입금액을 입력해 주세요."); + int price = scanner.nextInt(); + + return price; + } + + public static List inputWinning() { + System.out.println("\n지난 주 당첨 번호를 입력해 주세요."); + String win = scanner.nextLine(); + + String[] wins = win.split(","); + List nums = new ArrayList<>(); + + for (int i = 0; i < wins.length; i++) { + nums.add(Integer.parseInt(wins[i])); + } return nums; + } + public static int inputBonusBall() { + System.out.println("\n보너스 볼을 입력해 주세요."); + int bonusBall = scanner.nextInt(); + + return bonusBall; + } + + public static int inputPassiveCount() { + System.out.println("\n수동으로 구매할 로또 수를 입력해 주세요."); + int count = scanner.nextInt(); + return count; + } + + public static List> inputPassiveLotto(int manualCount) { + scanner.nextLine(); + + System.out.println("\n수동으로 구매할 번호를 입력해 주세요."); + List> passiveLottos = new ArrayList<>(); + + for (int i = 0; i < manualCount; i++) { + passiveLottos.add(inputManualLotto()); + } + return passiveLottos; + } + + private static List inputManualLotto() { + String input = scanner.nextLine(); + String[] numbers = input.split(","); + + List lotto = new ArrayList<>(); + + for (String number : numbers) { + lotto.add(LottoNumber.from(Integer.parseInt(number.trim()))); + } + + return lotto; + } +} diff --git a/src/main/java/view/ResultView.java b/src/main/java/view/ResultView.java new file mode 100644 index 000000000..6486d39e0 --- /dev/null +++ b/src/main/java/view/ResultView.java @@ -0,0 +1,35 @@ +package view; + +import domain.LottoNumber; + +import java.util.List; + +public class ResultView { + + public static void printPurchase(List> lottos, int passiveCount, int autoCount) { + System.out.println("수동으로 " + passiveCount + "장, 자동으로 " + autoCount + "개를 구매했습니다." + ); + for (List lotto : lottos) { + System.out.println(lotto); + } + } + + public static void printResult(List counts, double rate) { + System.out.println(); + System.out.println("당첨 통계"); + System.out.println("---------"); + + int[] result = new int[8]; + + for (int count : counts) { + result[count]++; + } + + System.out.println("3개 일치 (5,000원) - " + result[3] + "개"); + System.out.println("4개 일치 (50,000원) - " + result[4] + "개"); + System.out.println("5개 일치 (1,500,000원) - " + result[5] + "개"); + System.out.println("5개 일치, 보너스 볼 일치 (30,000,000원) - " + result[7] + "개"); + System.out.println("6개 일치 (2,000,000,000원) - " + result[6] + "개"); + System.out.printf("총 수익률은 %.2f입니다.\n", rate); + } +} diff --git a/src/test/java/LottoNumberTest.java b/src/test/java/LottoNumberTest.java new file mode 100644 index 000000000..050188b6c --- /dev/null +++ b/src/test/java/LottoNumberTest.java @@ -0,0 +1,54 @@ +import domain.LottoNumber; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + + +public class LottoNumberTest { + + @Test + @DisplayName("유효한 번호로 LottoNumber를 생성") + void lottoNumberWithValidNumber() { + LottoNumber.from(1); + LottoNumber.from(45); + } + + @Test + @DisplayName("1~45 범위를 벗어나면 예외") + void throwExceptionNumberIsOutOfRange() { + assertThrows(IllegalArgumentException.class, () -> LottoNumber.from(0)); + + assertThrows(IllegalArgumentException.class, () -> LottoNumber.from(46)); + } + + @Test + @DisplayName("값이 같을 때는 같은 객체") + void equalsLottoNumber() { + LottoNumber one = LottoNumber.from(3); + LottoNumber two = LottoNumber.from(3); + + assertEquals(one, two); + } + + @Test + @DisplayName("LottoNumber를 오름차순으로 정렬") + void sortLottoNumbersInAscendingOrder() { + List lottoNumbers = new ArrayList<>(); + + lottoNumbers.add(LottoNumber.from(2)); + lottoNumbers.add(LottoNumber.from(1)); + lottoNumbers.add(LottoNumber.from(3)); + + Collections.sort(lottoNumbers); + + assertEquals(LottoNumber.from(1), lottoNumbers.get(0)); + assertEquals(LottoNumber.from(2), lottoNumbers.get(1)); + assertEquals(LottoNumber.from(3), lottoNumbers.get(2)); + } +} diff --git a/src/test/java/LottoTest.java b/src/test/java/LottoTest.java new file mode 100644 index 000000000..b4a276047 --- /dev/null +++ b/src/test/java/LottoTest.java @@ -0,0 +1,56 @@ +import domain.Lotto; +import domain.LottoNumber; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class LottoTest { + + @Test + @DisplayName("로또 번호가 6개인가") + void createLotto() { + List numbers = List.of( + LottoNumber.from(1), + LottoNumber.from(2), + LottoNumber.from(3), + LottoNumber.from(4), + LottoNumber.from(5), + LottoNumber.from(6) + ); + + Lotto.from(numbers); + } + + @Test + @DisplayName("로또 번호가 6개가 아닌가") + void notSixLotto() { + List numbers = List.of( + LottoNumber.from(1), + LottoNumber.from(2), + LottoNumber.from(3), + LottoNumber.from(4), + LottoNumber.from(5) + ); + + assertThrows(IllegalArgumentException.class, () -> Lotto.from(numbers)); + } + + @Test + @DisplayName("중복된 번호가 있나") + void duplicateLotto() { + List numbers = List.of( + LottoNumber.from(1), + LottoNumber.from(2), + LottoNumber.from(3), + LottoNumber.from(4), + LottoNumber.from(5), + LottoNumber.from(5) + ); + + assertThrows(IllegalArgumentException.class, () -> Lotto.from(numbers)); + } +} diff --git a/src/test/java/PurchaseAmountTest.java b/src/test/java/PurchaseAmountTest.java new file mode 100644 index 000000000..dcb9715bd --- /dev/null +++ b/src/test/java/PurchaseAmountTest.java @@ -0,0 +1,19 @@ +import domain.PurchaseAmount; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class PurchaseAmountTest { + @Test + @DisplayName("금액이 1000원보다 작으면 예외") + void lessThan1000() { + assertThrows(IllegalArgumentException.class, () -> PurchaseAmount.from(500)); + } + + @Test + @DisplayName("금액이 1000원 단위가 아니면 예외") + void not1000Multiple() { + assertThrows(IllegalArgumentException.class, () -> PurchaseAmount.from(1500)); + } +}