diff --git a/src/main/java/lotto/LottoApplication.java b/src/main/java/lotto/LottoApplication.java index 394725f710..58743622f4 100644 --- a/src/main/java/lotto/LottoApplication.java +++ b/src/main/java/lotto/LottoApplication.java @@ -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 { @@ -24,20 +23,39 @@ public LottoApplication() { public void start() { try { - PurchaseAmount amount = inputView.inputPurchaseAmount(); - List 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 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 purchaseTickets(TotalTicketCount totalTicketCount) { + List manualTickets = inputView.inputManualTicketNumbers(totalTicketCount.getManualTicketCount()); + List totalTickets = service.purchaseTickets(manualTickets, totalTicketCount); + resultView.printTicketsWithManualCount(totalTickets, totalTicketCount); + return totalTickets; + } + + private LottoGameResult playLottoGame(List totalTickets) { + Set 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(); } diff --git a/src/main/java/lotto/domain/LottoService.java b/src/main/java/lotto/domain/LottoService.java index 1005a94b28..dc76e6a1e8 100644 --- a/src/main/java/lotto/domain/LottoService.java +++ b/src/main/java/lotto/domain/LottoService.java @@ -2,15 +2,9 @@ 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; @@ -18,13 +12,18 @@ public class LottoService { private final LottoTicketFactory ticketFactory = new LottoTicketFactory(); - public List purchaseTickets(final PurchaseAmount amount) { - TicketCount ticketCount = TicketCount.from(amount, TicketPrice.standard()); + public List purchaseTickets(final List manualTickets, final TotalTicketCount totalTicketCount) { + List allTickets = new ArrayList<>(manualTickets); + List autoTickets = purchaseAutoTickets(totalTicketCount.getAutoTicketCount()); + allTickets.addAll(autoTickets); + return allTickets; + } + + private List purchaseAutoTickets(final TicketCount ticketCount) { return ticketFactory.create(ticketCount.getCount()); } public LottoGameResult draw(final List lottoTickets, final WinningLottoTicket winningLottoTicket) { return new LottoGame(lottoTickets, winningLottoTicket).draw(); } - } diff --git a/src/main/java/lotto/domain/model/lotto/TicketCount.java b/src/main/java/lotto/domain/model/lotto/TicketCount.java index 00efbf5a10..d334ee1171 100644 --- a/src/main/java/lotto/domain/model/lotto/TicketCount.java +++ b/src/main/java/lotto/domain/model/lotto/TicketCount.java @@ -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 { private final int count; public TicketCount(final int count) { - if (count <= 0) { + if (count < 0) { throw new IllegalArgumentException("티켓 수량은 0보다 커야 합니다."); } this.count = count; @@ -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; @@ -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); + } +} diff --git a/src/main/java/lotto/domain/model/lotto/TotalTicketCount.java b/src/main/java/lotto/domain/model/lotto/TotalTicketCount.java new file mode 100644 index 0000000000..d13e0fa114 --- /dev/null +++ b/src/main/java/lotto/domain/model/lotto/TotalTicketCount.java @@ -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("수동으로 구매하려는 로또 수가 총 구매 가능한 로또 수를 초과합니다."); + } + } + + public TicketCount getTotalTicketCount() { + return totalTicketCount; + } + + public TicketCount getAutoTicketCount() { + return autoTicketCount; + } + + public TicketCount getManualTicketCount() { + return manualTicketCount; + } +} diff --git a/src/main/java/lotto/view/InputView.java b/src/main/java/lotto/view/InputView.java index 7bc1f01989..4cf3c15f7a 100644 --- a/src/main/java/lotto/view/InputView.java +++ b/src/main/java/lotto/view/InputView.java @@ -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; @@ -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 inputManualTicketNumbers(final TicketCount manualTicketCount) { + System.out.println("수동으로 구매할 번호를 입력해 주세요."); + List tickets = new ArrayList<>(); + + for (int i = 0; i < manualTicketCount.getCount(); i++) { + tickets.add(new LottoTicket(inputLottoNumbers())); + } + + return tickets; + } + public BonusNumber inputBonusNumber() { System.out.println("보너스 볼을 입력해 주세요."); return new BonusNumber(Integer.parseInt(scanner.nextLine())); } public Set inputWinningNumbers() { - System.out.println("지난 주 당첨 번호를 입력해 주세요. (쉼표로 구분)"); + System.out.println("지난 주 당첨 번호를 입력해 주세요."); + + return inputLottoNumbers(); + } + + private Set inputLottoNumbers() { String[] tokens = scanner.nextLine().split(","); return Stream.of(tokens) diff --git a/src/main/java/lotto/view/ResultView.java b/src/main/java/lotto/view/ResultView.java index 63e07500f2..84d9ec4ed2 100644 --- a/src/main/java/lotto/view/ResultView.java +++ b/src/main/java/lotto/view/ResultView.java @@ -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; @@ -12,8 +11,8 @@ public class ResultView { - public void printTickets(final List tickets) { - System.out.printf("%d개를 구매했습니다.%n", tickets.size()); + public void printTicketsWithManualCount(final List tickets, final TotalTicketCount totalTicketCount) { + System.out.printf("수동으로 %s장, 자동으로 %s개를 구매했습니다.%n", totalTicketCount.getManualTicketCount(), totalTicketCount.getAutoTicketCount()); tickets.forEach(System.out::println); } diff --git a/src/test/java/lotto/domain/LottoServiceTest.java b/src/test/java/lotto/domain/LottoServiceTest.java index 344e549237..cbb3040312 100644 --- a/src/test/java/lotto/domain/LottoServiceTest.java +++ b/src/test/java/lotto/domain/LottoServiceTest.java @@ -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; @@ -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 manualTickets = new ArrayList<>(); + int totalCount = 5; + TotalTicketCount totalTicketCount = new TotalTicketCount( + new TicketCount(totalCount), + new TicketCount(0) + ); - List tickets = lottoService.purchaseTickets(purchaseAmount); + List 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 tickets = lottoService.purchaseTickets(new PurchaseAmount(purchaseAmount)); + @ValueSource(ints = {1, 2, 5, 10}) + void calculateTicketCount(int count) { + List manualTickets = new ArrayList<>(); + TotalTicketCount totalTicketCount = new TotalTicketCount( + new TicketCount(count), + new TicketCount(0) + ); - int expectedCount = purchaseAmount / 1000; - assertThat(tickets).hasSize(expectedCount); - } + List 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("로또 게임 결과 계산 테스트") @@ -102,4 +102,32 @@ private Set createLottoNumbers(final int... numbers) { } return lottoNumbers; } + + @DisplayName("수동 티켓과 자동 티켓 함께 구매 테스트") + @Test + void purchaseTicketsWithManualAndAuto() { + List 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 allTickets = lottoService.purchaseTickets(manualTickets, totalTicketCount); + + assertThat(allTickets).hasSize(totalCount); + assertThat(allTickets.subList(0, manualCount)).containsExactlyElementsOf(manualTickets); + + List autoTickets = allTickets.subList(manualCount, totalCount); + assertThat(autoTickets).hasSize(autoCount); + for (LottoTicket ticket : autoTickets) { + assertThat(ticket.getNumbers()).hasSize(6); + } + } } diff --git a/src/test/java/lotto/domain/model/lotto/TicketCountTest.java b/src/test/java/lotto/domain/model/lotto/TicketCountTest.java index 35bbe8bcd1..b4e60d7d11 100644 --- a/src/test/java/lotto/domain/model/lotto/TicketCountTest.java +++ b/src/test/java/lotto/domain/model/lotto/TicketCountTest.java @@ -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)