Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e507445
docs: 기능구현 목록 및 확인목록 작성
hjlim456 Sep 9, 2024
b8867af
feat: 패키지 구조 설계 완료
hjlim456 Sep 9, 2024
3a6d7cb
feat: 구매금액 입력 기능 구현
hjlim456 Sep 9, 2024
2c06345
feat: 구매금액 입력 기능 중 음수 입력시 검증 구현
hjlim456 Sep 9, 2024
b9dffcc
feat: 구매금액 입력 기능 중 1000원 단위 검증 구현
hjlim456 Sep 9, 2024
d25aaba
feat: 금액만큼 로또 구입 기능 구현
hjlim456 Sep 9, 2024
6a38af7
feat: 공통된 검증매서드를 분리해 놓은 Validator 객체 생성
hjlim456 Sep 9, 2024
999800c
feat: 보너스 번호입력 기능 중 당첨번호와 중복 검증 추가
hjlim456 Sep 9, 2024
f59f685
feat: 당첨번호 입력 기능 구현
hjlim456 Sep 9, 2024
9b051fb
feat: 보너스 번호 입력 구현
hjlim456 Sep 9, 2024
103174e
feat: 로또 수량 및 번호(오름차순) 출력 구현
hjlim456 Sep 9, 2024
ba0232d
feat: 당첨 체크 기능 & 당첨 내역 출력 기능 구현
hjlim456 Sep 9, 2024
fe7d455
feat: 수익률 계산 및 출력 구현
hjlim456 Sep 9, 2024
86a7b1c
refactor: dpeth 3을 2로 하향. 상수값 enum 관리로 수정
hjlim456 Sep 10, 2024
2dbd04b
feat: 당첨번호 입력시 숫자가 6개 아닐때 검증 구현
hjlim456 Sep 10, 2024
6955891
refactor: 메서드에 1가지 책임만 갖도록 분리
hjlim456 Sep 10, 2024
2cd14c6
feat: 생성한 로또 번호 중복여부 검증 구현
hjlim456 Sep 11, 2024
a706e23
test: buyLottoUsingBudgetSuccessTest 구현
hjlim456 Sep 11, 2024
7e783d0
test: buyLottoUsingBudgetSuccessTest 구현
hjlim456 Sep 11, 2024
e101fc7
fix: Lottos 검증로직 수정
hjlim456 Sep 11, 2024
d175bd2
feat: compareLottosTest 구현
hjlim456 Sep 11, 2024
4fd7b3d
feat: calculateTotalReturnRateTest 구현
hjlim456 Sep 11, 2024
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
71 changes: 71 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# 📝설계 구조
- Application : 애플리케이션 실행을 관리한다.
- MainController : 데이터 전달 및 중계 역할을 한다.
- view
- InputView : 입력과 관련된 책임 관리한다.
- OutputView : 출력과 관련된 책임 관리한다.
- message(각 객체를 enum으로 관리)
- ErrorMessage : 에러 메시지를 관리한다.
- ViewMessage : 출력 메시지를 관리한다.
- domain
- Lotto : List<Integer>를 멤버변수로 갖는다. 숫자를 관리할 일급객체
- Lottos : Lotto객체의 List를 관리할 일급컬렉션
- User : winningLotto , bounusNumber, lottoBudget, 멤버변수를갖는다.
- User의 멤버변수는 원시값으로 포장한다
- Validator 클래스
- 공통 검증매서드를 관리한다


# 📝 구현 기능 목록
### 게임 초기화

- [x] 구입할 금액 입력
- [x] `예외처리` : 빈 문자열 입력 검증
- [x] `예외처리` : 숫자외 문자 입력 검증
- [x] `예외처리` : 음수 입력 검증
- [x] `예외처리` : 1000단위로 안떨어지는 경우 검증
- [x] 로또 구입 기능
- pickUniqueNumbersInRange() 매서드 사용
- [x] 당첨번호 입력
- [x] `예외처리` : 빈 문자열 입력 검증
- [x] `예외처리` : ,가 없을때 검증
- [x] `예외처리` : 1~45 사이를 벗어난 숫자
- [x] `예외처리` : 문자를 입력했을때 검증
- [x] `예외처리` : 6자리 미만이거나 초과일때 검증
- [x] 보너스 번호 입력
- [x] `예외처리` : 1~45 사이를 벗어난 숫자
- [x] `예외처리` : 당첨번호와 중복 검증
- [x] `예외처리` : 빈 문자열 입력 검증
<Br><Br>

### 게임 진행
- [x] 발행한 로또 수량 및 번호(오름차순) 출력한다.
- [x] 당첨 체크 기능

<Br><Br>

### 게임 종료
- [x] 당첨내역및 수익률 출력후 게임종료

<Br><Br>

