diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..06d1a74 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/** +!**/src/test/** +.DS_Store + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### IntelliJ IDEA ### +.idea/ +*.iws +*.iml +*.ipr +out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/README.md b/README.md index e82ca67..ef90333 100644 --- a/README.md +++ b/README.md @@ -143,4 +143,4 @@ 5개 일치, 보너스 볼 일치(30000000원) - 0개 6개 일치 (2000000000원)- 0개 총 수익률은 35.7%입니다. -``` \ No newline at end of file +``` diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 87b738c..0000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/src/main/java/com/hee/LottoApplication.java b/src/main/java/com/hee/LottoApplication.java new file mode 100644 index 0000000..561088d --- /dev/null +++ b/src/main/java/com/hee/LottoApplication.java @@ -0,0 +1,40 @@ +package com.hee; + +import com.hee.domain.number.LottoNumber; +import com.hee.strategy.RandomGenerationStrategy; +import com.hee.view.InputView; +import com.hee.view.ResultView; + +public class LottoApplication { + + private static final String INPUT_MESSAGE_OF_PURCHASE_AMOUNT = "구입 금액을 입력해 주세요."; + private static final String INPUT_MESSAGE_OF_MANUAL_COUNT = "\n수동으로 구매할 로또 수를 입력해 주세요."; + private static final String INPUT_MESSAGE_OF_MANUAL_NUMBER = "\n수동으로 구매할 번호를 입력해 주세요."; + private static final String INPUT_MESSAGE_OF_WINNING_NUMBER = "\n지난 주 당첨 번호를 입력해 주세요."; + private static final String INPUT_MESSAGE_OF_BONUS_NUMBER = "\n보너스 볼을 입력해 주세요."; + private static final int PRICE_OF_ONE_TICKET = 1000; + + public static void main(String[] args) { + LottoGame lottoGame = new LottoGame(); + + int purchaseAmount = InputView.inputInt(INPUT_MESSAGE_OF_PURCHASE_AMOUNT); // 구입 금액 + + // 수동 구매 번호 + int numberOfManualTickets = InputView.inputInt(INPUT_MESSAGE_OF_MANUAL_COUNT); + String[] manualLottoNumbers = InputView.inputStringArray(INPUT_MESSAGE_OF_MANUAL_NUMBER, numberOfManualTickets); + lottoGame.buyManualTickets(manualLottoNumbers); + + // 티켓 구매 (수동 + 구매전략) + int numberOfTickets = (purchaseAmount / PRICE_OF_ONE_TICKET) - numberOfManualTickets; + lottoGame.buyTickets(numberOfTickets, manualLottoNumbers, new RandomGenerationStrategy()); + + ResultView.printTypeOfTickets(numberOfManualTickets, numberOfTickets); + ResultView.printTickets(lottoGame.getTickets()); + + String winningNumberOfLastWeek = InputView.inputStringArray(INPUT_MESSAGE_OF_WINNING_NUMBER); // 지난 주 당첨 번호 + int bonusNumber = InputView.inputInt(INPUT_MESSAGE_OF_BONUS_NUMBER); // 보너스 번호 + LottoResult result = lottoGame.play(winningNumberOfLastWeek, new LottoNumber(bonusNumber)); + ResultView.printResult(result); // 당첨 결과 + ResultView.printProfitRate(result, purchaseAmount); // 수익률 결과 + } +} diff --git a/src/main/java/com/hee/LottoGame.java b/src/main/java/com/hee/LottoGame.java new file mode 100644 index 0000000..68a378c --- /dev/null +++ b/src/main/java/com/hee/LottoGame.java @@ -0,0 +1,53 @@ +package com.hee; + +import com.hee.domain.Prize; +import com.hee.domain.Ticket; +import com.hee.domain.number.LottoNumber; +import com.hee.strategy.GenerationStrategy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class LottoGame { + + private static final int PRICE_OF_ONE_TICKET = 1000; + + private List tickets; + + public LottoGame() { + tickets = new ArrayList<>(); + } + + public List buyTickets(final int numberOfTickets, final String[] manualLottoNumbers, final GenerationStrategy strategy) { + buyManualTickets(manualLottoNumbers); + + this.tickets.addAll( + IntStream.range(0, numberOfTickets) + .mapToObj(index -> new Ticket(strategy.generateNumbers())) + .collect(Collectors.toList())); + return this.tickets; + } + + public List buyManualTickets(final String[] manualLottoNumbers) { + this.tickets.addAll( + Arrays.stream(manualLottoNumbers) + .map(Ticket::new) + .collect(Collectors.toList())); + return this.tickets; + } + + public LottoResult play(final String winningNumbersOfLastWeek, final LottoNumber bonusNumber) { + Ticket winningTicket = new Ticket(winningNumbersOfLastWeek); + LottoResult result = new LottoResult(); + this.tickets.forEach(ticket -> + result.updateResult(Prize.valueOf(ticket.matchedCount(winningTicket), ticket.contains(bonusNumber)))); + return result; + } + + public List getTickets() { + return tickets; + } +} diff --git a/src/main/java/com/hee/LottoResult.java b/src/main/java/com/hee/LottoResult.java new file mode 100644 index 0000000..5f555e4 --- /dev/null +++ b/src/main/java/com/hee/LottoResult.java @@ -0,0 +1,47 @@ +package com.hee; + +import com.hee.domain.Prize; + +import java.util.EnumMap; + +public class LottoResult { + + private final EnumMap matchedPrizes; + + public LottoResult() { + this.matchedPrizes = new EnumMap<>(Prize.class); + for (Prize prize : Prize.values()) { + matchedPrizes.put(prize, 0); + } + } + + public void updateResult(final Prize prize) { + matchedPrizes.put(prize, matchedPrizes.get(prize) + 1); + } + + public float calculateProfitRate(final LottoResult lottoResult, final int purchaseAmount) { + return ((float) lottoResult.calculateTotalPrizes() / purchaseAmount) * 100; + } + + public int calculateTotalPrizes() { + return matchedPrizes.keySet() + .stream() + .map(prize -> matchedPrizes.get(prize) * prize.getPrizeMoney()) + .mapToInt(Integer::valueOf) + .sum(); + } + + public EnumMap getMatchedPrizes() { + return this.matchedPrizes; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + matchedPrizes.keySet() + .forEach(prize -> + stringBuilder.append(prize.getPrizeMoney() * matchedPrizes.get(prize))); + return stringBuilder.toString(); + } + +} diff --git a/src/main/java/com/hee/domain/Prize.java b/src/main/java/com/hee/domain/Prize.java new file mode 100644 index 0000000..3ac1b23 --- /dev/null +++ b/src/main/java/com/hee/domain/Prize.java @@ -0,0 +1,43 @@ +package com.hee.domain; + +import java.util.Arrays; + +public enum Prize { + + NONE(0, 0), + FIFTH(3, 5000), + FOURTH(4, 50000), + THIRD(5, 1500000), + SECOND(5, 30000000), + FIRST(6, 2000000000); + + private int numOfMatchingNumbers; + private int prizeMoney; + + Prize(final int numOfMatchingNumbers, final int prizeMoney) { + this.numOfMatchingNumbers = numOfMatchingNumbers; + this.prizeMoney = prizeMoney; + } + + public static Prize valueOf(final int numOfMatchingNumbers, final boolean containBonusNumber) { + if (numOfMatchingNumbers == Prize.SECOND.numOfMatchingNumbers && containBonusNumber) { + return Prize.SECOND; + } + return Arrays.stream(Prize.values()) + .filter(prize -> prize.numOfMatchingNumbers == numOfMatchingNumbers) + .findFirst() + .orElse(Prize.NONE); + } + + public boolean same(final Prize prize) { + return this.equals(prize); + } + + public int getPrizeMoney() { + return this.prizeMoney; + } + + public int getNumOfMatchingNumbers() { + return this.numOfMatchingNumbers; + } +} diff --git a/src/main/java/com/hee/domain/Ticket.java b/src/main/java/com/hee/domain/Ticket.java new file mode 100644 index 0000000..5975ed4 --- /dev/null +++ b/src/main/java/com/hee/domain/Ticket.java @@ -0,0 +1,49 @@ +package com.hee.domain; + +import com.hee.domain.number.LottoNumber; +import com.hee.domain.number.LottoNumbers; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class Ticket { + + private static final String DELIMITER_OF_LOTTO_NUMBER = ", "; + private LottoNumbers lottoNumbers; + + public Ticket(final List lottoNumbers) { + this.lottoNumbers = new LottoNumbers(lottoNumbers); + } + + public Ticket(final String lottoNumbers) { + List winningNumbers = toIntList(lottoNumbers); + this.lottoNumbers = LottoNumbers.of(winningNumbers); + } + + private static List toIntList(final String input) { + return Arrays.stream(input.split(", ")) + .map(Integer::parseInt) + .collect(Collectors.toList()); + } + + public int matchedCount(final Ticket winningTicket) { + return (int) this.lottoNumbers.getLottoNumbers() + .stream() + .filter(winningTicket::contains).count(); + } + + public boolean contains(LottoNumber lottoNumber) { + return this.lottoNumbers.contains(lottoNumber); + } + + @Override + public String toString() { + return "[" + + lottoNumbers.getLottoNumbers() + .stream() + .map(LottoNumber::toString) + .collect(Collectors.joining(DELIMITER_OF_LOTTO_NUMBER)) + + "]"; + } +} diff --git a/src/main/java/com/hee/domain/number/LottoNumber.java b/src/main/java/com/hee/domain/number/LottoNumber.java new file mode 100644 index 0000000..8f2e738 --- /dev/null +++ b/src/main/java/com/hee/domain/number/LottoNumber.java @@ -0,0 +1,56 @@ +package com.hee.domain.number; + +import java.security.InvalidParameterException; +import java.util.Objects; + +public class LottoNumber implements Comparable { + + public static final int MIN_VALUE = 1; + public static final int MAX_VALUE = 45; + + private int value; + + public LottoNumber(int value) { + verifyRange(value); + this.value = value; + } + + private void verifyRange(int value) { + if (MAX_VALUE < value || MIN_VALUE > value) { + throw new InvalidParameterException("1 ~ 45 사이의 숫자가 아닙니다."); + } + } +// +// public Integer getValue() { +// return this.value; +// } + + @Override + public int compareTo(LottoNumber o) { + LottoNumber target = (LottoNumber) o; + if (target.value > this.value) { + return -1; + } else if (target.value < this.value) { + return 1; + } + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LottoNumber)) return false; + LottoNumber that = (LottoNumber) o; + return value == that.value; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return String.valueOf(value); + } +} diff --git a/src/main/java/com/hee/domain/number/LottoNumbers.java b/src/main/java/com/hee/domain/number/LottoNumbers.java new file mode 100644 index 0000000..d9b1298 --- /dev/null +++ b/src/main/java/com/hee/domain/number/LottoNumbers.java @@ -0,0 +1,39 @@ +package com.hee.domain.number; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class LottoNumbers { + + private List values; + + public static LottoNumbers of(final int from, final int to) { + return new LottoNumbers(from, to); + } + + public static LottoNumbers of(final List values) { + return new LottoNumbers(values.stream() + .map(LottoNumber::new) + .collect(Collectors.toList())); + } + + private LottoNumbers(final int from, final int to) { + this.values = new ArrayList<>(); + for (int i = from; i <= to; i++) { + values.add(new LottoNumber(i)); + } + } + + public LottoNumbers(final List values) { + this.values = values; + } + + public boolean contains(final LottoNumber lottoNumber) { + return this.values.contains(lottoNumber); + } + + public List getLottoNumbers() { + return values; + } +} diff --git a/src/main/java/com/hee/strategy/GenerationStrategy.java b/src/main/java/com/hee/strategy/GenerationStrategy.java new file mode 100644 index 0000000..b256472 --- /dev/null +++ b/src/main/java/com/hee/strategy/GenerationStrategy.java @@ -0,0 +1,10 @@ +package com.hee.strategy; + +import com.hee.domain.number.LottoNumber; + +import java.util.List; + +@FunctionalInterface +public interface GenerationStrategy { + public List generateNumbers(); +} diff --git a/src/main/java/com/hee/strategy/RandomGenerationStrategy.java b/src/main/java/com/hee/strategy/RandomGenerationStrategy.java new file mode 100644 index 0000000..0f9a11d --- /dev/null +++ b/src/main/java/com/hee/strategy/RandomGenerationStrategy.java @@ -0,0 +1,25 @@ +package com.hee.strategy; + +import com.hee.domain.number.LottoNumber; +import com.hee.domain.number.LottoNumbers; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class RandomGenerationStrategy implements GenerationStrategy { + + private static final int LOTTO_NUMBER_SIZE = 6; + + @Override + public List generateNumbers() { + List numbers = LottoNumbers.of(LottoNumber.MIN_VALUE, LottoNumber.MAX_VALUE) + .getLottoNumbers(); + Collections.shuffle(numbers); + return numbers.stream() + .limit(LOTTO_NUMBER_SIZE) + .sorted() + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/hee/view/InputView.java b/src/main/java/com/hee/view/InputView.java new file mode 100644 index 0000000..34413a7 --- /dev/null +++ b/src/main/java/com/hee/view/InputView.java @@ -0,0 +1,28 @@ +package com.hee.view; + +import java.util.Scanner; + +public class InputView { + + private static final Scanner SCANNER = new Scanner(System.in); + + public static int inputInt(final String content) { + System.out.println(content); + return Integer.parseInt(SCANNER.nextLine()); + } + + public static String inputStringArray(final String content) { + System.out.println(content); + return SCANNER.nextLine(); + } + + public static String[] inputStringArray(final String content, final int count) { + System.out.println(content); + + String[] strings = new String[count]; + for (int i = 0; i < count; i++) { + strings[i] = SCANNER.nextLine(); + } + return strings; + } +} diff --git a/src/main/java/com/hee/view/ResultView.java b/src/main/java/com/hee/view/ResultView.java new file mode 100644 index 0000000..25ee929 --- /dev/null +++ b/src/main/java/com/hee/view/ResultView.java @@ -0,0 +1,47 @@ +package com.hee.view; + +import com.hee.LottoResult; +import com.hee.domain.Prize; +import com.hee.domain.Ticket; + +import java.util.List; + +public class ResultView { + + private final static String NUMBER_OF_TICKETS_MESSAGE = "\n수동으로 %d장, 자동으로 %d개를 구매했습니다."; + private final static String RESULT = "\n당첨 통계\n--------\n"; + private static final String RESULT_FORMAT = "%d개 일치 (%d원)- %d개"; + private static final String RESULT_FORMAT_OF_SECOND_PRIZE = "%d개 일치, 보너스 볼 일치 (%d원)- %d개"; + private static final String YIELD_FORMAT = "총 수익률은 %.1f%% 입니다."; + + public static void printTypeOfTickets(int numberOfManualTickets, int numberOfTickets) { + System.out.println(String.format(NUMBER_OF_TICKETS_MESSAGE, numberOfManualTickets, numberOfTickets)); + } + + public static void printTickets(final List tickets) { + tickets.forEach(ticket -> System.out.println(ticket.toString())); + } + + public static void printResult(final LottoResult result) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(RESULT); + result.getMatchedPrizes().keySet() + .forEach(prize -> { + String format = RESULT_FORMAT; + if (prize.same(Prize.SECOND)) { + format = RESULT_FORMAT_OF_SECOND_PRIZE; + } + stringBuilder + .append(String.format(format, + prize.getNumOfMatchingNumbers(), + prize.getPrizeMoney(), + result.getMatchedPrizes().get(prize))) + .append("\n"); + }); + System.out.println(stringBuilder.toString()); + } + + public static void printProfitRate(final LottoResult result, final int purchaseAmount) { + System.out.println(String.format(YIELD_FORMAT, result.calculateProfitRate(result, purchaseAmount))); // 수익률 + } +}