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 - 로또(2등) #3199

Merged
merged 4 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@
- [x] 1 ~ 45 범위의 랜덤한 숫자 6개를 뽑는다.
- [x] 위 숫자 리스트 생산 비용을 1000으로 책정하여, 전달받은 금액만큼 생성한다.
- [x] 당첨 번호와 숫자 일치 개수를 확인하여 당첨 통계를 낸다.
- [ ] 수익률을 계산한다.
- [x] 수익률을 계산한다.
- [x] 해당 결과를 콘솔에 출력한다.

### Step 3
- [x] 보너스 번호를 입력받는다.
- [x] 보너스 번호로 2등 여부를 확인한다.
5 changes: 2 additions & 3 deletions src/main/java/step2/controller/LottoGameController.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,18 @@ public void playLottoGame() {
List<LottoTicket> lottoTickets = lottoGames.buyLottoGame(gameCount);
ResultView.printLottoTicket(lottoTickets);
LottoTicket winningNumber = lottoGames.readWinningNumber(InputView.readWinningNumbers());
int bonusNumber = InputView.readBonusNumber();

ResultView.printBlankLine();
ResultView.printMessage("당첨 통계");

LottoResultReport lottoResultReport = new LottoResultReport();
for (LottoTicket lottoTicket : lottoTickets) {
lottoResultReport.recordRank(winningNumber.countMatchingNumbers(lottoTicket));
lottoResultReport.recordRank(winningNumber.checkLottoTicket(lottoTicket, bonusNumber));
}

ResultView.printResultReport(lottoResultReport);
double profit = lottoResultReport.calculateProfit(gameCount);
ResultView.printMessage("총 수익률은 " + profit + "입니다.");

}

}
27 changes: 14 additions & 13 deletions src/main/java/step2/domain/LottoResultReport.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,30 @@