### 확인 목록
- Git의 커밋 단위는 README.md에 정리한 기능 목록 단위로 추가
- Java Enum을 적용
- 입력문구
- 구입금액을 입력해 주세요.
- ${갯수}개를 구매했습니다.
- 당첨 번호를 입력해 주세요.
- 보너스 번호를 입력해 주세요.
- 당첨 통계
- \-\-\-
- 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%입니다.
- 사용자가 잘못된 값을 입력할 경우
- "[ERROR]"로 시작하는 에러 메시지를 출력
- Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리한다.
- 그 부분부터 입력을 다시 받는다.
2 changes: 1 addition & 1 deletion src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
MainController.run();
}
}
20 changes: 0 additions & 20 deletions src/main/java/lotto/Lotto.java

This file was deleted.

28 changes: 28 additions & 0 deletions src/main/java/lotto/MainController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package lotto;

import java.util.LinkedHashMap;
import java.util.Map;
import lotto.domain.Budget;
import lotto.domain.Lotto;
import lotto.domain.Lottos;
import lotto.view.InputView;
import lotto.view.OutputView;

public class MainController {

public static void run() {
//게임 초기화
Budget budget = InputView.inputBudget();
Lotto winningLotto = InputView.createWinningLotto();
int bonusNumber = InputView.createBonusNumber(winningLotto);
//게임진행
Lottos purchasedLottos = Lotto.buyLottoUsingBudget(budget);

//GameEnd
Map<String, Long> resultMap = Lottos.compareLottos(purchasedLottos, winningLotto, bonusNumber);

OutputView.printResult(resultMap);
OutputView.printInvestmentRate(Budget.calculateTotalReturnRate(budget,resultMap));
;
}
}
56 changes: 56 additions & 0 deletions src/main/java/lotto/Validator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package lotto;

import lotto.domain.Lotto;
import lotto.message.ErrorMessage;

public class Validator {
public static void validatePositiveNumber(String inputString) {
if (Integer.parseInt(inputString)<=0){
throw new IllegalArgumentException(ErrorMessage.INPUT_NOT_POSITIVE_NUMBER.getMessage());
}
}

public static void validateBlank(String inputString) {
if (inputString == null || inputString.isBlank()) {
throw new IllegalArgumentException(ErrorMessage.INPUT_BLANK.getMessage());
}
}

public static void validateType(String inputString) {
try {
Integer.parseInt(inputString);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(ErrorMessage.INPUT_NOT_NUMBER.getMessage());
}
}

public static void validateDeliiter(String input) {
input.contains(",");
}
public static Integer parseAndValidateNotNumber(String input) {
try {
int number = Integer.parseInt(input);
validateNumberRange(number);
return number;
} catch (NumberFormatException e) {
throw new IllegalArgumentException(ErrorMessage.INPUT_NOT_NUMBER.getMessage());
}
}

public static void validateNumberRange(int number) {
if (number < 1 || number > 45) {
throw new IllegalArgumentException(ErrorMessage.INPUT_NOT_LOTTO_RANGE.getMessage());
}
}

public static int parseAndValidateBonusNumber(String input, Lotto winningLotto) {
validateBlank(input);

int bonusNumber = Validator.parseAndValidateNotNumber(input);
if (winningLotto.getNumbers().contains(bonusNumber)) {
throw new IllegalArgumentException(ErrorMessage.INPUT_DUPLICATED_NUMBER_WITH_WINNINGNUMBERS.getMessage());
}
return bonusNumber;
}

}
46 changes: 46 additions & 0 deletions src/main/java/lotto/domain/Budget.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package lotto.domain;

import java.util.HashMap;
import java.util.Map;
import lotto.message.ViewMessage;
import lotto.view.InputView;

public class Budget {
private int amount;

public Budget(int amount) {
validateBudget(amount);
this.amount = amount;
}
public static double calculateTotalReturnRate(Budget budget, Map<String, Long> resultMap) {
// 당첨금액과 상금을 맵으로 정의
Map<String, Long> prizeMap = new HashMap<>();
prizeMap.put("3개 일치 (5,000원) - ", 5000L);
prizeMap.put("4개 일치 (50,000원) - ", 50000L);
prizeMap.put("5개 일치 (1,500,000원) - ", 1500000L);
prizeMap.put("5개 일치, 보너스 볼 일치 (30,000,000원) - ", 30000000L);
prizeMap.put("6개 일치 (2,000,000,000원) - ", 2000000000L);

// 당첨 금액 계산
long totalPrize = resultMap.entrySet().stream()
.mapToLong(entry -> prizeMap.getOrDefault(entry.getKey(), 0L) * entry.getValue())
.sum();

// 총 투자 금액 계산
long totalInvestment = budget.getAmount();

// 수익률 계산
return (double) totalPrize / totalInvestment * 100;

// 결과 출력
}
private static void validateBudget(int amount) {
if (amount % 1000 != 0) {
throw new IllegalArgumentException("1000원 단위로만 금액을 입력해주세요.");
}
}
public int getAmount() {
return amount;
}

}
59 changes: 59 additions & 0 deletions src/main/java/lotto/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package lotto.domain;

import camp.nextstep.edu.missionutils.Randoms;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import lotto.message.ViewMessage;
import lotto.view.OutputView;

