-
Notifications
You must be signed in to change notification settings - Fork 0
로또 미션 [sjiwon] #1
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
sjiwon
wants to merge
46
commits into
main
Choose a base branch
from
sjiwon
base: main
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 42 commits
Commits
Show all changes
46 commits
Select commit
Hold shift + click to select a range
16944f1
docs: 기본 feature 및 구조 적용
sjiwon 9833710
feat: Lotto 생성과 관련되 ExceptionConstants 정의
sjiwon b8b17b4
feat: Lotto 생성 로직 구현
sjiwon 132673f
test: Lotto 생성과 관련된 테스트 코드 작성
sjiwon b5f87e4
refactor: Lotto 관련 상수 컴포넌트 분리
sjiwon 048e27c
feat: 1000원 단위 로또 1장 자동 발급을 위한 UserLotto 컴포넌트 구현
sjiwon 3229f0e
feat: 구매한 N장 UserLotto 보관을 위한 UserLottos 컴포넌트 구현
sjiwon 5dae29f
feat: 로또 당첨 번호 & 보너스 번호를 기록하는 LottoWinningMachine 구현
sjiwon a64a1f9
feat: 로또 번호에 따른 순위 결정을 위한 WinningRank 구현
sjiwon 34471aa
refactor: Lotto 생성 시 numbers 정렬 로직 추가
sjiwon 4b844b0
refactor: UserLotto 생성 시 random에 대한 의존성 분리 (LottoRandomGenerator)
sjiwon 89dd6b3
feat: UserLottos 로또번호 주입을 위한 `@VisibleForTesting` 전용 생성자 추가
sjiwon f559c1a
feat: 로또 통계 추출을 위한 LottoStatistics 구현
sjiwon dfe2bc5
refactor: final 추가
sjiwon 7caf7a5
refactor: 구매한 로또 개수를 얻기 위한 메소드 추가
sjiwon 2081329
fix: 5등 당첨금 오류 수정
sjiwon 8c5ec97
feat: 로또 당첨 수익률 계산 로직 구현
sjiwon ccc2319
feat: 사용자 Input에 대한 기본 Validator 구현
sjiwon debb63e
feat: 로또 구입금액 입력에 대한 검증 컴포넌트 구현
sjiwon 03da5e1
refactor: validateInputIsNumeric Validator로 이동
sjiwon 116f429
feat: 당첨번호 입력에 대한 검증 컴포넌트 구현
sjiwon 62780ab
refactor: 당첨번호 검증 간 Exception 메시지 수정
sjiwon f6aeb7d
feat: 보너스 번호 입력에 대한 검증 컴포넌트 구현
sjiwon 52e8417
feat: 사용자 입력에 대한 InputView 구현
sjiwon 4400938
refactor: 미당첨자 matchCount 0으로 수정
sjiwon af69857
feat: UserLotto toString() 구현
sjiwon 1be1d24
feat: 순위에 따른 당첨 개수 반환하는 메소드 추가
sjiwon c96e0e6
fix: UserLottos generate()시 unmodifiable 예외 처리를 위한 wrapping
sjiwon a9838c3
refactor: 구입 금액 입력 시 금액 -> 금액에 따른 로또 개수 반환으로 수정
sjiwon 21bd2dc
feat: 게임 진행 시 콘솔 출력을 위한 OutputView 구현
sjiwon fdfaf44
feat: 콘솔 프로그램 진행을 위한 GameController 구현, Application 적용
sjiwon 54f6ff5
docs: check clear feature
sjiwon 488b96c
docs: validator 문서 추가
sjiwon fd0ce65
refactor: Lotto/UserLotto/UserLottos 계층에서 UserLotto Wrapping 제거
sjiwon ff34b25
docs: docs Model 수정
sjiwon 944fc21
typo: getLottoPurchseCount -> getLottoPurchaseCount
sjiwon 8bdd182
typo: WINNNG_FORMAT -> WINNING_FORMAT
sjiwon 8fb3ec9
refactor: 메소드 순서 수정
sjiwon 8668b15
refactor: `refineReward` 리턴 타입 Object -> String
sjiwon 3c8a799
refactor: 로또 구입금액에 대한 `음수 검증 케이스` 추가
sjiwon 2702a95
refactor: 당첨 보너스 번호에 대한 `BonusNumber 모델` 분리
sjiwon e9e86be
docs: `BonusNumber` docs 추가
sjiwon 8574505
typo: baseballs -> numbers
sjiwon ff2a951
typo: LottoStatistics of -> checkLotteryResult
sjiwon a40cb93
fix: matchCount 6에 대한 bonusNumber 케이스 오류 수정
sjiwon 05f3b14
refactor: 로또 당첨 통계 테스트 케이스 추가 및 이전 Calculation 오류 수정
sjiwon 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| ## Feature | ||
|
|
||
| - [X] User는 `1000원` 단위로 로또 N장을 구매한다 | ||
| - 구매 후 로또 생성기로부터 N장의 로또를 생성한다 | ||
| - `1000원` 단위로 입력하지 않을 경우 `IllegalArgumentException`를 발생시키고 `[Error]`로 시작하는 에러 메시지를 출력 후 `종료`한다 | ||
|
|
||
| - [X] LottoWinningMachine은 로또 당첨 번호를 생성한다 | ||
| - 총 7개의 중복되지 않는 숫자 (기본 당첨 번호 6개 + 보너스 번호 1개) | ||
|
|
||
| - [X] LottoStatistics는 N장의 로또에 대한 당첨 통계를 산출한다 | ||
|
|
||
| <br> | ||
| <hr> | ||
|
|
||
| ## Model | ||
|
|
||
| ### `Lotto` | ||
|
|
||
| - 로또 번호 List를 추상화시킨 모델 | ||
| - [X] 로또 번호는 1..45 범위 안에 존재해야 한다 | ||
| - [X] 각 번호들은 중복되지 않아야 한다 | ||
|
|
||
| ### `UserLotto` | ||
|
|
||
| - `1000원` 단위의 로또 N장을 구매하는 컴포넌트 | ||
| - `List<Lotto>` | ||
|
|
||
| ### `LottoWinningMachine` | ||
|
|
||
| - 로또 당첨 번호 6개 + 보너스 번호를 생성하는 컴포넌트 | ||
|
|
||
| ### `BonusNumber` | ||
|
|
||
| - `보너스 번호`에 대한 컴포넌트 | ||
|
|
||
| ### `WinningRank` | ||
|
|
||
| - 당첨과 관련된 순위를 표현하는 컴포넌트 | ||
|
|
||
| ### `LottoStatistics` | ||
|
|
||
| - 로또 당첨 내역 및 수익률을 산출하기 위한 통계용 컴포넌트 | ||
|
|
||
| <br> | ||
| <hr> | ||
|
|
||
| ## Utils | ||
|
|
||
| ### `ExceptionConstants` | ||
|
|
||
| - 전역 예외 메시지 통합 컴포넌트 | ||
|
|
||
| ### `LottoConstants` | ||
|
|
||
| - Lotto 숫자 범위 & 전체 사이즈 관련 상수 전용 컴포넌트 | ||
|
|
||
| ### `LottoRandomGenerator` | ||
|
|
||
| - 로또 번호 자동 생성기 | ||
|
|
||
| ### `Validator` | ||
|
|
||
| - 사용자 Input에 대한 기본 검증 컴포넌트 | ||
| - `LottoPurchaseAmountValidator` -> 로또 구입금액 검증 컴포넌트 | ||
| - `WinningNumberValidator` -> 로또 당첨번호 검증 컴포넌트 | ||
| - `BonusNumberValidator` -> 보너스 번호 검증 컴포넌트 | ||
|
|
||
| <br> | ||
| <hr> | ||
|
|
||
| ## View | ||
|
|
||
| ### `InputView` | ||
|
|
||
| - 사용자 Input을 받기 위한 컴포넌트 | ||
|
|
||
| ### `OutputView` | ||
|
|
||
| - 로또 게임 진행과 관련된 출력 컴포넌트 | ||
|
|
||
| <br> | ||
| <hr> | ||
|
|
||
| ## Controller | ||
|
|
||
| ### `GameController` | ||
|
|
||
| - 로또 게임 진행과 관련된 컨트롤러 | ||
|
|
||
| <br> |
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,7 +1,9 @@ | ||
| package lotto; | ||
|
|
||
| import lotto.controller.GameController; | ||
|
|
||
| public class Application { | ||
| public static void main(String[] args) { | ||
| // TODO: 프로그램 구현 | ||
| new GameController().run(); | ||
| } | ||
| } |
This file was deleted.
Oops, something went wrong.
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 lotto.controller; | ||
|
|
||
| import lotto.model.LottoStatistics; | ||
| import lotto.model.LottoWinningMachine; | ||
| import lotto.model.UserLotto; | ||
| import lotto.view.InputView; | ||
| import lotto.view.OutputView; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class GameController { | ||
| private static UserLotto userLotto; | ||
| private static LottoWinningMachine lottoWinningMachine; | ||
|
|
||
| public void run() { | ||
| try { | ||
| buyLotto(); | ||
| initLottoWinningMachine(); | ||
| displayLottoResult(); | ||
| } catch (IllegalArgumentException e) { | ||
| OutputView.printErrorMessage(e.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| private void buyLotto() { | ||
| final int lottoPurchaseCount = InputView.readLottoPurchaseCount(); | ||
| userLotto = UserLotto.issueLottoByPurchaseCount(lottoPurchaseCount); | ||
| OutputView.printPurchaseInformation(userLotto.getUserLottos()); | ||
| } | ||
|
|
||
| private void initLottoWinningMachine() { | ||
| final List<Integer> winingNumbers = InputView.readWiningNumbers(); | ||
| final int bonusNumber = InputView.readBonusNumber(); | ||
| lottoWinningMachine = LottoWinningMachine.drawWinningLottery(winingNumbers, bonusNumber); | ||
| } | ||
|
|
||
| private void displayLottoResult() { | ||
| final LottoStatistics lottoStatistics = LottoStatistics.of(lottoWinningMachine, userLotto); | ||
| OutputView.printWinningStatistics(lottoStatistics); | ||
| } | ||
| } |
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,28 @@ | ||
| package lotto.model; | ||
|
|
||
| import static lotto.utils.ExceptionConstants.LottoMachineException.BONUS_NUMBER_IS_NOT_IN_RANGE; | ||
| import static lotto.utils.LottoConstants.MAX_VALUE; | ||
| import static lotto.utils.LottoConstants.MIN_VALUE; | ||
|
|
||
| public class BonusNumber { | ||
| private final int value; | ||
|
|
||
| public BonusNumber(final int value) { | ||
| validateBonusNumberIsInRange(value); | ||
| this.value = value; | ||
| } | ||
|
|
||
| private void validateBonusNumberIsInRange(final int value) { | ||
| if (isOutOfRange(value)) { | ||
| throw new IllegalArgumentException(BONUS_NUMBER_IS_NOT_IN_RANGE.message); | ||
| } | ||
| } | ||
|
|
||
| private boolean isOutOfRange(final int value) { | ||
| return value < MIN_VALUE || value > MAX_VALUE; | ||
| } | ||
|
|
||
| public int getValue() { | ||
| return value; | ||
| } | ||
| } |
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,58 @@ | ||
| package lotto.model; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| import static java.util.Collections.sort; | ||
| import static lotto.utils.ExceptionConstants.LottoException.*; | ||
| import static lotto.utils.LottoConstants.*; | ||
|
|
||
| public class Lotto { | ||
| private final List<Integer> numbers; | ||
|
|
||
| public Lotto(final List<Integer> numbers) { | ||
| validateEachLottoElementIsInRange(numbers); | ||
| validateTotalLottoSize(numbers); | ||
| validateLottoHasDuplicateElement(numbers); | ||
| sort(numbers); | ||
| this.numbers = numbers; | ||
| } | ||
|
|
||
| private void validateEachLottoElementIsInRange(final List<Integer> numbers) { | ||
| if (hasOutOfRange(numbers)) { | ||
| throw new IllegalArgumentException(LOTTO_NUMBER_IS_NOT_IN_RANGE.message); | ||
| } | ||
| } | ||
|
|
||
| private boolean hasOutOfRange(final List<Integer> numbers) { | ||
| return numbers.stream() | ||
| .anyMatch(number -> number < MIN_VALUE || number > MAX_VALUE); | ||
| } | ||
|
|
||
| private void validateTotalLottoSize(final List<Integer> numbers) { | ||
| if (numbers.size() != LOTTO_SIZE) { | ||
| throw new IllegalArgumentException(LOTTO_SIZE_IS_NOT_FULFILL.message); | ||
| } | ||
| } | ||
|
|
||
| private void validateLottoHasDuplicateElement(final List<Integer> numbers) { | ||
| if (hasDuplicateNumber(numbers)) { | ||
| throw new IllegalArgumentException(LOTTO_NUMBER_MUST_BE_UNIQUE.message); | ||
| } | ||
| } | ||
|
|
||
| private boolean hasDuplicateNumber(final List<Integer> baseballs) { | ||
| return baseballs.stream() | ||
| .distinct() | ||
| .count() != LOTTO_SIZE; | ||
| } | ||
|
|
||
| public List<Integer> getNumbers() { | ||
| return Collections.unmodifiableList(numbers); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return numbers.toString(); | ||
| } | ||
| } |
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,104 @@ | ||
| package lotto.model; | ||
|
|
||
| import java.math.BigDecimal; | ||
| import java.math.RoundingMode; | ||
| import java.util.Collections; | ||
| import java.util.EnumMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| public class LottoStatistics { | ||
| private final LottoWinningMachine lottoWinningMachine; | ||
| private final UserLotto userLotto; | ||
| private final Map<WinningRank, Integer> winningResult = new EnumMap<>(WinningRank.class); | ||
|
|
||
| private LottoStatistics( | ||
| final LottoWinningMachine lottoWinningMachine, | ||
| final UserLotto userLotto | ||
| ) { | ||
| this.lottoWinningMachine = lottoWinningMachine; | ||
| this.userLotto = userLotto; | ||
| initWinningResult(); | ||
| calculateLotteryWinningResult(); | ||
| } | ||
|
|
||
| public static LottoStatistics of( | ||
| final LottoWinningMachine lottoWinningMachine, | ||
| final UserLotto userLotto | ||
| ) { | ||
| return new LottoStatistics(lottoWinningMachine, userLotto); | ||
| } | ||
|
|
||
| private void initWinningResult() { | ||
| for (WinningRank winningRank : WinningRank.values()) { | ||
| winningResult.put(winningRank, 0); | ||
| } | ||
| } | ||
|
|
||
| private void calculateLotteryWinningResult() { | ||
| List<Integer> winningLotteryNumbers = lottoWinningMachine.getWinningLotteryNumbers(); | ||
| int bonusNumber = lottoWinningMachine.getBonusNumber(); | ||
|
|
||
| for (Lotto lotto : userLotto.getUserLottos()) { | ||
| List<Integer> lottoNumbers = lotto.getNumbers(); | ||
| int matchCount = getLottoMatchCount(lottoNumbers, winningLotteryNumbers); | ||
| boolean hasBonus = isBonusNumberExists(lottoNumbers, bonusNumber); | ||
|
|
||
| WinningRank winningRank = WinningRank.of(matchCount, hasBonus); | ||
| updateWinningResult(winningRank); | ||
| } | ||
| } | ||
|
|
||
| private int getLottoMatchCount( | ||
| final List<Integer> lottoNumbers, | ||
| final List<Integer> winningLotteryNumbers | ||
| ) { | ||
| return (int) lottoNumbers.stream() | ||
| .filter(winningLotteryNumbers::contains) | ||
| .count(); | ||
| } | ||
|
|
||
| private boolean isBonusNumberExists( | ||
| final List<Integer> lottoNumbers, | ||
| final int bonusNumber | ||
| ) { | ||
| return lottoNumbers.contains(bonusNumber); | ||
| } | ||
|
|
||
| private void updateWinningResult(final WinningRank winningRank) { | ||
| winningResult.put(winningRank, winningResult.get(winningRank) + 1); | ||
| } | ||
|
|
||
| public Map<WinningRank, Integer> getWinningResult() { | ||
| return Collections.unmodifiableMap(winningResult); | ||
| } | ||
|
|
||
| public int getWinningCountByRank(final WinningRank winningRank) { | ||
| return winningResult.getOrDefault(winningRank, 0); | ||
| } | ||
|
|
||
| public BigDecimal getEarningRate() { | ||
| final BigDecimal lottoPurchaseAmount = userLotto.getLottoPurchaseAmount(); | ||
| final BigDecimal totalWinningAmount = calculateTotalWinningAmount(); | ||
|
|
||
| return totalWinningAmount | ||
| .multiply(BigDecimal.valueOf(100)) // 백분율 | ||
| .divide(lottoPurchaseAmount, 1, RoundingMode.HALF_UP); | ||
| } | ||
|
|
||
| private BigDecimal calculateTotalWinningAmount() { | ||
| BigDecimal amount = BigDecimal.ZERO; | ||
| for (WinningRank winningRank : winningResult.keySet()) { | ||
| final BigDecimal addPrize = getAddPrize(winningRank); | ||
| amount = amount.add(addPrize); | ||
| } | ||
| return amount; | ||
| } | ||
|
|
||
| private BigDecimal getAddPrize(final WinningRank winningRank) { | ||
| final int reward = winningRank.getReward(); | ||
| final int count = winningResult.get(winningRank); | ||
|
|
||
| return BigDecimal.valueOf((long) reward * count); | ||
| } | ||
| } | ||
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.
생성자를 private으로 하고 of 메서드로 생성하는 이유가 있나요?
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.
이름 붙이려고 정적 팩토리 메소드를 쓰긴하는데 LottoStatistics의 of는 네이밍을 수정해야겠네요. 기존 팩토리 관례를 그대로 따랐네요