Skip to content
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

로또 2차 수동 미션 제출입니다. #8

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea/
.gradle/
build/
out
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,60 @@
총 수익률은 0.35입니다.(기준이 1이기 때문에 결과적으로 손해라는 의미임)
```

# 🚀 로또 2단계 - 수동 구매

## 기능 요구사항
- 현재 로또 생성기는 자동 생성 기능만 제공한다. 사용자가 수동으로 추첨 번호를 입력할 수 있도록 해야 한다.
- 입력한 금액, 자동 생성 숫자, 수동 생성 번호를 입력하도록 해야 한다.

## 프로그래밍 요구사항
- 예외가 발생하는 부분에 대해 자바 Exception을 적용해 예외처리한다.
- 사용자가 입력한 값에 대한 예외 처리를 철저히 한다.

### 실행 결과
```
구입금액을 입력해 주세요.
14000

수동으로 구매할 로또 수를 입력해 주세요.
3

수동으로 구매할 번호를 입력해 주세요.
8, 21, 23, 41, 42, 43
3, 5, 11, 16, 32, 38
7, 11, 16, 35, 36, 44

수동으로 3장, 자동으로 11개를 구매했습니다.
[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]
[23, 25, 33, 36, 39, 41]
[1, 3, 5, 14, 22, 45]
[5, 9, 38, 41, 43, 44]
[2, 8, 9, 18, 19, 21]
[13, 14, 18, 21, 23, 35]
[17, 21, 29, 37, 42, 45]
[3, 8, 27, 30, 35, 44]

지난 주 당첨 번호를 입력해 주세요.
1, 2, 3, 4, 5, 6
보너스 볼을 입력해 주세요.
7

