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

Step2 - 로또(자동) #1790

Merged
merged 16 commits into from
Jul 28, 2021
Merged
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
37 changes: 37 additions & 0 deletions src/main/java/lotto/LottoGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package lotto;

import lotto.controller.LottoMachine;
import lotto.domain.Lotto;
import lotto.view.InputView;
import lotto.view.ResultView;

import java.util.List;
import java.util.Map;

public class LottoGame {
public static void main(String[] args) {
InputView inputView = new InputView();
LottoMachine lottoMachine = new LottoMachine();
ResultView resultView = new ResultView();

int price = inputView.buyLotto();

int count = lottoMachine.run(price);
resultView.printCount(count);

List<Lotto> lottos = lottoMachine.addLottos(count);

for (Lotto lotto: lottos) {
resultView.lottoList(lotto);
}

List<Integer> correctNumbers = inputView.lastWeekendNumber();

for (Lotto lotto: lottos) {
lottoMachine.lotteryJackpot(lotto, correctNumbers);
}
Map<String, Object> result = lottoMachine.lotteryRewards();

resultView.printResult(result, price);
}
}
9 changes: 9 additions & 0 deletions src/main/java/lotto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## 2단계 - 로또(자동)

### 기능 요구사항

### 기능 구현 완료 사항
- [X] 로또 구입 금액을 입력하면 구입 금액에 해당하는 로또를 발급 해야 한다.
- [X] 로또 1장의 가격은 1000원이다.
- [X] 지난주 당첨 번호
- [X] 당첨 통계
30 changes: 30 additions & 0 deletions src/main/java/lotto/controller/LottoMachine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package lotto.controller;

import lotto.domain.Lotto;
import lotto.domain.LottoValidate;
import lotto.domain.Lottos;

import java.util.List;
import java.util.Map;

public class LottoMachine {
private static final int REFERENCE_PRICE = 1000;

private final LottoValidate lottoValidate = new LottoValidate();

public int run(int price) {
return lottoValidate.priceValidation(price);
}

public List<Lotto> addLottos(int count) {
return Lottos.addLotto(count).getLottos();
}

public void lotteryJackpot(Lotto lotto, List<Integer> correctNumbers) {
lottoValidate.correctCheck(lotto, correctNumbers);
}

public Map<String, Object> lotteryRewards() {
return lottoValidate.lotteryRewards();
}
}
16 changes: 16 additions & 0 deletions src/main/java/lotto/domain/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package lotto.domain;

import java.util.List;

public class Lotto {

private List<Integer> lotto;

public Lotto(List<Integer> lotto) {
this.lotto = lotto;
}

public List<Integer> getLotto() {
return lotto;
}
}
29 changes: 29 additions & 0 deletions src/main/java/lotto/domain/LottoMaker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package lotto.domain;

import java.util.*;

public class LottoMaker {
private static final int LOTTO_MAX_NUMBER = 45;
private static final int LOTTO_COUNT = 6;

public static Lotto run() {
return new Lotto(makeLotto());
}

private static List<Integer> makeLotto() {
HashSet<Integer> lottoMaker = new HashSet<>();

while (lottoMaker.size() < LOTTO_COUNT) {
lottoMaker.add(generateRandomNumber());
}

List<Integer> lotto = new ArrayList<>(lottoMaker);
Collections.sort(lotto);

return lotto;
}

private static int generateRandomNumber() {
return new Random().nextInt(LOTTO_MAX_NUMBER) + 1;
}
}
74 changes: 74 additions & 0 deletions src/main/java/lotto/domain/LottoValidate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package lotto.domain;

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

