Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
81 changes: 81 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,82 @@
# java-planetlotto-precourse

# 개인 도전 과제

- 기능 확장
- 날짜별 판매된 로또의 개수를 집계하는 기능을 추가했습니다.
- 시뮬레이션임을 고려, 로또가 판매되는 날짜는 랜덤하게 설정되도록 하였습니다.
- 날짜 집계는 출력 마지막 부분에서 출력됩니다.

# 개요

# 구현 기능 목록

## 입력

### 구입 금앱 입력

- [x] 안내 메세지 출력 후, 사용자 입력 받음
- [x] 입력 유효성 검사
- [x] 입력이 숫자가 아닌경우 예외처리
- [x] 입력이 양의 정수가 아닌 경우 예외처리
- [x] !금액이 500원으로 나누어 떨어지지 않으면 예외처리

### 당첨 번호 입력

- [x] 안내 메세지 출력 후, 사용자 입력 받음
- [x] 입력 유효성 검사
- [x] 1~30범위가 아닌 수가 있는 경우 예외처리
- [x] 중복된 수가 있는 경우 예외처리
- [x] 5개의 숫자가 아닌 경우 예외처리

### 보너스 번호 입력

- [x] 안내 메세지 출력 후, 사용자 입력 받음
- [x] 입력 유효성 검사
- [x] 1~30범위가 아닌 수가 있는 경우 예외처리
- [x] 기본번호와 중복되는 경우 예외처리

## 출력

### 발행된 로또 결과 출력

- [x] 발행된 로또들을 형식에 맞춰 출력
-

### 추첨 결과 출력

- [x] 당첨 결과를 통해 당첨 금액 집계
- [x] 수익률 산출
- [x] 정해진 형식에 맞추어 당첨 통계 출력
- [x] 당첨 통계 메세지 출력
- [x] 당첨 내역 출력
- [x] 총 수익률 출력

### 날짜별 판매 통계 출력

- [x] 요일별 판매된 로또의 개수를 출력

## 비즈니스 로직

### 로또 발행

- [x] 발행할 로또 수량 계산
- [x] 수량만큼 로또 발행
- [x] 1~30 범위의 중복되지 않는 랜덤한 5개의 수 추출

### 로또 추첨

- [x] 발행 로또에 대해 당첨 검사
- [x] 각 로또 번호가 당첨 번호와 일치하는지 비교
- [x] 각 로또 번호가 보너스 번호와 일치하는지 비교
- [x] 당첨 번호 일치 갯수와 보너스 번호 일치 여부를 통해 결과 산출
- [x] 발행 수량만큼 반복 검사


- [x] 당첨된 로또들의 당첨 금액을 집계

### 날짜 집계 기능 추가

- [x] 로또가 발행된 날짜 기록
- [x] 당첨된 로또들의 발행 날짜 기록

8 changes: 7 additions & 1 deletion src/main/java/planetlotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package planetlotto;

import planetlotto.controller.LottoController;
import planetlotto.service.IssueService;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
IssueService issueService = new IssueService();
LottoController controller = new LottoController(issueService);

controller.run();
}
}
81 changes: 81 additions & 0 deletions src/main/java/planetlotto/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package planetlotto.controller;

import java.util.List;
import java.util.function.Supplier;
import planetlotto.domain.Amount;
import planetlotto.domain.DrawResult;
import planetlotto.domain.Lotto;
import planetlotto.domain.Lottos;
import planetlotto.domain.WinningNumbers;
import planetlotto.service.IssueService;
import planetlotto.view.InputView;
import planetlotto.view.OutputView;

public class LottoController {
private static final String INVALID_INPUT_ERROR = "유효하지 않은 입력 값입니다. 다시 입력해 주세요.";
private final IssueService issueService;

public LottoController(IssueService issueService) {
this.issueService = issueService;
}

public void run() {
Amount amount = readAmount();
Lottos purchasedLottos = issueService.issueByAmount(amount);

OutputView.printPurchasedLottos(purchasedLottos.getLottosList());

WinningNumbers winningNumbers = readWinningNumbers();

DrawResult drawResult = purchasedLottos.drawBy(winningNumbers);

OutputView.printResult(drawResult.get());
OutputView.printDateResult(drawResult.getDayOfWeekMap());
}

private Amount readAmount() {
return retry(() -> {
int amountValue = InputView.askAmount();
return Amount.of(amountValue);
});
}

private WinningNumbers readWinningNumbers() {
Lotto baseNumbers = readWinningBase();

return retry(() -> {
int bonusNumber = InputView.askBonusNumber();

return WinningNumbers.of(baseNumbers, bonusNumber);
});
}

private Lotto readWinningBase() {
return retry(() -> {
List<Integer> winningBase = InputView.askWinningLotto();

return Lotto.of(winningBase);
});
}


private <T> T retry(Supplier<T> supplier) {
while (true) {
try {
return supplier.get();
} catch (IllegalArgumentException exception) {
printExceptionMessage(exception);
}
}
}

private void printExceptionMessage(IllegalArgumentException exception) {
String message = exception.getMessage();

if ((message == null) || message.isBlank()) {
message = INVALID_INPUT_ERROR;
}

OutputView.printErrorMessage(message);
}
}
33 changes: 33 additions & 0 deletions src/main/java/planetlotto/domain/Amount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package planetlotto.domain;

