Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
cae8bfd
docs: README.md 작성
YONGMINJO1 Jan 10, 2026
0b3c2e2
feat: Lotto 기본 클래스 구현
YONGMINJO1 Jan 10, 2026
20a53ea
feat: Lotto 크기 검증 구현
YONGMINJO1 Jan 10, 2026
46da2d7
feat: Lotto 중복 검증 구현
YONGMINJO1 Jan 10, 2026
7fe5917
feat: Lotto 범위 검증 구현
YONGMINJO1 Jan 10, 2026
03f126e
feat: LottoRank 구현
YONGMINJO1 Jan 10, 2026
a4de278
docs: README.md 수정
YONGMINJO1 Jan 10, 2026
b710f48
feat: Lotto 클래스 contains 기능 구현
YONGMINJO1 Jan 10, 2026
08fea60
feat: WinningLotto 구현 및 당첨 번호 일치 기능 구현
YONGMINJO1 Jan 10, 2026
ddc843f
feat: LottoTickets 클래스 생성
YONGMINJO1 Jan 10, 2026
c50a214
feat: LottoTickets null 검증 기능 구현
YONGMINJO1 Jan 10, 2026
d51a667
feat: LottoTickets 빈 값 검증 구현 및 테스트
YONGMINJO1 Jan 10, 2026
4ef252f
docs: README.md 수정
YONGMINJO1 Jan 10, 2026
cc418f7
feat: LottoResult 클래스 구현
YONGMINJO1 Jan 10, 2026
5a60b58
feat: LottoResult 기능 구현
YONGMINJO1 Jan 10, 2026
455fd51
docs: README.md 수정
YONGMINJO1 Jan 10, 2026
360f876
feat: LottoGenerator 클래스 생성 및 기능 구현
YONGMINJO1 Jan 10, 2026
3677e8b
doce: README.md 수정
YONGMINJO1 Jan 10, 2026
514fa7d
feat: InputView 기능 추가
YONGMINJO1 Jan 10, 2026
13376ff
feat: WinningLotto 기능 추가
YONGMINJO1 Jan 10, 2026
899db60
feat: LottoController 구현
YONGMINJO1 Jan 10, 2026
277bec6
feat: Application 구현
YONGMINJO1 Jan 10, 2026
802d67b
docs: README.md 수정
YONGMINJO1 Jan 10, 2026
42fa5de
fix: 형변환 오류 해결 및 Controller 구조 개선
YONGMINJO1 Jan 10, 2026
2002278
fix: InputView 예외 처리를 재입력 방식 개선
YONGMINJO1 Jan 10, 2026
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
80 changes: 79 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,79 @@
# java-planetlotto-precourse
## < 행성 로또 >
최종테스트 2026. 1. 10

## 과제
로또 번호의 숫자 범위는 1~30까지이다.
1개의 로또를 발행할 때 중복되지 않는 5개의 숫자를 뽑는다.
당첨 번호 추첨 시 중복되지 않는 숫자 5개와 보너스 번호 1개를 뽑는다.
당첨은 1등부터 5등까지 있다. 당첨 기준과 금액은 아래와 같다.
1등: 5개 번호 일치 / 100,000,000원
2등: 4개 번호 + 보너스 번호 일치 / 10,000,000원
3등: 4개 번호 일치 / 1,500,000원
4등: 3개 번호 일치 + 보너스 번호 일치 / 500,000원
5등: 2개 번호 일치 + 보너스 번호 일치 / 5,000원
로또 구입 금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 한다.
로또 1장의 가격은 500원이다.
당첨 번호와 보너스 번호를 입력받는다.
사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역을 출력하고 로또 게임을 종료한다.
사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시키고,
"[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다.
Exception이 아닌 IllegalArgumentException,
IllegalStateException 등과 같은 명확한 유형을 처리한다.

