diff --git a/build.gradle b/build.gradle index 99385f2..836b96b 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,9 @@ repositories { } dependencies { + implementation 'com.github.woowacourse-projects:mission-utils:1.0.0' + + implementation 'com.github.kokodak:mission-utils:1.0.0' implementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' @@ -15,6 +18,7 @@ dependencies { implementation 'org.mockito:mockito-inline:3.12.4' implementation 'org.assertj:assertj-core:3.21.0' implementation 'org.junit.jupiter:junit-jupiter:5.8.1' + } java { @@ -23,6 +27,8 @@ java { } } + test { useJUnitPlatform() } + diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index d190922..cbf7603 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,7 +1,90 @@ package lotto; +import lotto.controller.LottoController; + +import java.util.Scanner; + public class Application { + public static void main(String[] args) { + LottoController lottoController = new LottoController(); + lottoController.run(); + + // TODO: 프로그램 구현 + } } + + + + + + + + + +// +//package lotto; +// +//import org.kokodak.Randoms; +//import org.kokodak.Console; +// +// +// +//public class Application { +// public static void main(String[] args) { +// // TODO: 프로그램 구현 +// +// int[] lotto = new int[6]; +// Randoms randoms = new Randoms; +// +// Lotto(randoms.in); +// +// int money; +// int bonus_number; +// +// +// +// +// System.out.print("구입 금액을 입력하세요: "); +// +// System.out.println("당첨 번호를 입력하세요(쉼표로 구분): "); +// +// System.out.println("보너스 번호를 입력하세요: "); +// +// +// +// +// +// +// +// +// for (int i = 0; i < lotto.length; i++) { +// lotto[i] = random.nextInt(45) + 1; +// // 중복번호 제거 +// for(int j = 0; j < i; j++) { +// if(lotto[i] == lotto[j]) { +// i--; +// break; +// } +// } +// } +// +// // 오름차순 정렬 +// for(int i = 0; i < lotto.length; i++) { +// for(int j = i + 1; j < lotto.length; j++) { +// if(lotto[i] > lotto[j]) { +// int temp = lotto[i]; +// lotto[i] = lotto[j]; +// lotto[j] = temp; +// } +// } +// } +// +// // 랜덤번호 출력 +// System.out.println("* 로또번호 : " + Arrays.toString(lotto)); +// +// +// } +//} diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java index 519793d..df35d78 100644 --- a/src/main/java/lotto/Lotto.java +++ b/src/main/java/lotto/Lotto.java @@ -1,20 +1,20 @@ -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: 추가 기능 구현 -} +//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/main/java/lotto/domain/Lotto.java b/src/main/java/lotto/domain/Lotto.java new file mode 100644 index 0000000..2fc85db --- /dev/null +++ b/src/main/java/lotto/domain/Lotto.java @@ -0,0 +1,59 @@ +package lotto.domain; + +import lotto.view.ExceptionMessage; + +import java.util.*; + +public class Lotto { + private static final int minNumber = 1; + private static final int maxNumber = 45; + private final List numbers; + public Lotto(List numbers){ + validate(numbers); + validateOverlap(numbers); + validateRange(numbers); + + Collections.sort(numbers); + this.numbers = numbers; + } + public List getLottoNumbers(){ + return numbers; + } + public int countMatch(Lotto winLotto){ + return (int) numbers.stream().filter(winLotto::containNumber).count(); + } + public boolean containNumber(int number){ + return numbers.contains(number); + } + private void validate(List numbers){ + if(numbers.size() != 6){ + ExceptionMessage.sizeException(); + throw new IllegalArgumentException(); + } + } + private void validateOverlap(List numbers){ + Set overlapCheck = new HashSet<>(); + for (int i = 0; i< numbers.size();i++){ + overlapCheck.add(numbers.get(i)); + } + if (overlapCheck.size() != 6){ + ExceptionMessage.overlapException(); + throw new IllegalArgumentException(); + } + } + private void validateRange(List numbers){ + for (int winNumber = 0;winNumber maxNumber){ + ExceptionMessage.rangeException(); + throw new IllegalArgumentException(); + } + } + } + public static void validateBonusNumber(List numbers, int bonusNumber){ + if (numbers.contains(bonusNumber)){ + ExceptionMessage.overlapException(); + throw new IllegalArgumentException(); + } + } + +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/LottoNumbers.java b/src/main/java/lotto/domain/LottoNumbers.java new file mode 100644 index 0000000..4315cd1 --- /dev/null +++ b/src/main/java/lotto/domain/LottoNumbers.java @@ -0,0 +1,22 @@ +package lotto.domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import camp.nextstep.edu.missionutils.Randoms; + +public class LottoNumbers { + public LottoNumbers(){ + + } + private static final int cntLottoNumber = 6; + private static final int minLottoNumber = 1; + private static final int maxLottoNumber = 45; + private static List lottoNumberList; + public static List setRandomNumbers(){ + lottoNumberList = Randoms.pickUniqueNumbersInRange(minLottoNumber,maxLottoNumber,cntLottoNumber); + List lottoTicketNumberList = new ArrayList<>(lottoNumberList); + Collections.sort(lottoTicketNumberList); + return lottoTicketNumberList; + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/PlayerLottoAmount.java b/src/main/java/lotto/domain/PlayerLottoAmount.java new file mode 100644 index 0000000..cf4f648 --- /dev/null +++ b/src/main/java/lotto/domain/PlayerLottoAmount.java @@ -0,0 +1,39 @@ +package lotto.domain; +import lotto.view.ExceptionMessage; + +public class PlayerLottoAmount { + private static final int lottoPrice = 1000; + private final int coin; + public PlayerLottoAmount(String coin){ + int coinNum = validateNumber(coin); + validateCoin(coinNum); + this.coin = coinNum; + } + public int calcLottoCount(){ + return coin / lottoPrice; + } + private void validateCoin(int coin){ + validateNatural(coin); + validateDivisible(coin); + } + private static int validateNumber(String coin) throws IllegalArgumentException{ + try{ + return Integer.parseInt(coin); + } catch (NumberFormatException e){ + ExceptionMessage.numberException(); + throw new IllegalArgumentException(); + } + } + private void validateNatural(int coin){ + if (coin <= 0) { + ExceptionMessage.naturalException(); + throw new IllegalArgumentException(); + } + } + private void validateDivisible(int coin){ + if (coin % lottoPrice != 0){ + ExceptionMessage.divisibleException(); + throw new IllegalArgumentException(); + } + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/Ranking.java b/src/main/java/lotto/domain/Ranking.java new file mode 100644 index 0000000..4cd4c45 --- /dev/null +++ b/src/main/java/lotto/domain/Ranking.java @@ -0,0 +1,57 @@ +package lotto.domain; + +import lotto.view.OutputView; + +public enum Ranking { + 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원) - "), + fifth(3,5_000, "3개 일치 (5,000원) - "), + miss(0,0,""); + + public int getMatchCount() { + return matchCount; + } + + public int getWinAmount() { + return winAmount; + } + private boolean counter(int matchCount){ + return this.matchCount == matchCount; + } + public void printMessage(int cnt){ + if (this!=miss){ + OutputView.printSuccessMessage(message,cnt); + } + } + + + Ranking(int matchCount, int winAmount, String message){ + this.matchCount = matchCount; + this.winAmount = winAmount; + this.message = message; + } + private static final int winMinCount = 3; + private static final String errorMessage = "[ERROR]"; + + private int matchCount; + private int winAmount; + private String message; + public static Ranking valueOf(int matchCount,boolean matchBonus){ + if (matchCount < winMinCount){ + return miss; + } + if (second.counter(matchCount) && matchBonus){ + return second; + } + for (Ranking rank : values()){ + if (rank.counter(matchCount)&&rank != second){ + return rank; + } + } + throw new IllegalArgumentException(errorMessage); + } + +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/WinResult.java b/src/main/java/lotto/domain/WinResult.java new file mode 100644 index 0000000..6615e74 --- /dev/null +++ b/src/main/java/lotto/domain/WinResult.java @@ -0,0 +1,15 @@ +package lotto.domain; + +public class WinResult { + private final Lotto lotto; + private final int bonus; + public WinResult(Lotto lotto,int bonus){ + this.lotto = lotto; + this.bonus = bonus; + } + public Ranking match(Lotto playername){ + int matchCount = playername.countMatch(lotto); + boolean bonusCheck = playername.containNumber(bonus); + return Ranking.valueOf(matchCount,bonusCheck); + } +} \ No newline at end of file diff --git a/src/main/java/lotto/view/ExceptionMessage.java b/src/main/java/lotto/view/ExceptionMessage.java new file mode 100644 index 0000000..65b2f11 --- /dev/null +++ b/src/main/java/lotto/view/ExceptionMessage.java @@ -0,0 +1,43 @@ +package lotto.view; + +public class ExceptionMessage { + private static final int MIN_NUMBER = 1; + private static final int MAX_NUMBER = 45; + private static final String NOT_NUMBER_RANGE = "[ERROR] 숫자는 " + MIN_NUMBER + "부터 " + MAX_NUMBER + " 사이의 숫자여야 합니다."; + private static final String NOT_NUMBER_SIZE = "[ERROR] 당첨 번호는 6개 입력 가능합니다."; + private static final String NOT_NUMBER_OVERLAP = "[ERROR] 중복된 숫자를 입력하셨습니다."; + private static final String INPUT_TYPE_ERROR = "[ERROR] 숫자만 입력해 주세요."; + private static final int LOTTO_MIN_AMOUNT = 1000; + private static final String NOT_NUMBER_ERROR = "[ERROR] 금액은 숫자만 등록 가능합니다."; + private static final String NOT_NATURAL_NUMBER_ERROR = "[ERROR] 금액은 0 초과이어야 합니다."; + private static final String NOT_DIVISIBLE_NUMBER_ERROR = "[ERROR] 금액은 " + LOTTO_MIN_AMOUNT + "단위여야 합니다."; + + public static void rangeException() { + System.out.println(NOT_NUMBER_RANGE); + } + + public static void sizeException() { + System.out.println(NOT_NUMBER_SIZE); + } + + public static void overlapException() { + System.out.println(NOT_NUMBER_OVERLAP); + } + + public static void typeException() { + System.out.println(INPUT_TYPE_ERROR); + } + + public static void numberException() { + System.out.println(NOT_NUMBER_ERROR); + } + + public static void naturalException() { + System.out.println(NOT_NATURAL_NUMBER_ERROR); + } + + public static void divisibleException() { + System.out.println(NOT_DIVISIBLE_NUMBER_ERROR); + } + +} \ No newline at end of file diff --git a/src/main/java/lotto/view/InputView.java b/src/main/java/lotto/view/InputView.java new file mode 100644 index 0000000..0815e1c --- /dev/null +++ b/src/main/java/lotto/view/InputView.java @@ -0,0 +1,48 @@ +package lotto.view; + +import org.kokodak.Console; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class InputView { + private static final String INPUT_LOTTO_AMOUNT = "구입금액을 입력해 주세요."; + private static final String INPUT_LOTTO_WINNING = "당첨 번호를 입력해 주세요."; + private static final String INPUT_BONUS_NUMBER = "보너스 번호를 입력해 주세요."; + + private static List winningNumberList; + + public static String inputPlayerAmount() { + System.out.println(INPUT_LOTTO_AMOUNT); + return Console.readLine(); + } + + public static List inputLottoWinningNum() { + System.out.println(INPUT_LOTTO_WINNING); + return numberList(Console.readLine()); + } + + public static int inputBonusNumber() { + System.out.println(INPUT_BONUS_NUMBER); + return Integer.parseInt(Console.readLine()); + } + + public static List numberList(String winningNumber) { + String[] result = winningNumber.split(","); + winningNumberList = new ArrayList<>(); + for (int i = 0; i < result.length; i++) { + winningNumberList.add(conventToInt(result[i])); + } + return winningNumberList; + } + + private static int conventToInt(String inputNumber) { + try { + return Integer.parseInt(inputNumber); + } catch (NumberFormatException e) { + ExceptionMessage.typeException(); + throw new IllegalArgumentException(); + } + } +} \ No newline at end of file diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java new file mode 100644 index 0000000..55a291a --- /dev/null +++ b/src/main/java/lotto/view/OutputView.java @@ -0,0 +1,22 @@ +package lotto.view; + +public class OutputView { + public static final String TICKET_COUNT = "개를 구매했습니다."; + + public static void printTicketCount(int count) { + System.out.println(count + TICKET_COUNT); + } + + public static void printSuccessResult() { + System.out.println("당첨 통계"); + System.out.println("---"); + } + + public static void printSuccessMessage(String message, int numberOfMatch) { + System.out.println(message + numberOfMatch + "개"); + } + + public static void printRevenueRate(double EarningRate) { + System.out.println("총 수익률은 " + String.format("%.1f", EarningRate) + "%입니다."); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/ApplicationTest.java b/src/test/java/lotto/ApplicationTest.java index 404cbe1..4dcf5b1 100644 --- a/src/test/java/lotto/ApplicationTest.java +++ b/src/test/java/lotto/ApplicationTest.java @@ -1,12 +1,13 @@ package lotto; -import static org.assertj.core.api.Assertions.assertThat; -import static org.kokodak.test.Assertions.assertRandomUniqueNumbersInRangeTest; -import static org.kokodak.test.Assertions.assertSimpleTest; +import camp.nextstep.edu.missionutils.test.NsTest; +import org.junit.jupiter.api.Test; import java.util.List; -import org.junit.jupiter.api.Test; -import org.kokodak.test.NsTest; + +import static camp.nextstep.edu.missionutils.test.Assertions.assertRandomUniqueNumbersInRangeTest; +import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest; +import static org.assertj.core.api.Assertions.assertThat; class ApplicationTest extends NsTest { private static final String ERROR_MESSAGE = "[ERROR]"; @@ -32,7 +33,7 @@ class ApplicationTest extends NsTest { "5개 일치, 보너스 볼 일치 (30,000,000원) - 0개", "6개 일치 (2,000,000,000원) - 0개", "총 수익률은 62.5%입니다." - ); + ); }, List.of(8, 21, 23, 41, 42, 43), List.of(3, 5, 11, 16, 32, 38), @@ -42,7 +43,7 @@ class ApplicationTest extends NsTest { List.of(7, 11, 30, 40, 42, 43), List.of(2, 13, 22, 32, 38, 45), List.of(1, 3, 5, 14, 22, 45) - ); + ); } @Test @@ -57,4 +58,4 @@ class ApplicationTest extends NsTest { public void runMain() { Application.main(new String[]{}); } -} +} \ No newline at end of file diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/LottoTest.java index 14ed50f..1d9cc61 100644 --- a/src/test/java/lotto/LottoTest.java +++ b/src/test/java/lotto/LottoTest.java @@ -1,11 +1,15 @@ -package lotto; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import java.util.List; +package lotto; + +import lotto.domain.Lotto; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + class LottoTest { @DisplayName("로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.") @Test @@ -17,10 +21,56 @@ void createLottoByOverSize() { @DisplayName("로또 번호에 중복된 숫자가 있으면 예외가 발생한다.") @Test void createLottoByDuplicatedNumber() { - // TODO: 이 테스트가 통과할 수 있게 구현 코드 작성 assertThatThrownBy(() -> new Lotto(List.of(1, 2, 3, 4, 5, 5))) .isInstanceOf(IllegalArgumentException.class); } - // 아래에 추가 테스트 작성 가능 + @DisplayName("보너스 번호에 중복된 숫자가 있으면 예외가 발생한다.") + @Test + void createBonusNumberByDuplicated() { + assertThatThrownBy(() -> Lotto.validateBonusNumber(List.of(1, 2, 3, 4, 5, 6), 6)) + .isInstanceOf(IllegalArgumentException.class); + } + } + + + + + + + + + + + + + + + +//package lotto; +// +//import static org.assertj.core.api.Assertions.assertThatThrownBy; +// +//import java.util.List; +//import org.junit.jupiter.api.DisplayName; +//import org.junit.jupiter.api.Test; +// +//class LottoTest { +// @DisplayName("로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.") +// @Test +// void createLottoByOverSize() { +// assertThatThrownBy(() -> new Lotto(List.of(1, 2, 3, 4, 5, 6, 7))) +// .isInstanceOf(IllegalArgumentException.class); +// } +// +// @DisplayName("로또 번호에 중복된 숫자가 있으면 예외가 발생한다.") +// @Test +// void createLottoByDuplicatedNumber() { +// // TODO: 이 테스트가 통과할 수 있게 구현 코드 작성 +// assertThatThrownBy(() -> new Lotto(List.of(1, 2, 3, 4, 5, 5))) +// .isInstanceOf(IllegalArgumentException.class); +// } +// +// // 아래에 추가 테스트 작성 가능 +//} diff --git a/src/test/java/lotto/domain/LottoNumbersTest.java b/src/test/java/lotto/domain/LottoNumbersTest.java new file mode 100644 index 0000000..ec2497f --- /dev/null +++ b/src/test/java/lotto/domain/LottoNumbersTest.java @@ -0,0 +1,23 @@ +package lotto.domain; + +import camp.nextstep.edu.missionutils.test.NsTest; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static camp.nextstep.edu.missionutils.test.Assertions.assertRandomUniqueNumbersInRangeTest; +import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest; +import static org.assertj.core.api.Assertions.assertThat; + +class LottoNumbersTest { + + private static List lottoNumberList; + + @Test + void 로또_랜덤숫자_생성() { + LottoNumbers lottoNumbers = new LottoNumbers(); + lottoNumberList = lottoNumbers.setRandomNumbers(); + + assertThat(lottoNumberList.size()).isEqualTo(6); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/domain/PlayerLottoAmountTest.java b/src/test/java/lotto/domain/PlayerLottoAmountTest.java new file mode 100644 index 0000000..df5ded9 --- /dev/null +++ b/src/test/java/lotto/domain/PlayerLottoAmountTest.java @@ -0,0 +1,31 @@ +package lotto.domain; + +import org.junit.jupiter.api.DisplayName; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThat; + +class PlayerLottoAmountTest { + + + @ParameterizedTest + @ValueSource(strings = {"1000j", "1100", "-1"}) + @DisplayName("올바르지 않은 금액") + void failed(String inputAmount) { + assertThatThrownBy(() -> new PlayerLottoAmount(inputAmount)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + @DisplayName("구매한 로또 티켓 장수") + void calcLottoCount() { + PlayerLottoAmount amount = new PlayerLottoAmount("1000"); + assertThat(amount.calcLottoCount()).isEqualTo(1); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/domain/WinningResultTest.java b/src/test/java/lotto/domain/WinningResultTest.java new file mode 100644 index 0000000..a52f3dd --- /dev/null +++ b/src/test/java/lotto/domain/WinningResultTest.java @@ -0,0 +1,35 @@ +package lotto.domain; + +import java.util.ArrayList; +import java.util.Arrays; +import org.junit.jupiter.api.DisplayName; + +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThat; + +class WinningResultTest { + + @ParameterizedTest + @CsvSource(value = {"1,2,3,4,5,6:FIRST", "1,2,3,4,5,7:SECOND", "1,2,3,4,5,8:THIRD", "1,2,3,4,8,10:FOURTH", + "1,2,3,8,9,10:FIFTH", "1,2,8,9,10,11:MISS"}, delimiter = ':') + @DisplayName("사용자가 구매한 로또 번호와 당첨번호를 비교해 등수 확인") + void compare(String input, Ranking ranking) { + String[] list = input.split(","); + List ticketNumberList = new ArrayList<>(); + for (int i = 0; i < list.length; i++) { + ticketNumberList.add(Integer.parseInt(list[i])); + } + Lotto lottoList = new Lotto(ticketNumberList); + Lotto lotto = new Lotto(Arrays.asList(1, 2, 3, 4, 5, 6)); + int bonusball = 7; + WinResult winningResult = new WinResult(lotto, bonusball); + + + assertThat(winningResult.match(lottoList)).isEqualTo(ranking); + } +} \ No newline at end of file