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

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
daa50f6
feat: Manager 추가
jeongyuneo Mar 29, 2023
b2cc359
feat: Lotto Manager 추가
jeongyuneo Mar 29, 2023
693dae4
feat: PurchasingMoney 추가
jeongyuneo Mar 29, 2023
a06762c
feat: Input 추가
jeongyuneo Mar 29, 2023
c0edc86
feat: LottoGenerator 추가
jeongyuneo Mar 29, 2023
3530ae6
feat: IssuedLottoGenerator 추가
jeongyuneo Mar 29, 2023
5cda10e
feat: Output 추가
jeongyuneo Mar 29, 2023
fd8c722
feat: Lottos 추가
jeongyuneo Mar 29, 2023
ae8f030
refactor: Lotto 패키지 이동 및 기능 추가
jeongyuneo Mar 29, 2023
594210f
feat: WinningLottoGenerator 추가
jeongyuneo Mar 29, 2023
3cc0e59
feat: WinningDetail 추가
jeongyuneo Mar 29, 2023
bb44cf0
feat: ProfileRate 추가
jeongyuneo Mar 29, 2023
9b2502c
feat: BonusNumber 추가
jeongyuneo Mar 29, 2023
6927b61
feat: Convertor 추가
jeongyuneo Mar 29, 2023
7720622
feat: LottoResult 추가
jeongyuneo Mar 29, 2023
7f09994
feat: Input - 당첨번호 입력 기능 추가
jeongyuneo Mar 29, 2023
9340475
feat: Input - 보너스번호 입력 기능 추가
jeongyuneo Mar 29, 2023
fc380a9
feat: Output - 당첨 결과 출력 기능 추가
jeongyuneo Mar 29, 2023
fbff9e1
test: LottoTest - 패키지 위치 수정
jeongyuneo Mar 29, 2023
8a4a9f7
test: ApplicationTest - 예외 테스트 수정
jeongyuneo Mar 29, 2023
b861e93
test: BonusNumberTest 추가
jeongyuneo Mar 29, 2023
fd76161
test: ProfitRateTest 추가
jeongyuneo Mar 29, 2023
457e2d5
test: IssuedLottoGeneratorTest 추가
jeongyuneo Mar 29, 2023
2e555b5
test: WinningLottoGeneratorTest 추가
jeongyuneo Mar 29, 2023
7c0c0ce
refactor: Lotto - 중복 검증 기능 추가
jeongyuneo Mar 29, 2023
f082361
refactor: LottoManager - 발행 로또 변수 네이밍 수정
jeongyuneo Mar 30, 2023
d62110d
refactor: PurchasingMoney - Convertor 의존성 제거
jeongyuneo Mar 30, 2023
6dc337d
refactor: BonusNumber - Convertor 의존성 제거
jeongyuneo Mar 30, 2023
a64f3d1
feat: PurchasingMoney - 양수 검증 기능 추가
jeongyuneo Mar 30, 2023
22abd29
refactor: IssuedLottoGenerator - 싱글톤 패턴 적용
jeongyuneo Mar 30, 2023
823f4a3
refactor: BonusNumber - 미사용 임포트 정리
jeongyuneo Mar 30, 2023
17a5994
refactor: Lottos - quantity 필드 삭제
jeongyuneo Mar 31, 2023
8d67c30
refactor: Lotto - 숫자 범위 검증 로직 수정
jeongyuneo Mar 31, 2023
82f1c0c
refactor: 로또 결과 산출 로직 수정
jeongyuneo Apr 1, 2023
05b2a03
style: LottoResult - 상금 값 언더바 추가
jeongyuneo Apr 1, 2023
fb6ca9c
refactor: 로또 비교 로직 수정
jeongyuneo Apr 1, 2023
7eca028
refactor: ProfitRate - 반올림 로직 삭제
jeongyuneo Apr 1, 2023
3ce2aab
test: ProfitRateTest - 소숫점 둘째 자리 반올림 테스트 수정
jeongyuneo Apr 1, 2023
4239f81
refactor: BonusNumber 검증 로직 수정
jeongyuneo Apr 1, 2023
51b31fb
test: BonusNumberTest - BonusNumber 생성 수정
jeongyuneo Apr 1, 2023
8e212ad
refactor: PurchasingMoney - 수량 필드 삭제
jeongyuneo Apr 1, 2023
760bb1d
refactor: WinningDetail - 필드 수정
jeongyuneo Apr 1, 2023
0f698e1
refactor: WinningDetail - 총 상금 계산 로직 수정
jeongyuneo Apr 1, 2023
35135e5
refactor: WinningDetail - toString 로직 수정
jeongyuneo Apr 1, 2023
083ef2c
refactor: LottoResult - message 필드 삭제 및 toString 추가
jeongyuneo Apr 1, 2023
1a689aa
refactor: 로또 당첨 결과 로직 수정
jeongyuneo Apr 1, 2023
b03ea09
refactor: ProfitRate - toString 추가
jeongyuneo Apr 1, 2023
7c59d24
test: ProfitRateTest - 소숫점 둘째 자리 반올림 테스트 수정
jeongyuneo Apr 1, 2023
d43590f
refactor: Lottos - PurchasingMoney 의존성 제거
jeongyuneo Apr 1, 2023
cb771f5
refactor: Lottos - 수량 계산 로직 삭제
jeongyuneo Apr 1, 2023
8cca416
refactor: 구매 로또 출력 로직 수정
jeongyuneo Apr 1, 2023
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
7 changes: 6 additions & 1 deletion src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package lotto;

