Skip to content

로또: 4단계 - 로또(수동) #4173

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

Open
wants to merge 1 commit into
base: mia-developer
Choose a base branch
from
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
42 changes: 30 additions & 12 deletions src/main/java/lotto/LottoApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

import lotto.domain.LottoService;
import lotto.domain.model.game.LottoGameResult;
import lotto.domain.model.lotto.PurchaseAmount;
import lotto.domain.model.lotto.LottoTicket;
import lotto.domain.model.lotto.WinningLottoTicket;
import lotto.domain.model.lotto.*;
import lotto.view.InputView;
import lotto.view.ResultView;

import java.util.List;
import java.util.Set;

public class LottoApplication {

Expand All @@ -24,20 +23,39 @@ public LottoApplication() {

public void start() {
try {
PurchaseAmount amount = inputView.inputPurchaseAmount();
List<LottoTicket> lottoTickets = service.purchaseTickets(amount);
resultView.printTickets(lottoTickets);

WinningLottoTicket winingLottoTicket =
new WinningLottoTicket(inputView.inputWinningNumbers(), inputView.inputBonusNumber());
LottoGameResult result = service.draw(lottoTickets, winingLottoTicket);

resultView.printResult(amount, result);
PurchaseAmount purchaseAmount = inputView.inputPurchaseAmount();
TotalTicketCount totalTicketCount = getPurchaseInformation(purchaseAmount);
List<LottoTicket> totalTickets = purchaseTickets(totalTicketCount);
LottoGameResult result = playLottoGame(totalTickets);
displayResults(purchaseAmount, result);
} finally {
inputView.close();
}
}

private TotalTicketCount getPurchaseInformation(PurchaseAmount amount) {
TicketCount purchasedTicketCount = TicketCount.from(amount, TicketPrice.standard());
TicketCount manualCount = inputView.inputManualTicketCount();
return new TotalTicketCount(purchasedTicketCount, manualCount);
}

private List<LottoTicket> purchaseTickets(TotalTicketCount totalTicketCount) {
List<LottoTicket> manualTickets = inputView.inputManualTicketNumbers(totalTicketCount.getManualTicketCount());
List<LottoTicket> totalTickets = service.purchaseTickets(manualTickets, totalTicketCount);
resultView.printTicketsWithManualCount(totalTickets, totalTicketCount);
return totalTickets;
}

private LottoGameResult playLottoGame(List<LottoTicket> totalTickets) {
Set<LottoNumber> winningNumbers = inputView.inputWinningNumbers();
BonusNumber bonusNumber = inputView.inputBonusNumber();
return service.draw(totalTickets, new WinningLottoTicket(winningNumbers, bonusNumber));
}

private void displayResults(PurchaseAmount amount, LottoGameResult result) {
resultView.printResult(amount, result);
}

public static void main(String[] args) {
new LottoApplication().start();
}
Expand Down
21 changes: 10 additions & 11 deletions src/main/java/lotto/domain/LottoService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,28 @@

import lotto.domain.model.game.LottoGame;
import lotto.domain.model.game.LottoGameResult;
import lotto.domain.model.lotto.PurchaseAmount;
import lotto.domain.model.lotto.TicketCount;
import lotto.domain.model.lotto.BonusNumber;
import lotto.domain.model.lotto.LottoNumber;
import lotto.domain.model.lotto.LottoTicket;
import lotto.domain.model.lotto.LottoTicketFactory;
import lotto.domain.model.lotto.TicketPrice;
import lotto.domain.model.lotto.WinningLottoTicket;
import lotto.domain.model.lotto.*;

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

public class LottoService {

private final LottoTicketFactory ticketFactory = new LottoTicketFactory();

public List<LottoTicket> purchaseTickets(final PurchaseAmount amount) {
TicketCount ticketCount = TicketCount.from(amount, TicketPrice.standard());
public List<LottoTicket> purchaseTickets(final List<LottoTicket> manualTickets, final TotalTicketCount totalTicketCount) {
List<LottoTicket> allTickets = new ArrayList<>(manualTickets);
List<LottoTicket> autoTickets = purchaseAutoTickets(totalTicketCount.getAutoTicketCount());
allTickets.addAll(autoTickets);
return allTickets;
}

private List<LottoTicket> purchaseAutoTickets(final TicketCount ticketCount) {
return ticketFactory.create(ticketCount.getCount());
}

public LottoGameResult draw(final List<LottoTicket> lottoTickets, final WinningLottoTicket winningLottoTicket) {
return new LottoGame(lottoTickets, winningLottoTicket).draw();
}

}
17 changes: 14 additions & 3 deletions src/main/java/lotto/domain/model/lotto/TicketCount.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package lotto.domain.model.lotto;

import lotto.domain.model.game.Prize;

import java.util.Objects;

public class TicketCount {
public class TicketCount implements Comparable<TicketCount> {
private final int count;

public TicketCount(final int count) {
if (count <= 0) {
if (count < 0) {
throw new IllegalArgumentException("티켓 수량은 0보다 커야 합니다.");
}
this.count = count;
Expand All @@ -20,6 +22,10 @@ public int getCount() {
return count;
}

public TicketCount substract(final int count) {
return new TicketCount(this.count - count);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -37,4 +43,9 @@ public int hashCode() {
public String toString() {
return String.valueOf(count);
}
}

@Override
public int compareTo(final TicketCount o) {
return Integer.compare(count, o.count);
}
}
33 changes: 33 additions & 0 deletions src/main/java/lotto/domain/model/lotto/TotalTicketCount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package lotto.domain.model.lotto;

public class TotalTicketCount {

private final TicketCount totalTicketCount;
private final TicketCount autoTicketCount;
private final TicketCount manualTicketCount;

public TotalTicketCount(final TicketCount totalTicketCount, final TicketCount manualTicketCount) {
validate(totalTicketCount, manualTicketCount);
this.totalTicketCount = totalTicketCount;
this.manualTicketCount = manualTicketCount;
this.autoTicketCount = totalTicketCount.substract(manualTicketCount.getCount());
}

private void validate(final TicketCount totalTicketCount, final TicketCount manualTicketCount) {
if (totalTicketCount.getCount() < manualTicketCount.getCount()) {
throw new IllegalArgumentException("수동으로 구매하려는 로또 수가 총 구매 가능한 로또 수를 초과합니다.");
}
}
Comment on lines +16 to +20
Copy link

Choose a reason for hiding this comment

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

이 validate의 의미가 조금 이상하네요.
로직이 틀렸다기 보단, 실제 "autoTicketCount"에 대해서도 필요하지 않을까 생각이 듭니다.


public TicketCount getTotalTicketCount() {
return totalTicketCount;
}

public TicketCount getAutoTicketCount() {
return autoTicketCount;
}

public TicketCount getManualTicketCount() {
return manualTicketCount;
}
}
27 changes: 23 additions & 4 deletions src/main/java/lotto/view/InputView.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package lotto.view;

import lotto.domain.model.lotto.PurchaseAmount;
import lotto.domain.model.lotto.BonusNumber;
import lotto.domain.model.lotto.LottoNumber;
import lotto.domain.model.lotto.*;

import java.util.*;
import java.util.stream.Collectors;
Expand All @@ -16,13 +14,34 @@ public PurchaseAmount inputPurchaseAmount() {
return new PurchaseAmount(Integer.parseInt(scanner.nextLine()));
}

public TicketCount inputManualTicketCount() {
System.out.println("수동으로 구매할 로또 수를 입력해 주세요.");
return new TicketCount(Integer.parseInt(scanner.nextLine()));
}

public List<LottoTicket> inputManualTicketNumbers(final TicketCount manualTicketCount) {
Comment on lines +17 to +22
Copy link

Choose a reason for hiding this comment

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

한번 디자인 패턴중 전략패턴을 고민해보셨으면 좋겠습니다.
티켓을 생성하는데에 있어 자동 생성, 수동 생성 두가지가 있는데 결국 이게 전략패턴으로 구분해서 할수 있지 않을까요?

System.out.println("수동으로 구매할 번호를 입력해 주세요.");
List<LottoTicket> tickets = new ArrayList<>();

for (int i = 0; i < manualTicketCount.getCount(); i++) {
tickets.add(new LottoTicket(inputLottoNumbers()));
}
Comment on lines +25 to +28
Copy link

Choose a reason for hiding this comment

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

실제 도메인을 View단에서 만드는게 맞을까요?


return tickets;
}

public BonusNumber inputBonusNumber() {
System.out.println("보너스 볼을 입력해 주세요.");
return new BonusNumber(Integer.parseInt(scanner.nextLine()));
}

public Set<LottoNumber> inputWinningNumbers() {
System.out.println("지난 주 당첨 번호를 입력해 주세요. (쉼표로 구분)");
System.out.println("지난 주 당첨 번호를 입력해 주세요.");

return inputLottoNumbers();
}

private Set<LottoNumber> inputLottoNumbers() {
String[] tokens = scanner.nextLine().split(",");

return Stream.of(tokens)
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/lotto/view/ResultView.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package lotto.view;

import lotto.domain.model.game.LottoGameResult;
import lotto.domain.model.lotto.PurchaseAmount;
import lotto.domain.model.lotto.LottoTicket;
import lotto.domain.model.lotto.*;
import lotto.domain.model.game.Rank;

import java.util.Arrays;
Expand All @@ -12,8 +11,8 @@

public class ResultView {

public void printTickets(final List<LottoTicket> tickets) {
System.out.printf("%d개를 구매했습니다.%n", tickets.size());
public void printTicketsWithManualCount(final List<LottoTicket> tickets, final TotalTicketCount totalTicketCount) {
System.out.printf("수동으로 %s장, 자동으로 %s개를 구매했습니다.%n", totalTicketCount.getManualTicketCount(), totalTicketCount.getAutoTicketCount());
tickets.forEach(System.out::println);
}

Expand Down
74 changes: 51 additions & 23 deletions src/test/java/lotto/domain/LottoServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package lotto.domain;

import lotto.domain.model.game.LottoGameResult;
import lotto.domain.model.lotto.PurchaseAmount;
import lotto.domain.model.lotto.*;
import lotto.domain.model.game.Rank;
import lotto.domain.model.game.Yield;
import lotto.domain.model.lotto.BonusNumber;
import lotto.domain.model.lotto.LottoNumber;
import lotto.domain.model.lotto.LottoTicket;
import lotto.domain.model.lotto.WinningLottoTicket;
import lotto.domain.model.lotto.TotalTicketCount;
import lotto.domain.model.lotto.TicketCount;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -25,36 +27,34 @@ class LottoServiceTest {

private final LottoService lottoService = new LottoService();

@DisplayName("로또 티켓 구매 테스트")
@DisplayName("자동 로또 티켓 구매 테스트")
@Test
void purchaseTickets() {
PurchaseAmount purchaseAmount = new PurchaseAmount(5000);
void purchaseOnlyAutoTickets() {
List<LottoTicket> manualTickets = new ArrayList<>();
int totalCount = 5;
TotalTicketCount totalTicketCount = new TotalTicketCount(
new TicketCount(totalCount),
new TicketCount(0)
);

List<LottoTicket> tickets = lottoService.purchaseTickets(purchaseAmount);
List<LottoTicket> tickets = lottoService.purchaseTickets(manualTickets, totalTicketCount);

assertThat(tickets).hasSize(5);
for (LottoTicket ticket : tickets) {
assertThat(ticket.getNumbers()).hasSize(6);
}
assertThat(tickets).hasSize(totalCount);
}

@DisplayName("로또 티켓 구매 수량 계산 테스트")
@ParameterizedTest
@ValueSource(ints = {1000, 2000, 5000, 10000})
void calculateTicketCount(int purchaseAmount) {
List<LottoTicket> tickets = lottoService.purchaseTickets(new PurchaseAmount(purchaseAmount));
@ValueSource(ints = {1, 2, 5, 10})
void calculateTicketCount(int count) {
List<LottoTicket> manualTickets = new ArrayList<>();
TotalTicketCount totalTicketCount = new TotalTicketCount(
new TicketCount(count),
new TicketCount(0)
);

int expectedCount = purchaseAmount / 1000;
assertThat(tickets).hasSize(expectedCount);
}
List<LottoTicket> tickets = lottoService.purchaseTickets(manualTickets, totalTicketCount);

@DisplayName("로또 티켓 구매 금액 검증 테스트")
@ParameterizedTest
@ValueSource(ints = {0, -1000})
void validateInvalidPurchaseAmount(int invalidAmount) {
assertThatThrownBy(() -> lottoService.purchaseTickets(new PurchaseAmount(invalidAmount)))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("구입 금액은 0보다 커야 합니다");
assertThat(tickets).hasSize(count);
}

@DisplayName("로또 게임 결과 계산 테스트")
Expand Down Expand Up @@ -102,4 +102,32 @@ private Set<LottoNumber> createLottoNumbers(final int... numbers) {
}
return lottoNumbers;
}

@DisplayName("수동 티켓과 자동 티켓 함께 구매 테스트")
@Test
void purchaseTicketsWithManualAndAuto() {
List<LottoTicket> manualTickets = List.of(
new LottoTicket(numbers(1, 2, 3, 4, 5, 6)),
new LottoTicket(numbers(10, 20, 30, 40, 41, 42))
);
int manualCount = manualTickets.size();
int totalCount = 5;
int autoCount = totalCount - manualCount;

TotalTicketCount totalTicketCount = new TotalTicketCount(
new TicketCount(totalCount),
new TicketCount(manualCount)
);

List<LottoTicket> allTickets = lottoService.purchaseTickets(manualTickets, totalTicketCount);

assertThat(allTickets).hasSize(totalCount);
assertThat(allTickets.subList(0, manualCount)).containsExactlyElementsOf(manualTickets);

List<LottoTicket> autoTickets = allTickets.subList(manualCount, totalCount);
assertThat(autoTickets).hasSize(autoCount);
for (LottoTicket ticket : autoTickets) {
assertThat(ticket.getNumbers()).hasSize(6);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ void createTicketCount() {

@DisplayName("티켓 수량 유효성 검증 테스트")
@ParameterizedTest
@ValueSource(ints = {0, -1})
@ValueSource(ints = {-1})
void validateTicketCount(int invalidCount) {
assertThatThrownBy(() -> new TicketCount(invalidCount))
.isInstanceOf(IllegalArgumentException.class)
Expand Down