public class Lotto {
private final List<Integer> numbers;

public Lotto(List<Integer> numbers) {
validate(numbers);
validateDuplicatedNumber(numbers);
this.numbers = numbers;
}

public static Lottos buyLottoUsingBudget(Budget budget) {
int lottoCount=budget.getAmount() / 1000;
Lottos lottos = new Lottos(new ArrayList<>());

for (int i = 0; i < lottoCount; i++) {
List<Integer> lottoNumbers = Randoms.pickUniqueNumbersInRange(1, 45, 6);
Lotto lotto = new Lotto(lottoNumbers);
lottos.addLotto(lotto);
}
OutputView.printBuyResult(lottoCount, lottos);
return lottos;
}

private void validate(List<Integer> numbers) {
if (numbers.size() != 6) {
throw new IllegalArgumentException();
}
}
private void validateDuplicatedNumber(List<Integer> numbers) {
Set<Integer> uniqueNumbers = new HashSet<>(numbers);
if (uniqueNumbers.size() != numbers.size()) {
throw new IllegalArgumentException("중복된 숫자가 있습니다.");
}
}
public List<Integer> getNumbers() {
return numbers;
}

public String printNumbers() {
String numberString = numbers.stream()
.sorted()
.map(String::valueOf)
.collect(Collectors.joining(", "));
return "[" + numberString + "]";
}

}
58 changes: 58 additions & 0 deletions src/main/java/lotto/domain/Lottos.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package lotto.domain;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public record Lottos(List<Lotto> lottoList) {
public void addLotto(Lotto lotto) {
lottoList.add(lotto);
}
public String printAllLottoNumbers() {
return lottoList.stream()
.map(Lotto::printNumbers)
.collect(Collectors.joining("\n"));
}
public static Map<String, Long> compareLottos(Lottos purchasedLottos, Lotto winningLotto, int bonusNumber) {
Map<String, Long> resultMap = new LinkedHashMap<>();
List<Integer> winningLottoNumbers = winningLotto.getNumbers();

for (Lotto lotto : purchasedLottos.lottoList()){
List<Integer> purchasedNumbers = lotto.getNumbers();
long matchCount = purchasedNumbers.stream()
.filter(winningLottoNumbers::contains)
.count();
boolean hasBonus = purchasedNumbers.contains(bonusNumber);
updateResult(resultMap, matchCount, hasBonus);
}
return resultMap;
}

public static void updateResult(Map<String, Long> resultMap, long matchCount, boolean hasBonus) {
resultMap.putIfAbsent("3개 일치 (5,000원) - ", 0L);
resultMap.putIfAbsent("4개 일치 (50,000원) - ", 0L);
resultMap.putIfAbsent("5개 일치 (1,500,000원) - ", 0L);
resultMap.putIfAbsent("5개 일치, 보너스 볼 일치 (30,000,000원) - ", 0L);
resultMap.putIfAbsent("6개 일치 (2,000,000,000원) - ", 0L);

if (matchCount == 3) {
resultMap.merge("3개 일치 (5,000원) - ", 1L, Long::sum);
}
if (matchCount == 4) {
resultMap.merge("4개 일치 (50,000원) - ", 1L, Long::sum);
}
if (matchCount == 5 && hasBonus) {
resultMap.merge("5개 일치, 보너스 볼 일치 (30,000,000원) - ", 1L, Long::sum);
}
if (matchCount == 5 && !hasBonus) {
resultMap.merge("5개 일치 (1,500,000원) - ", 1L, Long::sum);
}
if (matchCount == 6) {
resultMap.merge("6개 일치 (2,000,000,000원) - ", 1L, Long::sum);
}
}
public int getLottosSize() {
return lottoList.size();
}
}
17 changes: 17 additions & 0 deletions src/main/java/lotto/message/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lotto.message;

public enum ErrorMessage {
PURCHASED_COUNT_PRINT("개를 구매했습니다."),
INPUT_NOT_NUMBER("숫자가 아닌 값을 입력하셨습니다."),
INPUT_NOT_LOTTO_RANGE("번호는 1부터 45까지의 숫자여야 합니다."),
INPUT_DUPLICATED_NUMBER_WITH_WINNINGNUMBERS("보너스 번호는 당첨 번호와 중복될 수 없습니다. 다시입력해주세요."),
INPUT_BLANK("빈 값을 입력하셨습니다. 값을 입력해주세요."),
INPUT_NOT_POSITIVE_NUMBER("0또는 음수는 입력할수없습니다. 양수를 입력해주세요");
private final String message;
ErrorMessage(String message) {
this.message = message;
}
public String getMessage() {
return "[ERROR]" + message;
}
}
16 changes: 16 additions & 0 deletions src/main/java/lotto/message/ViewMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package lotto.message;

public enum ViewMessage {
PURCHASED_COUNT_PRINT("개를 구매했습니다."),
TOTAL_RETURN_RATE ("총 수익률은 %.1f%%입니다.%n");
private final String message;

ViewMessage(String message) {
this.message = message;
}

public String getMessage() {
return message;
}

}
Loading