diff --git a/build.gradle b/build.gradle index 99385f2..62f73d5 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,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 { diff --git a/src/main/java/controller/LottoController.java b/src/main/java/controller/LottoController.java new file mode 100644 index 0000000..13b4831 --- /dev/null +++ b/src/main/java/controller/LottoController.java @@ -0,0 +1,114 @@ +package controller; + +import domain.*; +import view.*; + + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + + + + +public class LottoController { + private static final int TICKET_PRICE = 1000;//로또 개당 가격 + private static final int PERCENTAGE = 100;//추후 성공률 계산에 이용 + + private static PlayerLottoAmount playerLottoAmount;//금액을 받고 로또를 할 수 있는 금액인지 적합성 검사 후 발행할 로또 개수 + //정해줌 + private static List lotto = new ArrayList<>(); + private static List lottoList;//로또들을 발행한 개수 만큼 리스트에 저장 + private static WinningResult winningResult;//당첨 로또 번호 6개와 와 보너스 번호 1개를 가지고 있는 객체, 추후 가지고 있는 + //로또(리스트)들과 당첨 로또 간의 비교를 한 후 Ranking enum 반환 할 예정 + public void run() { + start(); + return; + } + public void start(){ + int ticketCount = inputPlayerAmount();//발행할 로또 개수 + OutputView.printTicketCount(ticketCount);//로또 개수 출략 + lottoList = makeLottoList(ticketCount);//로또 개수 만큼의 리스트 배열 생성 + winningResult = validateBonus(); + lottoResult(lottoList, winningResult, ticketCount); + + + } + public int inputPlayerAmount(){ + playerLottoAmount = new PlayerLottoAmount(InputView.inputPlayerAmount()); + return playerLottoAmount.calculateLottoCount(); + + } + public WinningResult validateBonus(){ + Lotto lotto = new Lotto(InputView.inputLottoWinningNum()); + ListwinningList = lotto.getLottoNumbers(); + int ball = InputView.inputBonusNumber(); + lotto.validateBonusNumber(winningList, ball); + + + return new WinningResult(lotto, ball); + + } + + + public ListmakeLottoList(int ticketCount){ + lottoList = new ArrayList<>(); + for(int i = 0; i < ticketCount; i++){ + lottoList.add(makeLotto());//로또 개수만큼 로또 내부 리스트 생성(6개) 후 해당 로또를 lottoList에 저장함 + + } + return lottoList;//저장 후 결과 값 반환 + } + + private static Lotto makeLotto(){//로또 만드는 과정은 외부에서 접근하지 못하도록(랜덤하게 made) private 접근 제한자 사용 + LottoNumbers lottoNumbers = new LottoNumbers(); + lotto = lottoNumbers.setRandomLottos();//랜덤하게 로또 만들어 리스트 형태로 반환해 lotto에 넘겨줌 + System.out.println(lotto); + return new Lotto(lotto); + } + + public void lottoResult(ListlottoList, WinningResult winningResult, int ticketCount){ + Mapresult = setResult();//map 초기화 작업 진행 key에는 Ranking values() 각각 넣고 value는 0으로 초기화 + Ranking r; + + OutputView.printSuccessResult(); + for(int i = 0; i < lottoList.size(); i++){ + r = winningResult.match(lottoList.get(i));//lottoList에 들어있는 로또 하나씩을 꺼내서 당첨 로또와 유사성 비교 후 + //적절한 Ranking Enum 객체를 반환해주는 역할 수행 + result.put(r, result.get(r) + 1);//헤당 enum 객체와 그 수량을 하나 증가시켜서 map에 put해줌 + } + printResult(result);//결과를 map으로 출력 + printEarningRate(result, ticketCount);//수익률 계산하는 메서드 수행 + + + } + + public void printResult(Map result){ + for(int i = Ranking.values().length -1; i >= 0; i--){//3~6순으로 해야되므로 인덱스 역순으로 출력하게 작성 + Ranking.values()[i].printMessage(result.get(Ranking.values()[i]));//헤당 enum객체의 정보 출력 + } + } + public void printEarningRate(Mapresult, int ticketCount){ + double percent = 0.0; + + for(Ranking r : result.keySet()){ + percent += ((double)((r.getWinningAmount() * result.get(r))*PERCENTAGE) + / (TICKET_PRICE * ticketCount)); + + + } + OutputView.printRevenueRate(percent); + + + } + public MapsetResult(){ + Mapresult = new LinkedHashMap<>(); + for(Ranking r : Ranking.values()){ + result.put(r, 0); + } + return result; + + } + +} \ 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..8ded24a --- /dev/null +++ b/src/main/java/domain/Lotto.java @@ -0,0 +1,51 @@ +package domain; + +import java.util.List; + +public class Lotto { + private static final int MIN_NUMBER = 1; + private static final int MAX_NUMBER = 45; + private final List numbers; + + public Lotto(List numbers) { + validate(numbers);//로또 번호 개수가 6개로 정상적으로 들어왔는지 여부 확인 + validateRange(numbers);//1~45까지의 값이 있나 확인 + this.numbers = numbers;//검사 통과하면 numbers라는 리스트 객체에 저장 + } + + public List getLottoNumbers(){//로또 리스트 반환 + return numbers; + } + + public boolean containNumber(int number){//로또 리스트에 해당 숫자가 있는지 검사할 수 있는 메서드 + return numbers.contains(number); + } + public int countMatch(Lotto winningLotto){//winningLotto에 들어있는 로또 리스트 객체와 확인하고자 하는 로또 + //비교 후 같은 정수가 있으면 값을 증가시켜 반환 + return (int)numbers.stream().filter(w -> winningLotto.numbers.contains(w)).count(); + } + + + private void validate(List numbers) { + if (numbers.size() != 6) { + throw new IllegalArgumentException(); + } + } + private void validateRange(List numbers) { + for(int i = 0; i < numbers.size(); i++){ + if(numbers.get(i) < MIN_NUMBER || numbers.get(i) > MAX_NUMBER){ + throw new IllegalArgumentException(); + } + } + } + + public static void validateBonusNumber(List numbers, int bonusNumber) { + //추후 당첨 로또의 6개의 로또 번호와 1개의 보너스 번호에서 보너스 변호와 로또 번호가 겹치는게 있는지 확인하기 위한 매서드 + if (numbers.contains(bonusNumber)) { + throw new IllegalArgumentException(); + } + } + + +} + diff --git a/src/main/java/domain/LottoNumbers.java b/src/main/java/domain/LottoNumbers.java new file mode 100644 index 0000000..65d963c --- /dev/null +++ b/src/main/java/domain/LottoNumbers.java @@ -0,0 +1,24 @@ +package domain; + + + +import org.kokodak.Randoms; + +import java.util.Collections; +import java.util.List; + + +public class LottoNumbers { + private static final int CNT_LOTTO_NUMBER = 6; + private static final int MIN_LOTTO_NUMBER = 1; + private static final int MAX_LOTTO_NUMBER = 45; + + private static List lottoNumberList; + public static List setRandomLottos(){ + lottoNumberList = Randoms.pickUniqueNumbersInRange(MIN_LOTTO_NUMBER, MAX_LOTTO_NUMBER, CNT_LOTTO_NUMBER); + //해당 범위내 값에서 CNT만큼 증복되지 않는 로또 번호 가져와 리스트 형태로 반환해줌 + Collections.sort(lottoNumberList);//오름차순 정렬 위함 + return lottoNumberList; + } + +} \ No newline at end of file diff --git a/src/main/java/domain/PlayerLottoAmount.java b/src/main/java/domain/PlayerLottoAmount.java new file mode 100644 index 0000000..8a206d2 --- /dev/null +++ b/src/main/java/domain/PlayerLottoAmount.java @@ -0,0 +1,34 @@ +package domain; + +public class PlayerLottoAmount { + private static final int Lotto_Min_Amount = 1000;//로또 한개 당 가격 + private final int amount; + + public PlayerLottoAmount(String amount){ + int amountNum = changeToInt(amount); + validateAmount(amountNum); + validateNum(amountNum); + this.amount = amountNum; + } + public int changeToInt(String amount){ + return Integer.parseInt(amount); + } + public int calculateLottoCount() {//발행할 로또 개수 반환 + return amount / Lotto_Min_Amount; + } + + public void validateAmount(int amountNum){//1000보다 작으면 로또 못삼(예외 처리) + if(amountNum < Lotto_Min_Amount){ + throw new IllegalArgumentException(); + } + + } + + public void validateNum(int amountNum){//1000으로 안나누어지면 오류 + if(amountNum % Lotto_Min_Amount != 0){ + throw new IllegalArgumentException(); + } + } + + +} diff --git a/src/main/java/domain/Ranking.java b/src/main/java/domain/Ranking.java new file mode 100644 index 0000000..e4a85ac --- /dev/null +++ b/src/main/java/domain/Ranking.java @@ -0,0 +1,58 @@ +package domain; + +import view.OutputView; + +public enum Ranking { + FIRST(6, 2_000_000_000, "6개 일치 (2,000,000,000원) - "), // 1등 + SECOND(5, 30_000_000, "5개 일치, 보너스 볼 일치 (30,000,000원) - "), // 2등 + THIRD(5, 1_500_000, "5개 일치 (1,500,000원) - "), // 3등 + FOURTH(4, 50_000, "4개 일치 (50,000원) - "), // 4등 + FIFTH(3, 5_000, "3개 일치 (5,000원) - "), // 5등 + MISS(0, 0, "");//3개 미만 맞으면 꽝 + + private int countOfMatch; + private int winningAmount; + private String message; + + Ranking(int countOfMatch, int winningAmount, String message){ + this.countOfMatch = countOfMatch; + this.winningAmount = winningAmount; + this.message = message; + } + private static final int WINNING_MIN_COUNT = 3; + public static Ranking valuesOf(int countOfMatch, boolean bonusCheck){ + if(countOfMatch < WINNING_MIN_COUNT){ + return MISS; + } + if(SECOND.matchCount(countOfMatch) && bonusCheck){ + return SECOND; + } + for(Ranking rank : values()){ + if(rank.matchCount(countOfMatch) && rank != SECOND){ + return rank; + } + } + throw new IllegalArgumentException(); + } + + public int getCountOfMatch(){ + return countOfMatch; + } + public int getWinningAmount(){ + return winningAmount; + } + + public void printMessage(int countOfMatch){ + if(this != MISS){ + OutputView.printSuccessMessage(message, countOfMatch); + } + } + + private boolean matchCount(int countOfMatch) { + return this.countOfMatch == countOfMatch; + } + + + + +} \ No newline at end of file diff --git a/src/main/java/domain/WinningResult.java b/src/main/java/domain/WinningResult.java new file mode 100644 index 0000000..9fb93c5 --- /dev/null +++ b/src/main/java/domain/WinningResult.java @@ -0,0 +1,15 @@ +package domain; + +public class WinningResult { + private final Lotto lotto; + private final int bonus; + public WinningResult(Lotto lotto, int bonus){ + this.lotto = lotto; + this.bonus = bonus; + } + public Ranking match(Lotto playerNumber){ + int countOfMatch = playerNumber.countMatch(lotto);//각 로또들과 당첨 로또 비교해 몇개의 숫자 맞는지 반환 + boolean bonusCheck = playerNumber.containNumber(bonus);//보너스 번호를 맞았는지 여부 boolean형태로 반환 + return Ranking.valuesOf(countOfMatch, bonusCheck);//해당 정보들 가지고 Ranking Enum의 객체와 매치시키게 됨 + } +} \ No newline at end of file diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index d190922..ddc19e9 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,7 +1,10 @@ package lotto; +import controller.LottoController; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + LottoController lottoController = new LottoController(); + lottoController.run(); } } diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java deleted file mode 100644 index 519793d..0000000 --- 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/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 0000000..5f51962 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,48 @@ +package view; + + + +import org.kokodak.Console; + +import java.util.ArrayList; +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 = "보너스 번호를 입력해 주세요."; + + public 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 ListnumberList(String winningNumber){ + String[]result = winningNumber.split(","); + winningNumberList = new ArrayList<>(); + for(int i = 0; i < result.length; i++){ + winningNumberList.add(convertToInt(result[i])); + } + return winningNumberList; + } + public static int convertToInt(String s){ + + return Integer.parseInt(s); + } + + + + + + +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 0000000..9acbddb --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,22 @@ +package view; + +public class OutputView { + public static void printTicketCount(int count) { + System.out.println(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.printf("총 수익률은 %.1f%%입니다.\n", EarningRate); + } + + +} diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/LottoTest.java index 14ed50f..68566eb 100644 --- a/src/test/java/lotto/LottoTest.java +++ b/src/test/java/lotto/LottoTest.java @@ -3,6 +3,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.List; + +import domain.Lotto; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test;