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
9 changes: 8 additions & 1 deletion src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package lotto;

import lotto.config.AppConfig;
import lotto.controller.LottoController;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현

AppConfig appConfig = new AppConfig();
LottoController controller = appConfig.lottoController();

controller.run();
}
}
20 changes: 0 additions & 20 deletions src/main/java/lotto/Lotto.java

This file was deleted.

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

import lotto.controller.LottoController;
import lotto.domain.LottoMachine;
import lotto.view.InputView;
import lotto.view.OutputView;

public class AppConfig {

public LottoController lottoController() {
return new LottoController(inputView(), outputView(), lottoMachine());
}

private InputView inputView() {
return new InputView();
}

private OutputView outputView() {
return new OutputView();
}

private LottoMachine lottoMachine() {
return new LottoMachine();
}
}
22 changes: 22 additions & 0 deletions src/main/java/lotto/constants/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package lotto.constants;

public enum ErrorMessage {
INVALID_SIZE("로또 번호는 " + LottoRule.LOTTO_SIZE + "개여야 합니다."),
DUPLICATE_NUMBER("로또 번호는 중복될 수 없습니다."),
INVALID_RANGE("로또 번호는 " + LottoRule.MIN_NUMBER + "부터 " + LottoRule.MAX_NUMBER + " 사이여야 합니다."),
INVALID_MONEY("로또 구입 금액은 " + LottoRule.TICKET_PRICE + "원 단위여야 합니다."),
DUPLICATE_BONUS_NUMBER("보너스 번호는 당첨 번호와 중복될 수 없습니다."),
EMPTY_INPUT("입력값이 비어있습니다."),
NOT_NUMERIC("숫자만 입력해 주세요.");

private static final String PREFIX = "[ERROR] ";
private final String message;

ErrorMessage(String message) {
this.message = message;
}

public String getMessage() {
return PREFIX + message;
}
}
17 changes: 17 additions & 0 deletions src/main/java/lotto/constants/InputMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lotto.constants;

public enum InputMessage {
REQUEST_PURCHASE_AMOUNT("구입금액을 입력해 주세요."),
REQUEST_WINNING_NUMBERS("\n당첨 번호를 입력해 주세요."),
REQUEST_BONUS_NUMBER("\n보너스 번호를 입력해 주세요.");

private final String message;

InputMessage(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}
11 changes: 11 additions & 0 deletions src/main/java/lotto/constants/LottoRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package lotto.constants;

public class LottoRule {
public static final int MIN_NUMBER = 1;
public static final int MAX_NUMBER = 45;
public static final int LOTTO_SIZE = 6;
public static final int TICKET_PRICE = 1000;

private LottoRule() {
}
}
19 changes: 19 additions & 0 deletions src/main/java/lotto/constants/OutputMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package lotto.constants;

public enum OutputMessage {
PURCHASE_COUNT_MESSAGE("\n%d개를 구매했습니다.\n"),
WINNING_STATISTICS_HEADER("\n당첨 통계\n---"),
YIELD_MESSAGE("총 수익률은 %.1f%%입니다.\n"),
NORMAL_RANK_FORMAT("%d개 일치 (%,d원) - %d개\n"),
SECOND_RANK_FORMAT("%d개 일치, 보너스 볼 일치 (%,d원) - %d개\n");

private final String message;

OutputMessage(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}
46 changes: 46 additions & 0 deletions src/main/java/lotto/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package lotto.controller;

import lotto.domain.Lotto;
import lotto.domain.LottoMachine;
import lotto.domain.LottoResult;
import lotto.domain.WinningLotto;
import lotto.view.InputView;
import lotto.view.OutputView;

import java.util.List;

public class LottoController {
private final InputView inputView;
private final OutputView outputView;
private final LottoMachine lottoMachine; // 의존성 주입받을 도메인

public LottoController(InputView inputView, OutputView outputView, LottoMachine lottoMachine) {
this.inputView = inputView;
this.outputView = outputView;
this.lottoMachine = lottoMachine;
}

public void run() {
try {
int purchaseAmount = inputView.readPurchaseAmount();
List<Lotto> purchasedLottos = lottoMachine.buyLottos(purchaseAmount);
outputView.printPurchasedLottos(purchasedLottos);

List<Integer> winningNumbers = inputView.readWinningNumbers();
Lotto winningLottoNumbers = new Lotto(winningNumbers);

int bonusNumber = inputView.readBonusNumber();
WinningLotto winningLotto = new WinningLotto(winningLottoNumbers, bonusNumber);

LottoResult lottoResult = new LottoResult();
lottoResult.compareLottos(purchasedLottos, winningLotto);

outputView.printWinningStatistics(lottoResult);
double yield = lottoResult.calculateYield(purchaseAmount);
outputView.printTotalYield(yield);

} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e);
}
}
}
45 changes: 45 additions & 0 deletions src/main/java/lotto/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package lotto.domain;

import lotto.constants.ErrorMessage;
import lotto.constants.LottoRule;

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) {
validateSize(numbers);
validateDuplicate(numbers);
this.numbers = numbers;
}

public List<Integer> getNumbers() {
return numbers;
}