## 기능목록
- [x] README.md 작성
- [x] Lotto 기본 클래스 생성
- [x] Lotto 5개 번호 검증
- [x] Lotto 중복 번호 검증
- [x] Lotto Rank 클래스 생성
- [x] LottoTickets 클래스 생성
- [x] LottoTickets null 검증 구현
- [x] LottoTickets 빈 값 검증 구현
- [x] LottoResult 클래스 생성
- [x] LottoResult 등수별 개수 조회기능
- [x] LottoResult 상금 계산 기능
- [x] LottoResult 수익률 계산
- [x] LottoGenerator 클래스 생성
- [x] LottoGenerator 1장 생성 기능 구현
- [x] LottoGenerator 여러장 생성 기능 구현
- [x] 로또 구입 금액 입력 (로또 1장의 가격 500원)
- [x] 로또의 당첨번호, 보너스 번호 입력 (번호는 쉼표(,)를 기준으로 구분)
- [x] 사용자가 구매한 로또번호 생성 가능
- [x] 구매한 로또번호와 당첨번호 비교 가능
- [x] 당첨내역 출력
- [x] 수익률 출력
- [x] 잘못된 입력일 경우 예외를 발생
(IllegalArgumentException을 발생 시킨 후 "[ERROR] 로 시작하는 에러 메시지 출력 후 그 부분부터 다시 입력을 받는다.)


## 입출력 요구사항

**입력**
- 로또 구입 금액을 입력받는다.

1000
- 당첨 번호를 입력받는다. 번호는 쉼표(,)를 기준으로 구분한다.

1,2,3,4,5
- 보너스 번호를 입력받는다.

6
**출력**
- 발행한 로또 수량 및 번호를 출력한다. 로또 번호는 오름차순으로 정렬하여 보여준다.
2개를 구매했습니다.

[8, 11, 13, 21, 22]
[1, 3, 6, 14, 22]
- 당첨 내역을 출력한다.
- 당첨 통계
---
5개 일치 (100,000,000원) - 0개
4개 일치, 보너스 번호 일치 (10,000,000원) - 0개
4개 일치 (1,500,000원) - 0개
3개 일치, 보너스 번호 일치 (500,000원) - 0개
2개 일치, 보너스 번호 일치 (5,000원) - 1개
0개 일치 (0원) - 1개

- 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다.
[ERROR] 로또 번호는 1부터 30 사이의 숫자여야 합니다.

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

import planetlotto.controller.LottoController;
import planetlotto.util.LottoGenerator;
import planetlotto.view.InputView;
import planetlotto.view.OutputView;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
// InputView inputView = new InputView();
// OutputView outputView = new OutputView();
LottoGenerator lottoGenerator = new LottoGenerator();

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

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import planetlotto.domain.Lotto;
import planetlotto.domain.LottoRank;
import planetlotto.domain.LottoResult;
import planetlotto.domain.LottoTickets;
import planetlotto.domain.WinningLotto;
import planetlotto.util.LottoGenerator;
import planetlotto.view.InputView;
import planetlotto.view.OutputView;

public class LottoController {
private static final int LOTTO_PRICE = 500;

//private final InputView inputView;
//private final OutputView outputView;
private final LottoGenerator lottoGenerator;
private int purchaseAmount;

public LottoController(LottoGenerator lottoGenerator) {

//this.inputView = inputView;
//this.outputView = outputView;
this.lottoGenerator = lottoGenerator;
}

public void run() {
LottoTickets lottos = purchaseLottos();

List<List<Integer>> lottosNumbers = lottos.getLottos().stream()
.map(Lotto::getNumbers)
.toList();

OutputView.printPurchasedLottos(lottosNumbers);
WinningLotto winning = createWinningLotto();

LottoResult result = calculateResult(lottos, winning);
OutputView.printResult((result).toRankMap());

}

private LottoTickets purchaseLottos() {
int amount = InputView.askAmount();
this.purchaseAmount = amount;

int lottoCount = amount / LOTTO_PRICE;
List<Lotto> lottos = lottoGenerator.generate(lottoCount);
return new LottoTickets(lottos);
}

private WinningLotto createWinningLotto() {
while (true) {
try {
List<Integer> winningNumbers = InputView.askWinningLotto();
Lotto winningLotto = new Lotto(winningNumbers);

int bonusNumber = InputView.askBonusNumber();
return new WinningLotto(winningLotto, bonusNumber);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}

private LottoResult calculateResult(LottoTickets tickets, WinningLotto winning) {
Map<LottoRank, Integer> rankCounts = calculateRanks(tickets, winning);
int totalTickets = tickets.size();
return new LottoResult(rankCounts, purchaseAmount, totalTickets);
}

private Map<LottoRank, Integer> calculateRanks(LottoTickets tickets, WinningLotto winning) {
Map<LottoRank, Integer> rankCounts = new HashMap<>();

for (Lotto lotto : tickets.getLottos()) {
int matchCount = winning.countMatches(lotto);
boolean bonusMatch = lotto.contains(winning.getBonusNumber());

Optional<LottoRank> rank = LottoRank.of(matchCount, bonusMatch);
rank.ifPresent(r -> rankCounts.put(r, rankCounts.getOrDefault(r, 0) + 1));
}
return rankCounts;
}
}
47 changes: 47 additions & 0 deletions src/main/java/planetlotto/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package planetlotto.domain;

import java.util.List;

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

public Lotto(List<Integer> numbers) {
validateSize(numbers);
validateDuplicate(numbers);
validateRange(numbers);
this.numbers = numbers;
}

private void validateRange(List<Integer> numbers) {
for (int number : numbers) {
if (number < 1 || number > 30) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 1부터 30 사이여야 합니다.");
}
}
}

private void validateDuplicate(List<Integer> numbers) {
long distinctCount = numbers
.stream()
.distinct()
.count();

if (distinctCount != numbers.size()) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 중복될 수 없습니다.");
}
}

private void validateSize(List<Integer> numbers) {
if (numbers.size() != 5) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 5개여야 합니다.");
}
}

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