당첨 통계
---------
3개 일치 (5000원)- 1개
4개 일치 (50000원)- 0개
5개 일치 (1500000원)- 0개
5개 일치, 보너스 볼 일치(30000000원) - 0개
6개 일치 (2000000000원)- 0개
총 수익률은 0.35입니다.(기준이 1이기 때문에 결과적으로 손해라는 의미임)
```

## 프로그래밍 요구사항
- indent(인덴트, 들여쓰기) depth를 2단계에서 1단계로 줄여라.
- depth의 경우 if문을 사용하는 경우 1단계의 depth가 증가한다. if문 안에 while문을 사용한다면 depth가 2단계가 된다.
Expand All @@ -54,3 +108,26 @@
- 로또 자동 생성은 Collections.shuffle() 메소드 활용한다.
- Collections.sort() 메소드를 활용해 정렬 가능하다.
- ArrayList의 contains() 메소드를 활용하면 어떤 값이 존재하는지 유무를 판단할 수 있다.

## 구현 할 기능
- [X] 구입 금액을 입력 받는다.
- [X] 수동으로 구매할 수를 입력 받는다.
- [X] 수동으로 구매할 번호를 입력 받는다.
- [X] 구입 금액에 따라 수동, 자동으로 각각 몇개씩 구매 했는지 알려준다.
- [X] 1 - 45 사이의 랜덤한 6개의 숫자 리스트를 구입 개수만큼 만들어 준다.
- [X] 지난 주 당첨 번호를 입력 받는다.
- [X] 보너스 볼을 입력 받는다.
- [X] 일치 여부를 확인 후 당첨 통계를 출력한다.
- [X] 당첨 금액을 계산한다.
- [X] 수익률을 계산한다.

## 예외 목록
- 구매 금액
- [X] 1000원 미만의 금액이 입력될 경우

- 로또 번호
- [X] 1 - 45 범위의 입력이 아닐 경우
- [X] 6개 중 중복된 숫자가 있을 경우
- [X] 6개 아닌 수의 입력이 있을 경우
- [X] 보너스 볼이 1개가 아닐 경우
- [ ] 보너스 볼이 6개의 숫자와 중복될 경우
Binary file added out/production/classes/LottoApplication.class
Binary file not shown.
Binary file added out/production/classes/domain/Lotto.class
Binary file not shown.
Binary file added out/production/classes/domain/LottoCount.class
Binary file not shown.
Binary file added out/production/classes/domain/LottoNumber.class
Binary file not shown.
Binary file added out/production/classes/domain/LottoRank.class
Binary file not shown.
Binary file added out/production/classes/domain/LottoResult.class
Binary file not shown.
Binary file added out/production/classes/domain/Lottos.class
Binary file not shown.
Binary file added out/production/classes/domain/MatchCount.class
Binary file not shown.
Binary file added out/production/classes/domain/Money.class
Binary file not shown.
Binary file added out/production/classes/domain/ProfitResult.class
Binary file not shown.
Binary file added out/production/classes/domain/WinningLotto.class
Binary file not shown.
Binary file added out/production/classes/ui/Printer.class
Binary file not shown.
Binary file added out/production/classes/ui/Receiver.class
Binary file not shown.
Binary file added out/test/classes/LottoCountTest.class
Binary file not shown.
Binary file added out/test/classes/LottoRankTest.class
Binary file not shown.
Binary file added out/test/classes/LottoResultTest.class
Binary file not shown.
Binary file added out/test/classes/LottoTest.class
Binary file not shown.
Binary file added out/test/classes/LottosTest.class
Binary file not shown.
Binary file added out/test/classes/MatchCountTest.class
Binary file not shown.
Binary file added out/test/classes/MoneyTest.class
Binary file not shown.
Binary file added out/test/classes/ProfitResultTest.class
Binary file not shown.
Binary file added out/test/classes/WinningLottoTest.class
Binary file not shown.
54 changes: 54 additions & 0 deletions src/main/java/LottoApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import java.util.ArrayList;
import java.util.List;
import domain.LottoNumber;
import domain.Lotto;
import domain.LottoCount;
import domain.Lottos;
import domain.Money;
import domain.ProfitResult;
import domain.WinningLotto;
import ui.Receiver;
import ui.Printer;

public class LottoApplication {

Printer printer = new Printer();
Receiver receiver = new Receiver();
Comment on lines +15 to +16
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Printer printer = new Printer();
Receiver receiver = new Receiver();
private final Printer printer = new Printer();
private final Receiver receiver = new Receiver();

main이니 큰 문제는 없겠지만, 그래도 오용을 막기위해선 private final을 붙여주는게 안전할것 같네요 🙂


public static void main(String[] args) {
LottoApplication app = new LottoApplication();
app.start();
}

private void start() {
LottoCount count = getCountByMoney();
List<String> manualLottoNumbers = getManualLottoNumbers(count);
printer.printNumberOfLottoTickets(count);
Lottos lottos = Lottos.createLottos(manualLottoNumbers, count);
printer.printLottos(lottos);
WinningLotto winningLotto = getWinningLotto();
ProfitResult result = winningLotto.getResult(lottos);
printer.printLottoProfit(result);
printer.printIsLottoProfit(result.isProfit());
}

private List<String> getManualLottoNumbers(LottoCount count) {
List<String> manualLottoNumbers = new ArrayList<>();
if (count.hasManualLottoCount()) {
manualLottoNumbers.addAll(receiver.receiveManualLottoNumbers(count));
}
return manualLottoNumbers;
}

private LottoCount getCountByMoney() {
int inputMoney = receiver.receiveMoney();
Money money = new Money(inputMoney);
return money.getLottoCount(receiver.receiveManualNumberOfLottoTickets());
}

private WinningLotto getWinningLotto() {
Lotto winningLotto = Lotto.of(receiver.receiveWinningLottoNumbers());
LottoNumber bonusBall = LottoNumber.of(receiver.receiveBonusBall());
return new WinningLotto(winningLotto, bonusBall);
}
}
65 changes: 65 additions & 0 deletions src/main/java/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package domain;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class Lotto {

private static final String LOTTO_NUMBER_COUNT_EXCEPTION_MESSAGE = "6개를 입력해주세요";
private static final String DELIMITER = ", ";
private static final int NUMBER_COUNT_ZERO = 0;
private static final int NUMBER_COUNT = 6;

private final Set<LottoNumber> balls;

private Lotto(Set<LottoNumber> balls) {
validateBallCount(balls);
this.balls = Collections.unmodifiableSet(new HashSet<>(balls));
}

private void validateBallCount(Set<LottoNumber> balls) {
if (balls.size() != NUMBER_COUNT) {
throw new IllegalArgumentException(LOTTO_NUMBER_COUNT_EXCEPTION_MESSAGE);
}
}

public static Lotto of(String rawLotto) {
String[] numbers = rawLotto.split(DELIMITER);
Set<LottoNumber> balls = new HashSet<>();
for (String number : numbers) {
balls.add(LottoNumber.of(Integer.parseInt(number)));
}
return new Lotto(balls);
}

public static Lotto newAutoLotto() {
List<LottoNumber> balls = LottoNumber.getBalls();
Collections.shuffle(balls);
Set<LottoNumber> randomBalls = new HashSet<>(balls.subList(NUMBER_COUNT_ZERO, NUMBER_COUNT));
return new Lotto(randomBalls);
}

public static boolean moreThanBallCount(int matchCount) {
return matchCount > NUMBER_COUNT;
}

public boolean contains(LottoNumber ball) {
return balls.contains(ball);
}

public int countCommonBalls(Lotto lotto) {
Set<LottoNumber> sameBalls = new HashSet<>(balls);
sameBalls.retainAll(lotto.balls);
return sameBalls.size();
}

public List<String> getLotto() {
List<String> ballsData = balls.stream()
.map(LottoNumber::toString)
.collect(Collectors.toList());
return Collections.unmodifiableList(ballsData);
}
}
52 changes: 52 additions & 0 deletions src/main/java/domain/LottoCount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package domain;

import java.util.Objects;

public class LottoCount {
private static final int MINIMUM_MANUAL_LOTTO_COUNT = 0;
private final int manualLottoCount;
Comment on lines +6 to +7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private static final int MINIMUM_MANUAL_LOTTO_COUNT = 0;
private final int manualLottoCount;
private static final int MINIMUM_MANUAL_LOTTO_COUNT = 0;
private final int manualLottoCount;

🙂

private final int lottoCount;

public LottoCount(int lottoCount) {
this(lottoCount, MINIMUM_MANUAL_LOTTO_COUNT);
}

public LottoCount(int lottoCount, int manualLottoCount) {
this.lottoCount = lottoCount;
this.manualLottoCount = manualLottoCount;
}

public boolean hasManualLottoCount() {
return manualLottoCount != 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0을 NO_COUNT 정도로 표현해줄수 있지 않을까요?

}

public Money getBuyMoney(int lottoPrice) {
return new Money(lottoCount * lottoPrice);
}

public int getAutoLottoCount() {
return lottoCount - manualLottoCount;
}

public int getManualLottoCount() {
return manualLottoCount;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LottoCount that = (LottoCount) o;
return manualLottoCount == that.manualLottoCount &&
lottoCount == that.lottoCount;
}

@Override
public int hashCode() {
return Objects.hash(manualLottoCount, lottoCount);
}
}
69 changes: 69 additions & 0 deletions src/main/java/domain/LottoNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package domain;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class LottoNumber implements Comparable<LottoNumber> {

private static final int MINIMUM_LOTTO_NUMBER = 1;
private static final int MAXIMUM_LOTTO_NUMBER = 45;
private static final String PRINT_IF_NUMBER_IS_INVALID_NUMBER = "유효한 로또 번호가 아닙니다.";
private static final Map<Integer, LottoNumber> MAPPING_BALL = new HashMap<>();

private final int number;

static {
DisposeBall();
}

private static void DisposeBall() {
for (int ballNumber = MINIMUM_LOTTO_NUMBER; ballNumber <= MAXIMUM_LOTTO_NUMBER; ballNumber++) {
MAPPING_BALL.put(ballNumber, new LottoNumber(ballNumber));
}
}
Comment on lines +22 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로또 넘버들을 초기화하는데 Map을 사용하셨군요, 좋은 아이디어 같습니다!

오늘 세션에서처럼 이같은 경우 Map을 사용하면 중복을 제거하는 로직을 넣지 않아도 된다는 이점이 있을 것 같네요.
하지만 for문을 통해 횟수를 45회로 제한한다면 이와 같은 기능이 충분이 잘 동작할 수 있을까요?
만약 중간에 중복된 값이 들어간다면 44개의 공만 저장되나요?
45개의 숫자가 확실하게 들어온다고 가정한다면 Map을 쓸 이유가 있을까요?


private LottoNumber(int number) {
this.number = number;
}

public static LottoNumber of(int number) {
if (MAPPING_BALL.containsKey(number)) {
return MAPPING_BALL.get(number);
}
throw new IllegalArgumentException(PRINT_IF_NUMBER_IS_INVALID_NUMBER);
}

public static List<LottoNumber> getBalls() {
return new ArrayList<>(MAPPING_BALL.values());
}

@Override
public String toString() {
return Integer.toString(number);
}

@Override
public int compareTo(LottoNumber o) {
return Integer.compare(number, o.number);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LottoNumber ball = (LottoNumber) o;
return number == ball.number;
}

@Override
public int hashCode() {
return Objects.hash(number);
}
}
Loading