diff --git a/README.md b/README.md index d4cb06e07..020eb77b1 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,11 @@ - [x] Enter bonus number for second prize - [x] Calculate winning statistics considering bonus number - [x] Calculate rate considering bonus number -- [x] Check edge case and fix errors \ No newline at end of file +- [x] Check edge case and fix errors + +## Step4 - Lotto (Manual) + +- [x] Enter number of manual tickets to purchase +- [x] Enter numbers of each manual ticket +- [x] Generate automatic tickets except manual tickets +- [x] Check edge case and fix errors diff --git a/src/main/kotlin/lotto/controller/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt index 36a457143..beee4ead7 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -13,10 +13,11 @@ fun main() { } class LottoController(private val inputView: InputView, private val resultView: ResultView) { - fun purchase() : Tickets { + fun purchase(): Tickets { val purchaseAmount = inputView.enterPurchaseAmount() - val tickets = LottoShop().purchase(purchaseAmount) - resultView.printTickets(tickets) + val manualTickets = inputView.enterManualTickets() + val tickets = LottoShop().purchase(purchaseAmount, manualTickets) + resultView.printTickets(tickets, manualTickets.size, tickets.size - manualTickets.size) return tickets } diff --git a/src/main/kotlin/lotto/domain/LottoShop.kt b/src/main/kotlin/lotto/domain/LottoShop.kt index 5ff866808..63db3389e 100644 --- a/src/main/kotlin/lotto/domain/LottoShop.kt +++ b/src/main/kotlin/lotto/domain/LottoShop.kt @@ -6,8 +6,8 @@ class LottoShop { const val PRICE_FOR_ONT_TICKET = 1000 } - fun purchase(purchaseAmount: Int): Tickets { - val amountOfTicket = purchaseAmount / PRICE_FOR_ONT_TICKET - return Tickets(amountOfTicket) + fun purchase(purchaseAmount: Int, manualTickets: List): Tickets { + val numberOfRandomTickets = (purchaseAmount / PRICE_FOR_ONT_TICKET) - manualTickets.size + return Tickets(numberOfRandomTickets, manualTickets) } } diff --git a/src/main/kotlin/lotto/domain/MatchingPrize.kt b/src/main/kotlin/lotto/domain/MatchingPrize.kt index 411197930..0dde28d72 100644 --- a/src/main/kotlin/lotto/domain/MatchingPrize.kt +++ b/src/main/kotlin/lotto/domain/MatchingPrize.kt @@ -2,7 +2,7 @@ package lotto.domain enum class MatchPrize(val matchCount: Int, val usingBonus: Boolean, val price: Long) { FIRST(6, false, 20_000_000_000), - SECOND(5, true,30_000_000), + SECOND(5, true, 30_000_000), THIRD(5, false, 1_500_000), FOURTH(4, false, 50_000), FIFTH(3, false, 5_000); diff --git a/src/main/kotlin/lotto/domain/Ticket.kt b/src/main/kotlin/lotto/domain/Ticket.kt index c63151298..28e0c9f57 100644 --- a/src/main/kotlin/lotto/domain/Ticket.kt +++ b/src/main/kotlin/lotto/domain/Ticket.kt @@ -1,12 +1,24 @@ package lotto.domain +import lotto.controller.WinningNumbers + class Ticket(val lottoNumber: Set) { constructor() : this(generateLottoNumber()) + init { + require(lottoNumber.size == 6) { + throw IllegalArgumentException("Please enter $AMOUNT_OF_NUMBER_FOR_TICKET numbers") + } + } + constructor(input: List) : this(input.map { LottoNumber(it) }.toSet()) - fun contains(bonusNumber: LottoNumber): Boolean { - return lottoNumber.contains(bonusNumber) + fun checkMatches(winningNumbers: WinningNumbers): Int { + return winningNumbers.numbers.intersect(lottoNumber).size + } + + fun checkBonusMatches(winningNumbers: WinningNumbers): Boolean { + return lottoNumber.contains(winningNumbers.bonusNumber) } companion object { diff --git a/src/main/kotlin/lotto/domain/Tickets.kt b/src/main/kotlin/lotto/domain/Tickets.kt index 846a8441d..b3b79f6fe 100644 --- a/src/main/kotlin/lotto/domain/Tickets.kt +++ b/src/main/kotlin/lotto/domain/Tickets.kt @@ -6,29 +6,28 @@ class Tickets(val tickets: List) { val size: Int get() = tickets.size - constructor(amountOfTicket: Int) : this(generateTickets(amountOfTicket)) + constructor(numberOfRandomTickets: Int, manualTickets: List) + : this(generateTicketsWithManualTickets(numberOfRandomTickets, manualTickets)) fun checkMatches(winningNumbers: WinningNumbers): WinningStatistics { val statistics = WinningStatistics() for (ticket in tickets) { - val matches = checkMatches(winningNumbers, ticket) - val bonusMatches = checkBonusMatches(winningNumbers, ticket) + val matches = ticket.checkMatches(winningNumbers) + val bonusMatches = ticket.checkBonusMatches(winningNumbers) statistics.add(matches, bonusMatches) } return statistics } - private fun checkMatches(winningNumbers: WinningNumbers, ticket: Ticket): Int{ - return winningNumbers.numbers.intersect(ticket.lottoNumber).size - } - - private fun checkBonusMatches(winningNumbers: WinningNumbers, ticket: Ticket): Boolean { - return ticket.contains(winningNumbers.bonusNumber) - } - companion object { private fun generateTickets(amountOfTicket: Int): List { return List(amountOfTicket) { Ticket() } } + + private fun generateTicketsWithManualTickets(numberOfTickets: Int, manualTickets: List): List { + val generatedTickets = manualTickets.toMutableList() + generatedTickets.addAll(generateTickets(numberOfTickets)) + return generatedTickets + } } } diff --git a/src/main/kotlin/lotto/view/InputView.kt b/src/main/kotlin/lotto/view/InputView.kt index f54fd18b5..e2e9f6593 100644 --- a/src/main/kotlin/lotto/view/InputView.kt +++ b/src/main/kotlin/lotto/view/InputView.kt @@ -1,16 +1,16 @@ package lotto.view +import lotto.domain.Ticket + class InputView { fun enterPurchaseAmount(): Int { println("Please enter the purchase amount.") return readln().toIntOrNull() ?: throw IllegalArgumentException("Please enter a valid purchase.") } - fun enterWinningNumbers() : List { + fun enterWinningNumbers(): List { println("\nPlease enter last week’s winning numbers.") - val input = readlnOrNull() ?: throw IllegalArgumentException("Please enter a valid numbers.") - return input.split(",").map { it.trim().toIntOrNull() - ?: throw IllegalArgumentException("Please enter a valid numbers.") } + return enterLottoNumbers() } fun enterBonusNumber(): Int { @@ -18,4 +18,25 @@ class InputView { val input = readlnOrNull() ?: throw IllegalArgumentException("Please enter a valid number.") return input.toIntOrNull() ?: throw java.lang.IllegalArgumentException("Please enter a valid number.") } + + fun enterManualTickets(): List { + println("\nEnter the number of manual tickets to purchase:") + val numberOfManualTickets = readlnOrNull()?.toIntOrNull() + ?: throw IllegalArgumentException("Please enter a valid number of manual tickets.") + + println("\nEnter the numbers for manual tickets.") + val tickets = mutableListOf() + repeat(numberOfManualTickets) { + tickets.add(Ticket(enterLottoNumbers())) + } + return tickets + } + + private fun enterLottoNumbers(): List { + val input = readlnOrNull() ?: throw IllegalArgumentException("Please enter a valid numbers.") + return input.split(",").map { + it.trim().toIntOrNull() + ?: throw IllegalArgumentException("Please enter a valid numbers.") + } + } } diff --git a/src/main/kotlin/lotto/view/ResultView.kt b/src/main/kotlin/lotto/view/ResultView.kt index 47989a455..827dde13b 100644 --- a/src/main/kotlin/lotto/view/ResultView.kt +++ b/src/main/kotlin/lotto/view/ResultView.kt @@ -6,8 +6,8 @@ import lotto.domain.Tickets import lotto.domain.WinningStatistics class ResultView { - fun printTickets(tickets: Tickets) { - println("You have purchased ${tickets.size}") + fun printTickets(tickets: Tickets, numberOfManualTickets: Int, numberOfRandomTickets: Int) { + println("\nPurchased $numberOfManualTickets and $numberOfRandomTickets automatic tickets.") for (ticket in tickets.tickets) { printTicket(ticket) } @@ -17,12 +17,15 @@ class ResultView { println(ticket.lottoNumber.map { it.number } .joinToString(", ", "[", "]")) } + fun printWinningStatistics(winningStatistics: WinningStatistics, rate: Double) { println("\nWinning Statistics\n------------------") - for(prize in MatchPrize.entries) { - println("${prize.matchCount} Matches " + - (if (prize.usingBonus) "+ Bonus Ball " else "") + - "(${prize.price} KRW) - ${winningStatistics.get(prize.matchCount, prize.usingBonus)} tickets") + for (prize in MatchPrize.entries) { + println( + "${prize.matchCount} Matches " + + (if (prize.usingBonus) "+ Bonus Ball " else "") + + "(${prize.price} KRW) - ${winningStatistics.get(prize.matchCount, prize.usingBonus)} tickets" + ) } println("Total return rate is $rate (A rate below 1 means a loss)") } diff --git a/src/test/kotlin/lotto/domain/LottoShopTest.kt b/src/test/kotlin/lotto/domain/LottoShopTest.kt index 2ff308bac..18000d0d5 100644 --- a/src/test/kotlin/lotto/domain/LottoShopTest.kt +++ b/src/test/kotlin/lotto/domain/LottoShopTest.kt @@ -7,7 +7,20 @@ class LottoShopTest { @Test fun `purchase success`() { val purchaseAmount = 15000 - val tickets = LottoShop().purchase(purchaseAmount) + val tickets = LottoShop().purchase(purchaseAmount, listOf()) + assertThat(tickets.size).isEqualTo(15) + } + + @Test + fun `purchase with mutable tickets`() { + val purchaseAmount = 15000 + val tickets = LottoShop().purchase( + purchaseAmount, listOf( + Ticket(listOf(1, 2, 3, 4, 5, 6)), + Ticket(listOf(1, 2, 3, 4, 5, 6)), + Ticket(listOf(1, 2, 3, 4, 5, 6)) + ) + ) assertThat(tickets.size).isEqualTo(15) } } diff --git a/src/test/kotlin/lotto/domain/TicketTest.kt b/src/test/kotlin/lotto/domain/TicketTest.kt new file mode 100644 index 000000000..4db41718f --- /dev/null +++ b/src/test/kotlin/lotto/domain/TicketTest.kt @@ -0,0 +1,13 @@ +package lotto.domain + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + +class TicketTest { + @Test + fun `fail when under 6 numbers is entered`() { + assertThrows { + Ticket(listOf(1, 2, 3, 4, 5)) + } + } +}