Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f1590cd
리드미 초안
pleasebelieveme Oct 30, 2025
3c89ee4
Merge pull request #1 from pleasebelieveme/pleasebelieveme
pleasebelieveme Oct 30, 2025
51878c2
feat(readme): README 재컴토
pleasebelieveme Nov 1, 2025
9d5d7ab
feat(domain): Rank 열거형 구현
pleasebelieveme Nov 3, 2025
c9a7eef
Merge pull request #2 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
8a33026
feat(domain): Lotto 객체 기본 기능 구현
pleasebelieveme Nov 3, 2025
76e787e
Merge pull request #3 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
84c4e5a
feat(domain): LottoTickets 객체 구현
pleasebelieveme Nov 3, 2025
91370c6
Merge pull request #4 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
6f18405
feat(domain): LottoResult 객체 구현
pleasebelieveme Nov 3, 2025
8d8cbbf
Merge pull request #5 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
cc1c7f4
feat(parser): 구매 금액 파싱 구현
pleasebelieveme Nov 3, 2025
9194306
feat(parser): 구매 금액 파싱 구현 trim() 추가
pleasebelieveme Nov 3, 2025
e655f23
feat(parser): 구매 금액 파싱 구현 필요없는 import 제거
pleasebelieveme Nov 3, 2025
bad53ba
Merge pull request #6 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
6db568b
feat(parser): 당첨 번호 파싱 구현
pleasebelieveme Nov 3, 2025
bebfbe7
Merge pull request #7 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
2c28a1f
feat(parser): 보너스 번호 파싱 구현(추후 Parser 리팩토링 필요!)
pleasebelieveme Nov 3, 2025
e635f45
Merge pull request #8 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
f852873
feat(validator): 구매 금액 검증 구현
pleasebelieveme Nov 3, 2025
f842116
Merge pull request #9 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
c05041a
feat(validator): 당첨 번호 검증 구현
pleasebelieveme Nov 3, 2025
f242aff
Merge pull request #10 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
c92b726
feat(validator): 보너스 번호 검증 구현
pleasebelieveme Nov 3, 2025
b8541c2
Merge pull request #11 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
6e16065
feat(util): 구매 금액에 따른 자동 로또 생성 기능 구현 (LottoGenerator)
pleasebelieveme Nov 3, 2025
849674d
Merge pull request #12 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
58d3f10
feat: 최종 과제물
pleasebelieveme Nov 3, 2025
21899aa
Merge pull request #13 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 3, 2025
05361a0
fix: LottoTickets 주석해제
pleasebelieveme Nov 4, 2025
3f9edf8
Merge pull request #14 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 4, 2025
e3d0b37
fix: 3.1 validator까지 수정완료
pleasebelieveme Nov 4, 2025
8da9aee
Merge pull request #15 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 4, 2025
09082b2
feat(common): LottoConstants 공통 상수 클래스 생성, 에러메세지도 공통 상수를 사용할껀지 고민
pleasebelieveme Nov 4, 2025
151f660
Merge pull request #16 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 4, 2025
35ca8eb
fix: 에러메세지 상수 사용
pleasebelieveme Nov 5, 2025
4d29b74
Merge pull request #17 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 5, 2025
685070a
fix: 기능 개발 완료, Service는 View만 있기에 테스트를 안해도 상관 없음
pleasebelieveme Nov 6, 2025
2c09c21
Merge pull request #18 from pleasebelieveme/pleasebelieveme
pleasebelieveme Nov 6, 2025
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
641 changes: 640 additions & 1 deletion README.md

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package lotto;

import lotto.service.LottoGameService;

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

This file was deleted.

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

