diff --git a/src/main/java/Controller/LottoController.java b/src/main/java/Controller/LottoController.java new file mode 100644 index 00000000..c3201375 --- /dev/null +++ b/src/main/java/Controller/LottoController.java @@ -0,0 +1,30 @@ +package Controller; + +import Creator.RandomNumberCreator; +import Model.*; +import View.InputData; +import View.InputView; +import View.ResultView; + +import java.util.ArrayList; + +import static Model.Constants.LOTTO_PRICE; +import static View.InputData.*; +import static View.InputView.inputFirstLotto; + +public class LottoController { + public static void main(String[] args) { + Lottos lottos = new Lottos(); + + inputMoney = InputView.getInput(); + handLotto = InputView.getHandLotto(lottos); + autoLotto = InputView.getAutoLotto(lottos,getAutoLottoCount(inputMoney, handLotto)); + ResultView.printLottoResult(handLotto,autoLotto,lottos); + inputFirstLotto(); + ResultView.finalResult(lottos); + } + + private static int getAutoLottoCount(int inputMoney, int handLotto) { + return inputMoney / LOTTO_PRICE - handLotto; + } +} diff --git a/src/main/java/Creator/NumberCreator.java b/src/main/java/Creator/NumberCreator.java new file mode 100644 index 00000000..06f00b49 --- /dev/null +++ b/src/main/java/Creator/NumberCreator.java @@ -0,0 +1,5 @@ +package Creator; + +public interface NumberCreator { + int returnNumber(); +} diff --git a/src/main/java/Creator/RandomNumberCreator.java b/src/main/java/Creator/RandomNumberCreator.java new file mode 100644 index 00000000..d681f82d --- /dev/null +++ b/src/main/java/Creator/RandomNumberCreator.java @@ -0,0 +1,8 @@ +package Creator; + +import static java.lang.Math.random; +public class RandomNumberCreator implements NumberCreator{ + public int returnNumber(){ + return (int)(random()*45) + 1; + } +} diff --git a/src/main/java/Model/Constants.java b/src/main/java/Model/Constants.java new file mode 100644 index 00000000..1a73dd91 --- /dev/null +++ b/src/main/java/Model/Constants.java @@ -0,0 +1,7 @@ +package Model; + +public class Constants { + public static final int MIN_PRICE = 0; + public static final int UNIT = 1000; + public static final int LOTTO_PRICE = 1000; +} diff --git a/src/main/java/Model/DataEnum.java b/src/main/java/Model/DataEnum.java new file mode 100644 index 00000000..de41b70c --- /dev/null +++ b/src/main/java/Model/DataEnum.java @@ -0,0 +1,55 @@ +package Model; + +import View.InputData; + +public class DataEnum { + public enum LottoResult { + THREE_MATCHES(3, false, 5000), + FOUR_MATCHES(4, false, 50000), + FIVE_MATCHES(5, false, 1500000), + FIVE_MATCHES_BONUS(5, true, 30000000), + SIX_MATCHES(6, false, 2000000000); + + private final int matches; + private final boolean bonus; + private final int reward; + + LottoResult(int matches, boolean bonus, int reward) { + this.matches = matches; + this.bonus = bonus; + this.reward = reward; + } + + public int getMatches() { + return matches; + } + + public boolean isBonus() { + return bonus; + } + + public int getReward() { + return reward; + } + + public static void applyResult(int[] matchList, int matchCount, boolean bonusResult) { + for (LottoResult result : values()) { + isRight(matchList, matchCount, bonusResult, result); + } + } + + private static void isRight(int[] matchList, int matchCount, boolean bonusResult, LottoResult result) { + if (matchCount == 5 && result.bonus == bonusResult) { + int index = result.ordinal(); + matchList[index]++; + InputData.profit += result.reward; + } + else if (result.matches == matchCount){ + int index = result.ordinal(); + matchList[index]++; + InputData.profit += result.reward; + } + } + } + +} diff --git a/src/main/java/Model/Lotto.java b/src/main/java/Model/Lotto.java new file mode 100644 index 00000000..8b4ff8d7 --- /dev/null +++ b/src/main/java/Model/Lotto.java @@ -0,0 +1,33 @@ +package Model; +import Creator.RandomNumberCreator; + +import java.util.ArrayList; + +public class Lotto { + private int price; + private LottoCreator lottoCreator; + private LottoValidater lottoValidater = new LottoValidater(); + private ArrayList lottoNumbers = new ArrayList<>(); + + // 자동 로또 + public Lotto(LottoPrice price, LottoCreator lottoCreator) { + this.price = price.getPrice(); + this.lottoCreator = lottoCreator; + lottoNumbers = this.lottoCreator.getRandomNumbers(lottoNumbers,lottoValidater); + } + + // 수동 로또 + public Lotto(LottoPrice price,ArrayList lottoNumbers){ + this.price = price.getPrice(); + lottoValidater.validateLottos(lottoNumbers); + this.lottoNumbers = lottoNumbers; + } + + public int getPrice() { + return price; + } + + public ArrayList getLottoNumbers() { + return lottoNumbers; + } +} diff --git a/src/main/java/Model/LottoCreator.java b/src/main/java/Model/LottoCreator.java new file mode 100644 index 00000000..4bdc5e22 --- /dev/null +++ b/src/main/java/Model/LottoCreator.java @@ -0,0 +1,35 @@ +package Model; + +import Creator.NumberCreator; +import Creator.RandomNumberCreator; + +import java.util.ArrayList; + + +public class LottoCreator { + NumberCreator randomNumberCreator; + + public LottoCreator(RandomNumberCreator randomNumberCreator) { + this.randomNumberCreator = randomNumberCreator; + } + + public ArrayList getRandomNumbers(ArrayList lottoNumbers,LottoValidater lottoValidater) { + while (lottoNumbers.size() < 6) { + int returnNum = randomNumberCreator.returnNumber(); + + isNotInList(lottoNumbers, returnNum); + } + lottoValidater.validateLottos(lottoNumbers); + return lottoNumbers; + } + + private static void isNotInList(ArrayList lottoNumbers, int returnNum) { + if (lottoNumbers.stream() + .map(LottoNumber::getNumber) + .noneMatch(num -> num == returnNum)) { + // `returnNum`과 일치하는 숫자가 없으면 true 반환 + lottoNumbers.add(new LottoNumber(returnNum)); + } + } + +} diff --git a/src/main/java/Model/LottoNumber.java b/src/main/java/Model/LottoNumber.java new file mode 100644 index 00000000..7f1f13dd --- /dev/null +++ b/src/main/java/Model/LottoNumber.java @@ -0,0 +1,13 @@ +package Model; + +public class LottoNumber { + private int number; + + public LottoNumber(int number) { + this.number = number; + } + + public int getNumber() { + return number; + } +} diff --git a/src/main/java/Model/LottoPrice.java b/src/main/java/Model/LottoPrice.java new file mode 100644 index 00000000..30a93e04 --- /dev/null +++ b/src/main/java/Model/LottoPrice.java @@ -0,0 +1,30 @@ +package Model; + +import static Model.Constants.MIN_PRICE; +import static Model.Constants.UNIT; + +public class LottoPrice { + private int price; + + public LottoPrice(int price) { + validate(price); + this.price = price; + } + + public int getPrice() { + return price; + } + + private void validate(int price) { + validateUnit(price); + validateMin(price); + } + + private void validateMin(int price) { + if (price < MIN_PRICE) throw new IllegalArgumentException("값이 0원 미만일 수는 없습니다."); + } + + private void validateUnit(int price) { + if (price % UNIT != 0) throw new IllegalArgumentException("가격은 1000원 단위이어야 합니다."); + } +} diff --git a/src/main/java/Model/LottoValidater.java b/src/main/java/Model/LottoValidater.java new file mode 100644 index 00000000..fe0349b1 --- /dev/null +++ b/src/main/java/Model/LottoValidater.java @@ -0,0 +1,22 @@ +package Model; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +public class LottoValidater { + public void validateLottos(ArrayList lottoNumbers) { + sizeCheck(lottoNumbers); + duplicationCheck(lottoNumbers); + } + + public void duplicationCheck(ArrayList lottoNumbers) { + Set seen = new HashSet<>(); + if (lottoNumbers.stream() + .anyMatch(n -> !seen.add(n.getNumber()))) throw new IllegalArgumentException("로또는 중복돼서는 안됩니다."); + } + + public void sizeCheck(ArrayList lottoNumbers) { + if (lottoNumbers.size() != 6) throw new IllegalArgumentException("로또의 개수는 6개가 돼야합니다"); + } +} diff --git a/src/main/java/Model/Lottos.java b/src/main/java/Model/Lottos.java new file mode 100644 index 00000000..74894bbc --- /dev/null +++ b/src/main/java/Model/Lottos.java @@ -0,0 +1,33 @@ +package Model; + +import View.InputData; + +import java.util.ArrayList; +import java.util.List; + +public class Lottos { + private ArrayList lottos = new ArrayList<>(); + + public void addNewLotto(Lotto lotto){ + lottos.add(lotto); + } + + public ArrayList getLottos() { + return lottos; + } + + public int[] matchList(Lotto firstLotto, int bonus){ + int[] matchList = new int[5]; + List answerLotto = firstLotto.getLottoNumbers().stream().map(LottoNumber::getNumber).toList(); + + for (Lotto lotto:lottos) { + List buyLotto = lotto.getLottoNumbers().stream().map(LottoNumber::getNumber).toList(); + int matchCount = (int) buyLotto.stream().filter(answerLotto::contains).count(); + boolean bonusResult = buyLotto.contains(bonus); + + DataEnum.LottoResult.applyResult(matchList,matchCount,bonusResult); + } + return matchList; + } + +} diff --git a/src/main/java/View/InputData.java b/src/main/java/View/InputData.java new file mode 100644 index 00000000..31cd6432 --- /dev/null +++ b/src/main/java/View/InputData.java @@ -0,0 +1,15 @@ +package View; + +import Model.Lotto; + +public class InputData { + private InputData() { + } + public static int inputMoney = 0; + public static int handLotto = 0; + public static int autoLotto = 0; + public static Lotto firstLotto; + public static int bonus; + + public static int profit = 0; +} diff --git a/src/main/java/View/InputView.java b/src/main/java/View/InputView.java new file mode 100644 index 00000000..2891966b --- /dev/null +++ b/src/main/java/View/InputView.java @@ -0,0 +1,61 @@ +package View; + +import Creator.RandomNumberCreator; +import Model.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Collectors; + +import static Model.Constants.LOTTO_PRICE; + +public class InputView { + private static final Scanner sc = new Scanner(System.in); + public static int getInput() { + System.out.println("구입금액을 입력해 주세요."); + return sc.nextInt(); + } + public static int getHandLotto(Lottos lottos){ + System.out.println("수동으로 구매할 로또 수를 입력해 주세요."); + int numHand = sc.nextInt(); + sc.nextLine(); + handLotto(lottos, numHand); + + return numHand; + } + + private static void handLotto(Lottos lottos, int numHand) { + if (numHand > 0) System.out.println("수동으로 구매할 번호를 입력해 주세요."); + for (int i = 0; i < numHand; i++) { + ArrayList numbers = Arrays.stream(sc.nextLine().split(", ")) + .map(x -> new LottoNumber(Integer.parseInt(x))) + .collect(Collectors.toCollection(ArrayList::new)); + + lottos.addNewLotto(new Lotto(new LottoPrice(LOTTO_PRICE),numbers)); + } + } + + public static int getAutoLotto(Lottos lottos,int total){ + for (int i = 0; i < total; i++) { + Lotto lotto = new Lotto(new LottoPrice(1000), new LottoCreator(new RandomNumberCreator())); + ArrayList lottoNumbers = lotto.getLottoNumbers(); + lottos.addNewLotto(lotto); + } + return total; + } + + public static void inputFirstLotto(){ + System.out.println(); + System.out.println("지난 주 당첨 번호를 입력해 주세요."); + ArrayList numbers = Arrays.stream(sc.nextLine().split(", ")) + .map(x -> new LottoNumber(Integer.parseInt(x))) + .collect(Collectors.toCollection(ArrayList::new)); + InputData.firstLotto = new Lotto(new LottoPrice(LOTTO_PRICE),numbers); + System.out.println(); + System.out.println("보너스 볼을 입력해 주세요."); + InputData.bonus = sc.nextInt(); + } +} + diff --git a/src/main/java/View/ResultView.java b/src/main/java/View/ResultView.java new file mode 100644 index 00000000..bfee080b --- /dev/null +++ b/src/main/java/View/ResultView.java @@ -0,0 +1,31 @@ +package View; +import Model.*; + +import static View.InputData.bonus; +import static View.InputData.firstLotto; + +public class ResultView { + public static void printLottoResult(int hand, int auto, Lottos lottos) { + System.out.println("수동으로 " + hand + "장, 자동으로 " + auto + "개를 구매했습니다."); + lottos.getLottos() + .forEach(x -> System.out.println(x.getLottoNumbers() + .stream() + .map(LottoNumber::getNumber) + .sorted() + .toList())); + + } + public static void finalResult(Lottos lottos) { + printResults(lottos.matchList(firstLotto, bonus)); + } + + public static void printResults(int[] matchCounts) { + for (DataEnum.LottoResult rank : DataEnum.LottoResult.values()) { + int count = matchCounts[rank.ordinal()]; + System.out.printf("%d개 일치 (%d원)- %d개\n", rank.getMatches(), rank.getReward(), count); + } + double result = (double)InputData.profit / InputData.inputMoney; + System.out.printf("총 수익률은 %.2f입니다.\n",Math.floor(result * 100) / 100); + } + +} diff --git a/src/test/java/Model/LottoPriceTest.java b/src/test/java/Model/LottoPriceTest.java new file mode 100644 index 00000000..c1b893ec --- /dev/null +++ b/src/test/java/Model/LottoPriceTest.java @@ -0,0 +1,25 @@ +package Model; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public class LottoPriceTest { + + @Test + void 가격이_1000원_단위어야한다(){ + int price = 1557; + + Assertions.assertThatThrownBy(() -> { + LottoPrice price1 = new LottoPrice(price); + }).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 가격이_0원_미만이면_안된다(){ + int price = -10; + + Assertions.assertThatThrownBy(() -> { + LottoPrice price1 = new LottoPrice(price); + }).isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/src/test/java/Model/LottoTest.java b/src/test/java/Model/LottoTest.java new file mode 100644 index 00000000..bc7ca455 --- /dev/null +++ b/src/test/java/Model/LottoTest.java @@ -0,0 +1,32 @@ +package Model; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static Model.Constants.LOTTO_PRICE; + +public class LottoTest { + + @Test + void 로또가_잘_생성_돼야함(){ + int[] lottos = new int[]{1,2,3,4,5,6}; + ArrayList lottoNumbers = (ArrayList) Arrays.stream(lottos).mapToObj(LottoNumber::new).collect(Collectors.toList()); + Lotto lotto = new Lotto(new LottoPrice(LOTTO_PRICE),lottoNumbers); + + Assertions.assertThat(lotto.getLottoNumbers()).isEqualTo(lottoNumbers); + } + + @Test + void 로또가_가격이_잘_맞아야함(){ + int[] lottos = new int[]{1,2,3,4,5,6}; + ArrayList lottoNumbers = (ArrayList) Arrays.stream(lottos).mapToObj(LottoNumber::new).collect(Collectors.toList()); + Lotto lotto = new Lotto(new LottoPrice(LOTTO_PRICE),lottoNumbers); + + Assertions.assertThat(lotto.getPrice()).isEqualTo(LOTTO_PRICE); + } +} diff --git a/src/test/java/Model/LottoValidaterTest.java b/src/test/java/Model/LottoValidaterTest.java new file mode 100644 index 00000000..d09db085 --- /dev/null +++ b/src/test/java/Model/LottoValidaterTest.java @@ -0,0 +1,31 @@ +package Model; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.Collectors; + +public class LottoValidaterTest { + + @Test + void 로또_리스트에_중복이_있으면_안됨(){ + int[] lottos = new int[]{1,2,3,5,5,6}; + ArrayList lottoNumbers = (ArrayList) Arrays.stream(lottos).mapToObj(LottoNumber::new).collect(Collectors.toList()); + + Assertions.assertThatThrownBy(() -> { + Lotto lotto = new Lotto(new LottoPrice(Constants.LOTTO_PRICE),lottoNumbers); + }).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 로또_리스트가_6개여야만_한다(){ + int[] lottos = new int[]{1,2,3,5,6}; + ArrayList lottoNumbers = (ArrayList) Arrays.stream(lottos).mapToObj(LottoNumber::new).collect(Collectors.toList()); + + Assertions.assertThatThrownBy(() -> { + Lotto lotto = new Lotto(new LottoPrice(Constants.LOTTO_PRICE),lottoNumbers); + }).isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/src/test/java/Model/LottosTest.java b/src/test/java/Model/LottosTest.java new file mode 100644 index 00000000..ce657c61 --- /dev/null +++ b/src/test/java/Model/LottosTest.java @@ -0,0 +1,38 @@ +package Model; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.Collectors; + +public class LottosTest { + + @Test + void 매칭_결과를_잘_리턴해줘야함(){ + int[] lotto1 = new int[]{1,2,3,4,5,6}; + ArrayList lottoNumbers1 = (ArrayList) Arrays.stream(lotto1).mapToObj(LottoNumber::new).collect(Collectors.toList()); + Lotto lotto11 = new Lotto(new LottoPrice(Constants.LOTTO_PRICE),lottoNumbers1); + + int[] lotto2 = new int[]{4,5,6,7,8,9}; + ArrayList lottoNumbers2 = (ArrayList) Arrays.stream(lotto2).mapToObj(LottoNumber::new).collect(Collectors.toList()); + Lotto lotto22 = new Lotto(new LottoPrice(Constants.LOTTO_PRICE),lottoNumbers2); + + int[] lotto3 = new int[]{1,2,5,6,10,11}; + ArrayList lottoNumbers3 = (ArrayList) Arrays.stream(lotto3).mapToObj(LottoNumber::new).collect(Collectors.toList()); + Lotto lotto33 = new Lotto(new LottoPrice(Constants.LOTTO_PRICE),lottoNumbers3); + + Lottos lottos = new Lottos(); + lottos.addNewLotto(lotto11); + lottos.addNewLotto(lotto22); + lottos.addNewLotto(lotto33); + + int[] lotto4 = new int[]{1,2,5,15,16,17}; + ArrayList winnerLotto1 = (ArrayList) Arrays.stream(lotto4).mapToObj(LottoNumber::new).collect(Collectors.toList()); + + Lotto winnerLottos = new Lotto(new LottoPrice(Constants.LOTTO_PRICE),winnerLotto1); + Assertions.assertThat(lottos.matchList(winnerLottos,10)) + .isEqualTo(new int[]{2,0,0,0,0}); + } +}