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

Step3 #3251

Open
wants to merge 2 commits into
base: geatrigger
Choose a base branch
from
Open

Step3 #3251

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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
[x] 로또들을 구매하는 Lottery.buy
[x] 로또를 구매하는 buyLottery
[x] 당첨 로또 번호를 입력받는 InputView
[x] 보너스 볼을 입력받는 InputView
[x] 당첨 통계를 출력하는 OutputView
[x] 맞춘 개수별로 당첨금액 정보를 저장해 놓는 WinPrizes
[x] n개 일치하는 로또의 수를 계산해주는 countWinLottery
[x] 수익률 계산해주는 calculateRateOfReturn
3 changes: 2 additions & 1 deletion src/main/java/lottery/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ public class Main {
private static final PriceInputView priceInputView = new PriceInputView();
private static final NumberOfLotteryOutputView numberOfLotteryOutputView = new NumberOfLotteryOutputView();
private static final WinLotteryInputView winLotteryInputView = new WinLotteryInputView();
private static final InputView<BonusBall> bonusBallInputView = new BonusBallInputView();
private static final LotteryResultOutputView lotteryResultOutputView = new LotteryResultOutputView();

public static void main(String[] args) {
Integer price = priceInputView.receive();
LotteryStrategy lotteryStrategy = new RandomLotteryStrategy();
List<Lottery> lotteries = Lotteries.buy(price, lotteryStrategy);
numberOfLotteryOutputView.print(lotteries);
Lottery winLottery = winLotteryInputView.receive();
WinLottery winLottery = new WinLottery(winLotteryInputView.receive(), bonusBallInputView.receive());
LotteryResult lotteryResult = Lotteries.calculateResult(lotteries, winLottery);
lotteryResultOutputView.print(lotteryResult);
}
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/lottery/domain/BonusBall.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package lottery.domain;

public class BonusBall {
private final LotteryNumber value;

public BonusBall(LotteryNumber value) {
this.value = value;
}

public LotteryNumber value() {
return value;
}
Comment on lines +10 to +12
Copy link
Member

Choose a reason for hiding this comment

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

더욱 더 VO 스럽게 사용하기 위해 동등성을 부여해주면 어떨까요? (equals & hash code)

}
34 changes: 29 additions & 5 deletions src/main/java/lottery/domain/Lotteries.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package lottery.domain;

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

public class Lotteries {
public static final Integer BONUS_BALL_CHANCE_NUMBER = 5;
public static final Integer BONUS_BALL_CHANCE_NUMBER_RANK = 6;
public static final Integer RANK_LENGTH = 8;
public static final List<Integer> matchNumberToRank = Arrays.asList(0, 1, 2, 3, 4, 5, 7);

public static List<Lottery> buy(Integer price, LotteryStrategy lotteryStrategy) {
Comment on lines +14 to 15
Copy link
Member

Choose a reason for hiding this comment

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

#3099 (comment)

로또금액을 VO 로 포장하면 더 신뢰할 수 있는 값이 되겠네요.

int number = calculateNumberOfLottery(price);
List<Lottery> lotteries = new ArrayList<>();
Expand All @@ -18,19 +25,36 @@ private static int calculateNumberOfLottery(Integer price) {
return price / LotteryPrice.VALUE;
}

public static LotteryResult calculateResult(List<Lottery> lotteries, Lottery winLottery) {
public static LotteryResult calculateResult(List<Lottery> lotteries, WinLottery winLottery) {
List<Integer> numberOfMatchNumbers = lotteries.stream().map((lottery) -> calculateMatchCount(lottery, winLottery)).collect(Collectors.toList());
List<Boolean> hasBonusBalls = lotteries.stream().map((lottery) -> calculateHasBonusBall(lottery, winLottery)).collect(Collectors.toList());
List<Integer> winLotteryNumbers = new ArrayList<>();
for (int i = 0; i <= Lottery.LENGTH; i++) {
for (int i = 0; i < RANK_LENGTH; i++) {
winLotteryNumbers.add(0);
}
for (int number : numberOfMatchNumbers) {
winLotteryNumbers.set(number, winLotteryNumbers.get(number) + 1);
for (int i = 0; i < numberOfMatchNumbers.size(); i++) {
checkBonusBallAndAdd(hasBonusBalls.get(i), numberOfMatchNumbers.get(i), winLotteryNumbers);
}
Comment on lines 31 to 37
Copy link
Member

Choose a reason for hiding this comment

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

각 반복문의 의미를 잘 모르겠어요 😢 메서드로 분리하고 메서드 이름을 통해 의미를 부여해줄 수 있을까요?

return new LotteryResult(winLotteryNumbers, lotteries.size());
}

private static int calculateMatchCount(Lottery lottery, Lottery winLottery) {
private static void checkBonusBallAndAdd(Boolean hasBonusBall, int number, List<Integer> winLotteryNumbers) {
if (hasBonusBall && number == BONUS_BALL_CHANCE_NUMBER) {
winLotteryNumbers.set(BONUS_BALL_CHANCE_NUMBER_RANK, winLotteryNumbers.get(BONUS_BALL_CHANCE_NUMBER_RANK) + 1);
return;
}
winLotteryNumbers.set(matchNumberToRank.get(number), winLotteryNumbers.get(matchNumberToRank.get(number)) + 1);
}

private static Boolean calculateHasBonusBall(Lottery lottery, WinLottery winLottery) {
List<LotteryNumber> lotteryNumbers = lottery.numbers();
LotteryNumber bonusBallValue = winLottery.bonusBall().value();

return lotteryNumbers.contains(bonusBallValue);
}


private static int calculateMatchCount(Lottery lottery, WinLottery winLottery) {
List<LotteryNumber> lotteryNumbers = lottery.numbers();
List<LotteryNumber> winLotteryNumbers = winLottery.numbers();

Expand Down
21 changes: 21 additions & 0 deletions src/main/java/lottery/domain/WinLottery.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package lottery.domain;

import java.util.List;

public class WinLottery {
private final Lottery lottery;
private final BonusBall bonusBall;

public WinLottery(Lottery lottery, BonusBall bonusBall) {
this.lottery = lottery;
this.bonusBall = bonusBall;
}

public List<LotteryNumber> numbers() {
return lottery.numbers();
}

public BonusBall bonusBall() {
return bonusBall;
}
}
7 changes: 4 additions & 3 deletions src/main/java/lottery/domain/WinPrize.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

public enum WinPrize {
FIRST_PLACE(2000000000),
SECOND_PLACE(1500000),
THIRD_PLACE(50000),
FOURTH_PLACE(5000),
SECOND_PLACE(30000000),
THIRD_PLACE(1500000),
FOURTH_PLACE(50000),
FIFTH_PLACE(5000),
LOST(0);
Comment on lines 3 to 9
Copy link
Member

Choose a reason for hiding this comment

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

enum 을 통해서 상금과 당첨 개수, 보너스볼 여부도 관리해볼 수 있을까요? 🤔



Expand Down
16 changes: 16 additions & 0 deletions src/main/java/lottery/view/BonusBallInputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package lottery.view;

import lottery.domain.BonusBall;
import lottery.domain.Lottery;
import lottery.domain.LotteryNumber;

import java.util.Scanner;

public class BonusBallInputView implements InputView<BonusBall> {
Scanner scanner = new Scanner(System.in);
Copy link
Member

Choose a reason for hiding this comment

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

#3099 (comment)

기찬님 견해가 궁금합니다!

Copy link
Author

Choose a reason for hiding this comment

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

매번 새로운 인스턴스를 생성하는 건 비효율적인 것 같네요
생성자에서 입력받아 사용하도록 바꿀게요!

@Override
public BonusBall receive() {
System.out.println("보너스 볼을 입력해 주세요.");
return new BonusBall(new LotteryNumber(scanner.nextInt()));
}
}
26 changes: 23 additions & 3 deletions src/main/java/lottery/view/LotteryResultOutputView.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
package lottery.view;

import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lottery.domain.*;

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

public class LotteryResultOutputView implements OutputView<LotteryResult> {
private final List<Integer> winPrizes = Arrays.asList(WinPrize.LOST.value(), WinPrize.LOST.value(), WinPrize.LOST.value(), WinPrize.FOURTH_PLACE.value(), WinPrize.THIRD_PLACE.value(), WinPrize.SECOND_PLACE.value(), WinPrize.FIRST_PLACE.value());
private final List<Integer> winPrizes = Arrays.asList(WinPrize.LOST.value(), WinPrize.LOST.value(), WinPrize.LOST.value(), WinPrize.FIFTH_PLACE.value(), WinPrize.FOURTH_PLACE.value(), WinPrize.THIRD_PLACE.value(), WinPrize.SECOND_PLACE.value(), WinPrize.FIRST_PLACE.value());
private final List<Integer> rankToMatchNumber;

public LotteryResultOutputView() {
rankToMatchNumber = new ArrayList<>();
for (int i = 0; i <= Lotteries.RANK_LENGTH; i++) {
rankToMatchNumber.add(0);
}
for (int i = 0; i < Lotteries.matchNumberToRank.size(); i++) {
rankToMatchNumber.set(Lotteries.matchNumberToRank.get(i), i);
}
}

@Override
public void print(LotteryResult output) {
final int MIN_WIN_NUMBER = 3;
List<Integer> winNumbers = output.winNumbers();
int totalPrize = 0;
for (int i = MIN_WIN_NUMBER; i <= Lottery.LENGTH; i++) {
for (int i = MIN_WIN_NUMBER; i < Lotteries.RANK_LENGTH; i++) {
totalPrize += winNumbers.get(i) * winPrizes.get(i);
System.out.printf("%d개 일치 (%d원)- %d개\n", i, winPrizes.get(i), winNumbers.get(i));
System.out.printf("%s (%d원)- %d개\n", rankToDetail(i), winPrizes.get(i), winNumbers.get(i));
}
System.out.printf("총 수익률은 %.2f입니다", (float) totalPrize / (output.numberOfLottery() * LotteryPrice.VALUE));
}

private String rankToDetail(int i) {
if (i == Lotteries.BONUS_BALL_CHANCE_NUMBER_RANK) {
return String.format("%d개 일치, 보너스 볼 일치", Lotteries.BONUS_BALL_CHANCE_NUMBER);
}
return String.format("%d개 일치", rankToMatchNumber.get(i));
}
}
22 changes: 20 additions & 2 deletions src/test/java/lottery/domain/LotteriesTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lottery.domain;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
Expand All @@ -15,27 +16,44 @@ class LotteriesTest {
LotteryStrategy defaultLotteryStrategy;
List<LotteryNumber> defaultLotteryNumbers;
Lottery defaultLottery;
BonusBall defaultBonusBall;
WinLottery defaultWinLottery;
List<Lottery> defaultLotteries;

@BeforeEach
void setUp() {
defaultLotteryStrategy = new TestLotteryStrategy();
defaultLotteryNumbers = Arrays.asList(new LotteryNumber(1), new LotteryNumber(2), new LotteryNumber(3), new LotteryNumber(4), new LotteryNumber(5), new LotteryNumber(6));
defaultLottery = Lottery.createLottery(defaultLotteryNumbers);
defaultBonusBall = new BonusBall(new LotteryNumber(7));
defaultWinLottery = new WinLottery(defaultLottery, defaultBonusBall);
defaultLotteries = new ArrayList<>();
for (int i = 0; i < defaultNumberOfLottery; i++) {
defaultLotteries.add(defaultLottery);
}
}

@Test
@DisplayName("로또를 기본로또전략으로 샀을 때 기본로또들 값이랑 같아야한다")
void buy() {
assertEquals(defaultLotteries, Lotteries.buy(defaultPrice, defaultLotteryStrategy));
}

@Test
@DisplayName("기본로또들, 기본승리로또를 바탕으로 계산된 결과는 1등개수가 기본개수와 같고 일치하는 보너스볼이 없어야 한다")
void calculateResult() {
LotteryResult lotteryResult = new LotteryResult(Arrays.asList(0, 0, 0, 0, 0, 0, defaultNumberOfLottery), defaultNumberOfLottery);
assertEquals(lotteryResult, Lotteries.calculateResult(defaultLotteries, defaultLottery));
LotteryResult lotteryResult = new LotteryResult(Arrays.asList(0, 0, 0, 0, 0, 0, 0, defaultNumberOfLottery), defaultNumberOfLottery);
assertEquals(lotteryResult, Lotteries.calculateResult(defaultLotteries, defaultWinLottery));

}

@Test
@DisplayName("보너스볼이 있을 때 2등의 결과는 보너스볼에 따라 달라진다")
void calculateResultWithBonusBall() {
defaultBonusBall = new BonusBall(new LotteryNumber(6));
List<LotteryNumber> winLotteryNumbersWithBonusBall = Arrays.asList(new LotteryNumber(1), new LotteryNumber(2), new LotteryNumber(3), new LotteryNumber(4), new LotteryNumber(5), new LotteryNumber(7));
WinLottery winLotteryWithBonusBall = new WinLottery(Lottery.createLottery(winLotteryNumbersWithBonusBall), defaultBonusBall);
LotteryResult lotteryResult = new LotteryResult(Arrays.asList(0, 0, 0, 0, 0, 0, defaultNumberOfLottery, 0), defaultNumberOfLottery);
assertEquals(lotteryResult, Lotteries.calculateResult(defaultLotteries, winLotteryWithBonusBall));
}
}
6 changes: 5 additions & 1 deletion src/test/java/lottery/domain/LotteryResultTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lottery.domain;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
Expand All @@ -12,19 +13,22 @@ class LotteryResultTest {
Integer defaultNumberOfLottery = 1;
List<Integer> defaultWinNumbers;
LotteryResult defaultLotteryResult;
boolean defaultHasBonusBall = false;

@BeforeEach
void setUp() {
defaultWinNumbers = Arrays.asList(6, 5, 4, 3, 2, 1);
defaultWinNumbers = Arrays.asList(7, 6, 5, 4, 3, 2, 1);
defaultLotteryResult = new LotteryResult(defaultWinNumbers, defaultNumberOfLottery);
}

@Test
@DisplayName("등수정보, 확인한 로또수 결과가 같으면 논리적으로 같은 객체다")
void testEquals() {
assertEquals(defaultLotteryResult, new LotteryResult(defaultWinNumbers, defaultNumberOfLottery));
}

@Test
@DisplayName("문자열로 변환할 때 등수정보를 보여준다")
void testToString() {
assertEquals(defaultLotteryResult.toString(), defaultWinNumbers.toString());
}
Expand Down