/**
* 로또 게임에서 사용하는 에러 메시지를 정의합니다.
*/
public class ErrorMessages {

private ErrorMessages() {
// 상수 클래스는 인스턴스화 방지
}

// 구매 금액 관련
public static final String PURCHASE_AMOUNT_ZERO = "[ERROR] 구입 금액은 0보다 커야 합니다.";
public static final String PURCHASE_AMOUNT_MINIMUM = "[ERROR] 구입 금액은 1,000원 이상이어야 합니다.";
public static final String PURCHASE_AMOUNT_UNIT = "[ERROR] 구입 금액은 1,000원 단위여야 합니다.";
public static final String PURCHASE_AMOUNT_EMPTY = "[ERROR] 구입 금액을 입력해주세요.";
public static final String PURCHASE_AMOUNT_INVALID_FORMAT = "[ERROR] 구입 금액은 숫자여야 합니다.";

// 로또 번호 관련
public static final String LOTTO_NUMBERS_NULL = "[ERROR] 로또 번호를 입력해주세요.";
public static final String LOTTO_NUMBERS_SIZE = "[ERROR] 로또 번호는 6개여야 합니다.";
public static final String LOTTO_NUMBERS_DUPLICATE = "[ERROR] 로또 번호는 중복될 수 없습니다.";
public static final String LOTTO_NUMBERS_RANGE = "[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.";

// 당첨 번호 관련
public static final String WINNING_NUMBERS_EMPTY = "[ERROR] 당첨 번호를 입력해주세요.";
public static final String WINNING_NUMBERS_INVALID_FORMAT = "[ERROR] 당첨 번호는 숫자여야 합니다.";
public static final String WINNING_NUMBERS_EMPTY_VALUE = "[ERROR] 당첨 번호는 빈 값일 수 없습니다.";

// 보너스 번호 관련
public static final String BONUS_NUMBER_EMPTY = "[ERROR] 보너스 번호를 입력해주세요.";
public static final String BONUS_NUMBER_INVALID_FORMAT = "[ERROR] 보너스 번호는 숫자여야 합니다.";
public static final String BONUS_NUMBER_RANGE = "[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다.";
public static final String BONUS_NUMBER_DUPLICATE = "[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다.";

// 기타
public static final String LOTTO_TICKETS_NULL = "[ERROR] 로또 목록이 없습니다.";
public static final String LOTTO_TICKETS_EMPTY = "[ERROR] 최소 1개 이상의 로또를 구매해야 합니다.";
public static final String LOTTO_RESULT_PURCHASE_AMOUNT = "[ERROR] 구매 금액은 0보다 커야 합니다.";
}
21 changes: 21 additions & 0 deletions src/main/java/lotto/common/LottoConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package lotto.common;

/**
* 로또 게임에서 사용하는 공통 상수를 정의합니다.
*/
public class LottoConstants {

private LottoConstants() {
// 상수 클래스는 인스턴스화 방지
}

// 로또 번호 범위
public static final int MIN_LOTTO_NUMBER = 1;
public static final int MAX_LOTTO_NUMBER = 45;
public static final int LOTTO_NUMBER_COUNT = 6;

// 로또 가격
public static final int LOTTO_PRICE = 1000;

public static final int MIN_PURCHASE_AMOUNT = 1000;
}
23 changes: 23 additions & 0 deletions src/main/java/lotto/common/ViewMessages.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package lotto.common;

/**
* 로또 게임에서 사용하는 출력 메시지를 정의합니다.
*/
public class ViewMessages {

private ViewMessages() {
// 상수 클래스는 인스턴스화 방지
}

// 입력 안내
public static final String INPUT_PURCHASE_AMOUNT = "구입금액을 입력해 주세요.";
public static final String INPUT_WINNING_NUMBERS = "당첨 번호를 입력해 주세요.";
public static final String INPUT_BONUS_NUMBER = "보너스 번호를 입력해 주세요.";

// 결과 출력
public static final String PURCHASED_LOTTO_COUNT_FORMAT = "%d개를 구매했습니다.";
public static final String WINNING_STATISTICS_HEADER = "당첨 통계";
public static final String SEPARATOR = "---";
public static final String RANK_FORMAT = "%s (%s원) - %d개";
public static final String PROFIT_RATE_FORMAT = "총 수익률은 %.1f%%입니다.";
}
71 changes: 71 additions & 0 deletions src/main/java/lotto/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package lotto.domain;

import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import static lotto.common.ErrorMessages.*;
import static lotto.common.LottoConstants.*;

public class Lotto {

private final List<Integer> numbers;

public Lotto(List<Integer> numbers) {
validate(numbers);
this.numbers = numbers.stream()
.sorted()
.collect(Collectors.toList());
}

private void validate(List<Integer> numbers) {
validateNotNull(numbers);
validateSize(numbers);
validateDuplicate(numbers);
validateRange(numbers);
}

private void validateNotNull(List<Integer> numbers) {
if (numbers == null) {
throw new IllegalArgumentException(LOTTO_NUMBERS_NULL);
}
}

private void validateSize(List<Integer> numbers) {
if (numbers.size() != LOTTO_NUMBER_COUNT) {
throw new IllegalArgumentException(LOTTO_NUMBERS_SIZE);
}
}
private void validateDuplicate(List<Integer> numbers) {
if (numbers.size() != new HashSet<>(numbers).size()) {
throw new IllegalArgumentException(LOTTO_NUMBERS_DUPLICATE);
}
}

private void validateRange(List<Integer> numbers) {
boolean isOutOfRange = numbers.stream()
.anyMatch(number -> number < MIN_LOTTO_NUMBER || number > MAX_LOTTO_NUMBER);

if (isOutOfRange) {
throw new IllegalArgumentException(LOTTO_NUMBERS_RANGE);
}
}

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

public int countMatches(List<Integer> winningNumbers) {
return (int) numbers.stream()
.filter(winningNumbers::contains)
.count();
}

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

@Override
public String toString() {
return numbers.toString();
}
}
69 changes: 69 additions & 0 deletions src/main/java/lotto/domain/LottoResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package lotto.domain;

