Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[엘리] 로또 미션 제출합니다. #126

Merged
merged 23 commits into from
Feb 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
83f6878
[docs] README 작성
Feb 18, 2020
263b9af
[feature] 로또 숫자 객체 비교 기능 구현
Feb 18, 2020
2395c33
[feature] 로또 숫자 생성 예외처리 기능 구현
Feb 18, 2020
97e02d3
[feature] 돈 객체 생성자 구현
Feb 18, 2020
f26dcb6
[feature] InputView 구입금액 입력 구현
Feb 18, 2020
088692b
[feature] 티켓 객체 구현
Feb 18, 2020
1071d9a
[refactor] LottoNumber 클래스 enum type으로 수정
Feb 18, 2020
3b46dbf
[feature] 당첨 번호 객체 구현
Feb 18, 2020
25b425c
[refactor] LottoNumbersDto 적용 및 관련 로직 수정
Feb 19, 2020
62f3572
[feature] 티켓과 당첨 번호 중복 확인 구현
Feb 19, 2020
34361ab
[feature] 랜덤 팩토리 구현
Feb 19, 2020
9518660
[feature] 고정값으로 당첨번호 생성 구현
Feb 19, 2020
44404dc
[feature] InputView 당첨번호와 보너스볼 입력 구현
Feb 19, 2020
164be4e
[feature] OutputView 티켓 구매 출력 구현
Feb 19, 2020
50ebf5a
[feature] 로또 당첨 결과 찾기 메서드 구현
Feb 19, 2020
89b3bd8
[refactor / feature] 구조 리팩토링 및 로또 당첨 결과 구현
Feb 20, 2020
efc5d5a
[refactor] 리펙토링
Feb 20, 2020
9b9f778
[refactor] 리펙토링, 수익률 에러 수정
Feb 20, 2020
dc876fc
[refactor] 리펙토링
Feb 20, 2020
40468b3
[refactor] DTO와 비즈니스 로직 책임 분리
YebinK Feb 23, 2020
15292ad
[refactor] 티켓 생성 로직 수정
YebinK Feb 24, 2020
5081b5c
[refactor] 검증 로직 도메인으로 이동
YebinK Feb 25, 2020
4ee67e9
[refactor] Money 객체 테스트 케이스 추가
YebinK Feb 25, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,31 @@
# README

# java-lotto
로또 미션 진행을 위한 저장소

> 기능 요구사항

- [x] 구입금액을 입력받는다.
- [x] (예외) 1000원 이하 단위일 경우
- [x] (예외) 숫자가 아닐 경우
- [x] (예외) 음수 또는 50000원 이상 입력될 경우
- [x] 구매한 로또 장 수와 번호를 출력한다.
- [x] 지난 주 당첨 번호를 입력받는다.
- [x] (예외) 1~45 이외의 숫자가 입력되는 경우
- [x] (예외) 올바른 입력 형식이 아닌 경우
- [x] (예외) 6개가 아닌 경우
- [x] (예외) 공백이 입력되는 경우
- [x] 보너스 볼을 입력받는다.
- [x] (예외) 위와 동일
- [x] 당첨 번호를 대조해서 결과를 얻는다.
- [x] 당첨 통계와 수익률을 출력한다.

> 프로그래밍 요구사항

- indent(인덴트, 들여쓰기) depth를 2단계에서 1단계로 줄여라.
- else를 사용하지 마라.
- 메소드의 크기가 최대 10라인을 넘지 않도록 구현한다.
- 배열 대신 ArrayList를 사용한다.
- enum을 적용해 프로그래밍을 구현한다.
- 규칙 3: 모든 원시값과 문자열을 포장한다.
- 규칙 5: 줄여쓰지 않는다(축약 금지).
- 규칙 8: 일급 콜렉션을 쓴다.
44 changes: 44 additions & 0 deletions src/main/java/LottoApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import domain.*;
import domain.numberscontainer.BonusNumberDTO;
import domain.numberscontainer.SixLottoNumbersDTO;
import domain.numberscontainer.Ticket;
import domain.numberscontainer.WinningNumbers;
import view.InputView;
import view.OutputView;

import java.util.List;
import java.util.Map;

public class LottoApplication {
public static void main(String[] args) {
Money money = new Money(enterMoney());
List<Ticket> tickets = LottoStore.generateTickets(money.getNumberOfTickets());
OutputView.printNumberOfTickets(tickets.size());
OutputView.printTickets(tickets);

WinningNumbers winningNumbers = enterWinningNumbers();
Map<LottoResult, Integer> result = LottoResultMachine.confirmResult(tickets, winningNumbers);
OutputView.printLottoResults(result);
OutputView.printProfit(LottoProfit.ofProfit(result, money));
}

private static String enterMoney() {
try {
return InputView.enterMoney();
} catch (Exception e) {
System.out.println(e.getMessage());
return enterMoney();
}
}

private static WinningNumbers enterWinningNumbers() {
try {
SixLottoNumbersDTO sixLottoNumbersDTO = new SixLottoNumbersDTO(InputView.enterLastWeekWinningNumbers());
BonusNumberDTO bonusNumberDTO = new BonusNumberDTO(InputView.enterBonusNumber());
return new WinningNumbers(sixLottoNumbersDTO, bonusNumberDTO);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
return enterWinningNumbers();
}
}
}
27 changes: 27 additions & 0 deletions src/main/java/domain/LottoProfit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package domain;

