diff --git a/src/main/java/Controller/Controller.java b/src/main/java/Controller/Controller.java new file mode 100644 index 00000000000..0cd0284dcb2 --- /dev/null +++ b/src/main/java/Controller/Controller.java @@ -0,0 +1,63 @@ +package Controller; + +import Enum.FixNum; +import Enum.Reward; +import Model.Lotto; +import Model.WinningNum; +import camp.nextstep.edu.missionutils.Randoms; + +import java.util.*; + + +public class Controller { + + // 로또 랜덤 넘버 뽑기 + private List random() { + List lottoList = new ArrayList<>(Randoms.pickUniqueNumbersInRange(FixNum.MIN_NUM.get(), FixNum.MAX_NUM.get(), FixNum.LIST_SIZE.get())); + Collections.sort(lottoList); + return lottoList; + } + + // 금액 만큼 로또 리스트 만들기 + public List lottoList(int quntity) { + List list = new ArrayList<>(); + for (int i = 0; i < quntity; i++) { + list.add(new Lotto(random())); + } + return list; + } + + // 상금을 카운트해서 넣을 Map + private Map resultList() { + Map result = new LinkedHashMap<>(); + + for (Reward reward : Reward.values()) { + result.put(reward, 0); + } + return result; + } + + // 상금에 해당하는 만큼 카운트 넣어주기 + public Map lottoResult(List lottoList, WinningNum winningLotto) { + Map result = resultList(); + Reward reward; + + for (int i = 0; i < lottoList.size(); i++) { + reward = winningLotto.match(lottoList.get(i)); + result.put(reward, result.get(reward) + 1); + } + + return result; + } + + // 수익률 + public double rateOfReturn(Map result, int quntity) { + double rateOfReturn = 0; + for (Reward reward : result.keySet()) { + rateOfReturn += ((double) (reward.getReward()) + / (quntity * FixNum.MIN_MONEY.get()) * (result.get(reward)) * (FixNum.PERCENTAGE.get())); + + } + return rateOfReturn; + } +} diff --git a/src/main/java/Enum/FixNum.java b/src/main/java/Enum/FixNum.java new file mode 100644 index 00000000000..d1104c4e58a --- /dev/null +++ b/src/main/java/Enum/FixNum.java @@ -0,0 +1,21 @@ +package Enum; + +public enum FixNum { + MIN_MONEY(1000), + LIST_SIZE(6), + MIN_NUM(1), + MAX_NUM(45), + PLUS_BONUS_NUM_SIZE(7), + WINNING_MIN_COUNT(3), + PERCENTAGE(100); + + private int value; + + FixNum(int value) { + this.value = value; + } + + public int get() { + return value; + } +} diff --git a/src/main/java/Enum/FixString.java b/src/main/java/Enum/FixString.java new file mode 100644 index 00000000000..80dbb483743 --- /dev/null +++ b/src/main/java/Enum/FixString.java @@ -0,0 +1,20 @@ +package Enum; + +public enum FixString { + ERROR("[ERROR]"), + START("구입금액을 입력해 주세요."), + BUY_LOTTO("개를 구매했습니다."), + USER_LOTTO("당첨 번호를 입력해 주세요."), + BONUS_NUM("보너스 번호를 입력해 주세요."), + RESULT("당첨 통계"); + + private String message; + + FixString(String message) { + this.message = message; + } + + public String get() { + return message; + } +} diff --git a/src/main/java/Enum/Reward.java b/src/main/java/Enum/Reward.java new file mode 100644 index 00000000000..07f6e4ffa21 --- /dev/null +++ b/src/main/java/Enum/Reward.java @@ -0,0 +1,52 @@ +package Enum; + +import View.Print; + +public enum Reward { + FIRST(6, 2_000_000_000, "6개 일치 (2,000,000,000원) - "), + SECOND(5, 30_000_000, "5개 일치, 보너스 볼 일치 (30,000,000원) - "), + THIRD(5, 1_500_000, "5개 일치 (1,500,000원) - "), + FOURTH(4, 50_000, "4개 일치 (50,000원) - "), + FIVETH(3, 5_000, "3개 일치 (5,000원) - "), + MISS(0, 0, ""); + + + private int count; + private int reward; + private String message; + + Reward(int count, int reward, String message) { + this.count = count; + this.reward = reward; + this.message = message; + } + + public int getReward() { + return reward; + } + + public static Reward valueResult(int count, boolean bonusMatch) { + if (count < FixNum.WINNING_MIN_COUNT.get()) { + return MISS; + } + + if (SECOND.count == count && bonusMatch) { + return SECOND; + } + + for (Reward reward : values()) { + if (reward.count == count && reward != SECOND) { + return reward; + } + } + + throw new IllegalArgumentException(FixString.ERROR.get()); + } + + public void printMessage(int count) { + if (this != MISS) { + Print.resultMessage(message, count); + } + } +} + diff --git a/src/main/java/Model/Lotto.java b/src/main/java/Model/Lotto.java new file mode 100644 index 00000000000..a9304a6fac9 --- /dev/null +++ b/src/main/java/Model/Lotto.java @@ -0,0 +1,64 @@ +package Model; + +import Enum.FixNum; +import View.Print; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class Lotto { + private final List numbers; + + public Lotto(List numbers) { + validate(numbers); + validateOver(numbers); + rangeValue(numbers); + Collections.sort(numbers); + this.numbers = numbers; + } + + private void validate(List numbers) { + if (numbers.size() != 6) { + throw new IllegalArgumentException(); + } + } + + public List getNumbers() { + return numbers; + } + + private void validateOver(List numbers) { + Set overCheck = new HashSet<>(); + for (int i = 0; i < numbers.size(); i++) { + overCheck.add(numbers.get(i)); + } + + if (overCheck.size() != FixNum.LIST_SIZE.get()) { + Print.error(); + throw new IllegalArgumentException(); + } + } + + public int countMatch(Lotto winningNum) { + return (int) numbers.stream(). + filter(winningNum::containNumber). + count(); + } + + public boolean containNumber(int number) { + return numbers.contains(number); + } + + private void rangeValue(List numbers) { + for (int i = 0; i < numbers.size(); i++) { + if (!(FixNum.MIN_NUM.get() <= numbers.get(i) && numbers.get(i) <= FixNum.MAX_NUM.get())) { + Print.error(); + throw new IllegalArgumentException(); + } + } + } + + // TODO: 추가 기능 구현 +} diff --git a/src/main/java/Model/Money.java b/src/main/java/Model/Money.java new file mode 100644 index 00000000000..25b96c63291 --- /dev/null +++ b/src/main/java/Model/Money.java @@ -0,0 +1,46 @@ +package Model; + +import Enum.FixNum; +import View.Print; + +public class Money { + private int money; + + public Money(String money) { + int moneyMum = validateNm(money); + validateMoney(moneyMum); + this.money = moneyMum; + } + + public int quantity() { + return money / FixNum.MIN_MONEY.get(); + } + + private void validateMoney(int money) { + isvalidateNum(money); + validateDivide(money); + } + + private static int validateNm(String money) { + try { + return Integer.parseInt(money); + } catch (NumberFormatException e) { + Print.error(); + throw new IllegalArgumentException(); + } + } + + private void isvalidateNum(int money) { + if (money <= 0) { + Print.error(); + throw new IllegalArgumentException(); + } + } + + private void validateDivide(int money) { + if (money % FixNum.MIN_MONEY.get() != 0) { + Print.error(); + throw new IllegalArgumentException(); + } + } +} diff --git a/src/main/java/Model/WinningNum.java b/src/main/java/Model/WinningNum.java new file mode 100644 index 00000000000..b409006d802 --- /dev/null +++ b/src/main/java/Model/WinningNum.java @@ -0,0 +1,56 @@ +package Model; + +import Enum.FixNum; +import Enum.Reward; +import View.Print; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class WinningNum { + private Lotto winningNum; + private int bonusNum; + + public WinningNum(String winningLotto, String inputBonusNum) { + this.winningNum = new Lotto(makeWinningNum(winningLotto)); + this.bonusNum = validateDuplicate(winningNum, inputBonusNum); + } + + public Reward match(Lotto randomNums) { + int count = randomNums.countMatch(winningNum); + boolean bonusCheck = randomNums.containNumber(bonusNum); + return Reward.valueResult(count, bonusCheck); + } + + private List makeWinningNum(String winningLotto) { + List winLotto = new ArrayList<>(); + try { + String[] temp = winningLotto.split(","); + for (String s : temp) { + winLotto.add(Integer.parseInt(s)); + } + } catch (NumberFormatException e) { + Print.error(); + throw new IllegalArgumentException(); + } + return winLotto; + } + + private int validateDuplicate(Lotto winningLotto, String inputBonusNum) { + Set duplicateCheck = new HashSet<>(winningLotto.getNumbers()); + try { + duplicateCheck.add(Integer.parseInt(inputBonusNum)); + + if (duplicateCheck.size() != FixNum.PLUS_BONUS_NUM_SIZE.get()) { + Print.error(); + throw new IllegalArgumentException(); + } + } catch (IllegalArgumentException e) { + Print.error(); + throw new IllegalArgumentException(); + } + return Integer.parseInt(inputBonusNum); + } +} diff --git a/src/main/java/View/Input.java b/src/main/java/View/Input.java new file mode 100644 index 00000000000..acc64334fb7 --- /dev/null +++ b/src/main/java/View/Input.java @@ -0,0 +1,27 @@ +package View; + +import camp.nextstep.edu.missionutils.Console; + +public class Input { + + public static String inputMoney() { + return Console.readLine(); + } + + public static String inputWinLottoNum() { + String winingNum = Console.readLine(); + isvalidateInput(winingNum); + return winingNum; + } + + public static String inputBonusNum() { + return Console.readLine(); + } + + private static void isvalidateInput(String winingNum) { + if (winingNum.contains("\"") || winingNum.contains(",,")) { + Print.error(); + throw new IllegalArgumentException(); + } + } +} diff --git a/src/main/java/View/Print.java b/src/main/java/View/Print.java new file mode 100644 index 00000000000..574da3b70bb --- /dev/null +++ b/src/main/java/View/Print.java @@ -0,0 +1,39 @@ +package View; + +import Enum.FixString; + +public class Print { + + public static void start() { + System.out.println(FixString.START.get()); + } + + public static void error() { + System.out.println(FixString.ERROR.get()); + } + + public static void buyLotto(int quntity) { + System.out.println(quntity + FixString.BUY_LOTTO.get()); + } + + public static void userLotto() { + System.out.println(FixString.USER_LOTTO.get()); + } + + public static void bonusNum() { + System.out.println(FixString.BONUS_NUM.get()); + } + + public static void result() { + System.out.println(FixString.RESULT.get()); + System.out.println("---"); + } + + public static void resultMessage(String message, int count) { + System.out.println(message + count + "개"); + } + + public static void printRevenueRate(double EarningRate) { + System.out.println("총 수익률은 " + String.format("%.1f", EarningRate) + "%입니다."); + } +} diff --git a/src/main/java/View/Result.java b/src/main/java/View/Result.java new file mode 100644 index 00000000000..cb988e2e31d --- /dev/null +++ b/src/main/java/View/Result.java @@ -0,0 +1,65 @@ +package View; + +import Controller.Controller; +import Enum.Reward; +import Model.Lotto; +import Model.Money; +import Model.WinningNum; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class Result { + private List lottoList = new ArrayList<>(); + private Controller controller = new Controller(); + + public void run() { + try { + start(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + } + + private void start() { + Print.start(); + Money money = new Money(Input.inputMoney()); + + Print.buyLotto(money.quantity()); + + lottoList = controller.lottoList(money.quantity()); + printLottoList(lottoList, money.quantity()); + + Print.userLotto(); + String winningNums = Input.inputWinLottoNum(); + Print.bonusNum(); + String bonus = Input.inputBonusNum(); + WinningNum winningNum = new WinningNum(winningNums, bonus); + + lottoResult(winningNum, money.quantity()); + } + + private void lottoResult(WinningNum winningNum, int quntity) { + Print.result(); + Map result = controller.lottoResult(lottoList, winningNum); + printResult(result); + + double rateOfReturn = controller.rateOfReturn(result, quntity); + Print.printRevenueRate(rateOfReturn); + } + + private void printLottoList(List list, int quntity) { + for (Lotto lotto : list) { + System.out.println(lotto.getNumbers()); + } + } + + // lottoResult 출력하기 + private void printResult(Map result) { + for (int i = Reward.values().length - 1; i >= 0; i--) { + Reward.values()[i].printMessage(result.get(Reward.values()[i])); + } + } + +} diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index d190922ba44..dd47d21f04e 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,7 +1,11 @@ package lotto; +import View.Result; + public class Application { public static void main(String[] args) { // TODO: 프로그램 구현 + Result result = new Result(); + result.run(); } } diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java deleted file mode 100644 index 519793d1f73..00000000000 --- a/src/main/java/lotto/Lotto.java +++ /dev/null @@ -1,20 +0,0 @@ -package lotto; - -import java.util.List; - -public class Lotto { - private final List numbers; - - public Lotto(List numbers) { - validate(numbers); - this.numbers = numbers; - } - - private void validate(List numbers) { - if (numbers.size() != 6) { - throw new IllegalArgumentException(); - } - } - - // TODO: 추가 기능 구현 -} diff --git a/src/test/java/lotto/ApplicationTest.java b/src/test/java/java/lotto/ApplicationTest.java similarity index 100% rename from src/test/java/lotto/ApplicationTest.java rename to src/test/java/java/lotto/ApplicationTest.java diff --git a/src/test/java/java/lotto/ControllerTest.java b/src/test/java/java/lotto/ControllerTest.java new file mode 100644 index 00000000000..b9467707d84 --- /dev/null +++ b/src/test/java/java/lotto/ControllerTest.java @@ -0,0 +1,58 @@ +package lotto; + +import Controller.Controller; +import Enum.Reward; +import Model.Lotto; +import Model.WinningNum; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ControllerTest { + private Controller controller = new Controller(); + + @DisplayName("로또 리스트가 입력한 금액에 갯수만큼 만들어질때") + @Test + void WhenLottoListNotCreatedByInputMoney() { + Controller controller = new Controller(); + List lottoList = controller.lottoList(5); + assertThat(lottoList.size()).isEqualTo(5); + } + + @DisplayName("당첨금 횟수 세기") + @Test + void lottoResult() { + List lottoList = List.of( + new Lotto(new ArrayList<>(List.of(1, 2, 3, 4, 5, 6))), + new Lotto(new ArrayList<>(List.of(4, 5, 6, 7, 8, 9))), + new Lotto(new ArrayList<>(List.of(7, 8, 9, 10, 11, 12))) + ); + WinningNum winningNum = new WinningNum("1,2,3,4,5,6", "7"); + + Map result = new HashMap<>(); + result.put(Reward.FIRST, 1); + result.put(Reward.SECOND, 0); + result.put(Reward.THIRD, 0); + result.put(Reward.FOURTH, 0); + result.put(Reward.FIVETH, 1); + result.put(Reward.MISS, 1); + + assertEquals(result, controller.lottoResult(lottoList, winningNum)); + } + + @DisplayName("수익률 계산") + @Test + void rateOfReturn() { + Map result = new HashMap<>(); + result.put(Reward.FIRST, 1); + + assertEquals(2.0E8, controller.rateOfReturn(result, 1)); + } +} diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/java/lotto/LottoTest.java similarity index 58% rename from src/test/java/lotto/LottoTest.java rename to src/test/java/java/lotto/LottoTest.java index 9f5dfe7eb83..e19ec6f625e 100644 --- a/src/test/java/lotto/LottoTest.java +++ b/src/test/java/java/lotto/LottoTest.java @@ -1,11 +1,14 @@ package lotto; +import Model.Lotto; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; class LottoTest { @DisplayName("로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.") @@ -23,5 +26,13 @@ void createLottoByDuplicatedNumber() { .isInstanceOf(IllegalArgumentException.class); } - // 아래에 추가 테스트 작성 가능 + @DisplayName("로또 번호와 당첨 번호 조회해서 맞은 갯수세기") + @Test + void countMatch() { + Lotto lotto = new Lotto((new ArrayList<>(List.of(1, 2, 3, 4, 5, 6)))); + + assertEquals(6, lotto.countMatch(new Lotto(new ArrayList<>(List.of(1, 2, 3, 4, 5, 6))))); + assertEquals(5, lotto.countMatch(new Lotto(new ArrayList<>(List.of(1, 2, 3, 4, 5, 7))))); + assertEquals(0, lotto.countMatch(new Lotto(new ArrayList<>(List.of(7, 8, 9, 10, 11, 12))))); + } } \ No newline at end of file diff --git a/src/test/java/java/lotto/MoneyTest.java b/src/test/java/java/lotto/MoneyTest.java new file mode 100644 index 00000000000..f3b89cf518f --- /dev/null +++ b/src/test/java/java/lotto/MoneyTest.java @@ -0,0 +1,30 @@ +package lotto; + +import Model.Money; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class MoneyTest { + + @DisplayName("입력한 금액이 숫자가 아닐때") + @Test + void inputMoneyNotNum() { + Assertions.assertThatThrownBy(() -> new Money("가나다")) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("입력한 금액이 음수 일때") + @Test + void inputMoneyNegative() { + Assertions.assertThatThrownBy(() -> new Money("-1000")) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("입력한 금액이 1000의 배수가 아닐때") + @Test + void inputMoneyNotMultiplesOf1000() { + Assertions.assertThatThrownBy(() -> new Money("1500")) + .isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/src/test/java/java/lotto/WinningNumTest.java b/src/test/java/java/lotto/WinningNumTest.java new file mode 100644 index 00000000000..b392bf72a3e --- /dev/null +++ b/src/test/java/java/lotto/WinningNumTest.java @@ -0,0 +1,29 @@ +package lotto; + +import Model.WinningNum; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class WinningNumTest { + @DisplayName("당첨 번호의 개수가 6개가 넘어가면 예외가 발생한다.") + @Test + void WinningNum_ByOver_Size() { + Assertions.assertThatThrownBy(() -> new WinningNum("1, 2, 3, 4, 5, 6, 7", "8")) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("당첨 번호에 중복된 숫자가 있으면 예외가 발생한다.") + @Test + void winningNumByDuplicatedNumber() { + Assertions.assertThatThrownBy(() -> new WinningNum("1, 2, 3, 4, 5, 5", "8")) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("당첨 번호와 보너스 번호가 중복된 숫자가 있으면 예외가 발생한다.") + @Test + void winningNumAndBonusNumByDuplicated() { + Assertions.assertThatThrownBy(() -> new WinningNum("1, 2, 3, 4, 5, 6", "6")) + .isInstanceOf(IllegalArgumentException.class); + } +}