diff --git a/README.md b/README.md new file mode 100644 index 00000000..bc974a25 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# 1단계 기능 요구사항 +- [X] 로또 구입 금액을 입력하면 구입 금액에 해당하는 로또를 발급해야 한다. +- [X] 로또 1장의 가격은 1000원이다. +- [X] 새로운 프로그래밍 요구사항 +- [X] 배열 대신 컬렉션을 사용한다. +- [X] 줄여 쓰지 않는다(축약 금지). +- [X] 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다. +- [X] 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라. + +# 2단계 기능 요구사항 +- [X] 로또 당첨 번호를 받아 일치한 번호 수에 따라 당첨 결과를 보여준다. + +## 새로운 프로그래밍 요구사항 +모든 원시 값과 문자열을 포장한다. +일급 컬렉션을 쓴다. + +## 기존 프로그래밍 요구사항 +자바 코드 컨벤션을 지키면서 프로그래밍한다. +기본적으로 Java Style Guide을 원칙으로 한다. +indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다. +예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. +힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. +3항 연산자를 쓰지 않는다. +else 예약어를 쓰지 않는다. +else 예약어를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. +힌트: if문에서 값을 반환하는 방식으로 구현하면 else 예약어를 사용하지 않아도 된다. diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..f4ca619b --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,27 @@ +import domain.Cashier; +import domain.Lotto; +import domain.LottoResult; +import domain.LottoTicket; +import domain.NumberListGenerator; +import domain.RandomNumberListGenerator; +import view.InputView; +import view.OutputView; + +public class Application { + public static final Integer TICKET_LENGTH = 6; + + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + NumberListGenerator numberListGenerator = new RandomNumberListGenerator(TICKET_LENGTH); + Cashier cashier = new Cashier(numberListGenerator); + + Integer price = inputView.inputPrice(); + Lotto lotto = cashier.generateTickets(price); + outputView.showLottoTickets(lotto); + + LottoTicket winnerTicket = inputView.getWinnerTicket(); + LottoResult result = cashier.getResults(lotto, winnerTicket); + outputView.showLottoResults(result, cashier.getProfitRate(result, price)); + } +} diff --git a/src/main/java/domain/Cashier.java b/src/main/java/domain/Cashier.java new file mode 100644 index 00000000..b0eb936b --- /dev/null +++ b/src/main/java/domain/Cashier.java @@ -0,0 +1,63 @@ +package domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Cashier { + public static final Integer THREE_CORRECT = 3; + public static final Integer FOUR_CORRECT = 4; + public static final Integer FIVE_CORRECT = 5; + public static final Integer SIX_CORRECT = 6; + private final NumberListGenerator numberListGenerator; + + public Cashier(NumberListGenerator numberListGenerator) { + this.numberListGenerator = numberListGenerator; + } + + public Lotto generateTickets(Integer price) { + validatePrice(price); + Integer numberOfTickets = calculateNumberOfTickets(price); + List generatedTickets = new ArrayList<>(); + for (Integer i = 0; i < numberOfTickets; i++) { + generatedTickets.add(new LottoTicket(numberListGenerator.generate())); + } + + return new Lotto(generatedTickets); + } + + public LottoResult getResults(Lotto lotto, LottoTicket winnerTicket) { + List results = lotto.getResults(winnerTicket); + return new LottoResult( + Collections.frequency(results, THREE_CORRECT), + Collections.frequency(results, FOUR_CORRECT), + Collections.frequency(results, FIVE_CORRECT), + Collections.frequency(results, SIX_CORRECT) + ); + } + + public Double getProfitRate(LottoResult result, Integer price) { + Integer totalProfit = 5000 * result.getThreeCorrectCount() + + 50000 * result.getFourCorrectCount() + + 1500000 * result.getFiveCorrectCount() + + 2000000000 * result.getSixCorrectCount(); + + return totalProfit.doubleValue() / price; + } + + private void validatePrice(Integer price) { + if (price < 0) { + throw new IllegalArgumentException("잘못된 입력입니다."); + } + if (price < 1000) { + throw new IllegalArgumentException("돈이 부족합니다."); + } + if (price % 1000 != 0) { + throw new IllegalArgumentException("1000원 단위로 입력해주세요."); + } + } + + private Integer calculateNumberOfTickets(Integer price) { + return price / 1000; + } +} diff --git a/src/main/java/domain/Lotto.java b/src/main/java/domain/Lotto.java new file mode 100644 index 00000000..da4c277d --- /dev/null +++ b/src/main/java/domain/Lotto.java @@ -0,0 +1,28 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; + +public class Lotto { + private final List tickets; + + public Lotto(List tickets) { + this.tickets = tickets; + } + + public List getResults(LottoTicket winnerTicket) { + List results = new ArrayList<>(); + for (LottoTicket ticket : tickets) { + results.add(ticket.getResult(winnerTicket)); + } + return results; + } + + public List getTickets() { + return tickets; + } + + public int getNumberOfTickets() { + return tickets.size(); + } +} diff --git a/src/main/java/domain/LottoResult.java b/src/main/java/domain/LottoResult.java new file mode 100644 index 00000000..fe88c737 --- /dev/null +++ b/src/main/java/domain/LottoResult.java @@ -0,0 +1,36 @@ +package domain; + +public class LottoResult { + private final Integer threeCorrectCount; + private final Integer fourCorrectCount; + private final Integer fiveCorrectCount; + private final Integer sixCorrectCount; + + + public LottoResult(Integer threeCorrectCount, + Integer fourCorrectCount, + Integer fiveCorrectCount, + Integer sixCorrectCount) { + this.threeCorrectCount = threeCorrectCount; + this.fourCorrectCount = fourCorrectCount; + this.fiveCorrectCount = fiveCorrectCount; + this.sixCorrectCount = sixCorrectCount; + } + + + public Integer getThreeCorrectCount() { + return threeCorrectCount; + } + + public Integer getFourCorrectCount() { + return fourCorrectCount; + } + + public Integer getFiveCorrectCount() { + return fiveCorrectCount; + } + + public Integer getSixCorrectCount() { + return sixCorrectCount; + } +} diff --git a/src/main/java/domain/LottoTicket.java b/src/main/java/domain/LottoTicket.java new file mode 100644 index 00000000..9cd20ca5 --- /dev/null +++ b/src/main/java/domain/LottoTicket.java @@ -0,0 +1,37 @@ +package domain; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +public class LottoTicket { + private final List ticket; + + public LottoTicket(List ticket) { + validate(ticket); + Collections.sort(ticket); + this.ticket = ticket; + } + + static private void validate(List ticket) { + int length = ticket.size(); + Set ticketSet = new HashSet<>(ticket); + if (ticketSet.size() != length) { + throw new RuntimeException(); + } + } + + public Integer getResult(LottoTicket winnerTicket) { + Integer count = 0; + for (Integer number : winnerTicket.getTicket()) { + count += Boolean.compare(ticket.contains(number), false); + } + return count; + } + + public List getTicket() { + return ticket; + } +} diff --git a/src/main/java/domain/NumberListGenerator.java b/src/main/java/domain/NumberListGenerator.java new file mode 100644 index 00000000..7d5c3143 --- /dev/null +++ b/src/main/java/domain/NumberListGenerator.java @@ -0,0 +1,7 @@ +package domain; + +import java.util.List; + +public interface NumberListGenerator { + List generate(); +} diff --git a/src/main/java/domain/RandomNumberListGenerator.java b/src/main/java/domain/RandomNumberListGenerator.java new file mode 100644 index 00000000..b286801c --- /dev/null +++ b/src/main/java/domain/RandomNumberListGenerator.java @@ -0,0 +1,24 @@ +package domain; + +import java.util.*; + +public class RandomNumberListGenerator implements NumberListGenerator { + private static final Integer UPPER_BOUND = 46; + private static final Integer LOWER_BOUND = 1; + + private final Integer length; + + public RandomNumberListGenerator(final Integer length) { + this.length = length; + } + + @Override + public List generate() { + List numberList = new ArrayList<>(); + for (Integer i = LOWER_BOUND; i < UPPER_BOUND; i++) { + numberList.add(i); + } + Collections.shuffle(numberList); + return numberList.subList(0, length); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..dd903d57 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,25 @@ +package view; + +import domain.LottoTicket; +import java.util.Arrays; +import java.util.Scanner; +import java.util.stream.Collectors; + +public class InputView { + private final Scanner scanner; + + public InputView() { + scanner = new Scanner(System.in); + } + + public Integer inputPrice() { + System.out.println("구입 금액을 입력해 주세요."); + return Integer.valueOf(scanner.nextLine()); + } + + public LottoTicket getWinnerTicket() { + System.out.println("지난 주 당첨 번호를 입력해 주세요."); + return new LottoTicket( + Arrays.stream(scanner.nextLine().split(", ")).map(Integer::valueOf).collect(Collectors.toList())); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..326f6069 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,49 @@ +package view; + +import domain.Lotto; +import domain.LottoResult; +import domain.LottoTicket; +import java.util.List; + +public class OutputView { + public void showLottoTickets(Lotto lotto) { + System.out.println(); + System.out.println(lotto.getNumberOfTickets() + "개를 구매했습니다."); + for (LottoTicket lottoTicket : lotto.getTickets()) { + showLottoTicket(lottoTicket); + } + } + + public void showLottoResults(LottoResult result, Double profitRate) { + showLottoStatistics(result); + showProfitRate(profitRate); + } + + public void showLottoStatistics(LottoResult result) { + System.out.println("\n당첨 통계\n---------"); + System.out.println("3개 일치 (5000원)- " + result.getThreeCorrectCount() + "개"); + System.out.println("4개 일치 (50000원)- " + result.getFourCorrectCount() + "개"); + System.out.println("5개 일치 (1500000원)- " + result.getFiveCorrectCount() + "개"); + System.out.println("6개 일치 (2000000000원)- " + result.getSixCorrectCount() + "개"); + } + + public void showProfitRate(Double profitRate) { + System.out.printf("총 수익률은 %.2f입니다.", profitRate); + if (profitRate > 1) { + System.out.print("(기준이 1이기 때문에 결과적으로 이득이라는 의미임)"); + return; + } + + if (profitRate == 1) { + System.out.print("(기준이 1이기 때문에 결과적으로 본전이라는 의미임)"); + return; + } + + System.out.print("(기준이 1이기 때문에 결과적으로 손해라는 의미임)"); + } + + private void showLottoTicket(LottoTicket lottoTicket) { + List ticket = lottoTicket.getTicket(); + System.out.println(ticket); + } +}