public boolean contains(int number) {
return numbers.contains(number);
}
}
41 changes: 41 additions & 0 deletions src/main/java/planetlotto/domain/LottoRank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package planetlotto.domain;

import java.util.Arrays;
import java.util.Optional;

public enum LottoRank {
FIRST(5, false, 1_000_000_000),
SECOND(4, true, 10_000_000),
THIRD(4, false, 1_500_000),
FOURTH(3, false, 50_000),
FIFTH(2, false, 5_000);

private final int matchCount;
private final boolean requireBonus;
private final long prizeMoney;

LottoRank(int matchCount, boolean requireBonus, long prizeMoney) {
this.matchCount = matchCount;
this.requireBonus = requireBonus;
this.prizeMoney = prizeMoney;
}

public static Optional<LottoRank> of(int matchCount, boolean bonusMatch) {
return Arrays.stream(values())
.filter(rank -> rank.matchCount == matchCount
&& (!rank.requireBonus || bonusMatch))
.findFirst();
}

public long getPrizeMoney() {
return prizeMoney;
}

public int getMatchCount() {
return matchCount;
}

public boolean isRequireBonus() {
return requireBonus;
}
}
50 changes: 50 additions & 0 deletions src/main/java/planetlotto/domain/LottoResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package planetlotto.domain;

import java.util.HashMap;
import java.util.Map;

public class LottoResult {
private final Map<LottoRank, Integer> rankCounts;
private final int purchaseAmount;
private final int totalTickets;

public LottoResult(Map<LottoRank, Integer> rankCounts, int purchaseAmount , int totalTickets) {
this.rankCounts = new HashMap<>(rankCounts);
this.purchaseAmount = purchaseAmount;
this.totalTickets = totalTickets;
}

public int getCountByRank(LottoRank rank) {
return rankCounts.getOrDefault(rank, 0);
}


public long getTotalPrizeMoney() {
return rankCounts.entrySet().stream()
.mapToLong(entry -> entry.getKey().getPrizeMoney() * entry.getValue())
.sum();
}

public double getProfitRate() {
return ((double) getTotalPrizeMoney() / purchaseAmount) * 100;
}

public Map<Integer, Integer> toRankMap() {
Map<Integer, Integer> result = new HashMap<>();

result.put(1, rankCounts.getOrDefault(LottoRank.FIRST, 0));
result.put(2, rankCounts.getOrDefault(LottoRank.SECOND, 0));
result.put(3, rankCounts.getOrDefault(LottoRank.THIRD, 0));
result.put(4, rankCounts.getOrDefault(LottoRank.FOURTH, 0));
result.put(5, rankCounts.getOrDefault(LottoRank.FIFTH, 0));

// 미당첨 계산 (전체 개수 - 당첨된 개수)
int totalWin = rankCounts.values().stream()
.mapToInt(Integer::intValue)
.sum();
int totalTickets = purchaseAmount / 500;
result.put(0, this.totalTickets - totalWin);

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

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

public class LottoTickets {
private final List<Lotto> lottos;

public LottoTickets(List<Lotto> lottos) {
validateNull(lottos);
validateNotEmpty(lottos);
this.lottos = new ArrayList<>(lottos);
}

private void validateNull(List<Lotto> lottos) {
if (lottos == null) {
throw new IllegalArgumentException("[ERROR] 로또 목록이 null일 수 없습니다.");
}
}

private void validateNotEmpty(List<Lotto> lottos) {
if (lottos.isEmpty()) {
throw new IllegalArgumentException("[ERROR] 로또 최소 1장 이상이어야 합니다..");
}
}

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

public List<Lotto> getLottos() {
return new ArrayList<>(lottos);
}
}
Loading