public class LottoValidate {
Copy link

Choose a reason for hiding this comment

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

역할과 책임에 대해서 많이 정리가 됐습니다 👍
요청사항 반영해주시느라 정말 수고 많으셨습니다 😄

다만 로또 게임에 대한 검증역할을 하는 부분과
로또 게임의 결과를 (랭킹) 확인 하는 부분은 서로 분리가 되면 더 좋을 것 같습니다
검증과 결과를 확인하는건 도메인의 성격이 다르니까요 😄

다음단계 진행하시면서 이 부분에 대해서
개선 검토 해주시면 감사하겠습니다 🙇

private static final int REFERENCE_PRICE = 1000;
private static final int REMAINDER_VALUE = 10;

private int count = 0;
private int first = 0;
private int second = 0;
private int third = 0;
private int forth = 0;

public int priceValidation(int price) {
if (price % REMAINDER_VALUE != 0) {
throw new IllegalArgumentException("천원 단위로 입력해야 합니다.");
}

if (price < REFERENCE_PRICE) {
throw new IllegalArgumentException("돈이 천원보다 작습니다.");
}
return lottoCount(price);
}

private int lottoCount(int price) {
return (int) Math.floor(price / REFERENCE_PRICE);
}

public void correctCheck(Lotto lotto, List<Integer> correctNumbers) {
count = 0;
List<Integer> list = lotto.getLotto();
for(int i = 0 ; i < correctNumbers.size(); i++) {
getCorrectCount(list, correctNumbers, i);
}
addRank(count);
}

private void getCorrectCount(List<Integer> list, List<Integer> correctNumbers, int index) {
if (list.contains(correctNumbers.get(index))) {
count++;
}
}

private void addRank(int checkCount) {
switch (checkCount) {
case 6:
Copy link

Choose a reason for hiding this comment

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

요구사항 전체를 알고 있는 승재님이나 저와 같은 경우 이 6, 5, 4, 3 이 당첨된 번호 개수라는 것을 알지만
나중에 이 부분에 대해서 잘 모르는 개발자가 수정하려고 이 코드를 열었을 경우
6, 5, 4, 3의 의미는 정말 알기 어렵습니다 😅

최소 매직넘버가 추출 되거나 아니면 Enum을 활용해보시는 건 어떠실까요??
명시적 비교가 가능할 것 같습니다 😄

이 부분도 추가 개선 검토 부탁 드립니다 🙇

도움되실 만한 내용 공유 드립니다 🙇

https://techblog.woowahan.com/2527/

first++;
break;
case 5:
second++;
break;
case 4:
third++;
break;
case 3:
forth++;
break;
default:
break;
}
}

public Map<String, Object> lotteryRewards() {
Map<String, Object> map = new HashMap<>();
map.put("first", first);
Copy link

Choose a reason for hiding this comment

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

"first"와 같은 key 값은 상수로 추출 되여 명확한 의미를 갖도록 하는게 좋을 것 같습니다 😄

아니면 공통 변수에 선언해도 좋을 것 같은데요 😄
왜냐하면 lotteryRewards()를 호출하는 입장에서 보면 Map안에 어떤 key, value를 가지고 있을지 알기 어렵습니다

당첨 결과를 담당하는 객체를 만드시고 그 객체의 외부 method를 통해 "값을 달라고 해서 받을 수 있도록" 개선되거나
최소한 key값 만이라도 오타를 내거나 잘못된 값으로 인해 value 값을 가져가지 못하는 일은 없도록 해야 할 것 같습니다 😄
이 부분도 다시한번 개선 검토 부탁 드립니다 🙇

ex) map.get("frist"); --> null

map.put("second", second);
map.put("third", third);
map.put("forth", forth);
return map;
}
}
24 changes: 24 additions & 0 deletions src/main/java/lotto/domain/Lottos.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package lotto.domain;

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