import java.util.Map;

public class LottoProfit {
private static final int TO_PERCENTAGE = 100;

private long profit;

private LottoProfit(long profit) {
this.profit = profit;
}

public static LottoProfit ofProfit(Map<LottoResult, Integer> lottoResults, Money money) {
long totalPrize = 0;
for (LottoResult result : lottoResults.keySet()) {
long prize = result.getPrize();
long matchCount = lottoResults.get(result);
totalPrize += prize * matchCount;
}
return new LottoProfit(totalPrize / money.getMoney() * TO_PERCENTAGE);
}

public long getValue() {
return profit;
}
}
42 changes: 42 additions & 0 deletions src/main/java/domain/LottoResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package domain;

import java.util.Arrays;
import java.util.List;

public enum LottoResult {
YebinK marked this conversation as resolved.
Show resolved Hide resolved
FIRST(2_000_000_000, 6),
SECOND(30_000_000, 5),
THIRD(1_500_000, 5),
FOURTH(50_000, 4),
FIFTH(5_000, 3),
FAILED(0, 0);

private final int prize;
private final int matchCount;

LottoResult(int prize, int matchCount) {
this.prize = prize;
this.matchCount = matchCount;
}

public static LottoResult findLottoResult(int matchCount, boolean isBonus) {
YebinK marked this conversation as resolved.
Show resolved Hide resolved
List<LottoResult> lottoResults = Arrays.asList(LottoResult.values());
LottoResult lottoResult = lottoResults.stream()
.filter(result -> result.matchCount == matchCount)
.findFirst()
.orElse(FAILED);

if (lottoResult == SECOND && !isBonus) {
return THIRD;
}
return lottoResult;
}

public int getPrize() {
return prize;
}

public int getMatchCount() {
return matchCount;
}
}
16 changes: 16 additions & 0 deletions src/main/java/domain/LottoResultMachine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package domain;

import domain.numberscontainer.Ticket;
import domain.numberscontainer.WinningNumbers;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class LottoResultMachine {

public static Map<LottoResult, Integer> confirmResult(List<Ticket> tickets, WinningNumbers winningNumbers) {
return tickets.stream()
.collect(Collectors.groupingBy(winningNumbers::getLottoResult, Collectors.summingInt(x -> 1)));
}
}
38 changes: 38 additions & 0 deletions src/main/java/domain/LottoStore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package domain;

import domain.numberscontainer.SixLottoNumbersDTO;
import domain.numberscontainer.Ticket;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/*
* Ticket 리스트 생성
*/
public class LottoStore {

public static List<Ticket> generateTickets(int ticketSize) {
List<Ticket> tickets = new ArrayList<>();

for (int i = 0; i < ticketSize; i++) {
tickets.add(RandomTicketFactory.createTicket());
}
return tickets;
}

public static List<Ticket> generateTickets(int ticketSize, List<SixLottoNumbersDTO> givenNumbers) {
List<Ticket> tickets = givenNumbers.stream()
.map(Ticket::new)
.collect(Collectors.toList());

int randomTicketsSize = getRandomTicketSize(ticketSize, givenNumbers.size());
tickets.addAll(generateTickets(randomTicketsSize));

return tickets;
}

private static int getRandomTicketSize(int totalTicketSize, int manualTicketSize) {
return totalTicketSize - manualTicketSize;
}
}
38 changes: 38 additions & 0 deletions src/main/java/domain/Money.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package domain;

public class Money {
private static final String NUMBER_REGEX = "^[+-]?[0-9]+$";

private final int money;

public Money(String moneyInput) {
int money = parseInt(moneyInput);
validateMoneyUnit(money);
this.money = money;
}

private static int parseInt(String input) {
validateNumber(input);
return Integer.parseInt(input);
}

private static void validateNumber(String input) {
if (!input.matches(NUMBER_REGEX)) {
throw new NumberFormatException("0원 이상 숫자를 입력해주세요.");
}
}

public int getNumberOfTickets() {
return this.money / 1000;
YebinK marked this conversation as resolved.
Show resolved Hide resolved
}

private void validateMoneyUnit(int money) {
if (money % 1000 != 0) {
throw new IllegalArgumentException("천 원 단위로만 구매 가능합니다.");
}
}

public int getMoney() {
return this.money;
}
}
23 changes: 23 additions & 0 deletions src/main/java/domain/RandomTicketFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package domain;