private void validateSize(List<Integer> numbers) {
if (numbers.size() != LottoRule.LOTTO_SIZE) {
throw new IllegalArgumentException(ErrorMessage.INVALID_SIZE.getMessage());
}
}

private void validateDuplicate(List<Integer> numbers) {
Set<Integer> uniqueNumbers = new HashSet<>(numbers);
if (uniqueNumbers.size() != numbers.size()) {
throw new IllegalArgumentException(ErrorMessage.DUPLICATE_NUMBER.getMessage());
}
}

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

public int countMatchingNumbers(Lotto otherLotto) {
return (int) numbers.stream()
.filter(otherLotto::contains)
.count();
}
}
45 changes: 45 additions & 0 deletions src/main/java/lotto/domain/LottoMachine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package lotto.domain;

import camp.nextstep.edu.missionutils.Randoms;
import lotto.constants.ErrorMessage;
import lotto.constants.LottoRule;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class LottoMachine {

public List<Lotto> buyLottos(int money) {
validateMoney(money);
int count = money / LottoRule.TICKET_PRICE;
return generateLottos(count);
}

private void validateMoney(int money) {
if (money <= 0 || money % LottoRule.TICKET_PRICE != 0) {
throw new IllegalArgumentException(ErrorMessage.INVALID_MONEY.getMessage());
}
}

private List<Lotto> generateLottos(int count) {
List<Lotto> lottos = new ArrayList<>();
for (int i = 0; i < count; i++) {
lottos.add(generateSingleLotto());
}
return lottos;
}

private Lotto generateSingleLotto() {
List<Integer> numbers = Randoms.pickUniqueNumbersInRange(
LottoRule.MIN_NUMBER,
LottoRule.MAX_NUMBER,
LottoRule.LOTTO_SIZE
);

List<Integer> sortedNumbers = new ArrayList<>(numbers);
Collections.sort(sortedNumbers);

return new Lotto(sortedNumbers);
}
}
46 changes: 46 additions & 0 deletions src/main/java/lotto/domain/LottoResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package lotto.domain;

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

public class LottoResult {
private final Map<Rank, Integer> result;

public LottoResult() {
this.result = new EnumMap<>(Rank.class);
for (Rank rank : Rank.values()) {
result.put(rank, 0);
}
}

public void compareLottos(List<Lotto> userLottos, WinningLotto winningLotto) {
for (Lotto lotto : userLottos) {
Rank rank = winningLotto.match(lotto);
result.put(rank, result.get(rank) + 1);
}
}

private long calculateTotalPrize() {
long totalPrize = 0;
for (Map.Entry<Rank, Integer> entry : result.entrySet()) {
totalPrize += (long) entry.getKey().getPrizeMoney() * entry.getValue();
}
return totalPrize;
}

public double calculateYield(int purchaseAmount) {
if (purchaseAmount == 0) {
return 0.0;
}
long totalPrize = calculateTotalPrize();
double yield = ((double) totalPrize / purchaseAmount) * 100;

return Math.round(yield * 10.0) / 10.0;
}

public Map<Rank, Integer> getResult() {
return Collections.unmodifiableMap(result);
}
}
45 changes: 45 additions & 0 deletions src/main/java/lotto/domain/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package lotto.domain;

public enum Rank {
FIRST(6, 2_000_000_000),
SECOND(5, 30_000_000),
THIRD(5, 1_500_000),
FOURTH(4, 50_000),
FIFTH(3, 5_000),
NONE(0, 0);

private final int matchCount;
private final int prizeMoney;

Rank(int matchCount, int prizeMoney) {
this.matchCount = matchCount;
this.prizeMoney = prizeMoney;
}

public static Rank valueOf(int matchCount, boolean matchBonus) {
if (matchCount == 6) {
return FIRST;
}
if (matchCount == 5 && matchBonus) {
return SECOND;
}
if (matchCount == 5 && !matchBonus) {
return THIRD;
}
if (matchCount == 4) {
return FOURTH;
}
if (matchCount == 3) {
return FIFTH;
}
return NONE;
}

public int getMatchCount() {
return matchCount;
}

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

import lotto.constants.ErrorMessage;
import lotto.constants.LottoRule;

public class WinningLotto {
private final Lotto winningLotto;
private final int bonusNumber;

public WinningLotto(Lotto winningLotto, int bonusNumber) {
validateBonusNumber(winningLotto, bonusNumber);
this.winningLotto = winningLotto;
this.bonusNumber = bonusNumber;
}

private void validateBonusNumber(Lotto winningLotto, int bonusNumber) {
if (bonusNumber < LottoRule.MIN_NUMBER || bonusNumber > LottoRule.MAX_NUMBER) {
throw new IllegalArgumentException(ErrorMessage.INVALID_RANGE.getMessage());
}
if (winningLotto.contains(bonusNumber)) {
throw new IllegalArgumentException(ErrorMessage.DUPLICATE_BONUS_NUMBER.getMessage());
}
}

public Rank match(Lotto userLotto) {
int matchCount = userLotto.countMatchingNumbers(winningLotto);
boolean matchBonus = userLotto.contains(bonusNumber);

return Rank.valueOf(matchCount, matchBonus);
}
}
Loading