public class Lottos {
private final List<Lotto> lottos;

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

public static Lottos addLotto(int count) {
List<Lotto> lottoList = new ArrayList<>();
for (int i = 0; i < count; i++) {
lottoList.add(LottoMaker.run());
}
return new Lottos(lottoList);
}

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

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

public class InputView {
private final Scanner sc = new Scanner(System.in);

public int buyLotto() {
System.out.println("구매할 로또 금액을 입력하세요.");
return sc.nextInt();
}

public List<Integer> lastWeekendNumber() {
System.out.println("지난 주 당첨 번호를 입력해 주세요");
List<Integer> lastLottos = makeCorrectNumber(sc.next());
Collections.sort(lastLottos);
return lastLottos;
}

private List<Integer> makeCorrectNumber(String text) {
return Arrays.stream(text.split(","))
.map(str -> Integer.parseInt(str))
.collect(Collectors.toList());
}
}
38 changes: 38 additions & 0 deletions src/main/java/lotto/view/ResultView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package lotto.view;

import lotto.domain.Lotto;

import java.util.Map;

public class ResultView {
private static final int FIRST_REWARD = 20000000;
private static final int SECOND_REWARD = 1500000;
private static final int THIRD_REWARD = 50000;
private static final int FORTH_REWARD = 5000;

public void lottoList(Lotto lotto) {
System.out.println(lotto.getLotto());
}

public void printResult(Map<String, Object> resultMap, int price) {
int first = (int) resultMap.get("first");
int second = (int) resultMap.get("second");
int third = (int) resultMap.get("third");
int forth = (int) resultMap.get("forth");
System.out.println("당첨 통계");

System.out.println("-----------");

System.out.println("1등(" + FIRST_REWARD + "원) : " + first + "개");
System.out.println("2등(" + SECOND_REWARD + "원) : " + second + "개");
System.out.println("3등(" + THIRD_REWARD + "원) : " + third + "개");
System.out.println("4등(" + FORTH_REWARD + "원) : " + forth + "개");

double result = ((first * FIRST_REWARD) + (second * SECOND_REWARD) + (third * THIRD_REWARD) + (forth * FORTH_REWARD)) / price;
System.out.println("총 수익률은 : " + result + "입니다.");
}

public void printCount(int count) {
System.out.println(count + "개 구매했습니다.");
}
}
16 changes: 16 additions & 0 deletions src/test/java/lotto/LottoMakerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package lotto;

import lotto.domain.LottoMaker;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class LottoMakerTest {
Copy link

Choose a reason for hiding this comment

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

로또 당첨부분에 대한 테스트 코드도 누락 되어있습니다 😄
확인 한번 해주시면 감사하겠습니다 🙇


@Test
@DisplayName("로또 생성 테스트")
void makeLottoTest() {
LottoMaker lottoMaker = new LottoMaker();
System.out.println(lottoMaker.run());
}

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

import lotto.domain.Lotto;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

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

class LottoMachineTest {

LottoMachine lottoMachine = new LottoMachine();

@Test
@DisplayName("당첨 테스트")
Copy link

Choose a reason for hiding this comment

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

요청사항 반영 💯

void lotteryJackpotTest() {
Lotto lotto = new Lotto(Arrays.asList(1, 2, 3, 4, 5, 6));
List<Integer> correctNumbers = Arrays.asList(1, 2, 3, 4, 5, 6);

lottoMachine.lotteryJackpot(lotto, correctNumbers);

Map<String, Object> result = lottoMachine.lotteryRewards();

assertThat(result.get("first")).isEqualTo(1);
}

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

import lotto.view.InputView;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

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

class LottoValidateTest {

LottoValidate lottoValidate = new LottoValidate();
@Test
@DisplayName("로또 구매금액만큼 로또 생성")
void createLottoTest() {
lottoValidate.priceValidation(3000);
}

@Test
@DisplayName("로또 금액 예외(천원단위가 아닐때)")
void priceExceptionTest() {
InputView inputView = new InputView();
Copy link

Choose a reason for hiding this comment

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

이 부분은 테스트에서 필요 없는 부분이라 없애셔도 될 것 같습니다 😄


assertThatThrownBy(() -> lottoValidate.priceValidation(999))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("천원 단위로 입력해야 합니다.");
}

@Test
@DisplayName("로또 금액 예외(천원보다 작을때)")
void priceExceptionTest2() {
InputView inputView = new InputView();

assertThatThrownBy(() -> lottoValidate.priceValidation(900))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("작습니다.");
}

}