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
18 changes: 18 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
- [ ] 구입 금액 입력
- [ ] 1000원 단위인지 검사하는 기능
- [ ] 당첨 번호 입력
- [ ] 1 ~ 45 사이인지 검사하는 기능
- [ ] 중복 여부 검사하는 기능
- [ ] 쉼표로 구분하는 기능
- [ ] 보너스 번호 입력
- [ ] 1 ~ 45 사이인지 검사하는 기능
- [ ] 당첨 번호와의 중복 여부 검사하는 기능
- [ ] 발행한 로또 출력
- [ ] 1 ~ 45 사이의 중복되지 않는 숫자 6개를 뽑는 기능
- [ ] 오름차순으로 만드는 기능
- [ ] 당첨 내역 출력
- [ ] 당첨 번호와 발행한 로또를 비교하는 기능
- [ ] 당첨된를 등수 저장하는 기능
- [ ] 수익률 출력
- [ ] 수익금 계산하는 기능
- [ ] 소수점 둘째 자리에서 반올림하는 기능
4 changes: 4 additions & 0 deletions src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package lotto;

import lotto.controller.LottoController;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
LottoController lottoController = new LottoController();
lottoController.lottoStart();
}
}
20 changes: 0 additions & 20 deletions src/main/java/lotto/Lotto.java

This file was deleted.

36 changes: 36 additions & 0 deletions src/main/java/lotto/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package lotto.controller;

import lotto.domain.*;
import lotto.view.InputView;
import lotto.view.OutputView;

import java.util.Map;

public class LottoController {

public void lottoStart() {
try {
int purchaseAmount = InputView.getPurchaseAmount();
LottoGenerator lottoGenerator = new LottoGenerator(purchaseAmount);
Lottos lottos = new Lottos(lottoGenerator.generateLottos());
printLottosInformation(lottoGenerator, lottos);
WinningLotto winningLotto = new WinningLotto(InputView.getLottoNumber(), InputView.getLottoBonusNumber());
Map<WinningRank, Integer> winningDetails = WinningStatistics.getWinningDetails(lottos, winningLotto);
printWinningInformation(winningDetails, purchaseAmount);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}

private void printLottosInformation(LottoGenerator lottoGenerator, Lottos lottos) {
OutputView.printHowManyLottoUserPurchased(lottoGenerator.getLottoQuantity());
OutputView.printLottos(lottos);
}

private void printWinningInformation(Map<WinningRank, Integer> winningDetails, int purchaseAmount) {
OutputView.printWinningStatistics();
OutputView.printWinningDetails(winningDetails);
long winningAmount = WinningStatistics.getWinningAmount(winningDetails);
OutputView.printLottoYield(WinningStatistics.getLottoYield(winningAmount, purchaseAmount));
}
}
34 changes: 34 additions & 0 deletions src/main/java/lotto/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package lotto.domain;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

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

public Lotto(List<Integer> numbers) {
validate(numbers);
this.numbers = numbers;
}
// TODO: 추가 기능 구현

private void validate(List<Integer> numbers) {
if (!isSizeSix(numbers) || isDuplicate(numbers)) {
throw new IllegalArgumentException();
}
}

private boolean isSizeSix(List<Integer> numbers) {
return numbers.size() == 6;
}

private boolean isDuplicate(List<Integer> numbers) {
Set<Integer> duplicateChecker = new HashSet<>(numbers);
return duplicateChecker.size() != 6;
}

public List<Integer> getNumbers() {
return numbers;
}
}
57 changes: 57 additions & 0 deletions src/main/java/lotto/domain/LottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package lotto.domain;

