diff --git a/src/main/kotlin/controller/LottoApp.kt b/src/main/kotlin/controller/LottoApp.kt index 4b2a45d..ca27822 100644 --- a/src/main/kotlin/controller/LottoApp.kt +++ b/src/main/kotlin/controller/LottoApp.kt @@ -2,6 +2,8 @@ package controller import model.lotto.LottoCount import model.lotto.LottoNumbers +import model.lotto.LottoTicket +import model.lotto.LottoTicketGenerator import model.money.Money import view.InputView import view.OutputView @@ -10,8 +12,13 @@ import view.validInputView class LottoApp(private val inputView: InputView, private val outputView: OutputView) { fun run() { val money = validInputView({ inputCapital() }) { outputView.printMessage(it) } - val lottoCount: LottoCount = validInputView({ inputManualCount(money) }) { outputView.printMessage(it) } - validInputView({ inputManualLottoNumber(lottoCount) }) { outputView.printMessage(it) } + val lottoCount: LottoCount = validInputView({ requestManualCount(money) }) { outputView.printMessage(it) } + validInputView( + { + val lottoTickets = generateLottoTickets(lottoCount) + outputView.printLottoTickets(lottoTickets) + }, + ) { outputView.printMessage(it) } } private fun inputCapital(): Money { @@ -19,18 +26,23 @@ class LottoApp(private val inputView: InputView, private val outputView: OutputV return Money(inputView.requestAmount()) } - private fun inputManualCount(money: Money): LottoCount { + private fun requestManualCount(money: Money): LottoCount { outputView.requestManualCount() val manualCount = inputView.requestAmount().toInt() return LottoCount.of(manualCount, money) } - private fun inputManualLottoNumber(lottoCount: LottoCount): List { - return (1..lottoCount.manualCount) - .map { - outputView.requestManualLottoNumber() - inputView.requestLottoNumber() - } - .map { LottoNumbers.from(it) } + private fun generateLottoTickets(lottoCount: LottoCount): List { + val manualTicketNumbers = requestManualLottoNumbers(lottoCount.manualCount) + val manualTickets = LottoTicketGenerator.generate(manualTicketNumbers) + val autoTickets = LottoTicketGenerator.generate(lottoCount.autoCount) + return manualTickets + autoTickets + } + + private fun requestManualLottoNumbers(manualCount: Int): List { + return (1..manualCount).map { + outputView.requestManualLottoNumber() + LottoNumbers.from(inputView.requestLottoNumber()) + } } } diff --git a/src/main/kotlin/model/lotto/LottoNumber.kt b/src/main/kotlin/model/lotto/LottoNumber.kt index 1523cf3..8e9b0eb 100644 --- a/src/main/kotlin/model/lotto/LottoNumber.kt +++ b/src/main/kotlin/model/lotto/LottoNumber.kt @@ -6,4 +6,8 @@ data class LottoNumber(private val value: Int) { init { require(value in 1..45) { INVALID_LOTTO_NUMBER_MESSAGE } } + + override fun toString(): String { + return value.toString() + } } diff --git a/src/main/kotlin/model/lotto/LottoNumbers.kt b/src/main/kotlin/model/lotto/LottoNumbers.kt index 9990678..f2a3661 100644 --- a/src/main/kotlin/model/lotto/LottoNumbers.kt +++ b/src/main/kotlin/model/lotto/LottoNumbers.kt @@ -1,13 +1,19 @@ package model.lotto internal const val INVALID_LOTTO_NUMBER_COUNT_MESSAGE = "로또 번호는 6개여야 합니다." +internal const val INVALID_LOTTO_NUMBER_DUPLICATE_MESSAGE = "로또 번호는 중복될 수 없습니다." class LottoNumbers private constructor(private val numbers: List) { companion object { fun from(numbers: List): LottoNumbers { check(numbers.size == 6) { INVALID_LOTTO_NUMBER_COUNT_MESSAGE } + check(numbers.distinct().size == 6) { INVALID_LOTTO_NUMBER_DUPLICATE_MESSAGE } val lottoNumbers = numbers.map { LottoNumber(it) } return LottoNumbers(lottoNumbers) } } + + override fun toString(): String { + return numbers.joinToString(separator = ", ", prefix = "[", postfix = "]") { it.toString() } + } } diff --git a/src/main/kotlin/model/lotto/LottoTicket.kt b/src/main/kotlin/model/lotto/LottoTicket.kt new file mode 100644 index 0000000..9fbf8d2 --- /dev/null +++ b/src/main/kotlin/model/lotto/LottoTicket.kt @@ -0,0 +1,41 @@ +package model.lotto + +enum class TicketType { + Manual, + Auto, +} + +data class LottoTicket( + val numbers: LottoNumbers, + val type: TicketType, +) { + companion object { + fun of( + numbers: LottoNumbers, + type: TicketType, + ): LottoTicket { + return LottoTicket(numbers, type) + } + } + + override fun toString(): String { + return numbers.toString() + } +} + +object LottoTicketGenerator { + fun generate(count: Int): List { + val allPossibleNumbers = (1..45).toList() + return List(count) { + val selectedNumbers = allPossibleNumbers.shuffled().take(6).sorted() + val lottoNumbers = LottoNumbers.from(selectedNumbers) + LottoTicket.of(lottoNumbers, TicketType.Auto) + } + } + + fun generate(manualNumbers: List): List { + return manualNumbers.map { lottoNumbers -> + LottoTicket.of(lottoNumbers, TicketType.Manual) + } + } +} diff --git a/src/main/kotlin/view/OutputView.kt b/src/main/kotlin/view/OutputView.kt index 8d352a2..fd50815 100644 --- a/src/main/kotlin/view/OutputView.kt +++ b/src/main/kotlin/view/OutputView.kt @@ -1,5 +1,8 @@ package view +import model.lotto.LottoTicket +import model.lotto.TicketType + internal const val INPUT_MONEY_MESSAGE = "구입금액을 입력해 주세요." internal const val INPUT_MANUAL_INPUT_MESSAGE = "수동으로 구매할 로또 수를 입력해 주세요." internal const val INPUT_LOTTO_NUMBER_MESSAGE = "로또 번호를 입력해 주세요. (공백으로 구분)" @@ -20,4 +23,18 @@ class OutputView { fun requestManualLottoNumber() { println(INPUT_LOTTO_NUMBER_MESSAGE) } + + fun printLottoTickets(lottoTickets: List) { + val manualTickets = lottoTickets.filter { it.type == TicketType.Manual } + val autoTickets = lottoTickets.filter { it.type == TicketType.Auto } + println("수동으로 ${manualTickets.size}장, 자동으로 ${autoTickets.size}장을 구매하셨습니다.") + if (manualTickets.isNotEmpty()) { + println("수동으로 구매한 로또 번호") + manualTickets.forEach { println(it.numbers) } + } + if (autoTickets.isNotEmpty()) { + println("자동으로 구매한 로또 번호") + autoTickets.forEach { println(it.numbers) } + } + } } diff --git a/src/test/kotlin/model/lotto/LottoNumbersTest.kt b/src/test/kotlin/model/lotto/LottoNumbersTest.kt index 1c0072e..044e1a5 100644 --- a/src/test/kotlin/model/lotto/LottoNumbersTest.kt +++ b/src/test/kotlin/model/lotto/LottoNumbersTest.kt @@ -20,8 +20,13 @@ class LottoNumbersTest : DescribeSpec( LottoNumbers.from(numbers) } - xit("중복된 숫자가 있으면 예외가 발생한다") { - TODO("Not yet implemented") + it("중복된 숫자가 있으면 예외가 발생한다") { + val numbers = listOf(1, 2, 3, 4, 5, 5) + val exception = + shouldThrow { + LottoNumbers.from(numbers) + } + exception.message shouldBe INVALID_LOTTO_NUMBER_DUPLICATE_MESSAGE } } }, diff --git a/src/test/kotlin/model/lotto/LottoTicketGeneratorTest.kt b/src/test/kotlin/model/lotto/LottoTicketGeneratorTest.kt new file mode 100644 index 0000000..3c2a60d --- /dev/null +++ b/src/test/kotlin/model/lotto/LottoTicketGeneratorTest.kt @@ -0,0 +1,29 @@ +package model.lotto + +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe + +class LottoTicketGeneratorTest : FreeSpec( + { + "LottoTicketGenerator 생성" - { + "일정 수의 티켓 생성" { + val count = 5 + val tickets = LottoTicketGenerator.generate(count) + + tickets.size shouldBe count + } + + "수동 티켓 생성" { + val manualNumbers = + listOf( + LottoNumbers.from(listOf(1, 2, 3, 4, 5, 6)), + LottoNumbers.from(listOf(7, 8, 9, 10, 11, 12)), + ) + val tickets = LottoTicketGenerator.generate(manualNumbers) + + tickets.size shouldBe manualNumbers.size + tickets.forEach { it.type shouldBe TicketType.Manual } + } + } + }, +) diff --git a/src/test/kotlin/model/lotto/LottoTicketTest.kt b/src/test/kotlin/model/lotto/LottoTicketTest.kt new file mode 100644 index 0000000..16dbaf0 --- /dev/null +++ b/src/test/kotlin/model/lotto/LottoTicketTest.kt @@ -0,0 +1,28 @@ +package model.lotto + +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe + +class LottoTicketTest : FreeSpec( + { + "LottoTicket 생성" - { + "주어진 LottoNumbers 와 TicketType 을 가진 LottoTicket 을 반환" { + val numbers = LottoNumbers.from(listOf(1, 2, 3, 4, 5, 6)) + val ticketType = TicketType.Manual + val ticket = LottoTicket.of(numbers, ticketType) + + ticket.numbers shouldBe numbers + ticket.type shouldBe ticketType + } + } + + "LottoTicket 출력" - { + "LottoTicket 의 numbers 필드를 문자열화 하여 반환" { + val numbers = LottoNumbers.from(listOf(1, 2, 3, 4, 5, 6)) + val ticket = LottoTicket.of(numbers, TicketType.Manual) + + ticket.toString() shouldBe numbers.toString() + } + } + }, +)