Skip to content
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
54 changes: 54 additions & 0 deletions docs/step2요구사항.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# 로또 구현

## 기능 요구사항

### 입력

- [ ] 사용자로부터 로또 구입 금액을 입력받는다
- [ ] 입력받은 금액이 올바른지 검증한다
- [ ] 1000원 단위가 아니면 IllegalArgumentException을 발생시킨다
- [ ] 음수 또는 0원이 입력되면 IllegalArgumentException을 발생시킨다
- [ ] 당첨 번호를 입력받는다
- [ ] 쉼표 로 구분된 6개의 숫자가 아니면 IllegalArgumentException을 발생시킨다.

## 로또 번호

- [x] 로또 번호는 1부터 45 사이의 숫자이다
- [x] 로또 번호 범위를 벗어나면 IllegalArgumentException을 발생시킨다

## 로또

- [x] 로또 번호는 총 6개이다
- [x] 로또 번호는 중복되지 않아야 한다
- [x] 로또 번호 중복 시 IllegalArgumentException을 발생시킨다
- [x] 로또 번호를 오름차순으로 정렬한다

## 로또 티켓

- [x] 구입 금액을 1000으로 나눈 갯수반큼 로또 티켓을 발행한다.
- [x] 1부터 45까지의 숫자 중 중복되지 않는 6개의 숫자를 무작위로 선택한다


## 랭킹
- [x] 로또 번호와 당첨 번호를 비교하여 일치하는 개수에 따라 돈을 받는다
- 3개 일치: 5,000원
- 4개 일치: 50,000원
- 5개 일치: 1,500,000원
- 6개 일치: 2,000,000,000원
- [x] 2개 이하는 낙첨이다

## 당첨
- [ ] 각 등수별 당첨 개수를 집계한다

## 수익률 계산

- [ ] 총 당첨 금액을 계산하여 수익률을 계산한다
- [ ] 수익률 = 총 당첨 금액 / 구입 금액
- [ ] 수익률을 소수점 둘째 자리까지 표시한다

## 출력

