Skip to content
Open
74 changes: 45 additions & 29 deletions src/main/java/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -1,54 +1,70 @@
package controller;

import model.Lotto;
import model.LottoTickets;
import model.*;
import view.ErrorView;
import view.InputView;
import view.ResultView;

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


public class LottoController {

public void run() {
try {
int purchaseAmount = InputView.getPurchaseAmount();

validatePurchaseAmount(purchaseAmount);

int ticketCount = LottoTickets.getTicketCount(purchaseAmount);

LottoTickets lottoTickets = new LottoTickets(ticketCount);

ResultView.printOrderTickets(ticketCount);

ResultView.printPurchasedLottoTickets(formatTickets(lottoTickets.getTickets()));

LottoPurchaseInfo lottoPurchaseInfo = getPurchaseAmount();
int manualCount = getManualCount(lottoPurchaseInfo);
LottoTickets lottoTickets = generateLottoTickets(lottoPurchaseInfo, manualCount);
ResultView.printOrderTickets(manualCount, lottoPurchaseInfo.getTicketCount() - manualCount);
ResultView.printPurchasedLottoTickets(lottoTickets.getFormattedTicketNumbers());
processWinningResults(lottoTickets, lottoPurchaseInfo);
InputView.closeScanner();
} catch (IllegalArgumentException e) {
ErrorView.printErrorMessage(e.getMessage());
}
}

private List<String> formatTickets(List<Lotto> tickets) {
return tickets.stream()
.map(this::convertLottoToString)
.toList();
private LottoPurchaseInfo getPurchaseAmount() {
return new LottoPurchaseInfo(InputView.getPurchaseAmount());
}

private String convertLottoToString(Lotto lotto) {
return lotto.getSortedNumbers().stream()
.map(String::valueOf)
.collect(Collectors.joining(",", "[", "]"));
private int getManualCount(LottoPurchaseInfo lottoPurchaseInfo) {
int manualCount = InputView.getManualTicketCount();
validateManualCount(manualCount, lottoPurchaseInfo);
return manualCount;
}

private void validatePurchaseAmount(int purchaseAmount) {
if (purchaseAmount < LottoTickets.LOTTO_PRICE) {
throw new IllegalArgumentException("구매 금액은 1000원 이상이어야 합니다.");
}
private LottoTickets generateLottoTickets(LottoPurchaseInfo lottoPurchaseInfo, int manualCount) {
List<List<Integer>> manualNumbers = InputView.getManualNumbers(manualCount);
int autoCount = lottoPurchaseInfo.getTicketCount() - manualCount;
LottoTickets manualTickets = new LottoTickets(manualNumbers);
LottoTickets autoTickets = new LottoTickets(autoCount);
return LottoTickets.merge(manualTickets, autoTickets);
}

if (purchaseAmount % LottoTickets.LOTTO_PRICE != 0) {
throw new IllegalArgumentException("구매 금액은 1000원 단위여야 합니다.");
public void validateManualCount(int manualCount, LottoPurchaseInfo lottoPurchaseInfo) {
if (manualCount > lottoPurchaseInfo.getTicketCount()) {
throw new IllegalArgumentException("수동 구매 개수가 구매 가능한 개수를 초과할 수 없습니다.");
}
}

private void processWinningResults(LottoTickets lottoTickets, LottoPurchaseInfo lottoPurchaseInfo) {
LottoResult lottoResult = createLottoResult(lottoTickets, getWinningNumbers());

Map<String, Integer> formattedWinningDetails = lottoResult.getFormattedWinningDetails();
double profitRate = lottoResult.calculateProfitRate(lottoPurchaseInfo.getAmount());

ResultView.printWinningStatistics(formattedWinningDetails, profitRate);
}

private WinningNumbers getWinningNumbers() {
List<Integer> winningNumbers = InputView.getWinningNumbers();
int bonusNumber = InputView.getBonusNumber();
return new WinningNumbers(winningNumbers, bonusNumber);
}

private LottoResult createLottoResult(LottoTickets lottoTickets, WinningNumbers winningNumbers) {
return new LottoResult(lottoTickets.getTickets(), winningNumbers);
}
}
36 changes: 10 additions & 26 deletions src/main/java/model/Lotto.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,22 @@
package model;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

//로또 한 장
public class Lotto {
private final LottoNumbers lottoNumbers;

// 로또 번호 관련 상수 선언
public static final int LOTTO_MIN_NUMBER = 1;
public static final int LOTTO_MAX_NUMBER = 45;
public static final int LOTTO_CREATE_SIZE = 6;
public static final List<Integer> LOTTO_NUMBER_POOL =
IntStream.rangeClosed(LOTTO_MIN_NUMBER,LOTTO_MAX_NUMBER)
.boxed()
.collect(Collectors.toList());

private List<Integer> numbers;

public Lotto(){
this.numbers = createLottoNumbers();
//수동 로또
public Lotto(List<Integer> numbers) {
this.lottoNumbers = new LottoNumbers(numbers);
}

private List<Integer> createLottoNumbers(){
List<Integer> shuffledNumbers = new ArrayList<>(LOTTO_NUMBER_POOL);
Collections.shuffle(shuffledNumbers);
numbers = shuffledNumbers.subList(0, LOTTO_CREATE_SIZE);

return numbers;
//자동 로또
public Lotto(LottoNumbers lottoNumbers) {
this.lottoNumbers = lottoNumbers;
}

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

return sortedNumbers;
public List<Integer> getNumbers() {
return lottoNumbers.getNumbers();
}
}
53 changes: 53 additions & 0 deletions src/main/java/model/LottoNumbers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package model;

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

public class LottoNumbers {
private static final int LOTTO_MIN_NUMBER = 1;
private static final int LOTTO_MAX_NUMBER = 45;
private static final int LOTTO_CREATE_SIZE = 6;

private final List<Integer> numbers;

public LottoNumbers() {
this.numbers = sortedNumbers(generateAutoLottoNumbers());
}

public LottoNumbers(List<Integer> numbers) {
validate(numbers);
this.numbers = sortedNumbers(numbers);
}

private void validate(List<Integer> numbers) {
if (numbers.size() != LOTTO_CREATE_SIZE) {
throw new IllegalArgumentException("로또 번호는 6개여야 합니다.");
}
if (numbers.stream().distinct().count() != LOTTO_CREATE_SIZE) {
throw new IllegalArgumentException("중복된 숫자가 있습니다.");
}
if (numbers.stream().anyMatch(n -> n < LOTTO_MIN_NUMBER || n > LOTTO_MAX_NUMBER)) {
throw new IllegalArgumentException("로또 번호는 1~45 사이여야 합니다.");
}
}

private List<Integer> generateAutoLottoNumbers() {
List<Integer> shuffledNumbers = IntStream.rangeClosed(LOTTO_MIN_NUMBER, LOTTO_MAX_NUMBER)
.boxed()
.collect(Collectors.toList());
Collections.shuffle(shuffledNumbers);

return shuffledNumbers.subList(0,LOTTO_CREATE_SIZE);
}

private List<Integer> sortedNumbers(List<Integer> numbers) {
return List.copyOf(numbers.stream().sorted().toList());
}

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

public class LottoPurchaseInfo {
private static final int LOTTO_PRICE = 1000;
private final int amount;

public LottoPurchaseInfo(int amount) {
validatePurchaseAmount(amount);
this.amount = amount;
}

private void validatePurchaseAmount(int amount) {
if (amount < LOTTO_PRICE) {
throw new IllegalArgumentException("구매 금액은 1000원 이상이어야 합니다.");
}
if (amount % LOTTO_PRICE != 0) {
throw new IllegalArgumentException("구매 금액은 1000원 단위여야 합니다.");
}
}

public int getTicketCount() {
return amount / LOTTO_PRICE;
}

public int getAmount() {
return amount;
}

public void validateManualCount(int manualCount) {
if (manualCount > getTicketCount()) {
throw new IllegalArgumentException("수동 구매 개수가 구매 가능한 개수를 초과할 수 없습니다.");
}
}
}
92 changes: 92 additions & 0 deletions src/main/java/model/LottoResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package model;

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

public class LottoResult {
private final Map<Rank, Integer> matchCountMap = new EnumMap<>(Rank.class);

public LottoResult(List<Lotto> tickets, WinningNumbers winningNumbers) {
for (Lotto ticket : tickets) {
Rank rank = determineRank(ticket, winningNumbers);
matchCountMap.put(rank, matchCountMap.getOrDefault(rank, 0) + 1);
}
}

private Rank determineRank(Lotto ticket, WinningNumbers winningNumbers) {
int matchCount = countMatchingNumbers(ticket, winningNumbers);
boolean hasBonus = hasBonusNumber(ticket, winningNumbers);

return getRank(matchCount, hasBonus);
}

// 일치하는 숫자 개수 계산
private int countMatchingNumbers(Lotto ticket, WinningNumbers winningNumbers) {
return (int) ticket.getNumbers().stream()
.filter(winningNumbers.getNumbers()::contains)
.count();
}

// 보너스 번호 포함 여부 확인
private boolean hasBonusNumber(Lotto ticket, WinningNumbers winningNumbers) {
return ticket.getNumbers().contains(winningNumbers.getBonusNumber());
}

private Rank getRank(int matchCount, boolean hasBonus) {
if (matchCount == 6) return Rank.FIRST;
if (matchCount == 5 && hasBonus) return Rank.SECOND;
if (matchCount == 5) return Rank.THIRD;
if (matchCount == 4) return Rank.FOURTH;
if (matchCount == 3) return Rank.FIFTH;
return Rank.NONE;
}

public Map<Rank, Integer> getMatchCountMap() {
return matchCountMap;
}

public double calculateProfitRate(int totalCost) {
List<Integer> prizeAmounts = convertToPrizeAmounts();
int totalPrize = sumPrizeAmounts(prizeAmounts);
return (double) totalPrize / totalCost;
}

// 데이터 변환
private List<Integer> convertToPrizeAmounts() {
return matchCountMap.entrySet().stream()
.map(this::convertToPrizeAmount)
.toList();
}

// Rank 데이터를 변환
private int convertToPrizeAmount(Map.Entry<Rank, Integer> rankEntry) {
Rank rank = rankEntry.getKey();
int count = rankEntry.getValue();
return rank.getPrizeMoney() * count;
}

// 변환된 데이터를 계산
private int sumPrizeAmounts(List<Integer> prizeAmounts) {
return prizeAmounts.stream()
.mapToInt(Integer::intValue)
.sum();
}

public Map<String, Integer> getFormattedWinningDetails() {
Map<String, Integer> formattedDetails = new LinkedHashMap<>();

for (Rank rank : Rank.values()) {
addRankIfValid(formattedDetails, rank);
}

return formattedDetails;
}

private void addRankIfValid(Map<String, Integer> formattedDetails, Rank rank) {
if (rank != Rank.NONE) {
formattedDetails.put(rank.getDescription(), matchCountMap.getOrDefault(rank, 0));
}
}
}
48 changes: 36 additions & 12 deletions src/main/java/model/LottoTickets.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,51 @@
import java.util.List;

public class LottoTickets {

private final List<Lotto> tickets;
public static final int LOTTO_PRICE = 1000;

public LottoTickets(int ticketCount) {
this.tickets = generateLottoTickets(ticketCount);
private LottoTickets(List<Lotto> tickets, boolean unused) {
this.tickets = List.copyOf(tickets);
}

public LottoTickets(List<List<Integer>> manualNumbers) {
List<Lotto> manualTickets = new ArrayList<>();
addManualTickets(manualTickets, manualNumbers);
this.tickets = List.copyOf(manualTickets);
}

public LottoTickets(int autoTicketCount) {
List<Lotto> autoTickets = new ArrayList<>();
addAutoTickets(autoTickets, autoTicketCount);
this.tickets = List.copyOf(autoTickets);
}

public static LottoTickets merge(LottoTickets manualTickets, LottoTickets autoTickets) {
List<Lotto> mergedTickets = new ArrayList<>(manualTickets.tickets);
mergedTickets.addAll(autoTickets.tickets);
return new LottoTickets(mergedTickets, true);
}

private List<Lotto> generateLottoTickets(int ticketCount) {
List<Lotto> tickets = new ArrayList<>();
for (int i = 0; i < ticketCount; i++) {
tickets.add(new Lotto());
private static void addManualTickets(List<Lotto> tickets, List<List<Integer>> manualNumbers) {
for (List<Integer> numbers : manualNumbers) {
tickets.add(new Lotto(numbers));
}
}

private static void addAutoTickets(List<Lotto> tickets, int autoTicketCount) {
for (int i = 0; i < autoTicketCount; i++) {
tickets.add(new Lotto(new LottoNumbers()));
}
return tickets;
}

public List<Lotto> getTickets() {
return new ArrayList<>(tickets);
return tickets;
}

public static int getTicketCount(int purchaseAmount){
return purchaseAmount / LOTTO_PRICE;
public List<List<Integer>> getFormattedTicketNumbers() {
List<List<Integer>> ticketNumbers = new ArrayList<>();
for (Lotto ticket : tickets) {
ticketNumbers.add(ticket.getNumbers());
}
return ticketNumbers;
}
}
Loading