-
Notifications
You must be signed in to change notification settings - Fork 92
[그리디] 김태우 로또 미션 3,4,5 단계 제출합니다. #146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
tae-wooo
wants to merge
55
commits into
next-step:tae-wooo
Choose a base branch
from
tae-wooo:Lotto-tae-woo3
base: tae-wooo
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
55 commits
Select commit
Hold shift + click to select a range
849e2fe
RaceLotto 클래스에 금액 입력→번호 생성→당첨번호→통계 출력까지 실행 흐름 추가
84ad2df
RaceLottoMethod에 로또 게임 핵심 로직(입력·생성·당첨·통계) 구현
cf566ce
InputView 클래스 구현 (구입 금액·당첨 번호 입력)
84fe5a6
OutputView 클래스 구현 (구입 금액·로또·통계 출력)
ee9214d
구입 금액을 포장하는 Price 값 객체 구현 (검증·로또 개수 계산)
b0320e9
LottoNumber를 원시값 포장 객체로 구현 (1~45 범위 검증 포함)
caad7b4
LottoNumbers를 일급 컬렉션으로 구현 (6개 검증·정렬 기능 포함)
3625fd2
여러 LottoNumbers를 보관·조회하는 LottoNumbersRepository 구현
3c52ba5
자동 로또 번호 생성 구현
5256990
Main 클래스 추가 – RaceLotto 실행 엔트리 포인트
6eaeb8f
test: Price 값 객체 생성·예외·로또 개수 계산 단위 테스트 추가
35d5b27
test: LottoNumbersRepository에 로또번호 추가 및 불변리스트 반환 단위 테스트 추가
1925a09
test: LottoNumbers 생성·예외·불변리스트·정렬 기능 단위 테스트 추가
59a8dbd
test: LottoNumber 유효성 및 예외 처리 단위 테스트 추가
3960e78
test: RandomLottoNumberGenerator가 항상 6개의 번호를 생성하는지 단위 테스트 추가
8f78037
README 추가
bf9eb51
Controller 클래스명 RaceLotto → AutoLotooController로 변경
8a1ed8f
검증 메서드명을 validate… 패턴으로 통일
ea203ae
로또 일치 결과 계산 메서드로 분리 및 이름 명확화
53e53c6
printLotteryStatistics가 matchCounts와 profitRate를 받아 통계와 수익률을 출력하도록 변경
c0d24e0
로또 일치 결과/수익률 계산 메서드 분리 (countMatchResults, calculateProfitRate)
2578a3e
AutoLottoController에 showLotteryStatistics 메서드 추가 및 통계 출력 로직 분리
3b73ece
Controller 보조 클래스 → 모델 비즈니스 로직 클래스(LottoBusiness)로 역할 변경 및 View 의존성 제거
8f4157d
AutoLottoController를 단계별 메서드(showPrice, showLottoNumbers, readLastLot…
fa8c3ae
변수명을 더 의미 있게 변경
dcc3c70
변수명을 더 의미 있게 변경
32ff258
Main에서 AutoLottoController 메서드들을 호출해 프로그램 실행하도록 구성
0293eee
로또 번호 생성 로직을 모델로 이동하고 전략 패턴 적용
5dcf37f
몇 개의 번호가 맞았는지를 표현하는 MatchResult enum 추가
a45f213
로또 통계 계산 로직을 int[]에서 EnumMap 기반으로 변경
d87205d
AutoLottoController에서 EnumMap 기반 통계 출력 적용
98ea697
도메인 객체들에 equals/hashCode 구현
036ccdb
테스트 용이성을 위해 LottoBusiness에 전략 패턴 적용
510b0c0
테스트 코드 추가
9f18556
feat: 로또 3단계(수동 구매) 및 4단계(보너스볼 당첨 결과) 구현
f74a8ac
클래스/메서드 네이밍 개선
fd6c52f
클래스 네이밍 개선
87965f2
test: 보너스볼 포함 케이스 테스트 추가
3c5d1a1
buyTickets 메서드 책임 분리 및 리팩터링
eb187e4
createInputLotto, countMatchResults 메서드 로직 분리
6d47438
README 수정
de36cc9
와일드카드 import 제거, InputView 패키지명 및 mergeRepositories 메서드명 변경
2393907
LottoNumbers getter의 중복 불변 처리 로직 제거
b32bfa9
matchLottoNumber의 if문 내부 로직을 containsNumber 메서드로 분리하여 depth 감소
28647f0
MatchResult enum의 불필요한 description 파라미터 제거
579c2f3
fromCount의 for문 로직을 메서드로 분리하여 depth 감소
450573a
FixedLottoNumberGenerator 예외 상황 테스트 추가
022567f
Fixture 적용으로 테스트 중복 제거 및 가독성 향상
fb04843
빈줄 출력을printBlankLine() 메서드 호출로 변경
e1680af
LottoNumbers → LottoTicket 이름 변경 및 equals/hashCode 제거
e4cddbd
지역 변수와 함수 인자명을 명확하게 변경
6a4da86
LottoNumber 스트림을 사용해 매칭 로직 단순화
58fe1f0
Stream을 활용해 MatchResult 조회 로직 단순화
7b87bf7
동일객체 테스트 제거
5cda9d9
PurchaseAmount를 도메인 모델로 이동
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# 로또 미션 | ||
|
||
## 기능 요구사항 | ||
|
||
- 로또 당첨 번호를 받아 일치한 번호 수에 따라 당첨 결과를 보여준다. | ||
|
||
## 프로그래밍 요구사항 | ||
|
||
- 모든 원시 값과 문자열을 포장한다. | ||
- 일급 컬렉션을 쓴다. | ||
|
||
## 추가 기능 요구사항 | ||
|
||
- 2등을 위한 보너스볼을 추첨한다. | ||
- 당첨 통계에 2등을 추가한다. | ||
- 2등 당첨 조건은 당첨 번호 5개 + 보너스 볼이다 | ||
- 사용자가 수동으로 추첨 번호를 입력할 수 있도록 해야 한다. | ||
- 입력한 금액, 자동 생성 숫자, 수동 생성 번호를 입력하도록 해야 한다. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import controller.LottoController; | ||
import model.PurchaseAmount; | ||
import model.LottoNumber; | ||
import model.LottoTicket; | ||
import model.LottoTicketBundle; | ||
|
||
public class Main { | ||
public static void main(String[] args) { | ||
LottoController controller = new LottoController(); | ||
|
||
// 1. 구입 금액 입력 | ||
PurchaseAmount purchaseAmount = controller.askPurchaseAmount(); | ||
|
||
// 2. 수동 및 자동 로또 번호 생성 | ||
LottoTicketBundle allTickets = controller.buyTickets(purchaseAmount.calculateLottoCount()); | ||
|
||
// 3. 당첨 번호 입력 | ||
LottoTicket winningNumbers = controller.askWinningNumbers(); | ||
|
||
// 4. 보너스 볼 입력 | ||
LottoNumber bonusBall = controller.askBonusBall(); | ||
|
||
// 5. 통계 출력 | ||
controller.showStatistics(allTickets.readLottoNumbersRepository(), | ||
winningNumbers.getNumbers(), | ||
purchaseAmount.getValue(), | ||
bonusBall | ||
); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package controller; | ||
|
||
import view.InputView; | ||
import view.OutputView; | ||
import model.PurchaseAmount; | ||
import model.LottoNumber; | ||
import model.LottoTicket; | ||
import model.LottoService; | ||
import model.LottoTicketBundle; | ||
import model.MatchResult; | ||
|
||
|
||
import java.util.List; | ||
import java.util.Map; | ||
|
||
public class LottoController { | ||
private final LottoService lottoService = new LottoService(); | ||
private final OutputView outView = new OutputView(); | ||
private final InputView inputView = new InputView(); | ||
|
||
private PurchaseAmount readPrice() { | ||
outView.printInputPrice(); | ||
while (true) { | ||
PurchaseAmount purchaseAmount = readPriceException(); | ||
if (purchaseAmount != null) return purchaseAmount; | ||
} | ||
} | ||
|
||
private PurchaseAmount readPriceException() { | ||
try { | ||
return new PurchaseAmount(Integer.parseInt(inputView.inputPrice())); | ||
} catch (NumberFormatException input) { | ||
outView.printInvalidNumber(); | ||
} catch (IllegalArgumentException input) { | ||
outView.printInvalidPrice(); | ||
} | ||
return null; | ||
} | ||
|
||
public PurchaseAmount askPurchaseAmount() { | ||
PurchaseAmount purchaseAmount = readPrice(); | ||
outView.printPriceValue(purchaseAmount.getValue()); | ||
outView.printBlankLine(); | ||
return purchaseAmount; | ||
} | ||
|
||
public LottoTicketBundle buyTickets(int ticketCount) { | ||
int manualCount = requestManualTicketCount(); | ||
int autoCount = calculateAutoCount(ticketCount, manualCount); | ||
|
||
LottoTicketBundle tickets = generateTickets(manualCount, autoCount); | ||
displayTickets(manualCount, autoCount, tickets); | ||
|
||
return tickets; | ||
} | ||
|
||
private int requestManualTicketCount() { | ||
outView.printManualTicketCount(); | ||
return Integer.parseInt(inputView.inputManualCount()); | ||
} | ||
|
||
private int calculateAutoCount(int totalTickets, int manualCount) { | ||
return totalTickets - manualCount; | ||
} | ||
|
||
private LottoTicketBundle generateTickets(int manualCount, int autoCount) { | ||
outView.printManualLottoNumbersPrompt(); | ||
List<String> manualInputs = inputView.inputManualLottos(manualCount); | ||
|
||
LottoTicketBundle manualTickets = lottoService.createManualLottos(manualInputs); | ||
LottoTicketBundle autoTickets = lottoService.createLottos(autoCount); | ||
|
||
return lottoService.mergeAutoAndManualLottos(manualTickets, autoTickets); | ||
} | ||
|
||
private void displayTickets(int manualCount, int autoCount, LottoTicketBundle tickets) { | ||
outView.printBuyCount(manualCount, autoCount); | ||
outView.printLottos(tickets.readLottoNumbersRepository()); | ||
} | ||
|
||
public LottoTicket askWinningNumbers() { | ||
outView.printInputWinningNumbers(); | ||
LottoTicket winningLotto = lottoService.createInputLotto(inputView.inputWinningNumbers()); | ||
outView.printBlankLine(); | ||
return winningLotto; | ||
} | ||
|
||
public LottoNumber askBonusBall() { | ||
outView.printBonusBall(); | ||
LottoNumber bonusNumber = new LottoNumber(Integer.parseInt(inputView.inputBonusBall())); | ||
outView.printBlankLine(); | ||
return bonusNumber; | ||
} | ||
|
||
public void showStatistics(List<LottoTicket> allTickets, List<LottoNumber> winningNumbers, int purchaseAmount, LottoNumber bonusBall) { | ||
Map<MatchResult, Integer> matchCounts = lottoService.countMatchResults(allTickets, winningNumbers, bonusBall); | ||
String profitRate = lottoService.calculateProfitRate(matchCounts, purchaseAmount); | ||
outView.printLotteryStatistics(matchCounts, profitRate); | ||
} | ||
} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package model; | ||
|
||
import java.util.List; | ||
|
||
public class FixedLottoNumberGenerator implements LottoNumberGenerator { | ||
private final List<LottoNumber> fixedNumbers; | ||
|
||
public FixedLottoNumberGenerator(List<Integer> numbers) { | ||
if (numbers.size() != 6) { | ||
throw new IllegalArgumentException("로또 번호는 6개여야 합니다."); | ||
} | ||
this.fixedNumbers = numbers.stream() | ||
.map(LottoNumber::new) | ||
.toList(); | ||
} | ||
|
||
@Override | ||
public LottoTicket generate() { | ||
return new LottoTicket(fixedNumbers); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package model; | ||
|
||
import java.util.Objects; | ||
|
||
public class LottoNumber { | ||
private final int number; | ||
|
||
public LottoNumber(int number) { | ||
validateRange(number); | ||
this.number = number; | ||
} | ||
|
||
private void validateRange(int number) { | ||
if (number < 1 || number > 45) { | ||
throw new IllegalArgumentException("로또 번호는 1~45 사이여야 합니다"); | ||
} | ||
} | ||
|
||
public int getNumber() { | ||
return number; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return String.valueOf(number); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (!(o instanceof LottoNumber)) return false; | ||
LottoNumber lottoNumber = (LottoNumber) o; | ||
return number == lottoNumber.number; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(number); | ||
} | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package model; | ||
|
||
public interface LottoNumberGenerator { | ||
LottoTicket generate(); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package model; | ||
|
||
|
||
import java.util.ArrayList; | ||
import java.util.EnumMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
public class LottoService { | ||
private final LottoNumberGenerator generator; | ||
|
||
public LottoService() { | ||
this(new RandomLottoNumberGenerator()); | ||
} | ||
|
||
public LottoService(LottoNumberGenerator generator) { | ||
this.generator = generator; | ||
} | ||
|
||
public LottoTicket createOneLotto() { | ||
return generator.generate(); | ||
} | ||
|
||
public LottoTicketBundle createLottos(int count) { | ||
LottoTicketBundle repository = new LottoTicketBundle(); | ||
for (int i = 0; i < count; i++) { | ||
repository.addLottoNumbers(createOneLotto().sortNumbers()); | ||
} | ||
return repository; | ||
} | ||
|
||
public LottoTicket createInputLotto(String inputNumber) { | ||
List<LottoNumber> numbers = parseInputToNumbers(inputNumber); | ||
return new LottoTicket(numbers); | ||
} | ||
|
||
private List<LottoNumber> parseInputToNumbers(String inputNumber) { | ||
String[] rawNumbers = inputNumber.split(","); | ||
List<LottoNumber> numbers = new ArrayList<>(); | ||
for (String raw : rawNumbers) { | ||
numbers.add(new LottoNumber(Integer.parseInt(raw.trim()))); | ||
} | ||
return numbers; | ||
} | ||
|
||
public LottoTicketBundle createManualLottos(List<String> inputs) { | ||
LottoTicketBundle repository = new LottoTicketBundle(); | ||
for (String input : inputs) { | ||
repository.addLottoNumbers(createInputLotto(input)); | ||
} | ||
return repository; | ||
} | ||
|
||
public LottoTicketBundle mergeAutoAndManualLottos(LottoTicketBundle manual, LottoTicketBundle auto) { | ||
LottoTicketBundle repository = new LottoTicketBundle(); | ||
for (LottoTicket lotto : manual.readLottoNumbersRepository()) { | ||
repository.addLottoNumbers(lotto); | ||
} | ||
|
||
for (LottoTicket lotto : auto.readLottoNumbersRepository()) { | ||
repository.addLottoNumbers(lotto); | ||
} | ||
return repository; | ||
} | ||
|
||
public Map<MatchResult, Integer> countMatchResults(List<LottoTicket> allLotteries, | ||
List<LottoNumber> winningLotto, | ||
LottoNumber bonusBall) { | ||
Map<MatchResult, Integer> matchCounts = initializeMatchCounts(); | ||
for (LottoTicket lotto : allLotteries) { | ||
int count = matchLottoNumber(lotto.getNumbers(), winningLotto); | ||
boolean bonusMatch = matchBonus(lotto.getNumbers(), bonusBall, count); | ||
MatchResult result = MatchResult.fromCount(count, bonusMatch); | ||
matchCounts.put(result, matchCounts.get(result) + 1); | ||
} | ||
return matchCounts; | ||
} | ||
|
||
private Map<MatchResult, Integer> initializeMatchCounts() { | ||
Map<MatchResult, Integer> counts = new EnumMap<>(MatchResult.class); | ||
for (MatchResult result : MatchResult.values()) { | ||
counts.put(result, 0); | ||
} | ||
return counts; | ||
} | ||
|
||
private int matchLottoNumber(List<LottoNumber> lotto, List<LottoNumber> winningLotto) { | ||
return (int) lotto.stream() | ||
.filter(winningLotto::contains) | ||
.count(); | ||
} | ||
|
||
private boolean matchBonus(List<LottoNumber> lotto, LottoNumber bonusBall, int count) { | ||
if (count == 5) { | ||
return lotto.contains(bonusBall); | ||
} | ||
return false; | ||
} | ||
|
||
public String calculateProfitRate(Map<MatchResult, Integer> matchCounts, int money) { | ||
double profitRate = 0; | ||
for (MatchResult result : matchCounts.keySet()) { | ||
profitRate += matchCounts.get(result) * result.getReward(); | ||
} | ||
profitRate = profitRate / (double) money; | ||
return String.format("%.2f", profitRate); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package model; | ||
|
||
import java.util.*; | ||
|
||
public class LottoTicket { | ||
private final List<LottoNumber> numbers; | ||
|
||
public LottoTicket(List<LottoNumber> numbers) { | ||
validateSize(numbers); | ||
this.numbers = List.copyOf(numbers); | ||
} | ||
|
||
private void validateSize(List<LottoNumber> numbers) { | ||
if (numbers.size() != 6) { | ||
throw new IllegalArgumentException("로또 번호가 6개가 아닙니다"); | ||
} | ||
} | ||
|
||
public LottoTicket sortNumbers() { | ||
List<LottoNumber> sortNumber = new ArrayList<>(numbers); | ||
Collections.sort(sortNumber, Comparator.comparingInt(LottoNumber::getNumber)); | ||
return new LottoTicket(sortNumber); | ||
} | ||
|
||
public List<LottoNumber> getNumbers() { | ||
return numbers; | ||
} | ||
|
||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package model; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
public class LottoTicketBundle { | ||
private final List<LottoTicket> repository = new ArrayList<>(); | ||
|
||
public void addLottoNumbers(LottoTicket lottoTicket) { | ||
repository.add(lottoTicket); | ||
} | ||
|
||
public List<LottoTicket> readLottoNumbersRepository() { | ||
return Collections.unmodifiableList(repository); | ||
} | ||
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전체적으로 Controller 클래스임에도 출력문이 직접적으로 작성되어 있는 것 같아요!
MVC 패턴을 적용시키신 김에 출력의 책임은 컨트롤러에서 제외하는 것이 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저는 Controller가 출력까지 책임지는 것으로 이해하고 있었는데,
상희님 말씀대로라면 Controller가 그 책임을 갖지 않는 구조로 보입니다.
혹시 출력의 책임은 어느 계층에서 가져가는 게 더 적절할지 조언해주실 수 있을까요?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 말한 부분은 아래 코드인데요, 현재 print문은 모두 OutputView에서 작성해주신 것 같아요!
컨트롤러에서의 print문은 제거하고, OutputView가 출력의 책임을 모두 담당하게 하는 것이 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
view와 controller의 역할을 분리하려고 신경 썼는데, 말씀해주신 부분은 놓쳤네요!
System.out.println();을 printBlankLine() 메서드로 분리해서 OutputView에서 책임을 가지도록 수정했습니다.