import org.kokodak.Randoms;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class LottoGenerator {
private static final int LOTTO_PRICE = 1_000;
private static final int LOTTO_NUMBER_LOWER_LIMIT = 1;
private static final int LOTTO_NUMBER_UPPER_LIMIT = 45;
private static final int LOTTO_NUMBER_QUANTITY = 6;
private static final int ZERO = 0;
private static final String MONEY_SHOULD_BE_DIVIDED_BY_ONE_THOUSAND = "[ERROR] 구입 금액은 1,000원 단위로만 받을 수 있습니다.";
// static 변수로 생성
private final List<Lotto> lottos = new ArrayList<>();
private final int lottoQuantity;

public LottoGenerator(int money) {
validateMoney(money);
lottoQuantity = money / LOTTO_PRICE;
}

private void validateMoney(int money) {
if (money % LOTTO_PRICE != ZERO) {
throw new IllegalArgumentException(MONEY_SHOULD_BE_DIVIDED_BY_ONE_THOUSAND);
}
}

private boolean isZeroOrNegativeNumber(int money) {
return money <= ZERO;
}

private boolean isDividedByOneThousand(int money) {
return money % LOTTO_PRICE == ZERO;
}

public List<Lotto> generateLottos() { // 로또들을 담을 객체 반환
for (int i = 0; i < lottoQuantity; i++) {
Lotto lotto = generateLotto();
lottos.add(lotto);
}
return lottos;
}

private Lotto generateLotto() {
List<Integer> randomNumbers = Randoms.pickUniqueNumbersInRange(LOTTO_NUMBER_LOWER_LIMIT, LOTTO_NUMBER_UPPER_LIMIT, LOTTO_NUMBER_QUANTITY);
// 범위 내에서 로또 번호 생성
randomNumbers.sort(Comparator.naturalOrder()); // 오름차순 정렬
return new Lotto(randomNumbers); // 생성한 로또 반환
}

public int getLottoQuantity() {
return lottoQuantity;
}
}
14 changes: 14 additions & 0 deletions src/main/java/lotto/domain/Lottos.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package lotto.domain;

import java.util.List;