- [ ] 구입한 로또 개수를 출력한다
- [ ] 발행된 각 로또 번호를 출력한다
- [ ] 당첨 통계를 출력한다 (각 등수별 당첨 개수)
- [ ] 총 수익률을 출력한다
12 changes: 8 additions & 4 deletions src/main/java/calculator/Tokens.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ public class Tokens {
private final String[] values;

public Tokens(String expression) {
validate(expression);
this.values = parse(expression);
this(parse(validate(expression)));
}

private void validate(String expression) {
private Tokens(String[] values) {
this.values = values;
}

private static String validate(String expression) {
if (expression == null) {
throw new IllegalArgumentException("null을 입력할 수 없습니다.");
}
if (expression.trim().isEmpty()) {
throw new IllegalArgumentException("공백 혹은 빈문자열은 입력할 수 없습니다.");
}
return expression;
}

private String[] parse(String expression) {
private static String[] parse(String expression) {
return expression.split(" ");
}

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Lotto {

private static final int LOTTO_NUMBER_COUNT = 6;

private final List<LottoNumber> numbers;

public Lotto(List<Integer> numbers) {
validateSize(numbers);
validateDuplicate(numbers);
this.numbers = createLottoNumbers(numbers);
}
Comment on lines +16 to +20
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
public Lotto(List<Integer> numbers) {
validateSize(numbers);
validateDuplicate(numbers);
this.numbers = createLottoNumbers(numbers);
}
public Lotto(List<Integer> numbers) {
this(createLottoNumbers(numbers));
}
public Lotto(List<LottoNumber> numbers) {
validateSize(numbers);
validateDuplicate(numbers);
this.numbers = numbers;
}

위와 같이 주 생성자를 추가하고 부 생성자가 주 생성자를 호출하도록 구현하면 어떨까?

Copy link
Author

Choose a reason for hiding this comment

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

지속적으로 리뷰해주시는 내용인데 이부분이 바로 잘안되는듯하네요 신경써서 진행해보겠습니다


private void validateSize(List<Integer> numbers) {
if (numbers.size() != LOTTO_NUMBER_COUNT) {
throw new IllegalArgumentException("로또 번호는 총 6개여야 합니다.");
}
}

private void validateDuplicate(List<Integer> numbers) {
Set<Integer> uniqueNumbers = new HashSet<>(numbers);
Copy link
Contributor

Choose a reason for hiding this comment

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

중복을 허용하지 않는다면 인스턴스 변수를 List가 아니라 List으로 구현하는 것은 어떨까?

if (uniqueNumbers.size() != LOTTO_NUMBER_COUNT) {
throw new IllegalArgumentException("로또 번호는 중복될 수 없습니다.");
}
}

private List<LottoNumber> createLottoNumbers(List<Integer> numbers) {
List<LottoNumber> lottoNumbers = new ArrayList<>();
for (Integer number : numbers) {
lottoNumbers.add(new LottoNumber(number));
}
Collections.sort(lottoNumbers, Comparator.comparingInt(LottoNumber::getValue));
return lottoNumbers;
}

public List<Integer> getNumbers() {
List<Integer> result = new ArrayList<>();
for (LottoNumber number : numbers) {
result.add(number.getValue());
}
return result;
}

public int countMatchNumber(Lotto other) {
int count = 0;
for (LottoNumber number : numbers) {
if (other.contains(number)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

count++;
}
}
return count;
}

private boolean contains(LottoNumber number) {
for (LottoNumber lottoNumber : numbers) {
if (lottoNumber.equals(number)) {
return true;
}
}
return false;
Comment on lines +63 to +68
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
for (LottoNumber lottoNumber : numbers) {
if (lottoNumber.equals(number)) {
return true;
}
}
return false;
return this.numbers.contains(number);

콜렉션의 contains()를 활용해 구현하면 어떨까?

}

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

import java.util.Objects;

public class LottoNumber {
Copy link
Contributor

Choose a reason for hiding this comment

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

LottoNumber 값으로 추상화한 것 💯

private static final int MIN_NUMBER = 1;
private static final int MAX_NUMBER = 45;

private final int value;

public LottoNumber(int value) {
validate(value);
this.value = value;
}

public LottoNumber(String value) {
this(Integer.parseInt(value));
}
Comment on lines +11 to +18
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
public LottoNumber(int value) {
validate(value);
this.value = value;
}
public LottoNumber(String value) {
this(Integer.parseInt(value));
}
public LottoNumber(String value) {
this(Integer.parseInt(value));
}
public LottoNumber(int value) {
validate(value);
this.value = value;
}

주 생성자를 마지막에 구현하는 것이 컨벤션


private void validate(int value) {
if (value < MIN_NUMBER || value > MAX_NUMBER) {
throw new IllegalArgumentException("로또 번호는 1부터 45 사이의 숫자여야 한다");
}
}

public int getValue() {
return value;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
LottoNumber that = (LottoNumber) o;
return value == that.value;
}

@Override
public int hashCode() {
return Objects.hashCode(value);
}

@Override
public String toString() {
return "LottoNumber{value= " + value + "}";
}
}
51 changes: 51 additions & 0 deletions src/main/java/lotto/LottoTickets.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package lotto;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class LottoTickets {
private static final int LOTTO_PRICE = 1000;
private static final int MIN_LOTTO_NUMBER = 1;
private static final int MAX_LOTTO_NUMBER = 45;
private static final int LOTTO_NUMBER_COUNT = 6;

private final List<Lotto> lottos;

private LottoTickets(List<Lotto> lottos) {
this.lottos = lottos;
}

public static LottoTickets create(int purchaseAmount) {
Copy link
Contributor

Choose a reason for hiding this comment

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

purchaseAmount도 원시 값인데 포장해 보면 어떨까?
포장한 후에 이 객체의 역할에 대해 고민해 본다.

int count = purchaseAmount / LOTTO_PRICE;
List<Lotto> lottos = new ArrayList<>();
for (int i = 0; i < count; i++) {
lottos.add(createRandomLotto());
}
return new LottoTickets(lottos);
}

private static Lotto createRandomLotto() {
//TODO 많은 일을 하고 있음
Copy link
Contributor

Choose a reason for hiding this comment

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

공감함
메서드를 분리하거나 새로운 객체로 분리하는 것은 어떨까?

List<Integer> numbers = new ArrayList<>();
for (int i = MIN_LOTTO_NUMBER; i <= MAX_LOTTO_NUMBER; i++) {
numbers.add(i);
}
Collections.shuffle(numbers);

List<Integer> selectedNumbers = new ArrayList<>();
for (int i = 0; i < LOTTO_NUMBER_COUNT; i++) {
selectedNumbers.add(numbers.get(i));
}

return new Lotto(selectedNumbers);
}

public int size() {
return lottos.size();
}

public List<Lotto> getLottos() {
return new ArrayList<>(lottos);
}
}
31 changes: 31 additions & 0 deletions src/main/java/lotto/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package lotto;

public enum Rank {
FIRST(6, 2_000_000_000),
SECOND(5, 1_500_000),
THIRD(4, 50_000),
FOURTH(3, 5_000),
MISS(0, 0);

private final int matchCount;
private final int winningAmount;

Rank(int matchCount, int winningAmount) {
this.matchCount = matchCount;
this.winningAmount = winningAmount;
}

public static Rank valueOf(int matchCount) {
for (Rank rank : values()) {
if (rank.matchCount == matchCount) {
return rank;
}
}
return MISS;
}

public int getWinningAmount() {
return winningAmount;
}

}
41 changes: 41 additions & 0 deletions src/test/java/lotto/LottoNumberTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package lotto;

//- [ ] 로또 번호는 총 6개이다
//- [ ] 로또 번호는 1부터 45 사이의 숫자이다
// - [ ] 로또 번호 범위를 벗어나면 IllegalArgumentException을 발생시킨다
//- [ ] 로또 번호는 중복되지 않아야 한다
// - [ ] 로또 번호 중복 시 IllegalArgumentException을 발생시킨다

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class LottoNumberTest {
@Test
void 로또_번호_생성() {
LottoNumber lottoNumber = new LottoNumber(1);

assertThat(lottoNumber.getValue()).isEqualTo(1);
}

@Test
void 로또_번호의_범위를_벗어나면_예외발생1to45() {
assertThatThrownBy(() -> new LottoNumber(0))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("로또 번호는 1부터 45 사이의 숫자여야 한다");

assertThatThrownBy(() -> new LottoNumber(46))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("로또 번호는 1부터 45 사이의 숫자여야 한다");
}

@Test
void 같은_번호는_동등성을_가진다() {
LottoNumber number1 = new LottoNumber(1);
LottoNumber number2 = new LottoNumber(1);

assertThat(number1).isEqualTo(number2);
}

}
Loading