import lotto.service.LottoManager;
import lotto.service.Manager;

public class Application {

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

This file was deleted.

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

import lotto.util.Convertor;

public class BonusNumber {

private final int number;

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

public static BonusNumber from(Lotto lotto, String input) {
Copy link

Choose a reason for hiding this comment

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

BonusNumber의 생성자에서 lotto를 받아오는 게 어색합니다!
만약 winningLotto 보다 보너스 번호를 먼저 입력하도록 규칙이 변경된다면, 수정할 코드가 많아질 것 같아요.

Copy link
Author

Choose a reason for hiding this comment

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

오.. 거기까진 생각 못했습니다. 이런게 확장 가능한 설계인가요...!

제가 생각했을 때 보너스 번호의 의미가 당첨 번호를 다 뽑은 후 말 그대로 '보너스'로 뽑는 번호라고 생각해서, 앞서 뽑은 로또 번호들과 입력으로부터 생성되는게 어색하다고 생각하지 않았습니다.
먼저 뽑은 로또 번호가 없다면 보너스 번호도 없으니까요!

윤호님 피드백을 보고 당첨 번호와 보너스 번호를 저장하는 WinningLotto라는 클래스를 선언해보았는데, 이 방식으로 구현을 하다보니 BonusNumber는 검증로직조차 없는 오로지 값만 담고 있는 클래스가 되었습니다. 저는 BonusNumber가 의미있는 값이라고 생각해서 제가 의도한 바와 다른 것 같아 해당 부분은 수정하지 않았습니다.

혹시 또 의견주시면 즐겁게 의견에 대해 고민해보겠습니당ㅎㅎ

int number = Convertor.toInteger(input);
lotto.validateRange(number);
lotto.validateDuplication(number);
return new BonusNumber(number);
}

public int getNumber() {
return number;
}
}
86 changes: 86 additions & 0 deletions src/main/java/lotto/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package lotto.domain;

import lotto.domain.generator.LottoGenerator;
import lotto.domain.result.LottoResult;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class Lotto {

private static final int THE_NUMBER_OF_LOTTO = 6;
private static final int MIN_VALUE = 1;
private static final int MAX_VALUE = 45;

private final List<Integer> numbers;

public Lotto(List<Integer> numbers) {
validateSize(numbers);
validateRange(numbers);
validateDuplication(numbers);
this.numbers = new ArrayList<>(numbers);
}

public static Lotto from(LottoGenerator lottoGenerator) {
return new Lotto(lottoGenerator.issue(MIN_VALUE, MAX_VALUE, THE_NUMBER_OF_LOTTO));
}

public List<LottoResult> compare(Lottos issuedLotto, BonusNumber bonusNumber) {
return issuedLotto.compare(numbers, bonusNumber);
}
jeongyuneo marked this conversation as resolved.
Show resolved Hide resolved

public void validateDuplication(int bonusNumber) {
if (numbers.contains(bonusNumber)) {
throw new IllegalArgumentException(String.format("[ERROR] %d는 당첨 번호와 중복됩니다.", bonusNumber));
}
}

public void validateRange(int number) {
if (isNotInRange(number)) {
throw new IllegalArgumentException(String.format("[ERROR] 로또 번호는 %d부터 %d 사이의 숫자여야 합니다.", MIN_VALUE, MAX_VALUE));
}
}

public LottoResult getResult(List<Integer> other, BonusNumber bonusNumber) {
int matchingNumber = (int) numbers.stream()
.filter(other::contains)
.count();
if (matchingNumber < LottoResult.FIFTH_PRIZE.getMatchingNumber()) {
return LottoResult.NO_PRIZE;
}
jeongyuneo marked this conversation as resolved.
Show resolved Hide resolved
int matchingNumberWithBonusNumber = (int) numbers.stream()
.filter(number -> number == bonusNumber.getNumber())
jeongyuneo marked this conversation as resolved.
Show resolved Hide resolved
.count();
return LottoResult.find(matchingNumber, matchingNumberWithBonusNumber);
}

public List<Integer> getNumbers() {
return numbers;
}

private void validateSize(List<Integer> numbers) {
if (numbers.size() != THE_NUMBER_OF_LOTTO) {
throw new IllegalArgumentException(String.format("[ERROR] 로또 번호의 개수가 %d개가 아닙니다.", THE_NUMBER_OF_LOTTO));
}
}

private void validateRange(List<Integer> numbers) {
numbers.stream()
.filter(this::isNotInRange)
.findAny()
.ifPresent(number -> {
throw new IllegalArgumentException(String.format("[ERROR] 로또 번호는 %d부터 %d 사이의 숫자여야 합니다.", MIN_VALUE, MAX_VALUE));
});
}
jeongyuneo marked this conversation as resolved.
Show resolved Hide resolved

private boolean isNotInRange(int number) {
return number < MIN_VALUE || number > MAX_VALUE;
}

private void validateDuplication(List<Integer> numbers) {
if (new HashSet<>(numbers).size() != THE_NUMBER_OF_LOTTO) {
throw new IllegalArgumentException("중복되는 번호가 포함되어 있습니다.");
}
}
}
40 changes: 40 additions & 0 deletions src/main/java/lotto/domain/Lottos.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package lotto.domain;

import lotto.domain.generator.LottoGenerator;
import lotto.domain.result.LottoResult;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Lottos {

private final List<Lotto> lottos;
private final int quantity;
jeongyuneo marked this conversation as resolved.
Show resolved Hide resolved

public Lottos(List<Lotto> lottos) {
this.lottos = new ArrayList<>(lottos);
this.quantity = lottos.size();
}

public static Lottos from(LottoGenerator lottoGenerator, PurchasingMoney purchasingMoney) {
return new Lottos(Stream.generate(() -> Lotto.from(lottoGenerator))
.limit(purchasingMoney.getQuantity())
.collect(Collectors.toList()));
}

public List<LottoResult> compare(List<Integer> winningLotto, BonusNumber bonusNumber) {
return lottos.stream()
.map(lotto -> lotto.getResult(winningLotto, bonusNumber))
.collect(Collectors.toList());
}

public List<Lotto> getLottos() {
return lottos;
}

public int getQuantity() {
return quantity;
}
}
35 changes: 35 additions & 0 deletions src/main/java/lotto/domain/PurchasingMoney.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package lotto.domain;

import lotto.util.Convertor;

public class PurchasingMoney {

private static final int UNIT = 1000;

private final int money;
private final int quantity;

private PurchasingMoney(int money) {
validateUnit(money);
this.money = money;
this.quantity = money / UNIT;
}

public static PurchasingMoney from(String input) {
return new PurchasingMoney(Convertor.toInteger(input));
jeongyuneo marked this conversation as resolved.
Show resolved Hide resolved
}

public int getMoney() {
return money;
}

public int getQuantity() {
return quantity;
}

private void validateUnit(int money) {
if (money % UNIT != 0) {
throw new IllegalArgumentException(String.format("[ERROR] 구입금액은 %d원 단위여야 합니다.", UNIT));
}
jeongyuneo marked this conversation as resolved.
Show resolved Hide resolved
}
}
24 changes: 24 additions & 0 deletions src/main/java/lotto/domain/generator/IssuedLottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package lotto.domain.generator;

import camp.nextstep.edu.missionutils.Randoms;

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

public class IssuedLottoGenerator implements LottoGenerator {

private IssuedLottoGenerator() {
}

public static IssuedLottoGenerator create() {
return new IssuedLottoGenerator();
}
jeongyuneo marked this conversation as resolved.
Show resolved Hide resolved

@Override
public List<Integer> issue(int minValue, int maxValue, int quantity) {
return Randoms.pickUniqueNumbersInRange(minValue, maxValue, quantity)
.stream()
.sorted()
.collect(Collectors.toList());
}
}
8 changes: 8 additions & 0 deletions src/main/java/lotto/domain/generator/LottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package lotto.domain.generator;

import java.util.List;

public interface LottoGenerator {

List<Integer> issue(int minValue, int maxValue, int quantity);
}
63 changes: 63 additions & 0 deletions src/main/java/lotto/domain/generator/WinningLottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package lotto.domain.generator;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class WinningLottoGenerator implements LottoGenerator {

private static final String DELIMITER = ",";

private final String input;

private WinningLottoGenerator(String input) {
this.input = input;
}

public static WinningLottoGenerator from(String input) {
return new WinningLottoGenerator(input);
}

@Override
public List<Integer> issue(int minValue, int maxValue, int quantity) {
String[] numbers = input.split(DELIMITER);
validateDelimiter(numbers, quantity);
validateSize(numbers, quantity);
validateDuplication(numbers, quantity);
validateRange(numbers, minValue, maxValue);
return Arrays.stream(numbers)
.map(Integer::parseInt)
.collect(Collectors.toList());
}

private void validateDelimiter(String[] numbers, int quantity) {
if (numbers.length != quantity) {
throw new IllegalArgumentException(String.format("[ERROR] %s 외 구분자가 입력되었습니다.", DELIMITER));
}
}

private void validateDuplication(String[] numbers, int quantity) {
int numberWithoutDuplication = (int) Arrays.stream(numbers)
.distinct()
.count();
if (numberWithoutDuplication != quantity) {
throw new IllegalArgumentException("[ERROR] 당첨 번호는 중복될 수 없습니다.");
}
}

private void validateSize(String[] numbers, int quantity) {
if (numbers.length != quantity) {
throw new IllegalArgumentException(String.format("[ERROR] 당첨 번호의 개수가 %d개가 아닙니다.", quantity));
}
}

private void validateRange(String[] numbers, int minValue, int maxValue) {
Arrays.stream(numbers)
.mapToInt(Integer::parseInt)
.filter(number -> number < minValue || number > maxValue)
.findAny()
.ifPresent(number -> {
throw new IllegalArgumentException(String.format("[ERROR] 로또 번호는 %d부터 %d 사이의 숫자여야 합니다.", minValue, maxValue));
});
}
}
44 changes: 44 additions & 0 deletions src/main/java/lotto/domain/result/LottoResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package lotto.domain.result;

import java.util.Arrays;

public enum LottoResult {

FIRST_PRIZE(6, 0, 2000000000, "6개 일치"),
SECOND_PRIZE(5, 1, 30000000, "5개 일치, 보너스 볼 일치"),
THIRD_PRIZE(5, 0, 1500000, "5개 일치"),
FOURTH_PRIZE(4, 0, 50000, "4개 일치"),
FIFTH_PRIZE(3, 0, 5000, "3개 일치"),
NO_PRIZE(0, 0, 0, "");

private final int matchingNumber;
private final int matchingNumberWithBonusNumber;
private final int prize;
private final String message;

LottoResult(int matchingNumber, int matchingNumberWithBonusNumber, int prize, String message) {
this.matchingNumber = matchingNumber;
this.matchingNumberWithBonusNumber = matchingNumberWithBonusNumber;
this.prize = prize;
this.message = message;
}

public static LottoResult find(int matchingNumber, int matchingNumberWithBonusNumber) {
return Arrays.stream(values())
.filter(value -> value.matchingNumber == matchingNumber && value.matchingNumberWithBonusNumber <= matchingNumberWithBonusNumber)
.findAny()
.orElseThrow(() -> new IllegalArgumentException("[ERROR] 해당 로또에 대한 결과가 없습니다."));
}

public int getMatchingNumber() {
return matchingNumber;
}

public int getPrize() {
return prize;
}

public String getMessage() {
return message;
}
}
24 changes: 24 additions & 0 deletions src/main/java/lotto/domain/result/ProfitRate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package lotto.domain.result;

public class ProfitRate {

private static final int CIPHER = 10;

private final double value;

private ProfitRate(double value) {
this.value = value;
}

public static ProfitRate from(int prize, int purchasingMoney) {
return new ProfitRate(round(((double) prize / purchasingMoney) * 100));
}

public double getValue() {
return value;
}

private static double round(double profitRate) {
return Math.round(profitRate * CIPHER) / (double) CIPHER;
}
}
Loading