public class Lottos {
private List<Lotto> lottos;

public Lottos(List<Lotto> lottos) {
this.lottos = lottos;
}
public List<Lotto> getLottos() {
return lottos;
}
}
73 changes: 73 additions & 0 deletions src/main/java/lotto/domain/WinningLotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package lotto.domain;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class WinningLotto {
private static final String WINNING_NUMBERS_ARE_BETWEEN_ONE_AND_FORTY_FIVE = "[ERROR] 당첨 번호는 1부터 45 사이의 숫자여야 합니다.";
private static final String WINNING_NUMBERS_MUST_BE_SIX_DIFFERENT_NUMBERS = "[ERROR] 당첨 번호는 서로 다른 6개의 수여야 합니다.";
private static final String BONUS_NUMBER_IS_BETWEEN_ONE_AND_FORTY_FIVE = "[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다.";
private static final String WINNING_NUMBERS_CONTAIN_BONUS_NUMBER = "[ERROR] 당첨 번호와 보너스 번호가 중복됩니다.";
private static final int LOTTO_NUMBER_LOWER_LIMIT = 1;
private static final int LOTTO_NUMBER_UPPER_LIMIT = 45;
private static final int LOTTO_NUMBERS_SIZE = 6;

private final List<Integer> winningNumbers;
private final int bonusNumber;

public WinningLotto(List<Integer> winningNumbers, int bonusNumber) {
validateWinningNumbers(winningNumbers);
validateBonusNumber(bonusNumber);
validateDuplicate(winningNumbers, bonusNumber);
this.winningNumbers = winningNumbers;
this.bonusNumber = bonusNumber;
}

private void validateWinningNumbers(List<Integer> winningNumbers) {
if (!isSixDifferentNumbers(winningNumbers)) {
throw new IllegalArgumentException(WINNING_NUMBERS_MUST_BE_SIX_DIFFERENT_NUMBERS);
}
if (!isBetweenOneAndFortyFive(winningNumbers)) {
throw new IllegalArgumentException(WINNING_NUMBERS_ARE_BETWEEN_ONE_AND_FORTY_FIVE);
}
}

private boolean isBetweenOneAndFortyFive(List<Integer> winningNumbers) {
for (int winningNumber : winningNumbers) {
if (winningNumber < LOTTO_NUMBER_LOWER_LIMIT || winningNumber > LOTTO_NUMBER_UPPER_LIMIT) {
return false;
}
}
return true;
}

private boolean isSixDifferentNumbers(List<Integer> winningNumbers) {
Set<Integer> duplicateChecker = new HashSet<>(winningNumbers);
return duplicateChecker.size() == LOTTO_NUMBERS_SIZE;
}

private void validateBonusNumber(int bonusNumber) {
if (!isBetweenOneAndFortyFive(bonusNumber)) {
throw new IllegalArgumentException(BONUS_NUMBER_IS_BETWEEN_ONE_AND_FORTY_FIVE);
}
}

private boolean isBetweenOneAndFortyFive(int bonusNumber) {
return bonusNumber >= LOTTO_NUMBER_LOWER_LIMIT && bonusNumber <= LOTTO_NUMBER_UPPER_LIMIT;
}

private void validateDuplicate(List<Integer> winningNumbers, int bonusNumber) {
if (winningNumbers.contains(bonusNumber)) {
throw new IllegalArgumentException(WINNING_NUMBERS_CONTAIN_BONUS_NUMBER);
}
}

public List<Integer> getWinningNumbers() {
return winningNumbers;
}

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

import java.util.Arrays;
import java.util.EnumMap;
import java.util.Map;

public enum WinningRank {
LAST_PLACE(0, false, 0),
FIFTH_PLACE(3, false, 5_000),
FOURTH_PLACE(4, false, 50_000),
THIRD_PLACE(5, false, 1_500_000),
SECOND_PLACE(5, true, 30_000_000),
FIRST_PLACE(6, false, 2_000_000_000);

private final int matchingCount;
private final boolean containsBonusNumber;
private final int winningPrice;

WinningRank(int matchingCount, boolean containsBonusNumber, int winningPrice) {
this.matchingCount = matchingCount;
this.containsBonusNumber = containsBonusNumber;
this.winningPrice = winningPrice;
}

public static WinningRank findWinningRank(int matchingCount, boolean containsBonusNumber) {
return Arrays.stream(values())
.filter(winningRank -> winningRank.matchingCount == matchingCount)
.filter(winningRank -> winningRank.containsBonusNumber == containsBonusNumber)
.findFirst()
.orElse(WinningRank.LAST_PLACE);
}

public int getMatchingCount() {
return matchingCount;
}

public int getWinningPrice() {
return winningPrice;
}
}
58 changes: 58 additions & 0 deletions src/main/java/lotto/domain/WinningStatistics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package lotto.domain;

import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

public class WinningStatistics {
private static final int AT_LEAST_THIRD_PLACE = 5;
private static final int PERCENTAGE = 100;
private static final int INITIAL_VALUE = 0;

public static Map<WinningRank, Integer> getWinningDetails(Lottos lottos, WinningLotto winningLotto) {
Map<WinningRank, Integer> winningDetails = generateWinningDetails();
for (Lotto lotto : lottos.getLottos()) {
int matchingCount = compareNumbersWithWinningNumbers(lotto, winningLotto);
boolean containsBonusNumber = compareNumbersWithBonusNumber(lotto, winningLotto, matchingCount);
WinningRank winningRank = WinningRank.findWinningRank(matchingCount, containsBonusNumber);
winningDetails.replace(winningRank, winningDetails.get(winningRank) + 1);
}
return winningDetails;
}

public static Map<WinningRank, Integer> generateWinningDetails() {
Map<WinningRank, Integer> winningDetails = new EnumMap<>(WinningRank.class);
Arrays.stream(WinningRank.values()).forEach(winningRank -> winningDetails.put(winningRank, INITIAL_VALUE));
return winningDetails;
}

private static int compareNumbersWithWinningNumbers(Lotto lotto, WinningLotto winningLotto) {
List<Integer> numbers = lotto.getNumbers();
List<Integer> winningNumbers = winningLotto.getWinningNumbers();
return (int) numbers.stream()
.filter(winningNumbers::contains)
.count();
}

private static boolean compareNumbersWithBonusNumber(Lotto lotto, WinningLotto winningLotto, int matchingCount) {
if (matchingCount != AT_LEAST_THIRD_PLACE) {
return false;
}
List<Integer> numbers = lotto.getNumbers();
int bonusNumber = winningLotto.getBonusNumber();
return numbers.contains(bonusNumber);
}

public static long getWinningAmount(Map<WinningRank, Integer> winningDetails) {
return winningDetails.entrySet().stream()
.mapToLong(entry -> (long) entry.getKey().getWinningPrice() * entry.getValue())
.sum();
}

public static double getLottoYield(long winningAmount, int money) {
double lottoYield = PERCENTAGE + (double) (winningAmount - money) / money * PERCENTAGE;
return Math.round(lottoYield * 10) / 10.0;
}

}
Loading