From d80cae9b7772b68daebb754c1c67bd69095a8ae2 Mon Sep 17 00:00:00 2001 From: MingyumKim Date: Fri, 11 Apr 2025 20:29:27 +0200 Subject: [PATCH 1/2] feat: enter manual tickets and generate tickets with them --- README.md | 9 ++++++- .../lotto/controller/LottoController.kt | 5 ++-- src/main/kotlin/lotto/domain/LottoShop.kt | 6 ++--- src/main/kotlin/lotto/domain/Tickets.kt | 9 ++++++- src/main/kotlin/lotto/view/InputView.kt | 25 ++++++++++++++++--- src/main/kotlin/lotto/view/ResultView.kt | 4 +-- src/test/kotlin/lotto/domain/LottoShopTest.kt | 13 +++++++++- 7 files changed, 58 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d4cb06e07..7b6e2715c 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 +- [ ] 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..be653ba08 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -15,8 +15,9 @@ fun main() { class LottoController(private val inputView: InputView, private val resultView: ResultView) { 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/Tickets.kt b/src/main/kotlin/lotto/domain/Tickets.kt index 846a8441d..36ffb7ee1 100644 --- a/src/main/kotlin/lotto/domain/Tickets.kt +++ b/src/main/kotlin/lotto/domain/Tickets.kt @@ -6,7 +6,8 @@ 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() @@ -30,5 +31,11 @@ class Tickets(val tickets: List) { 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..5365445b3 100644 --- a/src/main/kotlin/lotto/view/InputView.kt +++ b/src/main/kotlin/lotto/view/InputView.kt @@ -1,5 +1,7 @@ package lotto.view +import lotto.domain.Ticket + class InputView { fun enterPurchaseAmount(): Int { println("Please enter the purchase amount.") @@ -8,9 +10,7 @@ class InputView { 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,23 @@ 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..68a026bc3 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) } diff --git a/src/test/kotlin/lotto/domain/LottoShopTest.kt b/src/test/kotlin/lotto/domain/LottoShopTest.kt index 2ff308bac..281483b0a 100644 --- a/src/test/kotlin/lotto/domain/LottoShopTest.kt +++ b/src/test/kotlin/lotto/domain/LottoShopTest.kt @@ -7,7 +7,18 @@ 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) } } From a87315bcdf77659e9e3b1cb7999fe527cedaffdb Mon Sep 17 00:00:00 2001 From: MingyumKim Date: Fri, 11 Apr 2025 20:45:33 +0200 Subject: [PATCH 2/2] refactor: reformat and refactor code --- README.md | 2 +- .../kotlin/lotto/controller/LottoController.kt | 2 +- src/main/kotlin/lotto/domain/MatchingPrize.kt | 2 +- src/main/kotlin/lotto/domain/Ticket.kt | 16 ++++++++++++++-- src/main/kotlin/lotto/domain/Tickets.kt | 12 ++---------- src/main/kotlin/lotto/view/InputView.kt | 8 +++++--- src/main/kotlin/lotto/view/ResultView.kt | 11 +++++++---- src/test/kotlin/lotto/domain/LottoShopTest.kt | 12 +++++++----- src/test/kotlin/lotto/domain/TicketTest.kt | 13 +++++++++++++ 9 files changed, 51 insertions(+), 27 deletions(-) create mode 100644 src/test/kotlin/lotto/domain/TicketTest.kt diff --git a/README.md b/README.md index 7b6e2715c..020eb77b1 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,4 @@ - [x] Enter number of manual tickets to purchase - [x] Enter numbers of each manual ticket - [x] Generate automatic tickets except manual tickets -- [ ] Check edge case and fix errors +- [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 be653ba08..beee4ead7 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -13,7 +13,7 @@ fun main() { } class LottoController(private val inputView: InputView, private val resultView: ResultView) { - fun purchase() : Tickets { + fun purchase(): Tickets { val purchaseAmount = inputView.enterPurchaseAmount() val manualTickets = inputView.enterManualTickets() val tickets = LottoShop().purchase(purchaseAmount, 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 36ffb7ee1..b3b79f6fe 100644 --- a/src/main/kotlin/lotto/domain/Tickets.kt +++ b/src/main/kotlin/lotto/domain/Tickets.kt @@ -12,21 +12,13 @@ class Tickets(val tickets: List) { 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() } diff --git a/src/main/kotlin/lotto/view/InputView.kt b/src/main/kotlin/lotto/view/InputView.kt index 5365445b3..e2e9f6593 100644 --- a/src/main/kotlin/lotto/view/InputView.kt +++ b/src/main/kotlin/lotto/view/InputView.kt @@ -8,7 +8,7 @@ class InputView { return readln().toIntOrNull() ?: throw IllegalArgumentException("Please enter a valid purchase.") } - fun enterWinningNumbers() : List { + fun enterWinningNumbers(): List { println("\nPlease enter last week’s winning numbers.") return enterLottoNumbers() } @@ -34,7 +34,9 @@ class InputView { 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.") } + 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 68a026bc3..827dde13b 100644 --- a/src/main/kotlin/lotto/view/ResultView.kt +++ b/src/main/kotlin/lotto/view/ResultView.kt @@ -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 281483b0a..18000d0d5 100644 --- a/src/test/kotlin/lotto/domain/LottoShopTest.kt +++ b/src/test/kotlin/lotto/domain/LottoShopTest.kt @@ -14,11 +14,13 @@ class LottoShopTest { @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)) - )) + 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)) + } + } +}