Skip to content

Commit

Permalink
Lotto Ticket 구현 (#20)
Browse files Browse the repository at this point in the history
* feat: LottoTicket model and enhance Print function

* feat: auto ticket generation functionality to LottoApp

* style: Adjust formatting in LottoTicket for better readability and ktlint compliance

* style: Adjust formatting in LottoTicket for better readability and ktlint compliance

* feat: Add toString method in LottoTicket

* test: Add LottoTicket unit tests

* feat: Added checking logic for duplicate numbers in a lotto ticket.

* style: ktlint

* style: ktlint

* feat: Improve readability by sorting auto-generated Lotto numbers

* refactor: Decouple LottoTicket generation logic to LottoTicketGenerator object

* refactor: Removed count methods from LottoNumbers for separation of concerns

* refactor: Decouple manual ticket generation for better separation of concerns

* test: LottoTicketGenerator's generate method

* style: Removed unnecessary line in LottoTicketGeneratorTest

* style: lint codes
  • Loading branch information
doxxx93 authored Oct 25, 2023
1 parent 431c915 commit d61f769
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 12 deletions.
32 changes: 22 additions & 10 deletions src/main/kotlin/controller/LottoApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -10,27 +12,37 @@ 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 {
outputView.requestCapital()
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<LottoNumbers> {
return (1..lottoCount.manualCount)
.map {
outputView.requestManualLottoNumber()
inputView.requestLottoNumber()
}
.map { LottoNumbers.from(it) }
private fun generateLottoTickets(lottoCount: LottoCount): List<LottoTicket> {
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<LottoNumbers> {
return (1..manualCount).map {
outputView.requestManualLottoNumber()
LottoNumbers.from(inputView.requestLottoNumber())
}
}
}
4 changes: 4 additions & 0 deletions src/main/kotlin/model/lotto/LottoNumber.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
6 changes: 6 additions & 0 deletions src/main/kotlin/model/lotto/LottoNumbers.kt
Original file line number Diff line number Diff line change
@@ -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<LottoNumber>) {
companion object {
fun from(numbers: List<Int>): 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() }
}
}
41 changes: 41 additions & 0 deletions src/main/kotlin/model/lotto/LottoTicket.kt
Original file line number Diff line number Diff line change
@@ -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<LottoTicket> {
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<LottoNumbers>): List<LottoTicket> {
return manualNumbers.map { lottoNumbers ->
LottoTicket.of(lottoNumbers, TicketType.Manual)
}
}
}
17 changes: 17 additions & 0 deletions src/main/kotlin/view/OutputView.kt
Original file line number Diff line number Diff line change
@@ -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 = "로또 번호를 입력해 주세요. (공백으로 구분)"
Expand All @@ -20,4 +23,18 @@ class OutputView {
fun requestManualLottoNumber() {
println(INPUT_LOTTO_NUMBER_MESSAGE)
}

fun printLottoTickets(lottoTickets: List<LottoTicket>) {
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) }
}
}
}
9 changes: 7 additions & 2 deletions src/test/kotlin/model/lotto/LottoNumbersTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<IllegalStateException> {
LottoNumbers.from(numbers)
}
exception.message shouldBe INVALID_LOTTO_NUMBER_DUPLICATE_MESSAGE
}
}
},
Expand Down
29 changes: 29 additions & 0 deletions src/test/kotlin/model/lotto/LottoTicketGeneratorTest.kt
Original file line number Diff line number Diff line change
@@ -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 }
}
}
},
)
28 changes: 28 additions & 0 deletions src/test/kotlin/model/lotto/LottoTicketTest.kt
Original file line number Diff line number Diff line change
@@ -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()
}
}
},
)

0 comments on commit d61f769

Please sign in to comment.