import static lotto.common.ErrorMessages.*;

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

public class LottoResult {
private static final int MIN_PURCHASE_AMOUNT = 1;
private static final String PROFIT_RATE_FORMAT = "%.1f";

private final Map<Rank, Integer> result;
private final int purchaseAmount;

public LottoResult(List<Rank> ranks, int purchaseAmount) {
if (purchaseAmount < MIN_PURCHASE_AMOUNT) {
throw new IllegalArgumentException(LOTTO_RESULT_PURCHASE_AMOUNT);
}
this.purchaseAmount = purchaseAmount;
this.result = countRanks(ranks);
}

private Map<Rank, Integer> countRanks(List<Rank> ranks) {
Map<Rank, Integer> counts = new EnumMap<>(Rank.class);

// NONE 등수를 제외한 모든 당첨 등수를 미리 0으로 초기화
for (Rank rank : Rank.values()) {
if (rank.isWinning()) {
counts.put(rank, 0);
}
}

// 실제 당첨 등수의 개수를 카운트
ranks.stream()
.filter(Rank::isWinning)
.forEach(rank -> counts.merge(rank, 1, Integer::sum));

return counts;
}

public int getPrizeCount(Rank rank) {
return result.getOrDefault(rank, 0);
}

public long calculateTotalProfit() {
return result.entrySet().stream()
.mapToLong(entry -> (long) entry.getKey().getPrize() * entry.getValue())
.sum();
}

/**
* 총 수익률을 계산합니다.
*
* @return 수익률 (퍼센트, 소수점 포함)
*/
public double calculateProfitRate() {
long totalProfit = calculateTotalProfit();
return (double) totalProfit * 100 / purchaseAmount;
}

public Map<Rank, Integer> getResult() {
return result;
}

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

import static lotto.common.ErrorMessages.*;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class LottoTickets {
private static final int MIN_LOTTO_COUNT = 1;

private final List<Lotto> lottos;

public LottoTickets(List<Lotto> lottos) {
if (Objects.isNull(lottos)) {
throw new IllegalArgumentException(LOTTO_TICKETS_NULL);
}

if (lottos.size() < MIN_LOTTO_COUNT) {
throw new IllegalArgumentException(LOTTO_TICKETS_EMPTY);
}

this.lottos = lottos;
}

public int getLottoCount() {
return lottos.size();
}

public List<Lotto> getLottos() {
return Collections.unmodifiableList(lottos);
}

public LottoResult compareWithWinningLotto(WinningLotto winningLotto, int purchaseAmount) {
// 모든 로또의 당첨 등수를 계산합니다.
List<Rank> ranks = lottos.stream()
.map(winningLotto::match)
.collect(Collectors.toList());

// LottoResult 객체를 생성하여 등수별 개수 및 수익률을 관리합니다.
return new LottoResult(ranks, purchaseAmount);
}
}
47 changes: 47 additions & 0 deletions src/main/java/lotto/domain/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package lotto.domain;

import java.util.Arrays;

public enum Rank {
FIRST(6, false, 2_000_000_000, "6개 일치"),
SECOND(5, true, 30_000_000, "5개 일치, 보너스 볼 일치"),
THIRD(5, false, 1_500_000, "5개 일치"),
FOURTH(4, false, 50_000, "4개 일치"),
FIFTH(3, false, 5_000, "3개 일치"),
NONE(0, false, 0, "");

private final int matchCount;
private final boolean matchBonus;
private final int prize;
private final String description;

Rank(int matchCount, boolean matchBonus, int prize, String description) {
this.matchCount = matchCount;
this.matchBonus = matchBonus;
this.prize = prize;
this.description = description;
}

public static Rank valueOf(int matchCount, boolean matchBonus) {
if (matchCount == 5 && matchBonus) {
return SECOND;
}
return Arrays.stream(values())
.filter(rank -> rank.matchCount == matchCount)
.filter(rank -> !rank.matchBonus)
.findFirst()
.orElse(NONE);
}

public int getPrize() {
return prize;
}

public String getDescription() {
return description;
}

public boolean isWinning() {
return this != NONE;
}
}
Loading