public class LottoResultReport {

static final int ZERO = 0;
static final int EMPTY_COUNT = 0;
static final int ONE = 1;
lxxjn0 marked this conversation as resolved.
Show resolved Hide resolved

private Map<PrizeMoney, Integer> lottoResultReport;
private Map<Rank, Integer> lottoResultReport;

public LottoResultReport() {
lottoResultReport = new HashMap<>();
}

public int recordRank(PrizeMoney prizeMoney) {
if (lottoResultReport.containsKey(prizeMoney)) {
Integer cnt = lottoResultReport.get(prizeMoney);
lottoResultReport.put(prizeMoney, cnt + 1);
public int recordRank(Rank rank) {
if (lottoResultReport.containsKey(rank)) {
Integer cnt = lottoResultReport.get(rank);
lottoResultReport.put(rank, cnt + 1);
return cnt;
}
lottoResultReport.put(prizeMoney, 1);
return 1;
lottoResultReport.put(rank, 1);
lxxjn0 marked this conversation as resolved.
Show resolved Hide resolved
return ONE;
}

public int findReportByMatchCount(PrizeMoney prizeMoney) {
if (lottoResultReport.containsKey(prizeMoney)) {
return lottoResultReport.get(prizeMoney);
public int findReportByMatchCount(Rank rank) {
if (lottoResultReport.containsKey(rank)) {
return lottoResultReport.get(rank);
}
return ZERO;
return EMPTY_COUNT;
lxxjn0 marked this conversation as resolved.
Show resolved Hide resolved
}

public double calculateProfit(int gameCount) {
Expand All @@ -38,7 +39,7 @@ public double calculateProfit(int gameCount) {
}

long sum() {
Set<Map.Entry<PrizeMoney, Integer>> entries = lottoResultReport.entrySet();
Set<Map.Entry<Rank, Integer>> entries = lottoResultReport.entrySet();
return entries.stream().mapToLong(e -> e.getKey().prizeMoney() * e.getValue()).sum();
}

Expand Down
9 changes: 7 additions & 2 deletions src/main/java/step2/domain/LottoTicket.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ public boolean isContain(Integer number) {
return this.lottoTicket.contains(number);
}

public PrizeMoney countMatchingNumbers(LottoTicket compareTarget) {
public Rank checkLottoTicket(LottoTicket compareTarget, int bonusNumber) {
int count = (int) lottoTicket.stream()
.filter(i -> compareTarget.isContain(i))
.count();
return PrizeMoney.toPrizeMoney(count);

if(count == 5 && compareTarget.isContain(bonusNumber)) {
return Rank.SECOND;
}
Copy link

Choose a reason for hiding this comment

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

지금은 2등을 Rank 클래스가 아닌 LottoTicket에서 판단하고 있어요. 이렇게 된다면 책임과 역할이 다른 두 클래스에 분산되고 있는 상황인데 해당 로직을 Rank가 가질 수 있도록 해보면 어떨까요?

Copy link
Author

@gisungPark gisungPark May 14, 2023

Choose a reason for hiding this comment

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

당첨 번호와 클라이언트 티켓간의 검증의 역할을 LottoTicket 클래스가 가지고 있다고 생각합니다.
만약 Rank enum 클래스가 2등을 판단하는 역할을 가지게 된다면, 해당 판단을 위한 티켓 번호 데이터를 가져야 할텐데요.
Rank 클래스 내에 아래와 같은 메서드가 필요하게 될 것 같으며, 이는 Rank 의 역할에서 벗어나는것 같습니다.
다른 방법이 있다면 피드백 부탁드리겠습니다.
감사합니다.

public Rank isSecond (int bonusNumber) {
    if ( this != THIRD ) return this;
    // 보너스 번호 포함 여부 확인을 위한 로직 필요
}

Copy link

Choose a reason for hiding this comment

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

만약 Rank 클래스에 일치하는 숫자의 개수와 보너스 번호의 일치 여부를 넘겨준다면 어떨까요? 그렇다면 Rank 클래스에서 티켓 번호 데이터를 가지고 있지 않더라도 가능하지 않을까요?

예를 들어 SECOND의 경우 (matchCount, bonusMatch) -> matchCount == 5 && bonusMatch라는 predicate 필드를 가지고 있다면 티켓의 데이터가 없더라도 Rank는 2등 여부를 식별할 수 있으며 보너스 번호와 일치하는 번호가 있는 지를 판단하는 역할은 로또 티켓에게 그대로 유지시켜줄 수 있으니 적절하게 대응이 될 것 같아요!! 지금의 코드는 로또의 순위를 정하는 로직을 LottoTicket에 가져와서 책임과 역할이 이상했던 것 같아요!!


return Rank.toPrizeMoney(count);
}

public String printTicket() {
Expand Down
37 changes: 0 additions & 37 deletions src/main/java/step2/domain/PrizeMoney.java

This file was deleted.

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

import java.security.InvalidParameterException;
import java.util.Arrays;

public enum Rank {
MISS(0, 0, "0개 일치 (0)"),
FIFTH(3, 5_000, "3개 일치 (5000)"),
FOURTH(4, 50_000, "4개 일치 (50000)"),
THIRD(5, 1_500_000, "5개 일치 (1500000)"),
SECOND(5, 30_000_000, "5개 일치, 보너스 볼 일치(30000000원)"),
FIRST(6, 2_000_000_000, "6개 일치 (2000000000)");

private static final int THIRD_COUNT = 5;

private int matchCount;
private long prizeMoney;

private String message;

Rank(int matchCount, long rank, String message) {
this.matchCount = matchCount;
this.prizeMoney = rank;
this.message = message;
}

public static Rank toPrizeMoney(int matchCount) {
if (matchCount == THIRD_COUNT) {
return Rank.THIRD;
}

return Arrays.stream(values())
.filter(prizeMoney -> prizeMoney.matchCount == matchCount)
.findAny()
.orElse(Rank.MISS);
}

public int matchCount() {
return this.matchCount;
}

public long prizeMoney() {
return this.prizeMoney;
}

public String message() {
return this.message;
}
}
4 changes: 4 additions & 0 deletions src/main/java/step2/view/InputView.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ public static int readAmountOfPurchase() {
return readInt("구매 금액을 입력해 주세요");
}

public static int readBonusNumber() {
return readInt("보너스 볼을 입력해 주세요.");
}

private static int readInt(String message) {
System.out.println(message);
return toInt(scanner.nextLine());
Expand Down
18 changes: 11 additions & 7 deletions src/main/java/step2/view/ResultView.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@

import step2.domain.LottoResultReport;
import step2.domain.LottoTicket;
import step2.domain.PrizeMoney;
import step2.domain.Rank;

import java.util.List;

public class ResultView {

private static final int MINIMUM_MATH_COUNT = 3;
private static final int MAXIMUM_MATH_COUNT = 6;

public static void printMessage(String message) {
System.out.println(message);
}
Expand All @@ -27,9 +24,16 @@ public static void printLottoTicket(List<LottoTicket> lottoTickets) {
}

public static void printResultReport(LottoResultReport lottoResultReport) {
for (int i = MINIMUM_MATH_COUNT; i < MAXIMUM_MATH_COUNT + 1; i++) {
PrizeMoney prizeMoney = PrizeMoney.toPrizeMoney(i);
printMessage(i + "개 일치 (" + PrizeMoney.toPrizeMoney(i).prizeMoney() + ") - " + lottoResultReport.findReportByMatchCount(prizeMoney) + "개");
Rank[] values = Rank.values();
for (Rank rank : values) {
printEachLottoRank(lottoResultReport, rank);
}
}

private static void printEachLottoRank(LottoResultReport lottoResultReport, Rank rank) {
if (rank == Rank.MISS) {
return;
}
printMessage(rank.message() + " - " + lottoResultReport.findReportByMatchCount(rank) + "개");
}
}
6 changes: 3 additions & 3 deletions src/test/java/step2/domain/LottoResultReportTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ class LottoResultReportTest {

List<Integer> matchCountList = Arrays.asList(3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6);
for (Integer count : matchCountList) {
lottoResultReport.recordRank(PrizeMoney.toPrizeMoney(count));
lottoResultReport.recordRank(Rank.toPrizeMoney(count));
}

for (int i = 3; i < 7; i++) {
assertThat(lottoResultReport.findReportByMatchCount(PrizeMoney.toPrizeMoney(i))).isEqualTo(i);
assertThat(lottoResultReport.findReportByMatchCount(Rank.toPrizeMoney(i))).isEqualTo(i);
}
}

Expand All @@ -36,7 +36,7 @@ class LottoResultReportTest {
LottoResultReport lottoResultReport = new LottoResultReport();
for (int i = 1; i <= 6; i++) {
if (matchCounts[i] == 0) continue;
lottoResultReport.recordRank(PrizeMoney.toPrizeMoney(i));
lottoResultReport.recordRank(Rank.toPrizeMoney(i));
}
assertThat(lottoResultReport.sum()).isEqualTo(expected);
}
Expand Down
17 changes: 16 additions & 1 deletion src/test/java/step2/domain/LottoTicketTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class LottoTicketTest {
@MethodSource("winningNumbersSample")
public void 로또_숫자_일치_개수_비교(List<Integer> winningNumbers, int matchCount) throws Exception {
LottoTicket lottoTicket = new LottoTicket(Arrays.asList(1, 12, 22, 23, 34, 44));
assertThat(lottoTicket.countMatchingNumbers(new LottoTicket(winningNumbers))).isEqualTo(PrizeMoney.toPrizeMoney(matchCount));
assertThat(lottoTicket.checkLottoTicket(new LottoTicket(winningNumbers), 0)).isEqualTo(Rank.toPrizeMoney(matchCount));
}

static Stream<Arguments> winningNumbersSample() throws Throwable {
Expand All @@ -32,4 +32,19 @@ static Stream<Arguments> winningNumbersSample() throws Throwable {
);
}

@DisplayName("2등 당첨 케이스를 테스트한다.")
@ParameterizedTest
@MethodSource("secondRankSample")
public void 로또_2등_당첨(List<Integer> numbers, List<Integer> winningNumbers, int bonusNumber) throws Exception {
LottoTicket winningTicket = new LottoTicket(winningNumbers);
assertThat(winningTicket.checkLottoTicket(new LottoTicket(numbers), bonusNumber)).isEqualTo(Rank.SECOND);
}

static Stream<Arguments> secondRankSample() throws Throwable {
return Stream.of(
Arguments.of(Arrays.asList(1, 12, 13, 14, 27, 45), Arrays.asList(10, 12, 13, 14, 27, 45), 1),
Arguments.of(Arrays.asList(7, 8, 17, 18, 32, 33), Arrays.asList(7, 8, 17, 29, 32, 33), 18),
Arguments.of(Arrays.asList(10, 16, 21, 24, 39, 40), Arrays.asList(10, 16, 21, 24, 39, 41), 40)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

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

class PrizeMoneyTest {
class RankTest {

@DisplayName("숫자 일치 갯수별 당첨 상금을 확인한다.")
@ParameterizedTest
@CsvSource(value = {"6:2000000000", "5:1500000", "4:50000", "3:5000", "2:0", "1:0"}, delimiter = ':')
public void 당첨금_확인(int rank, long prizeMoney) throws Exception {
assertThat(PrizeMoney.toPrizeMoney(rank).prizeMoney()).isEqualTo(prizeMoney);
assertThat(Rank.toPrizeMoney(rank).prizeMoney()).isEqualTo(prizeMoney);
}

}
Expand Down