public class Amount {
private final int amount;

private Amount(int amount) {
validateAmount(amount);
this.amount = amount;
}

public static Amount of(int amount) {
return new Amount(amount);
}

public int getAmount() {
return amount;
}

private void validateAmount(int amount) {
if (amount <= 0) {
throw new IllegalArgumentException();
}

if (amount % 500 != 0) {
throw new IllegalArgumentException();
}
}

public int availableQuantityByPolicy(int i) {
return amount / LottoPolicy.TICKET_PRICE.get();

}
}
53 changes: 53 additions & 0 deletions src/main/java/planetlotto/domain/DrawResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package planetlotto.domain;

import java.time.DayOfWeek;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

public class DrawResult {
private final Map<Integer, Integer> drawResultMap;
private final Map<DayOfWeek, Integer> issueLottoDayOfWeekMap;

private DrawResult(Map<Integer, Integer> drawResultMap) {
Map<Integer, Integer> drawDayResultMap = new HashMap<>();

for (WinningRules rule : WinningRules.values()) {
drawDayResultMap.put(rule.ordinal(), 0);
}
this.drawResultMap = drawDayResultMap;

Map<DayOfWeek, Integer> issueLottoDayOfWeekMap = new EnumMap<>(DayOfWeek.class);

for (DayOfWeek dayOfWeek : DayOfWeek.values()) {
issueLottoDayOfWeekMap.put(dayOfWeek, 0);
}
this.issueLottoDayOfWeekMap = issueLottoDayOfWeekMap;
}

public static DrawResult create() {
Map<Integer, Integer> drawResultMap = new HashMap<>();
for (WinningRules rule : WinningRules.values()) {
drawResultMap.put(rule.ordinal(), 0);
}
return new DrawResult(drawResultMap);
}

public void addWinner(WinningRules winningRule, DayOfWeek dayOfWeek) {
drawResultMap.merge(winningRule.ordinal(), 1, Integer::sum);
issueLottoDayOfWeekMap.merge(dayOfWeek, 1, Integer::sum);
}

public int countOf(WinningRules winningRules) {
return drawResultMap.get(winningRules.ordinal());
}

public Map<Integer, Integer> get() {
return Collections.unmodifiableMap(new HashMap<>(this.drawResultMap));
}

public Map<DayOfWeek, Integer> getDayOfWeekMap() {
return Collections.unmodifiableMap(issueLottoDayOfWeekMap);
}
}
93 changes: 93 additions & 0 deletions src/main/java/planetlotto/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package planetlotto.domain;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Lotto {
private final DayOfWeek dayOfWeek;
private final List<Integer> numbers;

public Lotto(List<Integer> numbers, DayOfWeek dayOfWeek) {
validate(numbers);

List<Integer> newNumbers = new ArrayList<>(numbers);
newNumbers.sort(Comparator.naturalOrder());
this.numbers = newNumbers;
this.dayOfWeek = dayOfWeek;
}

public static Lotto of(List<Integer> numbers) {
int dayOfWeekIndex = (int) (Math.random() * 7) + 1;

return new Lotto(numbers, DayOfWeek.of(dayOfWeekIndex));
}

public static Lotto ofToday(List<Integer> numbers) {

LocalDate today = LocalDate.now();
return new Lotto(numbers, today.getDayOfWeek());
}

private static void validate(List<Integer> numbers) {
validateNumberCount(numbers);
validateNumberRange(numbers);
validateDuplicateNumber(numbers);
}

private static void validateNumberRange(List<Integer> numbers) {
if (hasOutOfRange(numbers)) {
throw new IllegalArgumentException();
}
}

private static boolean hasOutOfRange(List<Integer> numbers) {
return numbers.stream()
.anyMatch(Lotto::isOutOfRange);
}

private static boolean isOutOfRange(Integer number) {
return number < LottoPolicy.MIN_NUMBER.get() || LottoPolicy.MAX_NUMBER.get() < number;
}

private static void validateDuplicateNumber(List<Integer> numbers) {
if (hasDuplicates(numbers)) {
throw new IllegalArgumentException();
}
}

private static boolean hasDuplicates(List<Integer> numbers) {
Set<Integer> uniqueNumbers = new HashSet<>(numbers);
return uniqueNumbers.size() != numbers.size();
}

private static void validateNumberCount(List<Integer> numbers) {
if (numbers.size() != LottoPolicy.SIZE.get()) {
throw new IllegalArgumentException();
}
}

public boolean contains(int bonus) {
return this.numbers.contains(bonus);
}

public int countMatchesWith(Lotto other) {
long matchCount = this.numbers.stream()
.filter(other::contains)
.count();
return (int) matchCount;
}

public List<Integer> getList() {
return List.copyOf(this.numbers);
}

public DayOfWeek getDayOfWeek() {
return dayOfWeek;
}
}

18 changes: 18 additions & 0 deletions src/main/java/planetlotto/domain/LottoPolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package planetlotto.domain;

public enum LottoPolicy {
SIZE(5),
MIN_NUMBER(1),
MAX_NUMBER(30),
TICKET_PRICE(500);

private final int value;

LottoPolicy(int value) {
this.value = value;
}

public int get() {
return value;
}
}
Loading