import domain.numberscontainer.LottoNumber;
import domain.numberscontainer.SixLottoNumbersDTO;
import domain.numberscontainer.Ticket;

import java.util.*;

public class RandomTicketFactory {
private static final int FIRST_INDEX = 0;
private static final int SIXTH_INDEX = 6;

public static Ticket createTicket() {
return new Ticket(new SixLottoNumbersDTO(getShuffledList()));
YebinK marked this conversation as resolved.
Show resolved Hide resolved
}

private static Set<LottoNumber> getShuffledList() {
List<LottoNumber> lottoNumbers = Arrays.asList(LottoNumber.values());
Collections.shuffle(lottoNumbers);

return new HashSet<>(lottoNumbers.subList(FIRST_INDEX, SIXTH_INDEX));
}
}
26 changes: 26 additions & 0 deletions src/main/java/domain/numberscontainer/BonusNumberDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package domain.numberscontainer;

public class BonusNumberDTO {
private static final String NUMBER_REGEX = "^[+-]?[0-9]+$";

private final LottoNumber bonusNumber;

public BonusNumberDTO(String bonusNumberInput) {
this.bonusNumber = LottoNumber.getLottoNumber(parseInt(bonusNumberInput));
}

private static int parseInt(String input) {
validateNumber(input);
return Integer.parseInt(input);
}

private static void validateNumber(String input) {
if (!input.matches(NUMBER_REGEX)) {
throw new NumberFormatException("숫자를 입력해주세요.");
}
}

public LottoNumber getBonusNumber() {
return bonusNumber;
}
}
71 changes: 71 additions & 0 deletions src/main/java/domain/numberscontainer/LottoNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package domain.numberscontainer;

import java.util.Arrays;
import java.util.List;

public enum LottoNumber {
YebinK marked this conversation as resolved.
Show resolved Hide resolved
ONE(1),
TWO(2),
THREE(3),
FOUR(4),
FIVE(5),
SIX(6),
SEVEN(7),
EIGHT(8),
NINE(9),
TEN(10),
ELEVEN(11),
TWELVE(12),
THIRTEEN(13),
FOURTEEN(14),
FIFTEEN(15),
SIXTEEN(16),
SEVENTEEN(17),
EIGHTEEN(18),
NINETEEN(19),
TWENTY(20),
TWENTY_ONE(21),
TWENTY_TWO(22),
TWENTY_THREE(23),
TWENTY_FOUR(24),
TWENTY_FIVE(25),
TWENTY_SIX(26),
TWENTY_SEVEN(27),
TWENTY_EIGHT(28),
TWENTY_NINE(29),
THIRTY(30),
THIRTY_ONE(31),
THIRTY_TWO(32),
THIRTY_THREE(33),
THIRTY_FOUR(34),
THIRTY_FIVE(35),
THIRTY_SIX(36),
THIRTY_SEVEN(37),
THIRTY_EIGHT(38),
THIRTY_NINE(39),
FORTY(40),
FORTY_ONE(41),
FORTY_TWO(42),
FORTY_THREE(43),
FORTY_FOUR(44),
FORTY_FIVE(45);

private final int number;

LottoNumber(int number) {
this.number = number;
}

public static LottoNumber getLottoNumber(int number) {
List<LottoNumber> lottoNumbers = Arrays.asList(LottoNumber.values());

return lottoNumbers.stream()
.filter(lottoNumber -> lottoNumber.number == number)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(String.format("%d이(가) 입력되었습니다. 1부터 45까지의 숫자를 입력해주세요.", number)));
}

public int getValue() {
return this.number;
}
}
20 changes: 20 additions & 0 deletions src/main/java/domain/numberscontainer/SixLottoNumbers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package domain.numberscontainer;

import java.util.Set;

public class SixLottoNumbers {
YebinK marked this conversation as resolved.
Show resolved Hide resolved
private static final int LOTTO_NUMBERS_SIZE = 6;
YebinK marked this conversation as resolved.
Show resolved Hide resolved

protected final Set<LottoNumber> sixLottoNumbers;

public SixLottoNumbers(SixLottoNumbersDTO sixLottoNumbersDTO) {
validateSize(sixLottoNumbersDTO.getSixNumbers());
this.sixLottoNumbers = sixLottoNumbersDTO.getSixNumbers();
}

protected void validateSize(Set<LottoNumber> lottoNumbers) {
if (lottoNumbers.size() != LOTTO_NUMBERS_SIZE) {
throw new IllegalArgumentException(String.format("%d개의 숫자를 입력해주세요.", LOTTO_NUMBERS_SIZE));
}
}
}
Loading