-
Notifications
You must be signed in to change notification settings - Fork 8
[로또] 박호건 미션 제출합니다. #3
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
moongua404
wants to merge
7
commits into
Java-JavaScript-Language-Stuty:main
Choose a base branch
from
moongua404:moongua404
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 all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
42aab52
docs(README.md): 리드미 작성
moongua404 04bc535
chore(init): 프로젝트 디렉토리 구성
moongua404 0cde100
feat(utils): 상수, 예외, 당첨 관리 상수 Enum 작성
moongua404 5aa6526
feat(View): 입출력 구현
moongua404 c80ab0c
feat(model): Lotto와 관련 기능 구현
moongua404 2a8598f
feat(service): 비지니스 로직 구현
moongua404 652663e
feat: 마무리
moongua404 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 |
|---|---|---|
| @@ -1 +1,130 @@ | ||
| # java-lotto-precourse | ||
|
|
||
| > 로또 맞게 해주세요...ㅠ | ||
|
|
||
| <details> | ||
| <summary>과제 세부 내용</summary> | ||
|
|
||
| ## 과제 내용 | ||
| 로또 게임 기능을 구현해야 한다. 로또 게임은 아래와 같은 규칙으로 진행된다. | ||
| ``` | ||
| - 로또 번호의 숫자 범위는 1~45까지이다. | ||
| - 1개의 로또를 발행할 때 중복되지 않는 6개의 숫자를 뽑는다. | ||
| - 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑는다. | ||
| - 당첨은 1등부터 5등까지 있다. 당첨 기준과 금액은 아래와 같다. | ||
| - 1등: 6개 번호 일치 / 2,000,000,000원 | ||
| - 2등: 5개 번호 + 보너스 번호 일치 / 30,000,000원 | ||
| - 3등: 5개 번호 일치 / 1,500,000원 | ||
| - 4등: 4개 번호 일치 / 50,000원 | ||
| - 5등: 3개 번호 일치 / 5,000원 | ||
| ``` | ||
| - 로또 구입 금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 한다. | ||
| - 로또 1장의 가격은 1,000원이다. | ||
| - 당첨 번호와 보너스 번호를 입력받는다. | ||
| - 사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 로또 게임을 종료한다. | ||
| - 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다. | ||
| - `Exception`이 아닌 `IllegalArgumentException`, `IllegalStateException` 등과 같은 명확한 유형을 처리한다. | ||
|
|
||
| ### 입출력 | ||
| - 입력 | ||
| - 로또 구입 금액 | ||
| - 당첨 번호 6개 | ||
| - 보너스 번호 | ||
| - 출력 | ||
| - 발행한 로또 수량 및 번호 | ||
| - 당첨 내역 | ||
| - 수익률 | ||
| - (예외 문구) | ||
|
|
||
| ex) | ||
|
|
||
| ``` | ||
| 구입금액을 입력해 주세요. | ||
| 8000 | ||
|
|
||
| 8개를 구매했습니다. | ||
| [8, 21, 23, 41, 42, 43] | ||
| [3, 5, 11, 16, 32, 38] | ||
| [7, 11, 16, 35, 36, 44] | ||
| [1, 8, 11, 31, 41, 42] | ||
| [13, 14, 16, 38, 42, 45] | ||
| [7, 11, 30, 40, 42, 43] | ||
| [2, 13, 22, 32, 38, 45] | ||
| [1, 3, 5, 14, 22, 45] | ||
|
|
||
| 당첨 번호를 입력해 주세요. | ||
| 1,2,3,4,5,6 | ||
|
|
||
| 보너스 번호를 입력해 주세요. | ||
| 7 | ||
|
|
||
| 당첨 통계 | ||
| --- | ||
| 3개 일치 (5,000원) - 1개 | ||
| 4개 일치 (50,000원) - 0개 | ||
| 5개 일치 (1,500,000원) - 0개 | ||
| 5개 일치, 보너스 볼 일치 (30,000,000원) - 0개 | ||
| 6개 일치 (2,000,000,000원) - 0개 | ||
| 총 수익률은 62.5%입니다. | ||
| ``` | ||
|
|
||
| </details> | ||
|
|
||
| ## 코드 흐름 | ||
| - 로또 구매 금액을 입력받는다. | ||
| - 로또를 번호를 생성하고 출력한다. | ||
| - 당첨 번호를 입력받는다. | ||
| - 결과를 계산한 후 출력한다. | ||
|
|
||
| ```mermaid | ||
| sequenceDiagram | ||
| participant View | ||
| participant Controller | ||
| participant Model | ||
|
|
||
| Controller->>View: 금액 입력 요청 | ||
| View->>Controller: 구입 금액 반환 | ||
| Controller->>Model: 구입 금액 전달 | ||
| Model-->Model: 로또 생성 | ||
| Model->>Controller: 로또 번호 반환 | ||
| Controller->>View: 로또 번호 출력 | ||
| View->>Controller: - | ||
| Controller->>View: 당첨 번호 입력 요청 | ||
| View->>Controller: 당첨 번호 반환 | ||
| Controller->>Model: 당첨 번호 전달 | ||
| Model-->Model: 당첨 여부 확인 | ||
| Model->>Controller: 결과 반환 | ||
| Controller->>View: 결과 출력 | ||
| View->>Controller: - | ||
| Controller-->Controller: 프로그램 종료 | ||
|
|
||
| ``` | ||
|
|
||
| ## 구현 기능 목록 | ||
| - 입출력 | ||
| - [ ] 구입 금액 입력 | ||
| - [ ] 당첨 번호 입력 | ||
| - [ ] 보너스 번호 입력 | ||
| - [ ] 발행한 로또 수량 및 번호 | ||
| - [ ] 당첨 내역 | ||
| - [ ] 수익률 | ||
| - [ ] 예외 | ||
| - 로또 | ||
| - [ ] 로또 생성 | ||
| - [ ] 당첨 확인 | ||
| - [ ] 수익률 계산 | ||
|
|
||
| ## 처리할 예외 | ||
| - 나누어 떨어지지 않는 금액 (1000 단위로 떨어지지 않을 때) | ||
| - `[ERROR] 1,000원 단위로 입력해 주세요.` | ||
| - 너무 큰 구입 금액 | ||
| - `[ERROR] $입력한 금액 보다 작은 금액을 입력해 주세요.` | ||
| - 부적절한 구입 금액 (음수 입력 등 포함, 입력 예외) | ||
| - `[ERROR] 유효한 구입 금액을 입력해 주세요` | ||
| - 부적절한 로또의 범위 (1-45 밖의 숫자) | ||
| - `[ERROR] 1부터 45 사이의 값을 입력해 주세요.` | ||
| - 중복되는 번호 / 보너스 번호 | ||
| - `[ERROR] 중복되지 않은 번호를 입력해주세요.` | ||
| - 부적절한 양식 혹은 갯수 | ||
| - `[ERROR] 당첨 번호 6개를 정확히 입력해주세요. ex)1,2,3,4,5,6` | ||
| - `[ERROR] 보너스 번호 하나를 정확히 입력해주세요. ex)7` |
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,42 @@ | ||
| package lotto; | ||
|
|
||
| import lotto.controller.LottoController; | ||
| import lotto.service.LottoControlService; | ||
| import lotto.service.LottoControlServiceImpl; | ||
| import lotto.service.RandomService; | ||
| import lotto.service.RandomServiceImpl; | ||
| import lotto.view.InputView; | ||
| import lotto.view.OutputView; | ||
| import lotto.view.provider.InputProvider; | ||
| import lotto.view.provider.WoowaInputProvider; | ||
|
|
||
| public class AppConfig { | ||
| public InputProvider inputProvider() { | ||
| return new WoowaInputProvider(); | ||
| } | ||
|
|
||
| public InputView inputView() { | ||
| return new InputView(inputProvider()); | ||
| } | ||
|
|
||
| public OutputView outputView() { | ||
| return new OutputView(); | ||
| } | ||
|
|
||
| public LottoControlService lottoControlService() { | ||
| return new LottoControlServiceImpl(); | ||
| } | ||
|
|
||
| public RandomService randomService() { | ||
| return new RandomServiceImpl(); | ||
| } | ||
|
|
||
| public LottoController lottoController() { | ||
| return new LottoController( | ||
| inputView(), | ||
| outputView(), | ||
| lottoControlService(), | ||
| randomService() | ||
| ); | ||
| } | ||
| } |
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,13 @@ | ||
| package lotto; | ||
|
|
||
| import lotto.controller.LottoController; | ||
|
|
||
| public class Application { | ||
|
|
||
| public static void main(String[] args) { | ||
| // TODO: 프로그램 구현 | ||
| AppConfig appConfig = new AppConfig(); | ||
| LottoController lottoController = appConfig.lottoController(); | ||
| lottoController.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,135 @@ | ||
| package lotto.controller; | ||
|
|
||
| import static lotto.utils.LottoConstants.LOTTO_PRICE; | ||
|
|
||
| import java.util.List; | ||
| import lotto.model.dto.WinningDataDto; | ||
| import lotto.service.LottoControlService; | ||
| import lotto.service.RandomService; | ||
| import lotto.utils.ExceptionConstants; | ||
| import lotto.utils.Utility; | ||
| import lotto.view.InputView; | ||
| import lotto.view.OutputView; | ||
|
|
||
| public class LottoController { | ||
| InputView inputView; | ||
| OutputView outputView; | ||
| LottoControlService lottoControlService; | ||
| RandomService randomService; | ||
| ErrorHandler errorHandler; | ||
|
|
||
| private static final int MAX_ATTEMPTS = 100; | ||
|
|
||
| public LottoController(InputView inputView, OutputView outputView, LottoControlService lottoControlService, | ||
| RandomService randomService) { | ||
| this.inputView = inputView; | ||
| this.outputView = outputView; | ||
| this.lottoControlService = lottoControlService; | ||
| this.randomService = randomService; | ||
| errorHandler = new ErrorHandler(); | ||
| } | ||
|
|
||
| public void run() { | ||
| try { | ||
| int amount = inputPrice(); | ||
| inputLottoNumber(); | ||
| outputLottoData(amount); | ||
| inputBonusNumber(); | ||
| composeLottoSystem(); | ||
| printResult(amount); | ||
| } catch (Exception e) { | ||
| outputView.printException(e); | ||
| } | ||
| } | ||
|
|
||
| private int inputPrice() { | ||
| while (true) { | ||
| if (errorHandler.willGenerateError()) { | ||
| throw new IllegalStateException(ExceptionConstants.INTERNAL_SERVER_ERROR.getMessage()); | ||
| } | ||
| try { | ||
| int price = inputView.getPrice(); | ||
| validatePrice(price); | ||
| lottoControlService.buyLotto(price / LOTTO_PRICE, randomService::getLottoNumbers); | ||
| errorHandler.resetAttemptCount(); | ||
| return price / LOTTO_PRICE; | ||
| } catch (Exception e) { | ||
| outputView.printException(e); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void validatePrice(int price) { | ||
| if (!Utility.isDividedByThousand(price)) { | ||
| throw new IllegalArgumentException(ExceptionConstants.INDIVISIBLE_PRICE.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| private void outputLottoData(int amount) { | ||
| outputView.printResultGuide(amount); | ||
| lottoControlService.getLotto().forEach(lotto -> outputView.printLotto(lotto)); | ||
| } | ||
|
|
||
| private void inputLottoNumber() { | ||
| while (true) { | ||
| if (errorHandler.willGenerateError()) { | ||
| throw new IllegalStateException(ExceptionConstants.INTERNAL_SERVER_ERROR.getMessage()); | ||
| } | ||
| try { | ||
| String line = inputView.getLottoNumber(); | ||
| lottoControlService.setWinningNumbers(line); | ||
| errorHandler.resetAttemptCount(); | ||
| break; | ||
| } catch (Exception e) { | ||
| outputView.printException(e); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void inputBonusNumber() { | ||
| while (true) { | ||
| if (errorHandler.willGenerateError()) { | ||
| throw new IllegalStateException(ExceptionConstants.INTERNAL_SERVER_ERROR.getMessage()); | ||
| } | ||
| try { | ||
| int bonusNumber = inputView.getBonusNumber(); | ||
| lottoControlService.setBonusNumber(bonusNumber); | ||
| errorHandler.resetAttemptCount(); | ||
| break; | ||
| } catch (Exception e) { | ||
| outputView.printException(e); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void composeLottoSystem() { | ||
| lottoControlService.composeLotto(); | ||
| } | ||
|
|
||
| private void printResult(int amount) { | ||
| List<WinningDataDto> lottoResult = lottoControlService.checkWinning(); | ||
| outputView.printResult(lottoResult); | ||
| float result = lottoControlService.calculateROI(lottoResult, amount * LOTTO_PRICE); | ||
| outputView.printRateOfReturn(result); | ||
| } | ||
|
|
||
| static class ErrorHandler { | ||
| private int attempts; | ||
|
|
||
| ErrorHandler() { | ||
| this.attempts = 0; | ||
| } | ||
|
|
||
| boolean willGenerateError() { | ||
| attempts++; | ||
| if (attempts > MAX_ATTEMPTS) { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| void resetAttemptCount() { | ||
| attempts = 0; | ||
| } | ||
| } | ||
| } |
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,53 @@ | ||
| package lotto.model; | ||
|
|
||
| import static lotto.utils.ExceptionConstants.DUPLICATED_LOTTO_NUMBER; | ||
| import static lotto.utils.ExceptionConstants.INVALID_LOTTO_RANGE; | ||
| import static lotto.utils.LottoConstants.LOWER_BOUND_NUMBER; | ||
| import static lotto.utils.LottoConstants.UPPER_BOUND_NUMBER; | ||
|
|
||
| import java.util.List; | ||
| import java.util.stream.Stream; | ||
| import lotto.utils.LottoPrize; | ||
| import lotto.utils.Utility; | ||
|
|
||
| public class Lotto { | ||
| private final List<Integer> numbers; | ||
|
|
||
| public Lotto(List<Integer> numbers) { | ||
| validate(numbers); | ||
| this.numbers = numbers; | ||
| } | ||
|
|
||
| private void validate(List<Integer> numbers) { | ||
| if (numbers.size() != 6) { | ||
| throw new IllegalArgumentException("[ERROR] 로또 번호는 6개여야 합니다."); | ||
| } | ||
| if (Utility.hasDuplicatedValue(numbers)) { | ||
| throw new IllegalArgumentException(DUPLICATED_LOTTO_NUMBER.getMessage()); | ||
| } | ||
| if (!Utility.isInRange(numbers, LOWER_BOUND_NUMBER, UPPER_BOUND_NUMBER)) { | ||
| throw new IllegalArgumentException(INVALID_LOTTO_RANGE.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| public LottoPrize checkWinning(List<Integer> winningNumbers, int bonusNumber) { | ||
| List<Integer> totalWinningNumber = Stream.concat(winningNumbers.stream(), Stream.of(bonusNumber)).toList(); | ||
| int matchCount = (int) numbers.stream().filter(totalWinningNumber::contains).count(); | ||
| boolean matchBonus = numbers.contains(bonusNumber); | ||
| return LottoPrize.getLottoPrize(matchCount, matchBonus); | ||
| } | ||
|
|
||
| public void validateAdditionalNumber(int value) { | ||
| List<Integer> tempNumbers = Stream.concat(numbers.stream(), Stream.of(value)).toList(); | ||
| if (Utility.hasDuplicatedValue(tempNumbers)) { | ||
| throw new IllegalArgumentException(DUPLICATED_LOTTO_NUMBER.getMessage()); | ||
| } | ||
| if (!Utility.isInRange(value, LOWER_BOUND_NUMBER, UPPER_BOUND_NUMBER)) { | ||
| throw new IllegalArgumentException(INVALID_LOTTO_RANGE.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| public List<Integer> getNumbers() { | ||
| return numbers; | ||
| } | ||
| } | ||
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.
다른건 다 utility 사용하고 exceptionConstants throw하게 만드셨던데 얘는 그냥 내비둔 이유가 있을까용? 없으면 저 사이즈 검사도 utility내의 validating 함수로 만드시는게 더 나을듯용
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.
원본 파일을 수정하지 않으려고 그냥 뒀는데, 코드의 전체적 흐름에서 맞지 않는 것은 사실인 것 같네요...ㅎㅎ