-
Notifications
You must be signed in to change notification settings - Fork 1.1k
lotto - step3 #4172
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
Merged
Merged
lotto - step3 #4172
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
11bf70b
refactor: Add Rank enum class
liter-1 cea6c30
refactor: Use first-class collection for Lotto.class
liter-1 8728e4a
feat: Add calcualtion logic for bonus
liter-1 ba3f838
feat: Add result view for 2nd
liter-1 f4e3ee2
chore: Modify gitignore
liter-1 f810351
refactor: Remove unused methods
liter-1 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
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,22 @@ | ||
# 3단계 - 로또(2등) 기능 목록 | ||
|
||
## 데이터 모델 개선 | ||
|
||
- [x] Rank enum 별도 클래스로 구현 | ||
- 로또 등수별 일치 개수와 상금 정보 관리 | ||
- 일치 개수와 보너스 볼 여부에 따른 등수 계산 로직 구현 | ||
|
||
- [x] 일급 컬렉션 적용 - Lotto 클래스 | ||
|
||
## 기능 구현 | ||
|
||
- [x] 보너스 볼 입력 기능 구현 | ||
- [x] InputView에 보너스 볼 입력 메서드 추가 | ||
- [x] 보너스 볼 유효성 검증 (1~45 사이, 당첨 번호와 중복 불가) | ||
|
||
- [x] 당첨 결과 계산 기능 개선 | ||
- [x] 보너스 볼 일치 여부 확인 로직 구현 | ||
- [x] LottoResult 클래스 개선하여 2등 당첨 관리 | ||
|
||
- [x] 출력 기능 개선 | ||
- [x] ResultView 수정하여 2등 당첨 결과 출력 |
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 |
---|---|---|
@@ -1,27 +1,35 @@ | ||
package lotto; | ||
|
||
import java.util.List; | ||
import lotto.domain.Lotto; | ||
import lotto.domain.LottoGenerator; | ||
import lotto.domain.LottoNumber; | ||
import lotto.domain.LottoResult; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import lotto.domain.Rank; | ||
|
||
public class LottoService { | ||
private final LottoGenerator lottoGenerator; | ||
private final LottoGenerator lottoGenerator; | ||
|
||
public LottoService() { | ||
this.lottoGenerator = new LottoGenerator(); | ||
} | ||
public LottoService() { | ||
this.lottoGenerator = new LottoGenerator(); | ||
} | ||
|
||
public List<Lotto> buyLottos(int money) { | ||
return lottoGenerator.generate(money); | ||
} | ||
public List<Lotto> buyLottos(int money) { | ||
return lottoGenerator.generate(money); | ||
} | ||
|
||
public LottoResult calculateResult( | ||
List<Lotto> lottos, Lotto winningLotto, LottoNumber bonusNumber) { | ||
LottoResult lottoResult = new LottoResult(); | ||
|
||
public LottoResult calculateResult(List<Lotto> lottos, Lotto winningLotto) { | ||
List<LottoResult.Rank> ranks = | ||
lottos.stream().map(lotto -> lotto.countMatchingNumbers(winningLotto)) | ||
.map(LottoResult.Rank::valueOf).collect(Collectors.toList()); | ||
return new LottoResult(ranks); | ||
for (Lotto lotto : lottos) { | ||
int matchCount = lotto.countMatchingNumbers(winningLotto); | ||
boolean bonusMatch = lotto.contains(bonusNumber); | ||
|
||
Rank rank = Rank.valueOf(matchCount, bonusMatch); | ||
lottoResult.addRank(rank); | ||
} | ||
|
||
return lottoResult; | ||
} | ||
} |
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 |
---|---|---|
@@ -1,30 +1,39 @@ | ||
package lotto; | ||
|
||
import java.util.List; | ||
import lotto.domain.Lotto; | ||
import lotto.domain.LottoNumber; | ||
import lotto.domain.LottoResult; | ||
import lotto.ui.InputView; | ||
import lotto.ui.ResultView; | ||
|
||
import java.util.List; | ||
|
||
public class Main { | ||
public static void main(String[] args) { | ||
InputView inputView = new InputView(); | ||
ResultView resultView = new ResultView(); | ||
LottoService lottoService = new LottoService(); | ||
public static void main(String[] args) { | ||
InputView inputView = new InputView(); | ||
ResultView resultView = new ResultView(); | ||
LottoService lottoService = new LottoService(); | ||
|
||
int money = inputView.readMoney(); | ||
List<Lotto> lottos = lottoService.buyLottos(money); | ||
|
||
resultView.printLottoCount(lottos.size()); | ||
resultView.printLottos(lottos); | ||
|
||
int money = inputView.readMoney(); | ||
List<Lotto> lottos = lottoService.buyLottos(money); | ||
List<Integer> winningNumbers = inputView.readWinningNumbers(); | ||
Lotto winningLotto = Lotto.of(winningNumbers); | ||
|
||
resultView.printLottoCount(lottos.size()); | ||
resultView.printLottos(lottos); | ||
LottoNumber bonusNumber = inputView.readBonusLottoNumber(); | ||
validateBonusNumber(bonusNumber, winningLotto); | ||
|
||
List<Integer> winningNumbers = inputView.readWinningNumbers(); | ||
Lotto winningLotto = new Lotto(winningNumbers); | ||
LottoResult lottoResult = lottoService.calculateResult(lottos, winningLotto, bonusNumber); | ||
|
||
LottoResult lottoResult = lottoService.calculateResult(lottos, winningLotto); | ||
resultView.printLottoResult(lottoResult); | ||
resultView.printProfitRate(lottoResult.calculateProfitRate(money)); | ||
} | ||
|
||
resultView.printLottoResult(lottoResult); | ||
resultView.printProfitRate(lottoResult.calculateProfitRate(money)); | ||
private static void validateBonusNumber(LottoNumber bonusNumber, Lotto winningLotto) { | ||
if (winningLotto.contains(bonusNumber)) { | ||
throw new IllegalArgumentException("보너스 번호는 당첨 번호와 중복되면 안 됩니다."); | ||
} | ||
} | ||
} |
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 |
---|---|---|
@@ -1,32 +1,45 @@ | ||
package lotto.domain; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class Lotto { | ||
private static final int LOTTO_SIZE = 6; | ||
private final List<Integer> numbers; | ||
private static final int LOTTO_SIZE = 6; | ||
private final List<LottoNumber> numbers; | ||
|
||
public Lotto(List<Integer> numbers) { | ||
validate(numbers); | ||
this.numbers = numbers; | ||
} | ||
public Lotto(List<LottoNumber> lottoNumbers) { | ||
validateSize(lottoNumbers); | ||
validateDuplicate(lottoNumbers); | ||
this.numbers = lottoNumbers; | ||
} | ||
|
||
private void validate(List<Integer> numbers) { | ||
if (numbers.size() != LOTTO_SIZE) { | ||
throw new IllegalArgumentException("로또 번호는 6개여야 합니다."); | ||
} | ||
public static Lotto of(List<Integer> numbers) { | ||
List<LottoNumber> lottoNumbers = | ||
numbers.stream().map(LottoNumber::new).collect(Collectors.toList()); | ||
return new Lotto(lottoNumbers); | ||
} | ||
|
||
if (numbers.stream().distinct().count() != LOTTO_SIZE) { | ||
throw new IllegalArgumentException("로또 번호에 중복이 있습니다."); | ||
} | ||
private static void validateSize(List<?> numbers) { | ||
if (numbers.size() != LOTTO_SIZE) { | ||
throw new IllegalArgumentException("로또 번호는 6개여야 합니다."); | ||
} | ||
} | ||
|
||
public List<Integer> getNumbers() { | ||
return Collections.unmodifiableList(numbers); | ||
private static void validateDuplicate(List<?> numbers) { | ||
if (numbers.stream().distinct().count() != LOTTO_SIZE) { | ||
throw new IllegalArgumentException("로또 번호에 중복이 있습니다."); | ||
} | ||
} | ||
|
||
public int countMatchingNumbers(Lotto winningLotto) { | ||
return (int) numbers.stream().filter(winningLotto.getNumbers()::contains).count(); | ||
} | ||
public List<Integer> getNumbers() { | ||
return numbers.stream().map(LottoNumber::getNumber).collect(Collectors.toUnmodifiableList()); | ||
} | ||
|
||
public int countMatchingNumbers(Lotto winningLotto) { | ||
return (int) numbers.stream().filter(number -> winningLotto.contains(number)).count(); | ||
} | ||
|
||
public boolean contains(LottoNumber lottoNumber) { | ||
return numbers.contains(lottoNumber); | ||
} | ||
} |
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,38 @@ | ||
package lotto.domain; | ||
|
||
import java.util.Objects; | ||
|
||
public class LottoNumber { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. value object 👍 |
||
public static final int MIN_LOTTO_NUMBER = 1; | ||
public static final int MAX_LOTTO_NUMBER = 45; | ||
|
||
private final int number; | ||
|
||
public LottoNumber(int number) { | ||
validate(number); | ||
this.number = number; | ||
} | ||
|
||
private void validate(int number) { | ||
if (number < MIN_LOTTO_NUMBER || number > MAX_LOTTO_NUMBER) { | ||
throw new IllegalArgumentException("로또 번호는 1부터 45 사이여야 합니다."); | ||
} | ||
} | ||
|
||
public int getNumber() { | ||
return number; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
LottoNumber that = (LottoNumber) o; | ||
return number == that.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 |
---|---|---|
@@ -1,56 +1,41 @@ | ||
package lotto.domain; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
public class LottoResult { | ||
private final List<Rank> ranks; | ||
private final Map<Rank, Integer> rankCounts; | ||
|
||
public LottoResult(List<Rank> ranks) { | ||
this.ranks = ranks; | ||
} | ||
public LottoResult() { | ||
this.rankCounts = new HashMap<>(); | ||
initializeRankCounts(); | ||
} | ||
|
||
public List<Rank> getRanks() { | ||
return ranks; | ||
private void initializeRankCounts() { | ||
for (Rank rank : Rank.values()) { | ||
rankCounts.put(rank, 0); | ||
} | ||
} | ||
|
||
public Map<Rank, Long> getStatistics() { | ||
return ranks.stream().collect(Collectors.groupingBy(rank -> rank, Collectors.counting())); | ||
} | ||
public void addRank(Rank rank) { | ||
rankCounts.put(rank, rankCounts.get(rank) + 1); | ||
} | ||
|
||
public long calculateTotalPrize() { | ||
return ranks.stream().mapToLong(Rank::getPrize).sum(); | ||
} | ||
|
||
public double calculateProfitRate(int purchaseAmount) { | ||
return (double) calculateTotalPrize() / purchaseAmount; | ||
} | ||
public int getRankCount(Rank rank) { | ||
return rankCounts.getOrDefault(rank, 0); | ||
} | ||
|
||
public enum Rank { | ||
FIRST(6, 2_000_000_000), SECOND(5, 1_500_000), THIRD(4, 50_000), FOURTH(3, 5_000), MISS(0, | ||
0); | ||
public Map<Rank, Integer> getRankCounts() { | ||
return new HashMap<>(rankCounts); | ||
} | ||
|
||
private final int matchCount; | ||
private final int prize; | ||
public long calculateTotalPrize() { | ||
return rankCounts.entrySet().stream() | ||
.mapToLong(entry -> (long) entry.getKey().getWinningMoney() * entry.getValue()) | ||
.sum(); | ||
} | ||
|
||
Rank(int matchCount, int prize) { | ||
this.matchCount = matchCount; | ||
this.prize = prize; | ||
} | ||
|
||
public static Rank valueOf(int matchCount) { | ||
return Arrays.stream(values()).filter(rank -> rank.matchCount == matchCount).findFirst() | ||
.orElse(MISS); | ||
} | ||
|
||
public int getMatchCount() { | ||
return matchCount; | ||
} | ||
|
||
public int getPrize() { | ||
return prize; | ||
} | ||
} | ||
public double calculateProfitRate(int purchaseAmount) { | ||
return (double) calculateTotalPrize() / purchaseAmount; | ||
} | ||
} |
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.
정적 팩토리 메서드의 경우 관습적으로 파라메터가 1개인 경우
from
을 사용합니다. 파라메터가 여러개일 때of
를 사용하여요.영문표현과 연관있는 관습이라고 봐주시면 좋을 것 같네요 😄