From 3069eaabfdcf468064730a4bdc6a3fed6177c6ee Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 23 Nov 2024 03:49:39 +0900 Subject: [PATCH 01/18] =?UTF-8?q?=EB=AF=B8=EC=85=981=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=20=EC=84=B8=ED=8C=85=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=8B=A4=ED=8C=A8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/.gitkeep | 0 src/main/kotlin/additioncalculator/README.md | 14 +++++ .../additioncalculator/StringAddCalculator.kt | 8 +++ src/test/kotlin/.gitkeep | 0 .../StringAddCalculatorTest.kt | 61 +++++++++++++++++++ 5 files changed, 83 insertions(+) delete mode 100644 src/main/kotlin/.gitkeep create mode 100644 src/main/kotlin/additioncalculator/README.md create mode 100644 src/main/kotlin/additioncalculator/StringAddCalculator.kt delete mode 100644 src/test/kotlin/.gitkeep create mode 100644 src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt diff --git a/src/main/kotlin/.gitkeep b/src/main/kotlin/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/main/kotlin/additioncalculator/README.md b/src/main/kotlin/additioncalculator/README.md new file mode 100644 index 0000000000..8178bb7dbf --- /dev/null +++ b/src/main/kotlin/additioncalculator/README.md @@ -0,0 +1,14 @@ +## 기능 요구 사항 +- 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환 + (예: “” => 0, "1,2" => 3, "1,2,3" => 6, “1,2:3” => 6) +- 앞의 기본 구분자(쉼표, 콜론) 외에 커스텀 구분자를 지정할 수 있다. +- 커스텀 구분자는 문자열 앞부분의 “//”와 “\n” 사이에 위치하는 문자를 커스텀 구분자로 사용한다. + 예를 들어 “//;\n1;2;3”과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다. +- 문자열 계산기에 숫자 이외의 값 또는 음수를 전달하는 경우 RuntimeException 예외를 throw 한다. + +## 프로그래밍 요구 사항 +- indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다. + 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. +- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. +- 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다. +- 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다. diff --git a/src/main/kotlin/additioncalculator/StringAddCalculator.kt b/src/main/kotlin/additioncalculator/StringAddCalculator.kt new file mode 100644 index 0000000000..8bb0b2a046 --- /dev/null +++ b/src/main/kotlin/additioncalculator/StringAddCalculator.kt @@ -0,0 +1,8 @@ +package additioncalculator + +class StringAddCalculator { + + fun add(text: String): Int { + return 0 + } +} \ No newline at end of file diff --git a/src/test/kotlin/.gitkeep b/src/test/kotlin/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt b/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt new file mode 100644 index 0000000000..4cebf0e06f --- /dev/null +++ b/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt @@ -0,0 +1,61 @@ +package additioncalculator + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.NullAndEmptySource +import org.junit.jupiter.params.provider.ValueSource + +class StringAddCalculatorTest { + private lateinit var calculator: StringAddCalculator + + @BeforeEach + fun setUp() { + calculator = StringAddCalculator(); + } + + @DisplayName(value = "빈 문자열 또는 null 값을 입력할 경우 0을 반환해야 한다.") + @ParameterizedTest + @NullAndEmptySource + fun emptyOrNull(text: String) { + assertThat(calculator.add(text)).isZero(); + } + + @DisplayName(value = "숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다.") + @ParameterizedTest + @ValueSource(strings = ["1"]) + fun oneNumber(text: String) { + assertThat(calculator.add(text)).isSameAs(Integer.parseInt(text)); + } + + @DisplayName(value = "숫자 두개를 쉼표(,) 구분자로 입력할 경우 두 숫자의 합을 반환한다.") + @ParameterizedTest + @ValueSource(strings = ["1,2"]) + fun twoNumbers(text: String) { + assertThat(calculator.add(text)).isSameAs(3); + } + + @DisplayName(value = "구분자를 쉼표(,) 이외에 콜론(:)을 사용할 수 있다.") + @ParameterizedTest + @ValueSource(strings = ["1,2:3"]) + fun colons(text: String) { + assertThat(calculator.add(text)).isSameAs(6); + } + + @DisplayName(value = "//와 \\n 문자 사이에 커스텀 구분자를 지정할 수 있다.") + @ParameterizedTest + @ValueSource(strings = ["//;\n1;2;3"]) + fun customDelimiter(text: String) { + assertThat(calculator.add(text)).isSameAs(6); + } + + @DisplayName(value = "문자열 계산기에 음수를 전달하는 경우 RuntimeException 예외 처리를 한다.") + @Test + fun negative() { + assertThatExceptionOfType(RuntimeException::class.java) + .isThrownBy { calculator.add("-1") }; + } +} From 24366d5098f25336a9985c14b66aea547b5dd9ea Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Mon, 2 Dec 2024 02:45:38 +0900 Subject: [PATCH 02/18] =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= =?UTF-8?q?=20-=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0,=20enum=20=ED=99=9C=EC=9A=A9,=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=9C=84=EC=B9=98=20=EC=88=98=EC=A0=95,=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20=EB=93=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + .../additioncalculator/StringAddCalculator.kt | 3 +- .../lotto/application/LottoApplication.kt | 4 +- .../kotlin/lotto/domain/LottoNumberChecker.kt | 61 ------------------- .../{view => domain}/LottoNumberGenerator.kt | 4 +- .../lotto/domain/LottoNumberMatchPayout.kt | 35 ++++++----- src/main/kotlin/lotto/domain/LottoTicket.kt | 13 +++- .../kotlin/lotto/domain/LottoTicketIssuer.kt | 4 +- .../kotlin/lotto/domain/LottoWinnerNumbers.kt | 39 ++---------- .../lotto/domain/PurchasedLottoResults.kt | 12 ++-- .../lotto/domain/PurchasedLottoTickets.kt | 53 ++++++++++++++-- src/main/kotlin/lotto/view/LottoController.kt | 28 ++++----- src/main/kotlin/lotto/view/LottoPayoutView.kt | 2 +- .../lotto/view/PurchaseLottoResultView.kt | 2 +- .../kotlin/lotto/view/PurchaseLottoView.kt | 2 +- .../lotto/view/WinnerLottoNumberView.kt | 41 ++++++++++++- .../StringAddCalculatorTest.kt | 14 ++--- .../lotto/domain/LottoNumberCheckerTest.kt | 51 ---------------- .../lotto/domain/LottoNumberGeneratorTest.kt | 11 ++++ .../domain/LottoNumberMatchPayoutTest.kt | 5 +- .../lotto/domain/LottoTicketIssuerTest.kt | 21 ++++--- .../kotlin/lotto/domain/LottoTicketTest.kt | 47 +++++++++++--- .../lotto/domain/LottoWinnerNumbersTest.kt | 53 +--------------- .../lotto/domain/PurchasedLottoResultsTest.kt | 42 +++++++++++++ .../lotto/domain/PurchasedLottoTicketsTest.kt | 3 +- 25 files changed, 265 insertions(+), 287 deletions(-) delete mode 100644 src/main/kotlin/lotto/domain/LottoNumberChecker.kt rename src/main/kotlin/lotto/{view => domain}/LottoNumberGenerator.kt (84%) delete mode 100644 src/test/kotlin/lotto/domain/LottoNumberCheckerTest.kt create mode 100644 src/test/kotlin/lotto/domain/LottoNumberGeneratorTest.kt diff --git a/README.md b/README.md index a3a5bcf8ea..50232cbf32 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ - [x] 로또 구입 비용이 1,000원 미만일 경우 에러가 발생한다 - [x] 로또 구입 비용이 1,000원 단위가 아닐 경우 에러가 발생한다 - [x] 로또 구입 비용에 대해 몇 장의 로또가 구입 됐는지 확인활 수 있다 +- [x] 로또 번호가 1부터 45사이의 숫자가 아니면 에러가 발생한다 +- [x] 로또 번호를 6개로 지정할 경우가 아니면 에러가 발생한다 (예를 들어 5개 또는 7개) - [x] 로또 번호를 자동으로 부여한다 - [x] 로또 번호는 1부터 45사이의 중복되지 않는 숫자 6개로 이루어져야한다 - [x] 로또 당첨 번호를 입력할 수 있다 diff --git a/src/main/kotlin/additioncalculator/StringAddCalculator.kt b/src/main/kotlin/additioncalculator/StringAddCalculator.kt index 8bb0b2a046..b2a868d34a 100644 --- a/src/main/kotlin/additioncalculator/StringAddCalculator.kt +++ b/src/main/kotlin/additioncalculator/StringAddCalculator.kt @@ -1,8 +1,7 @@ package additioncalculator class StringAddCalculator { - fun add(text: String): Int { return 0 } -} \ No newline at end of file +} diff --git a/src/main/kotlin/lotto/application/LottoApplication.kt b/src/main/kotlin/lotto/application/LottoApplication.kt index 7b330c6207..61f70e4fbc 100644 --- a/src/main/kotlin/lotto/application/LottoApplication.kt +++ b/src/main/kotlin/lotto/application/LottoApplication.kt @@ -3,5 +3,7 @@ package lotto.application import lotto.view.LottoController fun main() { - LottoController.payoutResult(LottoController.lottoPurchased(), LottoController.lottoWinnerNumber()) + val purchasedLottoTickets = LottoController.purchaseLotto() + val lottoWinnerNumbers = LottoController.createWinningLottoNumbers() + LottoController.resultPayout(purchasedLottoTickets = purchasedLottoTickets, lottoWinnerNumbers = lottoWinnerNumbers) } diff --git a/src/main/kotlin/lotto/domain/LottoNumberChecker.kt b/src/main/kotlin/lotto/domain/LottoNumberChecker.kt deleted file mode 100644 index 9d8be13aaa..0000000000 --- a/src/main/kotlin/lotto/domain/LottoNumberChecker.kt +++ /dev/null @@ -1,61 +0,0 @@ -package lotto.domain - -import lotto.domain.LottoNumberMatchPayout.FIVE_NUMBER_MATCH -import lotto.domain.LottoNumberMatchPayout.FOUR_NUMBER_MATCH -import lotto.domain.LottoNumberMatchPayout.SIX_NUMBER_MATCH -import lotto.domain.LottoNumberMatchPayout.THREE_NUMBER_MATCH - -object LottoNumberChecker { - fun purchasedLottoTicketsNumberCheck( - purchasedLottoTickets: PurchasedLottoTickets, - winnerNumbers: LottoWinnerNumbers, - ): PurchasedLottoResults { - val threeNumberMatchs = mutableListOf() - val fourNumberMatchs = mutableListOf() - val fiveNumberMatchs = mutableListOf() - val sixNumberMatchs = mutableListOf() - - purchasedLottoTickets.purchasedLottoTickets.forEach { - LottoTicket -> - numberMatchApply( - lottoTicket = LottoTicket, - winnerNumbers = winnerNumbers, - threeNumberMatchs = threeNumberMatchs, - fourNumberMatchs = fourNumberMatchs, - fiveNumberMatchs = fiveNumberMatchs, - sixNumberMatchs = sixNumberMatchs, - ) - } - - return PurchasedLottoResults( - purchasedCount = purchasedLottoTickets.purchasedCount, - threeNumberMatchCount = threeNumberMatchs.size, - fourNumberMatchCount = fourNumberMatchs.size, - fiveNumberMatchCount = fiveNumberMatchs.size, - sixNumberMatchCount = sixNumberMatchs.size, - ) - } - - private fun numberMatchApply( - lottoTicket: LottoTicket, - winnerNumbers: LottoWinnerNumbers, - threeNumberMatchs: MutableList, - fourNumberMatchs: MutableList, - fiveNumberMatchs: MutableList, - sixNumberMatchs: MutableList, - ) { - when (matchCountCalculator(lottoTicket = lottoTicket, winnerNumbers = winnerNumbers)) { - THREE_NUMBER_MATCH -> threeNumberMatchs.add(lottoTicket) - FOUR_NUMBER_MATCH -> fourNumberMatchs.add(lottoTicket) - FIVE_NUMBER_MATCH -> fiveNumberMatchs.add(lottoTicket) - SIX_NUMBER_MATCH -> sixNumberMatchs.add(lottoTicket) - } - } - - private fun matchCountCalculator( - lottoTicket: LottoTicket, - winnerNumbers: LottoWinnerNumbers, - ): Int { - return lottoTicket.lottoNumbers.intersect(winnerNumbers.winnerNumbers).size - } -} diff --git a/src/main/kotlin/lotto/view/LottoNumberGenerator.kt b/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt similarity index 84% rename from src/main/kotlin/lotto/view/LottoNumberGenerator.kt rename to src/main/kotlin/lotto/domain/LottoNumberGenerator.kt index f67a9d3e6d..e3861ee572 100644 --- a/src/main/kotlin/lotto/view/LottoNumberGenerator.kt +++ b/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt @@ -1,10 +1,10 @@ -package lotto.view +package lotto.domain import lotto.domain.LottoTicket.Companion.LOTTO_NUMBER_COUNT import lotto.domain.LottoTicket.Companion.LOTTO_NUMBER_MAX_VALUE import lotto.domain.LottoTicket.Companion.LOTTO_NUMBER_MIN_VALUE -fun lottoNumberGenerator(): Set { +fun generateLottoNumbers(): Set { return (LOTTO_NUMBER_MIN_VALUE..LOTTO_NUMBER_MAX_VALUE) .toSet().shuffled().take(LOTTO_NUMBER_COUNT).sorted().toSet() } diff --git a/src/main/kotlin/lotto/domain/LottoNumberMatchPayout.kt b/src/main/kotlin/lotto/domain/LottoNumberMatchPayout.kt index 43fe483429..6f48c65ea0 100644 --- a/src/main/kotlin/lotto/domain/LottoNumberMatchPayout.kt +++ b/src/main/kotlin/lotto/domain/LottoNumberMatchPayout.kt @@ -1,23 +1,22 @@ package lotto.domain -object LottoNumberMatchPayout { - fun matchCountToPayout(matchCount: Int): Int { - return when (matchCount) { - THREE_NUMBER_MATCH -> THREE_NUMBER_MATCH_LOTTO_PAYOUT - FOUR_NUMBER_MATCH -> FOUR_NUMBER_MATCH_LOTTO_PAYOUT - FIVE_NUMBER_MATCH -> FIVE_NUMBER_MATCH_LOTTO_PAYOUT - SIX_NUMBER_MATCH -> SIX_NUMBER_MATCH_LOTTO_PAYOUT - else -> NO_MATCH_PAYOUT +enum class LottoNumberMatchPayout(val matchCount: Int, val matchCountPayout: Int) { + NO_NUMBER_MATCH(matchCount = 0, matchCountPayout = 0), + ONE_NUMBER_MATCH(matchCount = 1, matchCountPayout = 0), + TWO_NUMBER_MATCH(matchCount = 2, matchCountPayout = 0), + THREE_NUMBER_MATCH(matchCount = 3, matchCountPayout = 5000), + FOUR_NUMBER_MATCH(matchCount = 4, matchCountPayout = 50000), + FIVE_NUMBER_MATCH(matchCount = 5, matchCountPayout = 1500000), + SIX_NUMBER_MATCH(matchCount = 6, matchCountPayout = 2000000000), + ; + + companion object { + fun byMatchCount(matchCount: Int): LottoNumberMatchPayout { + val findLottoMatchCountPayout = entries.find { it.matchCount == matchCount } + requireNotNull(findLottoMatchCountPayout) { INVALID_MATCH_COUNT_MESSAGE } + return findLottoMatchCountPayout } - } - const val THREE_NUMBER_MATCH: Int = 3 - private const val THREE_NUMBER_MATCH_LOTTO_PAYOUT: Int = 5000 - const val FOUR_NUMBER_MATCH: Int = 4 - private const val FOUR_NUMBER_MATCH_LOTTO_PAYOUT: Int = 50000 - const val FIVE_NUMBER_MATCH: Int = 5 - private const val FIVE_NUMBER_MATCH_LOTTO_PAYOUT: Int = 1500000 - const val SIX_NUMBER_MATCH: Int = 6 - private const val SIX_NUMBER_MATCH_LOTTO_PAYOUT: Int = 2000000000 - private const val NO_MATCH_PAYOUT: Int = 0 + const val INVALID_MATCH_COUNT_MESSAGE: String = "로또 번호 매칭 카운트는 0부터 6까지만 존재할 수 있습니다" + } } diff --git a/src/main/kotlin/lotto/domain/LottoTicket.kt b/src/main/kotlin/lotto/domain/LottoTicket.kt index 2b1397f0f0..a622455370 100644 --- a/src/main/kotlin/lotto/domain/LottoTicket.kt +++ b/src/main/kotlin/lotto/domain/LottoTicket.kt @@ -1,10 +1,18 @@ package lotto.domain -class LottoTicket(lottoNumberGenerator: () -> Set) { - val lottoNumbers = lottoNumberGenerator() +data class LottoTicket(private val generateLottoNumbers: () -> Set) { + val lottoNumbers = generateLottoNumbers() init { require(lottoNumbers.size == LOTTO_NUMBER_COUNT) { INVALID_LOTTO_NUMBER_COUNT_MESSAGE } + require((LOTTO_NUMBER_MIN_VALUE..LOTTO_NUMBER_MAX_VALUE).toSet().containsAll(lottoNumbers)) { + INVALID_WINNER_NUMBERS_RANGE_MESSAGE + } + } + + fun checkLottoWinnerNumbersMatchPayout(winnerNumbers: LottoWinnerNumbers): LottoNumberMatchPayout { + val matchCount = lottoNumbers.intersect(winnerNumbers.winnerNumbers).size + return LottoNumberMatchPayout.byMatchCount(matchCount) } companion object { @@ -12,5 +20,6 @@ class LottoTicket(lottoNumberGenerator: () -> Set) { const val LOTTO_NUMBER_MAX_VALUE: Int = 45 const val LOTTO_NUMBER_COUNT: Int = 6 const val INVALID_LOTTO_NUMBER_COUNT_MESSAGE: String = "자동 생성된 로또 번호가 6개가 아닙니다" + const val INVALID_WINNER_NUMBERS_RANGE_MESSAGE: String = "로또 당첨 번호는 1부터 45 사이 여야 합니다" } } diff --git a/src/main/kotlin/lotto/domain/LottoTicketIssuer.kt b/src/main/kotlin/lotto/domain/LottoTicketIssuer.kt index 63c427e342..9613880c74 100644 --- a/src/main/kotlin/lotto/domain/LottoTicketIssuer.kt +++ b/src/main/kotlin/lotto/domain/LottoTicketIssuer.kt @@ -3,12 +3,12 @@ package lotto.domain object LottoTicketIssuer { fun issueTickets( amountPaid: Int, - lottoNumberGenerator: () -> Set, + generateLottoNumbers: () -> Set, ): PurchasedLottoTickets { checkAmountPaid(amountPaid) return PurchasedLottoTickets( purchasedCount = (amountPaid / DEFAULT_LOTTO_PRICE), - lottoNumberGenerator = lottoNumberGenerator, + generateLottoNumbers = generateLottoNumbers, ) } diff --git a/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt b/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt index 58621fc1b0..938751073e 100644 --- a/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt +++ b/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt @@ -1,48 +1,19 @@ package lotto.domain +import lotto.domain.LottoTicket.Companion.INVALID_WINNER_NUMBERS_RANGE_MESSAGE import lotto.domain.LottoTicket.Companion.LOTTO_NUMBER_COUNT import lotto.domain.LottoTicket.Companion.LOTTO_NUMBER_MAX_VALUE import lotto.domain.LottoTicket.Companion.LOTTO_NUMBER_MIN_VALUE -class LottoWinnerNumbers(private val inputWinnerNumbersCommand: String?) { - val winnerNumbers: Set - +data class LottoWinnerNumbers(val winnerNumbers: Set) { init { - val splitWinnerNumbers = splitInputWinnerNumbersCommand() - require(splitWinnerNumbers.size == LOTTO_NUMBER_COUNT) { INVALID_WINNER_NUMBERS_COUNT_MESSAGE } - winnerNumbers = splitWinnerNumbers.toSet() require(winnerNumbers.size == LOTTO_NUMBER_COUNT) { INVALID_WINNER_NUMBERS_COUNT_MESSAGE } - } - - private fun splitInputWinnerNumbersCommand(): List { - requireNotNull(inputWinnerNumbersCommand) { INVALID_NULL_OR_BLANK_WINNER_NUMBERS_MESSAGE } - require(inputWinnerNumbersCommand.isNotBlank()) { INVALID_BLANK_WINNER_NUMBERS_MESSAGE } - require(inputWinnerNumbersCommand.contains(WINNER_NUMBERS_DELIMITER)) { - INVALID_DELIMITER_WINNER_NUMBERS_MESSAGE + require((LOTTO_NUMBER_MIN_VALUE..LOTTO_NUMBER_MAX_VALUE).toSet().containsAll(winnerNumbers)) { + INVALID_WINNER_NUMBERS_RANGE_MESSAGE } - - return inputWinnerNumbersCommand.split(WINNER_NUMBERS_DELIMITER) - .map { inputWinnerNumber -> lottoNumberStringToInt(inputWinnerNumber.trim()) } - } - - private fun lottoNumberStringToInt(numberString: String): Int { - val lottoNumberOrNull = numberString.toIntOrNull() - - requireNotNull(lottoNumberOrNull) { INVALID_WINNER_NUMBERS_TO_INT_MESSAGE } - require((LOTTO_NUMBER_MIN_VALUE..LOTTO_NUMBER_MAX_VALUE).toSet().contains(lottoNumberOrNull)) { - INVALID_WINNER_NUMBERS_LOTTO_RANGE_MESSAGE - } - - return lottoNumberOrNull } companion object { - const val INVALID_NULL_OR_BLANK_WINNER_NUMBERS_MESSAGE: String = "입력된 로또 당첨 번호가 없습니다" - const val INVALID_BLANK_WINNER_NUMBERS_MESSAGE: String = "입력된 로또 당첨 번호가 공백입니다" - const val INVALID_DELIMITER_WINNER_NUMBERS_MESSAGE: String = "로또 당첨 번호 구분자가 올바르지 않습니다" - const val WINNER_NUMBERS_DELIMITER: String = "," - const val INVALID_WINNER_NUMBERS_TO_INT_MESSAGE: String = "로또 당첨 번호가 숫자로 입력되지 않았습니다" - const val INVALID_WINNER_NUMBERS_LOTTO_RANGE_MESSAGE: String = "로또 당첨 번호가 1~45 사이의 숫자가 아닙니다" - const val INVALID_WINNER_NUMBERS_COUNT_MESSAGE: String = "로또 당첨 번호가 중복되지 않은 6개로 입력되지 않았습니다" + const val INVALID_WINNER_NUMBERS_COUNT_MESSAGE: String = "로또 당첨 번호 개수는 6개여야 합니다" } } diff --git a/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt b/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt index 3ce10d2be6..11b4a29495 100644 --- a/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt +++ b/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt @@ -1,9 +1,5 @@ package lotto.domain -import lotto.domain.LottoNumberMatchPayout.FIVE_NUMBER_MATCH -import lotto.domain.LottoNumberMatchPayout.FOUR_NUMBER_MATCH -import lotto.domain.LottoNumberMatchPayout.SIX_NUMBER_MATCH -import lotto.domain.LottoNumberMatchPayout.THREE_NUMBER_MATCH import lotto.domain.LottoTicketIssuer.DEFAULT_LOTTO_PRICE import lotto.domain.PurchasedLottoTickets.Companion.INVALID_PURCHASED_COUNT_MESSAGE import lotto.domain.PurchasedLottoTickets.Companion.PURCHASED_COUNT_MIN_VALUE @@ -29,10 +25,10 @@ data class PurchasedLottoResults( fun getProfitMargin(): Double { val totalPayout = - threeNumberMatchCount * LottoNumberMatchPayout.matchCountToPayout(THREE_NUMBER_MATCH) + - fourNumberMatchCount * LottoNumberMatchPayout.matchCountToPayout(FOUR_NUMBER_MATCH) + - fiveNumberMatchCount * LottoNumberMatchPayout.matchCountToPayout(FIVE_NUMBER_MATCH) + - sixNumberMatchCount * LottoNumberMatchPayout.matchCountToPayout(SIX_NUMBER_MATCH) + threeNumberMatchCount * LottoNumberMatchPayout.byMatchCount(threeNumberMatchCount).matchCountPayout + + fourNumberMatchCount * LottoNumberMatchPayout.byMatchCount(fourNumberMatchCount).matchCountPayout + + fiveNumberMatchCount * LottoNumberMatchPayout.byMatchCount(fiveNumberMatchCount).matchCountPayout + + sixNumberMatchCount * LottoNumberMatchPayout.byMatchCount(sixNumberMatchCount).matchCountPayout return totalPayout.toDouble() / (purchasedCount * DEFAULT_LOTTO_PRICE).toDouble() } diff --git a/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt b/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt index 3fe1df82b7..e5c6a86fe7 100644 --- a/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt +++ b/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt @@ -1,17 +1,58 @@ package lotto.domain -class PurchasedLottoTickets(val purchasedCount: Int, lottoNumberGenerator: () -> Set) { - val purchasedLottoTickets: List = generateLottoTickets(lottoNumberGenerator) +data class PurchasedLottoTickets(val purchasedCount: Int, private val generateLottoNumbers: () -> Set) { + val purchasedLottoTickets: List = + List(purchasedCount) { + LottoTicket(generateLottoNumbers = generateLottoNumbers) + } init { require(purchasedCount >= PURCHASED_COUNT_MIN_VALUE) { INVALID_PURCHASED_COUNT_MESSAGE } } - private fun generateLottoTickets(lottoNumberGenerator: () -> Set): List { - val lottoTickets: MutableList = mutableListOf() - repeat(purchasedCount) { lottoTickets.add(LottoTicket(lottoNumberGenerator)) } + fun resultLottoPayout(lottoWinnerNumbers: LottoWinnerNumbers): PurchasedLottoResults { + val threeNumberMatchs = mutableListOf() + val fourNumberMatchs = mutableListOf() + val fiveNumberMatchs = mutableListOf() + val sixNumberMatchs = mutableListOf() - return lottoTickets + purchasedLottoTickets.forEach { lottoTicket -> + numberMatchApply( + lottoTicket = lottoTicket, + lottoWinnerNumbers = lottoWinnerNumbers, + threeNumberMatchs = threeNumberMatchs, + fourNumberMatchs = fourNumberMatchs, + fiveNumberMatchs = fiveNumberMatchs, + sixNumberMatchs = sixNumberMatchs, + ) + } + + return PurchasedLottoResults( + purchasedCount = purchasedCount, + threeNumberMatchCount = threeNumberMatchs.size, + fourNumberMatchCount = fourNumberMatchs.size, + fiveNumberMatchCount = fiveNumberMatchs.size, + sixNumberMatchCount = sixNumberMatchs.size, + ) + } + + private fun numberMatchApply( + lottoTicket: LottoTicket, + lottoWinnerNumbers: LottoWinnerNumbers, + threeNumberMatchs: MutableList, + fourNumberMatchs: MutableList, + fiveNumberMatchs: MutableList, + sixNumberMatchs: MutableList, + ) { + val lottoNumberMatchPayout = lottoTicket.checkLottoWinnerNumbersMatchPayout(lottoWinnerNumbers) + + when (lottoNumberMatchPayout) { + LottoNumberMatchPayout.THREE_NUMBER_MATCH -> threeNumberMatchs.add(lottoTicket) + LottoNumberMatchPayout.FOUR_NUMBER_MATCH -> fourNumberMatchs.add(lottoTicket) + LottoNumberMatchPayout.FIVE_NUMBER_MATCH -> fiveNumberMatchs.add(lottoTicket) + LottoNumberMatchPayout.SIX_NUMBER_MATCH -> sixNumberMatchs.add(lottoTicket) + else -> return + } } companion object { diff --git a/src/main/kotlin/lotto/view/LottoController.kt b/src/main/kotlin/lotto/view/LottoController.kt index a61f81a6a2..127c6204eb 100644 --- a/src/main/kotlin/lotto/view/LottoController.kt +++ b/src/main/kotlin/lotto/view/LottoController.kt @@ -1,33 +1,31 @@ package lotto.view -import lotto.domain.LottoNumberChecker import lotto.domain.LottoTicketIssuer import lotto.domain.LottoWinnerNumbers import lotto.domain.PurchasedLottoTickets +import lotto.domain.generateLottoNumbers object LottoController { - fun lottoPurchased(): PurchasedLottoTickets { + fun purchaseLotto(): PurchasedLottoTickets { + val amountPaid = PurchaseLottoView.inputPurchaseCost() + val purchasedLottoTickets = - LottoTicketIssuer - .issueTickets(amountPaid = PurchaseLottoView.view(), lottoNumberGenerator = { lottoNumberGenerator() }) + LottoTicketIssuer.issueTickets(amountPaid = amountPaid, generateLottoNumbers = { generateLottoNumbers() }) + + PurchaseLottoResultView.displayPurchaseLottoResults(purchasedLottoTickets = purchasedLottoTickets) - PurchaseLottoResultView.view(purchasedLottoTickets = purchasedLottoTickets) return purchasedLottoTickets } - fun lottoWinnerNumber(): LottoWinnerNumbers { - return LottoWinnerNumbers(inputWinnerNumbersCommand = WinnerLottoNumberView.view()) + fun createWinningLottoNumbers(): LottoWinnerNumbers { + return LottoWinnerNumbers(winnerNumbers = WinnerLottoNumberView.inputWinningLottoNumbers()) } - fun payoutResult( - purchasedLottoResults: PurchasedLottoTickets, + fun resultPayout( + purchasedLottoTickets: PurchasedLottoTickets, lottoWinnerNumbers: LottoWinnerNumbers, ) { - return LottoPayoutView.view( - LottoNumberChecker.purchasedLottoTicketsNumberCheck( - purchasedLottoTickets = purchasedLottoResults, - winnerNumbers = lottoWinnerNumbers, - ), - ) + val purchasedLottoResults = purchasedLottoTickets.resultLottoPayout(lottoWinnerNumbers = lottoWinnerNumbers) + return LottoPayoutView.displayWinningStatistics(purchasedLottoResults = purchasedLottoResults) } } diff --git a/src/main/kotlin/lotto/view/LottoPayoutView.kt b/src/main/kotlin/lotto/view/LottoPayoutView.kt index 5394ad16e2..cfb23e701e 100644 --- a/src/main/kotlin/lotto/view/LottoPayoutView.kt +++ b/src/main/kotlin/lotto/view/LottoPayoutView.kt @@ -3,7 +3,7 @@ package lotto.view import lotto.domain.PurchasedLottoResults object LottoPayoutView { - fun view(purchasedLottoResults: PurchasedLottoResults) { + fun displayWinningStatistics(purchasedLottoResults: PurchasedLottoResults) { println("\n당첨 통계") println("---------") println("3개 일치 (5000원)- ${purchasedLottoResults.threeNumberMatchCount}개") diff --git a/src/main/kotlin/lotto/view/PurchaseLottoResultView.kt b/src/main/kotlin/lotto/view/PurchaseLottoResultView.kt index 38541313b9..008c6f1ae9 100644 --- a/src/main/kotlin/lotto/view/PurchaseLottoResultView.kt +++ b/src/main/kotlin/lotto/view/PurchaseLottoResultView.kt @@ -3,7 +3,7 @@ package lotto.view import lotto.domain.PurchasedLottoTickets object PurchaseLottoResultView { - fun view(purchasedLottoTickets: PurchasedLottoTickets) { + fun displayPurchaseLottoResults(purchasedLottoTickets: PurchasedLottoTickets) { println("${purchasedLottoTickets.purchasedCount}개를 구매했습니다.") purchasedLottoTickets.purchasedLottoTickets.forEach { lottoTicket -> println(lottoTicket.lottoNumbers) } } diff --git a/src/main/kotlin/lotto/view/PurchaseLottoView.kt b/src/main/kotlin/lotto/view/PurchaseLottoView.kt index 6b8b8fdebe..f3c10d8979 100644 --- a/src/main/kotlin/lotto/view/PurchaseLottoView.kt +++ b/src/main/kotlin/lotto/view/PurchaseLottoView.kt @@ -1,7 +1,7 @@ package lotto.view object PurchaseLottoView { - fun view(): Int { + fun inputPurchaseCost(): Int { println("구입금액을 입력해 주세요.") val inputCost: String? = readlnOrNull() requireNotNull(inputCost) { "구입금액이 입력되지 않았습니다" } diff --git a/src/main/kotlin/lotto/view/WinnerLottoNumberView.kt b/src/main/kotlin/lotto/view/WinnerLottoNumberView.kt index 6e94bc1ab1..1ac1cb10de 100644 --- a/src/main/kotlin/lotto/view/WinnerLottoNumberView.kt +++ b/src/main/kotlin/lotto/view/WinnerLottoNumberView.kt @@ -1,8 +1,45 @@ package lotto.view object WinnerLottoNumberView { - fun view(): String? { + fun inputWinningLottoNumbers(): Set { println("\n지난 주 당첨 번호를 입력해 주세요.") - return readlnOrNull() + val inputWinnerNumbersCommand: String? = readlnOrNull() + requireNotNull(inputWinnerNumbersCommand) { INVALID_NULL_OR_BLANK_WINNER_NUMBERS_MESSAGE } + + val splitInputWinnerNumbers = splitInputWinnerNumbersCommand(inputWinnerNumbersCommand) + require(splitInputWinnerNumbers.size == 6) { INVALID_WINNER_NUMBERS_COUNT_MESSAGE } + return splitInputWinnerNumbers } + + private fun splitInputWinnerNumbersCommand(inputWinnerNumbersCommand: String): Set { + require(inputWinnerNumbersCommand.isNotBlank()) { INVALID_BLANK_WINNER_NUMBERS_MESSAGE } + require(inputWinnerNumbersCommand.contains(WINNER_NUMBERS_DELIMITER)) { + INVALID_DELIMITER_WINNER_NUMBERS_MESSAGE + } + + return inputWinnerNumbersCommand.split(WINNER_NUMBERS_DELIMITER) + .map { inputWinnerNumber -> lottoNumberStringToInt(numberString = inputWinnerNumber.trim()) } + .toSet() + } + + private fun lottoNumberStringToInt(numberString: String): Int { + val lottoNumberOrNull = numberString.toIntOrNull() + + requireNotNull(lottoNumberOrNull) { INVALID_WINNER_NUMBERS_TO_INT_MESSAGE } + require((LOTTO_NUMBER_MIN_VALUE..LOTTO_NUMBER_MAX_VALUE).toSet().contains(lottoNumberOrNull)) { + INVALID_WINNER_NUMBERS_LOTTO_RANGE_MESSAGE + } + + return lottoNumberOrNull + } + + const val INVALID_NULL_OR_BLANK_WINNER_NUMBERS_MESSAGE: String = "입력된 로또 당첨 번호가 없습니다" + const val INVALID_BLANK_WINNER_NUMBERS_MESSAGE: String = "입력된 로또 당첨 번호가 공백입니다" + const val INVALID_DELIMITER_WINNER_NUMBERS_MESSAGE: String = "로또 당첨 번호 구분자가 올바르지 않습니다" + const val WINNER_NUMBERS_DELIMITER: String = "," + const val INVALID_WINNER_NUMBERS_TO_INT_MESSAGE: String = "로또 당첨 번호가 숫자로 입력되지 않았습니다" + const val INVALID_WINNER_NUMBERS_LOTTO_RANGE_MESSAGE: String = "로또 당첨 번호가 1~45 사이의 숫자가 아닙니다" + const val LOTTO_NUMBER_MIN_VALUE: Int = 1 + const val LOTTO_NUMBER_MAX_VALUE: Int = 45 + const val INVALID_WINNER_NUMBERS_COUNT_MESSAGE: String = "로또 당첨 번호가 중복되지 않은 6개로 입력되지 않았습니다" } diff --git a/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt b/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt index 4cebf0e06f..ecab8aabfc 100644 --- a/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt +++ b/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt @@ -14,48 +14,48 @@ class StringAddCalculatorTest { @BeforeEach fun setUp() { - calculator = StringAddCalculator(); + calculator = StringAddCalculator() } @DisplayName(value = "빈 문자열 또는 null 값을 입력할 경우 0을 반환해야 한다.") @ParameterizedTest @NullAndEmptySource fun emptyOrNull(text: String) { - assertThat(calculator.add(text)).isZero(); + assertThat(calculator.add(text)).isZero() } @DisplayName(value = "숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다.") @ParameterizedTest @ValueSource(strings = ["1"]) fun oneNumber(text: String) { - assertThat(calculator.add(text)).isSameAs(Integer.parseInt(text)); + assertThat(calculator.add(text)).isSameAs(Integer.parseInt(text)) } @DisplayName(value = "숫자 두개를 쉼표(,) 구분자로 입력할 경우 두 숫자의 합을 반환한다.") @ParameterizedTest @ValueSource(strings = ["1,2"]) fun twoNumbers(text: String) { - assertThat(calculator.add(text)).isSameAs(3); + assertThat(calculator.add(text)).isSameAs(3) } @DisplayName(value = "구분자를 쉼표(,) 이외에 콜론(:)을 사용할 수 있다.") @ParameterizedTest @ValueSource(strings = ["1,2:3"]) fun colons(text: String) { - assertThat(calculator.add(text)).isSameAs(6); + assertThat(calculator.add(text)).isSameAs(6) } @DisplayName(value = "//와 \\n 문자 사이에 커스텀 구분자를 지정할 수 있다.") @ParameterizedTest @ValueSource(strings = ["//;\n1;2;3"]) fun customDelimiter(text: String) { - assertThat(calculator.add(text)).isSameAs(6); + assertThat(calculator.add(text)).isSameAs(6) } @DisplayName(value = "문자열 계산기에 음수를 전달하는 경우 RuntimeException 예외 처리를 한다.") @Test fun negative() { assertThatExceptionOfType(RuntimeException::class.java) - .isThrownBy { calculator.add("-1") }; + .isThrownBy { calculator.add("-1") } } } diff --git a/src/test/kotlin/lotto/domain/LottoNumberCheckerTest.kt b/src/test/kotlin/lotto/domain/LottoNumberCheckerTest.kt deleted file mode 100644 index 560d52c1b0..0000000000 --- a/src/test/kotlin/lotto/domain/LottoNumberCheckerTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -package lotto.domain - -import io.kotest.matchers.equals.shouldBeEqual -import org.junit.jupiter.api.TestInstance -import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import java.util.stream.Stream - -@TestInstance(PER_CLASS) -class LottoNumberCheckerTest { - @MethodSource("구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공") - @ParameterizedTest - fun `구매한 로또 번호가 당첨 번호와 몇개가 일치하는지와 수익률 등 결과 확인 (3개부터)`( - purchasedCount: Int, - lottoNumbers: Set, - inputWinnerNumbersCommand: String, - threeNumberMatchCount: Int, - fourNumberMatchCount: Int, - fiveNumberMatchCount: Int, - sixNumberMatchCount: Int, - profitMargin: Double, - ) { - val purchasedLottoTickets = - PurchasedLottoTickets(purchasedCount = purchasedCount, lottoNumberGenerator = { lottoNumbers }) - val lottoWinnerNumbers = LottoWinnerNumbers(inputWinnerNumbersCommand = inputWinnerNumbersCommand) - val purchasedLottoResults = - LottoNumberChecker.purchasedLottoTicketsNumberCheck( - purchasedLottoTickets = purchasedLottoTickets, - winnerNumbers = lottoWinnerNumbers, - ) - purchasedLottoResults.threeNumberMatchCount shouldBeEqual threeNumberMatchCount - purchasedLottoResults.fourNumberMatchCount shouldBeEqual fourNumberMatchCount - purchasedLottoResults.fiveNumberMatchCount shouldBeEqual fiveNumberMatchCount - purchasedLottoResults.sixNumberMatchCount shouldBeEqual sixNumberMatchCount - purchasedLottoResults.getProfitMargin() shouldBeEqual profitMargin - } - - fun `구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공`(): Stream { - return Stream.of( - Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), "11,15,16,17,18,19", 0, 0, 0, 0, 0.0), - Arguments.of(25, setOf(1, 2, 3, 4, 5, 6), "4,15,16,17,18,19", 0, 0, 0, 0, 0.0), - Arguments.of(35, setOf(1, 2, 3, 4, 5, 6), "4,5,16,17,18,19", 0, 0, 0, 0, 0.0), - Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), "4,5,6,7,8,9", 5, 0, 0, 0, 5.0), - Arguments.of(8, setOf(11, 12, 13, 14, 15, 16), "13,14,15,16,17,18", 0, 8, 0, 0, 50.0), - Arguments.of(3, setOf(21, 22, 23, 24, 25, 26), "21,22,23,24,25,1", 0, 0, 3, 0, 1500.0), - Arguments.of(1, setOf(31, 32, 33, 34, 35, 41), "31,32,33,34,35,41", 0, 0, 0, 1, 2000000.0), - ) - } -} diff --git a/src/test/kotlin/lotto/domain/LottoNumberGeneratorTest.kt b/src/test/kotlin/lotto/domain/LottoNumberGeneratorTest.kt new file mode 100644 index 0000000000..5062f8dac5 --- /dev/null +++ b/src/test/kotlin/lotto/domain/LottoNumberGeneratorTest.kt @@ -0,0 +1,11 @@ +package lotto.domain + +import io.kotest.matchers.equals.shouldBeEqual +import org.junit.jupiter.api.Test + +class LottoNumberGeneratorTest { + @Test + fun `로또 번호 자동 생성은 1부터 45사이의 6개의 숫자로 이루어져야한다`() { + (1..45).toSet().containsAll(generateLottoNumbers()) shouldBeEqual true + } +} diff --git a/src/test/kotlin/lotto/domain/LottoNumberMatchPayoutTest.kt b/src/test/kotlin/lotto/domain/LottoNumberMatchPayoutTest.kt index 53ce32eff6..9e2edddb7f 100644 --- a/src/test/kotlin/lotto/domain/LottoNumberMatchPayoutTest.kt +++ b/src/test/kotlin/lotto/domain/LottoNumberMatchPayoutTest.kt @@ -7,6 +7,9 @@ import org.junit.jupiter.params.provider.CsvSource class LottoNumberMatchPayoutTest { @ParameterizedTest @CsvSource( + "0, 0", + "1, 0", + "2, 0", "3, 5000", "4, 50000", "5, 1500000", @@ -16,6 +19,6 @@ class LottoNumberMatchPayoutTest { matchCount: Int, payout: Int, ) { - LottoNumberMatchPayout.matchCountToPayout(matchCount = matchCount) shouldBe payout + LottoNumberMatchPayout.byMatchCount(matchCount = matchCount).matchCountPayout shouldBe payout } } diff --git a/src/test/kotlin/lotto/domain/LottoTicketIssuerTest.kt b/src/test/kotlin/lotto/domain/LottoTicketIssuerTest.kt index 79c7cd4a24..c8ae7a46da 100644 --- a/src/test/kotlin/lotto/domain/LottoTicketIssuerTest.kt +++ b/src/test/kotlin/lotto/domain/LottoTicketIssuerTest.kt @@ -2,11 +2,10 @@ package lotto.domain import io.kotest.assertions.throwables.shouldThrowWithMessage import io.kotest.matchers.shouldBe -import lotto.domain.LottoTicketIssuer.DEFAULT_LOTTO_PRICE import lotto.domain.LottoTicketIssuer.INVALID_MIN_COST_LOTTO_PAID_MESSAGE import lotto.domain.LottoTicketIssuer.INVALID_THOUSAND_UNIT_LOTTO_PAID_MESSAGE -import lotto.view.lottoNumberGenerator import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource import org.junit.jupiter.params.provider.ValueSource class LottoTicketIssuerTest { @@ -14,7 +13,7 @@ class LottoTicketIssuerTest { @ValueSource(ints = [500, 999]) fun `로또 구입 비용이 1,000원 미만일 경우 에러가 발생한다`(amountPaid: Int) { shouldThrowWithMessage(message = INVALID_MIN_COST_LOTTO_PAID_MESSAGE) { - LottoTicketIssuer.issueTickets(amountPaid = amountPaid, lottoNumberGenerator = { lottoNumberGenerator() }) + LottoTicketIssuer.issueTickets(amountPaid = amountPaid, generateLottoNumbers = { setOf(1, 2, 3, 4, 5, 6) }) } } @@ -22,17 +21,19 @@ class LottoTicketIssuerTest { @ValueSource(ints = [1500, 22200, 10500, 2100005]) fun `로또 구입 비용이 1,000원 단위가 아닐 경우 에러가 발생한다`(amountPaid: Int) { shouldThrowWithMessage(message = INVALID_THOUSAND_UNIT_LOTTO_PAID_MESSAGE) { - LottoTicketIssuer.issueTickets(amountPaid = amountPaid, lottoNumberGenerator = { lottoNumberGenerator() }) + LottoTicketIssuer.issueTickets(amountPaid = amountPaid, generateLottoNumbers = { setOf(1, 2, 3, 4, 5, 6) }) } } @ParameterizedTest - @ValueSource(ints = [5000, 1000, 23000, 3000]) - fun `로또 구입 비용에 대해 몇 장의 로또가 구입됐는지 확인활 수 있다`(amountPaid: Int) { + @CsvSource("5000, 5", "1000, 1") + fun `로또 구입 비용에 대해 몇 장의 로또가 구입됐는지 확인활 수 있다`( + amountPaid: Int, + expectedTicketCount: Int, + ) { val purchasedLottoTickets = - LottoTicketIssuer.issueTickets(amountPaid = amountPaid, lottoNumberGenerator = { lottoNumberGenerator() }) - val purchasedCount = amountPaid / DEFAULT_LOTTO_PRICE - purchasedLottoTickets.purchasedCount shouldBe purchasedCount - purchasedLottoTickets.purchasedLottoTickets.size shouldBe purchasedCount + LottoTicketIssuer.issueTickets(amountPaid = amountPaid, generateLottoNumbers = { setOf(1, 2, 3, 4, 5, 6) }) + purchasedLottoTickets.purchasedCount shouldBe expectedTicketCount + purchasedLottoTickets.purchasedLottoTickets.size shouldBe expectedTicketCount } } diff --git a/src/test/kotlin/lotto/domain/LottoTicketTest.kt b/src/test/kotlin/lotto/domain/LottoTicketTest.kt index c895b1ff6a..0b1adc4bb3 100644 --- a/src/test/kotlin/lotto/domain/LottoTicketTest.kt +++ b/src/test/kotlin/lotto/domain/LottoTicketTest.kt @@ -1,14 +1,45 @@ package lotto.domain -import io.kotest.matchers.equals.shouldBeEqual -import lotto.view.lottoNumberGenerator -import org.junit.jupiter.api.Test +import io.kotest.assertions.throwables.shouldThrowWithMessage +import lotto.domain.LottoTicket.Companion.INVALID_LOTTO_NUMBER_COUNT_MESSAGE +import lotto.domain.LottoTicket.Companion.INVALID_WINNER_NUMBERS_RANGE_MESSAGE +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import java.util.stream.Stream +@TestInstance(TestInstance.Lifecycle.PER_CLASS) class LottoTicketTest { - @Test - fun `로또 번호는 1부터 45사이의 중복되지 않는 숫자 6개로 이루어져야한다`() { - val lottoTicket = LottoTicket(lottoNumberGenerator = { lottoNumberGenerator() }) - (1..45).toSet().containsAll(lottoTicket.lottoNumbers) shouldBeEqual true - lottoTicket.lottoNumbers.size shouldBeEqual 6 + @MethodSource("7개 이상, 또는 6개 미만의 숫자 제공") + @ParameterizedTest + fun `로또 번호는 숫자 6개가 아니면 에러가 발생한다`(numberSet: Set) { + shouldThrowWithMessage(message = INVALID_LOTTO_NUMBER_COUNT_MESSAGE) { + LottoTicket(generateLottoNumbers = { numberSet }) + } + } + + fun `7개 이상, 또는 6개 미만의 숫자 제공`(): Stream { + return Stream.of( + Arguments.of(setOf(5, 11, 15, 16, 17, 18, 19)), + Arguments.of(setOf(4, 5, 6, 7)), + Arguments.of(setOf(15, 16, 17, 18, 19)), + ) + } + + @MethodSource("1미만 46 이상의 숫자가 있는 로또 번호 제공") + @ParameterizedTest + fun `로또 번호는 1부터 45사이의 숫자가 아니면 에러가 발생한다`(numberSet: Set) { + shouldThrowWithMessage(message = INVALID_WINNER_NUMBERS_RANGE_MESSAGE) { + LottoTicket(generateLottoNumbers = { numberSet }) + } + } + + fun `1미만 46 이상의 숫자가 있는 로또 번호 제공`(): Stream { + return Stream.of( + Arguments.of(setOf(0, 11, 15, 1, 2, 3)), + Arguments.of(setOf(14, 15, 46, 7, 4, 5)), + Arguments.of(setOf(15, 16, 17, 18, -3, 1)), + ) } } diff --git a/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt b/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt index 42490f4725..0027b926e5 100644 --- a/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt +++ b/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt @@ -1,54 +1,3 @@ package lotto.domain -import io.kotest.assertions.throwables.shouldThrowWithMessage -import lotto.domain.LottoWinnerNumbers.Companion.INVALID_BLANK_WINNER_NUMBERS_MESSAGE -import lotto.domain.LottoWinnerNumbers.Companion.INVALID_DELIMITER_WINNER_NUMBERS_MESSAGE -import lotto.domain.LottoWinnerNumbers.Companion.INVALID_NULL_OR_BLANK_WINNER_NUMBERS_MESSAGE -import lotto.domain.LottoWinnerNumbers.Companion.INVALID_WINNER_NUMBERS_COUNT_MESSAGE -import lotto.domain.LottoWinnerNumbers.Companion.INVALID_WINNER_NUMBERS_LOTTO_RANGE_MESSAGE -import lotto.domain.LottoWinnerNumbers.Companion.INVALID_WINNER_NUMBERS_TO_INT_MESSAGE -import org.junit.jupiter.api.Test - -class LottoWinnerNumbersTest { - @Test - fun `로또 당첨 번호가 입력되지 않으면 에러가 발생한다`() { - shouldThrowWithMessage(message = INVALID_NULL_OR_BLANK_WINNER_NUMBERS_MESSAGE) { - LottoWinnerNumbers(inputWinnerNumbersCommand = null) - } - } - - @Test - fun `로또 당첨 번호가 공백으로 입력되면 에러가 발생한다`() { - shouldThrowWithMessage(message = INVALID_BLANK_WINNER_NUMBERS_MESSAGE) { - LottoWinnerNumbers(inputWinnerNumbersCommand = " ") - } - } - - @Test - fun `로또 당첨 번호의 구분자가 올바르지 않으면 에러가 발생한다`() { - shouldThrowWithMessage(message = INVALID_DELIMITER_WINNER_NUMBERS_MESSAGE) { - LottoWinnerNumbers(inputWinnerNumbersCommand = "1;2;3;4;5;6") - } - } - - @Test - fun `로또 당첨 번호가 구분자 제외 숫자로 이루어져 있지 않으면 에러가 발생한다`() { - shouldThrowWithMessage(message = INVALID_WINNER_NUMBERS_TO_INT_MESSAGE) { - LottoWinnerNumbers(inputWinnerNumbersCommand = "1,2,3,4,5,6t") - } - } - - @Test - fun `로또 당첨 번호가 1부터 45사이의 숫자가 아닐 경우 에러가 발생한다`() { - shouldThrowWithMessage(message = INVALID_WINNER_NUMBERS_LOTTO_RANGE_MESSAGE) { - LottoWinnerNumbers(inputWinnerNumbersCommand = "1,2,3,4,5,46") - } - } - - @Test - fun `로또 당첨 번호가 6개가 아닐 경우 에러가 발생한다`() { - shouldThrowWithMessage(message = INVALID_WINNER_NUMBERS_COUNT_MESSAGE) { - LottoWinnerNumbers(inputWinnerNumbersCommand = "1,2,3,4,5,6,7") - } - } -} +class LottoWinnerNumbersTest diff --git a/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt b/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt index bcff59eedc..ca99541641 100644 --- a/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt +++ b/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt @@ -1,13 +1,19 @@ package lotto.domain import io.kotest.assertions.throwables.shouldThrowWithMessage +import io.kotest.matchers.equals.shouldBeEqual import lotto.domain.PurchasedLottoResults.Companion.INVALID_LOTTO_MATCH_COUNT_MESSAGE import lotto.domain.PurchasedLottoResults.Companion.INVALID_PURCHASED_COUNT_LOTTO_MATCH_COUNT_MESSAGE import lotto.domain.PurchasedLottoTickets.Companion.INVALID_PURCHASED_COUNT_MESSAGE import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.CsvSource +import org.junit.jupiter.params.provider.MethodSource +import java.util.stream.Stream +@TestInstance(TestInstance.Lifecycle.PER_CLASS) class PurchasedLottoResultsTest { @Test fun `로또 구매 개수가 1개 미만 일 경우 에러가 발생한다`() { @@ -71,4 +77,40 @@ class PurchasedLottoResultsTest { ) } } + + @MethodSource("구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공") + @ParameterizedTest + fun `구매한 로또 번호가 당첨 번호와 몇개가 일치하는지와 수익률 등 결과 확인 (3개부터)`( + purchasedCount: Int, + lottoNumbers: Set, + winnerNumbers: Set, + threeNumberMatchCount: Int, + fourNumberMatchCount: Int, + fiveNumberMatchCount: Int, + sixNumberMatchCount: Int, + profitMargin: Double, + ) { + val purchasedLottoTickets = + PurchasedLottoTickets(purchasedCount = purchasedCount, generateLottoNumbers = { lottoNumbers }) + val lottoWinnerNumbers = LottoWinnerNumbers(winnerNumbers = winnerNumbers) + val purchasedLottoResults = purchasedLottoTickets.resultLottoPayout(lottoWinnerNumbers) + + purchasedLottoResults.threeNumberMatchCount shouldBeEqual threeNumberMatchCount + purchasedLottoResults.fourNumberMatchCount shouldBeEqual fourNumberMatchCount + purchasedLottoResults.fiveNumberMatchCount shouldBeEqual fiveNumberMatchCount + purchasedLottoResults.sixNumberMatchCount shouldBeEqual sixNumberMatchCount + purchasedLottoResults.getProfitMargin() shouldBeEqual profitMargin + } + + fun `구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공`(): Stream { + return Stream.of( + Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), setOf(11, 15, 16, 17, 18, 19), 0, 0, 0, 0, 0.0), + Arguments.of(25, setOf(1, 2, 3, 4, 5, 6), setOf(4, 15, 16, 17, 18, 19), 0, 0, 0, 0, 0.0), + Arguments.of(35, setOf(1, 2, 3, 4, 5, 6), setOf(4, 5, 16, 17, 18, 19), 0, 0, 0, 0, 0.0), + Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), setOf(4, 5, 6, 7, 8, 9), 5, 0, 0, 0, 5.0), + Arguments.of(8, setOf(11, 12, 13, 14, 15, 16), setOf(13, 14, 15, 16, 17, 18), 0, 8, 0, 0, 50.0), + Arguments.of(3, setOf(21, 22, 23, 24, 25, 26), setOf(21, 22, 23, 24, 25, 1), 0, 0, 3, 0, 1500.0), + Arguments.of(1, setOf(31, 32, 33, 34, 35, 41), setOf(31, 32, 33, 34, 35, 41), 0, 0, 0, 1, 2000000.0), + ) + } } diff --git a/src/test/kotlin/lotto/domain/PurchasedLottoTicketsTest.kt b/src/test/kotlin/lotto/domain/PurchasedLottoTicketsTest.kt index c0aadf4ddb..130b2f986d 100644 --- a/src/test/kotlin/lotto/domain/PurchasedLottoTicketsTest.kt +++ b/src/test/kotlin/lotto/domain/PurchasedLottoTicketsTest.kt @@ -2,7 +2,6 @@ package lotto.domain import io.kotest.assertions.throwables.shouldThrowWithMessage import lotto.domain.PurchasedLottoTickets.Companion.INVALID_PURCHASED_COUNT_MESSAGE -import lotto.view.lottoNumberGenerator import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource @@ -11,7 +10,7 @@ class PurchasedLottoTicketsTest { @ValueSource(ints = [0, -1, -100]) fun `구매한 로또 티켓 개수가 1개 미만일 경우 에러가 발생한다 `(purchasedCount: Int) { shouldThrowWithMessage(message = INVALID_PURCHASED_COUNT_MESSAGE) { - PurchasedLottoTickets(purchasedCount = purchasedCount, lottoNumberGenerator = { lottoNumberGenerator() }) + PurchasedLottoTickets(purchasedCount = purchasedCount, generateLottoNumbers = { setOf(1, 2, 3, 4, 5, 6) }) } } } From aae33460a4670b4087b1c768e58b52ce4a4a4322 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Mon, 2 Dec 2024 02:59:06 +0900 Subject: [PATCH 03/18] =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lotto/domain/PurchasedLottoResults.kt | 12 ++-- .../lotto/domain/PurchasedLottoTickets.kt | 9 +-- .../StringAddCalculatorTest.kt | 61 ------------------- 3 files changed, 13 insertions(+), 69 deletions(-) delete mode 100644 src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt diff --git a/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt b/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt index 11b4a29495..031d243f1c 100644 --- a/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt +++ b/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt @@ -25,10 +25,10 @@ data class PurchasedLottoResults( fun getProfitMargin(): Double { val totalPayout = - threeNumberMatchCount * LottoNumberMatchPayout.byMatchCount(threeNumberMatchCount).matchCountPayout + - fourNumberMatchCount * LottoNumberMatchPayout.byMatchCount(fourNumberMatchCount).matchCountPayout + - fiveNumberMatchCount * LottoNumberMatchPayout.byMatchCount(fiveNumberMatchCount).matchCountPayout + - sixNumberMatchCount * LottoNumberMatchPayout.byMatchCount(sixNumberMatchCount).matchCountPayout + threeNumberMatchCount * LottoNumberMatchPayout.byMatchCount(THREE_NUMBER_MATCH).matchCountPayout + + fourNumberMatchCount * LottoNumberMatchPayout.byMatchCount(FOUR_NUMBER_MATCH).matchCountPayout + + fiveNumberMatchCount * LottoNumberMatchPayout.byMatchCount(FIVE_NUMBER_MATCH).matchCountPayout + + sixNumberMatchCount * LottoNumberMatchPayout.byMatchCount(SIX_NUMBER_MATCH).matchCountPayout return totalPayout.toDouble() / (purchasedCount * DEFAULT_LOTTO_PRICE).toDouble() } @@ -37,5 +37,9 @@ data class PurchasedLottoResults( const val LOTTO_MATCH_COUNT_MIN_VALUE: Int = 0 const val INVALID_LOTTO_MATCH_COUNT_MESSAGE: String = "로또 당첨 번호 매치 결과는 0 이상 이어야합니다" const val INVALID_PURCHASED_COUNT_LOTTO_MATCH_COUNT_MESSAGE: String = "당첨된 내역의 합이 구매한 개수보다 많을 수 없습니다" + const val THREE_NUMBER_MATCH: Int = 3 + const val FOUR_NUMBER_MATCH: Int = 4 + const val FIVE_NUMBER_MATCH: Int = 5 + const val SIX_NUMBER_MATCH: Int = 6 } } diff --git a/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt b/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt index e5c6a86fe7..08e528d1ef 100644 --- a/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt +++ b/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt @@ -1,13 +1,14 @@ package lotto.domain data class PurchasedLottoTickets(val purchasedCount: Int, private val generateLottoNumbers: () -> Set) { - val purchasedLottoTickets: List = - List(purchasedCount) { - LottoTicket(generateLottoNumbers = generateLottoNumbers) - } + val purchasedLottoTickets: List init { require(purchasedCount >= PURCHASED_COUNT_MIN_VALUE) { INVALID_PURCHASED_COUNT_MESSAGE } + purchasedLottoTickets = + List(purchasedCount) { + LottoTicket(generateLottoNumbers = generateLottoNumbers) + } } fun resultLottoPayout(lottoWinnerNumbers: LottoWinnerNumbers): PurchasedLottoResults { diff --git a/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt b/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt deleted file mode 100644 index ecab8aabfc..0000000000 --- a/src/test/kotlin/additioncalculator/StringAddCalculatorTest.kt +++ /dev/null @@ -1,61 +0,0 @@ -package additioncalculator - -import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatExceptionOfType -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.DisplayName -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.NullAndEmptySource -import org.junit.jupiter.params.provider.ValueSource - -class StringAddCalculatorTest { - private lateinit var calculator: StringAddCalculator - - @BeforeEach - fun setUp() { - calculator = StringAddCalculator() - } - - @DisplayName(value = "빈 문자열 또는 null 값을 입력할 경우 0을 반환해야 한다.") - @ParameterizedTest - @NullAndEmptySource - fun emptyOrNull(text: String) { - assertThat(calculator.add(text)).isZero() - } - - @DisplayName(value = "숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다.") - @ParameterizedTest - @ValueSource(strings = ["1"]) - fun oneNumber(text: String) { - assertThat(calculator.add(text)).isSameAs(Integer.parseInt(text)) - } - - @DisplayName(value = "숫자 두개를 쉼표(,) 구분자로 입력할 경우 두 숫자의 합을 반환한다.") - @ParameterizedTest - @ValueSource(strings = ["1,2"]) - fun twoNumbers(text: String) { - assertThat(calculator.add(text)).isSameAs(3) - } - - @DisplayName(value = "구분자를 쉼표(,) 이외에 콜론(:)을 사용할 수 있다.") - @ParameterizedTest - @ValueSource(strings = ["1,2:3"]) - fun colons(text: String) { - assertThat(calculator.add(text)).isSameAs(6) - } - - @DisplayName(value = "//와 \\n 문자 사이에 커스텀 구분자를 지정할 수 있다.") - @ParameterizedTest - @ValueSource(strings = ["//;\n1;2;3"]) - fun customDelimiter(text: String) { - assertThat(calculator.add(text)).isSameAs(6) - } - - @DisplayName(value = "문자열 계산기에 음수를 전달하는 경우 RuntimeException 예외 처리를 한다.") - @Test - fun negative() { - assertThatExceptionOfType(RuntimeException::class.java) - .isThrownBy { calculator.add("-1") } - } -} From c5e0aad94d8c658de0c5f4c72e9d01b3393bc1ca Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Mon, 2 Dec 2024 04:00:04 +0900 Subject: [PATCH 04/18] =?UTF-8?q?2=EB=8B=A8=EA=B3=84=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/domain/LottoTicket.kt | 5 -- .../kotlin/lotto/domain/LottoWinnerNumbers.kt | 47 ++++++++++++++ .../lotto/domain/PurchasedLottoTickets.kt | 45 ------------- src/main/kotlin/lotto/view/LottoController.kt | 2 +- .../lotto/domain/LottoWinnerNumbersTest.kt | 64 ++++++++++++++++++- .../lotto/domain/PurchasedLottoResultsTest.kt | 40 ------------ 6 files changed, 111 insertions(+), 92 deletions(-) diff --git a/src/main/kotlin/lotto/domain/LottoTicket.kt b/src/main/kotlin/lotto/domain/LottoTicket.kt index a622455370..b363f03d85 100644 --- a/src/main/kotlin/lotto/domain/LottoTicket.kt +++ b/src/main/kotlin/lotto/domain/LottoTicket.kt @@ -10,11 +10,6 @@ data class LottoTicket(private val generateLottoNumbers: () -> Set) { } } - fun checkLottoWinnerNumbersMatchPayout(winnerNumbers: LottoWinnerNumbers): LottoNumberMatchPayout { - val matchCount = lottoNumbers.intersect(winnerNumbers.winnerNumbers).size - return LottoNumberMatchPayout.byMatchCount(matchCount) - } - companion object { const val LOTTO_NUMBER_MIN_VALUE: Int = 1 const val LOTTO_NUMBER_MAX_VALUE: Int = 45 diff --git a/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt b/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt index 938751073e..0978951745 100644 --- a/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt +++ b/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt @@ -13,6 +13,53 @@ data class LottoWinnerNumbers(val winnerNumbers: Set) { } } + fun resultLottoPayout(purchasedLottoTickets: PurchasedLottoTickets): PurchasedLottoResults { + val threeNumberMatchs = mutableListOf() + val fourNumberMatchs = mutableListOf() + val fiveNumberMatchs = mutableListOf() + val sixNumberMatchs = mutableListOf() + + purchasedLottoTickets.purchasedLottoTickets.forEach { lottoTicket -> + numberMatchApply( + lottoTicket = lottoTicket, + threeNumberMatchs = threeNumberMatchs, + fourNumberMatchs = fourNumberMatchs, + fiveNumberMatchs = fiveNumberMatchs, + sixNumberMatchs = sixNumberMatchs, + ) + } + + return PurchasedLottoResults( + purchasedCount = purchasedLottoTickets.purchasedCount, + threeNumberMatchCount = threeNumberMatchs.size, + fourNumberMatchCount = fourNumberMatchs.size, + fiveNumberMatchCount = fiveNumberMatchs.size, + sixNumberMatchCount = sixNumberMatchs.size, + ) + } + + private fun numberMatchApply( + lottoTicket: LottoTicket, + threeNumberMatchs: MutableList, + fourNumberMatchs: MutableList, + fiveNumberMatchs: MutableList, + sixNumberMatchs: MutableList, + ) { + val lottoNumberMatchPayout = checkLottoWinnerNumbersMatchPayout(lottoTicket) + + when (lottoNumberMatchPayout) { + LottoNumberMatchPayout.THREE_NUMBER_MATCH -> threeNumberMatchs.add(lottoTicket) + LottoNumberMatchPayout.FOUR_NUMBER_MATCH -> fourNumberMatchs.add(lottoTicket) + LottoNumberMatchPayout.FIVE_NUMBER_MATCH -> fiveNumberMatchs.add(lottoTicket) + LottoNumberMatchPayout.SIX_NUMBER_MATCH -> sixNumberMatchs.add(lottoTicket) + else -> return + } + } + + private fun checkLottoWinnerNumbersMatchPayout(lottoTicket: LottoTicket,): LottoNumberMatchPayout { + val matchCount = lottoTicket.lottoNumbers.intersect(winnerNumbers).size + return LottoNumberMatchPayout.byMatchCount(matchCount) + } companion object { const val INVALID_WINNER_NUMBERS_COUNT_MESSAGE: String = "로또 당첨 번호 개수는 6개여야 합니다" } diff --git a/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt b/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt index 08e528d1ef..b8e3f5c62d 100644 --- a/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt +++ b/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt @@ -11,51 +11,6 @@ data class PurchasedLottoTickets(val purchasedCount: Int, private val generateLo } } - fun resultLottoPayout(lottoWinnerNumbers: LottoWinnerNumbers): PurchasedLottoResults { - val threeNumberMatchs = mutableListOf() - val fourNumberMatchs = mutableListOf() - val fiveNumberMatchs = mutableListOf() - val sixNumberMatchs = mutableListOf() - - purchasedLottoTickets.forEach { lottoTicket -> - numberMatchApply( - lottoTicket = lottoTicket, - lottoWinnerNumbers = lottoWinnerNumbers, - threeNumberMatchs = threeNumberMatchs, - fourNumberMatchs = fourNumberMatchs, - fiveNumberMatchs = fiveNumberMatchs, - sixNumberMatchs = sixNumberMatchs, - ) - } - - return PurchasedLottoResults( - purchasedCount = purchasedCount, - threeNumberMatchCount = threeNumberMatchs.size, - fourNumberMatchCount = fourNumberMatchs.size, - fiveNumberMatchCount = fiveNumberMatchs.size, - sixNumberMatchCount = sixNumberMatchs.size, - ) - } - - private fun numberMatchApply( - lottoTicket: LottoTicket, - lottoWinnerNumbers: LottoWinnerNumbers, - threeNumberMatchs: MutableList, - fourNumberMatchs: MutableList, - fiveNumberMatchs: MutableList, - sixNumberMatchs: MutableList, - ) { - val lottoNumberMatchPayout = lottoTicket.checkLottoWinnerNumbersMatchPayout(lottoWinnerNumbers) - - when (lottoNumberMatchPayout) { - LottoNumberMatchPayout.THREE_NUMBER_MATCH -> threeNumberMatchs.add(lottoTicket) - LottoNumberMatchPayout.FOUR_NUMBER_MATCH -> fourNumberMatchs.add(lottoTicket) - LottoNumberMatchPayout.FIVE_NUMBER_MATCH -> fiveNumberMatchs.add(lottoTicket) - LottoNumberMatchPayout.SIX_NUMBER_MATCH -> sixNumberMatchs.add(lottoTicket) - else -> return - } - } - companion object { const val PURCHASED_COUNT_MIN_VALUE: Int = 1 const val INVALID_PURCHASED_COUNT_MESSAGE: String = "최소한 로또 1장 이상 구입해야 합니다" diff --git a/src/main/kotlin/lotto/view/LottoController.kt b/src/main/kotlin/lotto/view/LottoController.kt index 127c6204eb..59798606bc 100644 --- a/src/main/kotlin/lotto/view/LottoController.kt +++ b/src/main/kotlin/lotto/view/LottoController.kt @@ -25,7 +25,7 @@ object LottoController { purchasedLottoTickets: PurchasedLottoTickets, lottoWinnerNumbers: LottoWinnerNumbers, ) { - val purchasedLottoResults = purchasedLottoTickets.resultLottoPayout(lottoWinnerNumbers = lottoWinnerNumbers) + val purchasedLottoResults = lottoWinnerNumbers.resultLottoPayout(purchasedLottoTickets) return LottoPayoutView.displayWinningStatistics(purchasedLottoResults = purchasedLottoResults) } } diff --git a/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt b/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt index 0027b926e5..bb86615671 100644 --- a/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt +++ b/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt @@ -1,3 +1,65 @@ package lotto.domain -class LottoWinnerNumbersTest +import io.kotest.assertions.throwables.shouldThrowWithMessage +import io.kotest.matchers.equals.shouldBeEqual +import lotto.domain.LottoTicket.Companion.INVALID_WINNER_NUMBERS_RANGE_MESSAGE +import lotto.domain.LottoWinnerNumbers.Companion.INVALID_WINNER_NUMBERS_COUNT_MESSAGE +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import java.util.stream.Stream + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class LottoWinnerNumbersTest { + @Test + fun `로또 당첨 번호가 1부터 45사이의 숫자가 아닐 경우 에러가 발생한다`() { + shouldThrowWithMessage(message = INVALID_WINNER_NUMBERS_RANGE_MESSAGE) { + LottoWinnerNumbers(setOf(1,2,3,4,5,46)) + } + } + + @Test + fun `로또 당첨 번호가 6개가 아닐 경우 에러가 발생한다`() { + shouldThrowWithMessage(message = INVALID_WINNER_NUMBERS_COUNT_MESSAGE) { + LottoWinnerNumbers(setOf(1,2,3,4,5,6,7)) + } + } + + @MethodSource("구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공") + @ParameterizedTest + fun `구매한 로또 번호가 당첨 번호와 몇개가 일치하는지와 수익률 등 결과 확인 (3개부터)`( + purchasedCount: Int, + lottoNumbers: Set, + winnerNumbers: Set, + threeNumberMatchCount: Int, + fourNumberMatchCount: Int, + fiveNumberMatchCount: Int, + sixNumberMatchCount: Int, + profitMargin: Double, + ) { + val purchasedLottoTickets = + PurchasedLottoTickets(purchasedCount = purchasedCount, generateLottoNumbers = { lottoNumbers }) + val lottoWinnerNumbers = LottoWinnerNumbers(winnerNumbers = winnerNumbers) + val purchasedLottoResults = lottoWinnerNumbers.resultLottoPayout(purchasedLottoTickets) + + purchasedLottoResults.threeNumberMatchCount shouldBeEqual threeNumberMatchCount + purchasedLottoResults.fourNumberMatchCount shouldBeEqual fourNumberMatchCount + purchasedLottoResults.fiveNumberMatchCount shouldBeEqual fiveNumberMatchCount + purchasedLottoResults.sixNumberMatchCount shouldBeEqual sixNumberMatchCount + purchasedLottoResults.getProfitMargin() shouldBeEqual profitMargin + } + + fun `구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공`(): Stream { + return Stream.of( + Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), setOf(11, 15, 16, 17, 18, 19), 0, 0, 0, 0, 0.0), + Arguments.of(25, setOf(1, 2, 3, 4, 5, 6), setOf(4, 15, 16, 17, 18, 19), 0, 0, 0, 0, 0.0), + Arguments.of(35, setOf(1, 2, 3, 4, 5, 6), setOf(4, 5, 16, 17, 18, 19), 0, 0, 0, 0, 0.0), + Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), setOf(4, 5, 6, 7, 8, 9), 5, 0, 0, 0, 5.0), + Arguments.of(8, setOf(11, 12, 13, 14, 15, 16), setOf(13, 14, 15, 16, 17, 18), 0, 8, 0, 0, 50.0), + Arguments.of(3, setOf(21, 22, 23, 24, 25, 26), setOf(21, 22, 23, 24, 25, 1), 0, 0, 3, 0, 1500.0), + Arguments.of(1, setOf(31, 32, 33, 34, 35, 41), setOf(31, 32, 33, 34, 35, 41), 0, 0, 0, 1, 2000000.0), + ) + } +} diff --git a/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt b/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt index ca99541641..86d25b899d 100644 --- a/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt +++ b/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt @@ -1,17 +1,13 @@ package lotto.domain import io.kotest.assertions.throwables.shouldThrowWithMessage -import io.kotest.matchers.equals.shouldBeEqual import lotto.domain.PurchasedLottoResults.Companion.INVALID_LOTTO_MATCH_COUNT_MESSAGE import lotto.domain.PurchasedLottoResults.Companion.INVALID_PURCHASED_COUNT_LOTTO_MATCH_COUNT_MESSAGE import lotto.domain.PurchasedLottoTickets.Companion.INVALID_PURCHASED_COUNT_MESSAGE import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.CsvSource -import org.junit.jupiter.params.provider.MethodSource -import java.util.stream.Stream @TestInstance(TestInstance.Lifecycle.PER_CLASS) class PurchasedLottoResultsTest { @@ -77,40 +73,4 @@ class PurchasedLottoResultsTest { ) } } - - @MethodSource("구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공") - @ParameterizedTest - fun `구매한 로또 번호가 당첨 번호와 몇개가 일치하는지와 수익률 등 결과 확인 (3개부터)`( - purchasedCount: Int, - lottoNumbers: Set, - winnerNumbers: Set, - threeNumberMatchCount: Int, - fourNumberMatchCount: Int, - fiveNumberMatchCount: Int, - sixNumberMatchCount: Int, - profitMargin: Double, - ) { - val purchasedLottoTickets = - PurchasedLottoTickets(purchasedCount = purchasedCount, generateLottoNumbers = { lottoNumbers }) - val lottoWinnerNumbers = LottoWinnerNumbers(winnerNumbers = winnerNumbers) - val purchasedLottoResults = purchasedLottoTickets.resultLottoPayout(lottoWinnerNumbers) - - purchasedLottoResults.threeNumberMatchCount shouldBeEqual threeNumberMatchCount - purchasedLottoResults.fourNumberMatchCount shouldBeEqual fourNumberMatchCount - purchasedLottoResults.fiveNumberMatchCount shouldBeEqual fiveNumberMatchCount - purchasedLottoResults.sixNumberMatchCount shouldBeEqual sixNumberMatchCount - purchasedLottoResults.getProfitMargin() shouldBeEqual profitMargin - } - - fun `구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공`(): Stream { - return Stream.of( - Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), setOf(11, 15, 16, 17, 18, 19), 0, 0, 0, 0, 0.0), - Arguments.of(25, setOf(1, 2, 3, 4, 5, 6), setOf(4, 15, 16, 17, 18, 19), 0, 0, 0, 0, 0.0), - Arguments.of(35, setOf(1, 2, 3, 4, 5, 6), setOf(4, 5, 16, 17, 18, 19), 0, 0, 0, 0, 0.0), - Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), setOf(4, 5, 6, 7, 8, 9), 5, 0, 0, 0, 5.0), - Arguments.of(8, setOf(11, 12, 13, 14, 15, 16), setOf(13, 14, 15, 16, 17, 18), 0, 8, 0, 0, 50.0), - Arguments.of(3, setOf(21, 22, 23, 24, 25, 26), setOf(21, 22, 23, 24, 25, 1), 0, 0, 3, 0, 1500.0), - Arguments.of(1, setOf(31, 32, 33, 34, 35, 41), setOf(31, 32, 33, 34, 35, 41), 0, 0, 0, 1, 2000000.0), - ) - } } From 7da206a36aa92cc8bae3155e7ac3ed017fafc1e8 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:37:24 +0900 Subject: [PATCH 05/18] =?UTF-8?q?lottoTicket=20=EC=88=98=EB=8F=99=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90,=20=EC=9E=90=EB=8F=99=20=EB=A1=9C=EB=98=90?= =?UTF-8?q?=20sealed=20class=20=ED=99=9C=EC=9A=A9=20=EB=B0=8F=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/lotto/domain/AutoLottoIssuer.kt | 4 + .../lotto/domain/LottoNumberGenerator.kt | 11 +-- ...etIssuer.kt => LottoPurchaseCalculator.kt} | 16 ++-- src/main/kotlin/lotto/domain/LottoTicket.kt | 10 ++- src/main/kotlin/lotto/domain/LottoTickets.kt | 4 + .../lotto/domain/PurchasedLottoTickets.kt | 18 ----- src/main/kotlin/lotto/view/ManualLottoView.kt | 41 ++++++++++ .../lotto/view/PurchaseLottoResultView.kt | 13 --- .../view/util/SplitInputNumbersCommand.kt | 4 + .../lotto/domain/AutoLottoIssuerTest.kt | 4 + .../domain/LottoPurchaseCalculatorTest.kt | 4 + .../lotto/domain/LottoTicketIssuerTest.kt | 39 --------- .../kotlin/lotto/domain/LottoTicketTest.kt | 80 ++++++++++++------- .../lotto/domain/PurchasedLottoTicketsTest.kt | 16 ---- 14 files changed, 132 insertions(+), 132 deletions(-) create mode 100644 src/main/kotlin/lotto/domain/AutoLottoIssuer.kt rename src/main/kotlin/lotto/domain/{LottoTicketIssuer.kt => LottoPurchaseCalculator.kt} (68%) create mode 100644 src/main/kotlin/lotto/domain/LottoTickets.kt delete mode 100644 src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt create mode 100644 src/main/kotlin/lotto/view/ManualLottoView.kt delete mode 100644 src/main/kotlin/lotto/view/PurchaseLottoResultView.kt create mode 100644 src/main/kotlin/lotto/view/util/SplitInputNumbersCommand.kt create mode 100644 src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt create mode 100644 src/test/kotlin/lotto/domain/LottoPurchaseCalculatorTest.kt delete mode 100644 src/test/kotlin/lotto/domain/LottoTicketIssuerTest.kt delete mode 100644 src/test/kotlin/lotto/domain/PurchasedLottoTicketsTest.kt diff --git a/src/main/kotlin/lotto/domain/AutoLottoIssuer.kt b/src/main/kotlin/lotto/domain/AutoLottoIssuer.kt new file mode 100644 index 0000000000..cbf56bf83c --- /dev/null +++ b/src/main/kotlin/lotto/domain/AutoLottoIssuer.kt @@ -0,0 +1,4 @@ +package lotto.domain + +class AutoLottoIssuer { +} diff --git a/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt b/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt index 4ea5be9792..6cf8cbc82b 100644 --- a/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt +++ b/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt @@ -1,10 +1,7 @@ package lotto.domain -import lotto.domain.LottoNumber.Companion.LOTTO_NUMBER_MAX_VALUE -import lotto.domain.LottoNumber.Companion.LOTTO_NUMBER_MIN_VALUE -import lotto.domain.LottoNumbers.Companion.LOTTO_NUMBER_COUNT - -fun generateLottoNumbers(): Set { - return (LOTTO_NUMBER_MIN_VALUE..LOTTO_NUMBER_MAX_VALUE) - .toSet().shuffled().take(LOTTO_NUMBER_COUNT).sorted().toSet() +fun generateLottoNumbers(): LottoNumbers { + val randomNumbers = (LottoNumber.LOTTO_NUMBER_MIN_VALUE..LottoNumber.LOTTO_NUMBER_MAX_VALUE) + .shuffled().take(LottoNumbers.LOTTO_NUMBER_COUNT).sorted() + return LottoNumbers(randomNumbers.map { LottoNumber.of(it) }.toSet()) } diff --git a/src/main/kotlin/lotto/domain/LottoTicketIssuer.kt b/src/main/kotlin/lotto/domain/LottoPurchaseCalculator.kt similarity index 68% rename from src/main/kotlin/lotto/domain/LottoTicketIssuer.kt rename to src/main/kotlin/lotto/domain/LottoPurchaseCalculator.kt index 9613880c74..4ae91fb2ec 100644 --- a/src/main/kotlin/lotto/domain/LottoTicketIssuer.kt +++ b/src/main/kotlin/lotto/domain/LottoPurchaseCalculator.kt @@ -1,15 +1,13 @@ package lotto.domain -object LottoTicketIssuer { - fun issueTickets( - amountPaid: Int, - generateLottoNumbers: () -> Set, - ): PurchasedLottoTickets { +object LottoTicketIssuer2 { + fun issueTickets(lottoTicket: LottoTicket): PurchasedLottoTickets2 { + return PurchasedLottoTickets2() + } + + fun getMaxPurchasedLottoTicketCount(amountPaid: Int): Int { checkAmountPaid(amountPaid) - return PurchasedLottoTickets( - purchasedCount = (amountPaid / DEFAULT_LOTTO_PRICE), - generateLottoNumbers = generateLottoNumbers, - ) + return amountPaid / DEFAULT_LOTTO_PRICE } private fun checkAmountPaid(amountPaid: Int) { diff --git a/src/main/kotlin/lotto/domain/LottoTicket.kt b/src/main/kotlin/lotto/domain/LottoTicket.kt index e185922731..e4d491c015 100644 --- a/src/main/kotlin/lotto/domain/LottoTicket.kt +++ b/src/main/kotlin/lotto/domain/LottoTicket.kt @@ -1,11 +1,17 @@ package lotto.domain -data class LottoTicket(private val generateLottoNumbers: () -> Set) { - val lottoNumbers = LottoNumbers(generateLottoNumbers().map { LottoNumber.of(it) }.toSet()) +sealed class LottoTicket { + abstract val lottoNumbers: LottoNumbers fun checkLottoWinnerRank(lottoWinnerNumbers: LottoWinnerNumbers): LottoWinnerRank { val matchCount = lottoNumbers.checkLottoNumbersMatch(lottoWinnerNumbers.lottoNumbers) val bonusCheck = lottoNumbers.contains(lottoWinnerNumbers.bonusNumber) return LottoWinnerRank.getRankByMatches(matchCount = matchCount, bonusCheck = bonusCheck) } + + class ManualLottoTicket(override val lottoNumbers: LottoNumbers) : LottoTicket() + + class AutoLottoTicket(private val generateLottoNumbers: () -> LottoNumbers) : LottoTicket() { + override val lottoNumbers: LottoNumbers = generateLottoNumbers() + } } diff --git a/src/main/kotlin/lotto/domain/LottoTickets.kt b/src/main/kotlin/lotto/domain/LottoTickets.kt new file mode 100644 index 0000000000..82131f8b87 --- /dev/null +++ b/src/main/kotlin/lotto/domain/LottoTickets.kt @@ -0,0 +1,4 @@ +package lotto.domain + +class LottoTickets { +} diff --git a/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt b/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt deleted file mode 100644 index b8e3f5c62d..0000000000 --- a/src/main/kotlin/lotto/domain/PurchasedLottoTickets.kt +++ /dev/null @@ -1,18 +0,0 @@ -package lotto.domain - -data class PurchasedLottoTickets(val purchasedCount: Int, private val generateLottoNumbers: () -> Set) { - val purchasedLottoTickets: List - - init { - require(purchasedCount >= PURCHASED_COUNT_MIN_VALUE) { INVALID_PURCHASED_COUNT_MESSAGE } - purchasedLottoTickets = - List(purchasedCount) { - LottoTicket(generateLottoNumbers = generateLottoNumbers) - } - } - - companion object { - const val PURCHASED_COUNT_MIN_VALUE: Int = 1 - const val INVALID_PURCHASED_COUNT_MESSAGE: String = "최소한 로또 1장 이상 구입해야 합니다" - } -} diff --git a/src/main/kotlin/lotto/view/ManualLottoView.kt b/src/main/kotlin/lotto/view/ManualLottoView.kt new file mode 100644 index 0000000000..24fd902953 --- /dev/null +++ b/src/main/kotlin/lotto/view/ManualLottoView.kt @@ -0,0 +1,41 @@ +package lotto.view.util + +import lotto.domain.LottoNumbers +import lotto.domain.LottoTicket +import lotto.domain.LottoTicket2 +import lotto.domain.LottoTickets +import lotto.view.WinnerLottoNumberView + +object ManualLottoView { + fun inputManualLottoCount(maxPurchaseLottoCount: Int): Int { + println("\n수동으로 구매할 로또 수를 입력해 주세요.") + val inputManualLottoCountCommand: String? = readlnOrNull() + requireNotNull(inputManualLottoCountCommand) { "입력된 수동 로또 개수가 없습니다." } + + val inputManualLottoCount = inputManualLottoCountCommand.toIntOrNull() + requireNotNull(inputManualLottoCount) { "구입금액이 올바르게 입력되지 않았습니다." } + require(inputManualLottoCount >= 0) { "수동 로또 개수는 0개부터 입력 가능합니다." } + require(inputManualLottoCount <= maxPurchaseLottoCount) { "구입 가능한 수동 로또 개수를 초과했습니다." } + + return inputManualLottoCount + } + + fun repeatInputManualLottoNumbers(manualLottoCount: Int): LottoTickets { + println("\n수동으로 구매할 번호를 입력해 주세요.") + + val lottoNumbersList = mutableListOf() + repeat(manualLottoCount) { lottoNumbersList.add(inputManualLottoNumbers()) } + + val lottoTickets = lottoNumbersList.map { LottoTicket2(it) } + + return LottoTickets(lottoTickets) + } + + private fun inputManualLottoNumbers(): LottoNumbers { + val inputManualNumbersCommand: String? = readlnOrNull() + + requireNotNull(inputManualNumbersCommand) { "입력된 수동 번호가 없습니다." } + + return splitInputNumbersCommand(inputManualNumbersCommand) + } +} diff --git a/src/main/kotlin/lotto/view/PurchaseLottoResultView.kt b/src/main/kotlin/lotto/view/PurchaseLottoResultView.kt deleted file mode 100644 index ac88f716d2..0000000000 --- a/src/main/kotlin/lotto/view/PurchaseLottoResultView.kt +++ /dev/null @@ -1,13 +0,0 @@ -package lotto.view - -import lotto.domain.PurchasedLottoTickets - -object PurchaseLottoResultView { - fun displayPurchaseLottoResults(purchasedLottoTickets: PurchasedLottoTickets) { - println("${purchasedLottoTickets.purchasedCount}개를 구매했습니다.") - purchasedLottoTickets.purchasedLottoTickets.forEach { - lottoTicket -> - println(lottoTicket.lottoNumbers.getNumbers().joinToString(",")) - } - } -} diff --git a/src/main/kotlin/lotto/view/util/SplitInputNumbersCommand.kt b/src/main/kotlin/lotto/view/util/SplitInputNumbersCommand.kt new file mode 100644 index 0000000000..30bb93d5b7 --- /dev/null +++ b/src/main/kotlin/lotto/view/util/SplitInputNumbersCommand.kt @@ -0,0 +1,4 @@ +package lotto.view.util + +class SplitInputNumbersCommand { +} diff --git a/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt b/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt new file mode 100644 index 0000000000..55a19a40ab --- /dev/null +++ b/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt @@ -0,0 +1,4 @@ +package lotto.domain + +class AutoLottoIssuerTest { +} diff --git a/src/test/kotlin/lotto/domain/LottoPurchaseCalculatorTest.kt b/src/test/kotlin/lotto/domain/LottoPurchaseCalculatorTest.kt new file mode 100644 index 0000000000..e2a3af6d0d --- /dev/null +++ b/src/test/kotlin/lotto/domain/LottoPurchaseCalculatorTest.kt @@ -0,0 +1,4 @@ +package lotto.domain + +class LottoPurchaseCalculatorTest { +} diff --git a/src/test/kotlin/lotto/domain/LottoTicketIssuerTest.kt b/src/test/kotlin/lotto/domain/LottoTicketIssuerTest.kt deleted file mode 100644 index c8ae7a46da..0000000000 --- a/src/test/kotlin/lotto/domain/LottoTicketIssuerTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -package lotto.domain - -import io.kotest.assertions.throwables.shouldThrowWithMessage -import io.kotest.matchers.shouldBe -import lotto.domain.LottoTicketIssuer.INVALID_MIN_COST_LOTTO_PAID_MESSAGE -import lotto.domain.LottoTicketIssuer.INVALID_THOUSAND_UNIT_LOTTO_PAID_MESSAGE -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.CsvSource -import org.junit.jupiter.params.provider.ValueSource - -class LottoTicketIssuerTest { - @ParameterizedTest - @ValueSource(ints = [500, 999]) - fun `로또 구입 비용이 1,000원 미만일 경우 에러가 발생한다`(amountPaid: Int) { - shouldThrowWithMessage(message = INVALID_MIN_COST_LOTTO_PAID_MESSAGE) { - LottoTicketIssuer.issueTickets(amountPaid = amountPaid, generateLottoNumbers = { setOf(1, 2, 3, 4, 5, 6) }) - } - } - - @ParameterizedTest - @ValueSource(ints = [1500, 22200, 10500, 2100005]) - fun `로또 구입 비용이 1,000원 단위가 아닐 경우 에러가 발생한다`(amountPaid: Int) { - shouldThrowWithMessage(message = INVALID_THOUSAND_UNIT_LOTTO_PAID_MESSAGE) { - LottoTicketIssuer.issueTickets(amountPaid = amountPaid, generateLottoNumbers = { setOf(1, 2, 3, 4, 5, 6) }) - } - } - - @ParameterizedTest - @CsvSource("5000, 5", "1000, 1") - fun `로또 구입 비용에 대해 몇 장의 로또가 구입됐는지 확인활 수 있다`( - amountPaid: Int, - expectedTicketCount: Int, - ) { - val purchasedLottoTickets = - LottoTicketIssuer.issueTickets(amountPaid = amountPaid, generateLottoNumbers = { setOf(1, 2, 3, 4, 5, 6) }) - purchasedLottoTickets.purchasedCount shouldBe expectedTicketCount - purchasedLottoTickets.purchasedLottoTickets.size shouldBe expectedTicketCount - } -} diff --git a/src/test/kotlin/lotto/domain/LottoTicketTest.kt b/src/test/kotlin/lotto/domain/LottoTicketTest.kt index 14df047d64..8136c37a63 100644 --- a/src/test/kotlin/lotto/domain/LottoTicketTest.kt +++ b/src/test/kotlin/lotto/domain/LottoTicketTest.kt @@ -1,8 +1,9 @@ package lotto.domain -import io.kotest.assertions.throwables.shouldThrowWithMessage -import lotto.domain.LottoNumber.Companion.INVALID_LOTTO_NUMBER_MESSAGE -import lotto.domain.LottoNumbers.Companion.INVALID_LOTTO_NUMBER_COUNT_MESSAGE +import io.kotest.matchers.equals.shouldBeEqual +import lotto.domain.LottoTicket.AutoLottoTicket +import lotto.domain.LottoTicket.ManualLottoTicket +import lotto.util.createLottoNumbers import org.junit.jupiter.api.TestInstance import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments @@ -11,35 +12,58 @@ import java.util.stream.Stream @TestInstance(TestInstance.Lifecycle.PER_CLASS) class LottoTicketTest { - @MethodSource("7개 이상, 또는 6개 미만의 숫자 제공") + @MethodSource("구매한 로또의 번호, 당첨 번호, 매칭 결과 제공") @ParameterizedTest - fun `로또 번호는 숫자 6개가 아니면 에러가 발생한다`(numberSet: Set) { - shouldThrowWithMessage(message = INVALID_LOTTO_NUMBER_COUNT_MESSAGE) { - LottoTicket(generateLottoNumbers = { numberSet }) - } + fun `당첨 번호를 토대로 몇 등 인지 확인 할 수 있다`( + lottoTicket: LottoTicket, + lottoWinnerNumbers: LottoWinnerNumbers, + lottoWinnerRank: LottoWinnerRank, + ) { + lottoTicket.checkLottoWinnerRank(lottoWinnerNumbers) shouldBeEqual lottoWinnerRank } - fun `7개 이상, 또는 6개 미만의 숫자 제공`(): Stream { + fun `구매한 로또의 번호, 당첨 번호, 매칭 결과 제공`(): Stream { return Stream.of( - Arguments.of(setOf(5, 11, 15, 16, 17, 18, 19)), - Arguments.of(setOf(4, 5, 6, 7)), - Arguments.of(setOf(15, 16, 17, 18, 19)), - ) - } - - @MethodSource("1미만 46 이상의 숫자가 있는 로또 번호 제공") - @ParameterizedTest - fun `로또 번호는 1부터 45사이의 숫자가 아니면 에러가 발생한다`(numberSet: Set) { - shouldThrowWithMessage(message = INVALID_LOTTO_NUMBER_MESSAGE) { - LottoTicket(generateLottoNumbers = { numberSet }) - } - } - - fun `1미만 46 이상의 숫자가 있는 로또 번호 제공`(): Stream { - return Stream.of( - Arguments.of(setOf(0, 11, 15, 1, 2, 3)), - Arguments.of(setOf(14, 15, 46, 7, 4, 5)), - Arguments.of(setOf(15, 16, 17, 18, -3, 1)), + Arguments.of( + ManualLottoTicket(createLottoNumbers(1, 2, 3, 4, 5, 6)), + LottoWinnerNumbers(createLottoNumbers(1, 2, 3, 4, 5, 6), LottoNumber.of(7)), + LottoWinnerRank.FIRST, + ), + Arguments.of( + ManualLottoTicket(createLottoNumbers(1, 2, 3, 4, 5, 6)), + LottoWinnerNumbers(createLottoNumbers(1, 2, 3, 4, 5, 7), LottoNumber.of(6)), + LottoWinnerRank.SECOND, + ), + Arguments.of( + AutoLottoTicket { createLottoNumbers(1, 2, 3, 4, 5, 6) }, + LottoWinnerNumbers(createLottoNumbers(1, 2, 3, 4, 5, 8), LottoNumber.of(7)), + LottoWinnerRank.THIRD, + ), + Arguments.of( + ManualLottoTicket(createLottoNumbers(1, 2, 3, 4, 5, 6)), + LottoWinnerNumbers(createLottoNumbers(1, 2, 3, 4, 8, 9), LottoNumber.of(7)), + LottoWinnerRank.FOURTH, + ), + Arguments.of( + AutoLottoTicket { createLottoNumbers(1, 2, 3, 4, 5, 6) }, + LottoWinnerNumbers(createLottoNumbers(1, 2, 3, 8, 9, 10), LottoNumber.of(7)), + LottoWinnerRank.FIFTH, + ), + Arguments.of( + ManualLottoTicket(createLottoNumbers(1, 2, 3, 4, 5, 6)), + LottoWinnerNumbers(createLottoNumbers(1, 2, 8, 9, 10, 11), LottoNumber.of(7)), + LottoWinnerRank.MISS, + ), + Arguments.of( + AutoLottoTicket { createLottoNumbers(1, 2, 3, 4, 5, 6) }, + LottoWinnerNumbers(createLottoNumbers(1, 8, 9, 10, 11, 12), LottoNumber.of(7)), + LottoWinnerRank.MISS, + ), + Arguments.of( + ManualLottoTicket(createLottoNumbers(1, 2, 3, 4, 5, 6)), + LottoWinnerNumbers(createLottoNumbers(8, 9, 10, 11, 12, 13), LottoNumber.of(7)), + LottoWinnerRank.MISS, + ), ) } } diff --git a/src/test/kotlin/lotto/domain/PurchasedLottoTicketsTest.kt b/src/test/kotlin/lotto/domain/PurchasedLottoTicketsTest.kt deleted file mode 100644 index 130b2f986d..0000000000 --- a/src/test/kotlin/lotto/domain/PurchasedLottoTicketsTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package lotto.domain - -import io.kotest.assertions.throwables.shouldThrowWithMessage -import lotto.domain.PurchasedLottoTickets.Companion.INVALID_PURCHASED_COUNT_MESSAGE -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource - -class PurchasedLottoTicketsTest { - @ParameterizedTest - @ValueSource(ints = [0, -1, -100]) - fun `구매한 로또 티켓 개수가 1개 미만일 경우 에러가 발생한다 `(purchasedCount: Int) { - shouldThrowWithMessage(message = INVALID_PURCHASED_COUNT_MESSAGE) { - PurchasedLottoTickets(purchasedCount = purchasedCount, generateLottoNumbers = { setOf(1, 2, 3, 4, 5, 6) }) - } - } -} From 83f7e25cee45d2a2df4285dafecd40dba3409187 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:38:41 +0900 Subject: [PATCH 06/18] =?UTF-8?q?lottoTicket=EB=93=A4=EC=9D=84=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EB=8A=94=20=EC=9D=BC=EA=B8=89=20=EC=BB=AC?= =?UTF-8?q?=EB=A0=89=EC=85=98=20LottoTickets=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/domain/LottoTickets.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/kotlin/lotto/domain/LottoTickets.kt b/src/main/kotlin/lotto/domain/LottoTickets.kt index 82131f8b87..aa59279031 100644 --- a/src/main/kotlin/lotto/domain/LottoTickets.kt +++ b/src/main/kotlin/lotto/domain/LottoTickets.kt @@ -1,4 +1,3 @@ package lotto.domain -class LottoTickets { -} +data class LottoTickets(val lottoTickets: List) From c5e644191762fedce00d0db0040bf0bd6e3525a5 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:39:59 +0900 Subject: [PATCH 07/18] =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8?= =?UTF-8?q?=20=EC=9E=90=EB=8F=99=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/lotto/domain/LottoNumberGenerator.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt b/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt index 6cf8cbc82b..428171fa71 100644 --- a/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt +++ b/src/main/kotlin/lotto/domain/LottoNumberGenerator.kt @@ -1,7 +1,13 @@ package lotto.domain -fun generateLottoNumbers(): LottoNumbers { - val randomNumbers = (LottoNumber.LOTTO_NUMBER_MIN_VALUE..LottoNumber.LOTTO_NUMBER_MAX_VALUE) - .shuffled().take(LottoNumbers.LOTTO_NUMBER_COUNT).sorted() - return LottoNumbers(randomNumbers.map { LottoNumber.of(it) }.toSet()) +object LottoNumberGenerator { + fun generateAutoLottoNumbers(): LottoNumbers { + val randomNumbers = generatorRandomNumber() + return LottoNumbers(randomNumbers.map { LottoNumber.of(it) }.toSet()) + } + + fun generatorRandomNumber(): List { + return (LottoNumber.LOTTO_NUMBER_MIN_VALUE..LottoNumber.LOTTO_NUMBER_MAX_VALUE) + .shuffled().take(LottoNumbers.LOTTO_NUMBER_COUNT).sorted() + } } From 38ef9bf132f84959ab42b1c7fcbe4db2850279f3 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:41:35 +0900 Subject: [PATCH 08/18] =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EA=B5=AC=EC=9E=85?= =?UTF-8?q?=20=EB=B9=84=EC=9A=A9=EC=9D=84=20=ED=86=A0=EB=8C=80=EB=A1=9C=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EA=B5=AC=EB=A7=A4=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B6=84=EB=A6=AC=20LottoPurchas?= =?UTF-8?q?eCalculator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lotto/domain/LottoPurchaseCalculator.kt | 10 ++---- .../domain/LottoPurchaseCalculatorTest.kt | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/lotto/domain/LottoPurchaseCalculator.kt b/src/main/kotlin/lotto/domain/LottoPurchaseCalculator.kt index 4ae91fb2ec..714ce1363c 100644 --- a/src/main/kotlin/lotto/domain/LottoPurchaseCalculator.kt +++ b/src/main/kotlin/lotto/domain/LottoPurchaseCalculator.kt @@ -1,10 +1,6 @@ package lotto.domain -object LottoTicketIssuer2 { - fun issueTickets(lottoTicket: LottoTicket): PurchasedLottoTickets2 { - return PurchasedLottoTickets2() - } - +object LottoPurchaseCalculator { fun getMaxPurchasedLottoTicketCount(amountPaid: Int): Int { checkAmountPaid(amountPaid) return amountPaid / DEFAULT_LOTTO_PRICE @@ -17,6 +13,6 @@ object LottoTicketIssuer2 { const val DEFAULT_LOTTO_PRICE: Int = 1000 private const val CHECK_SURPLUS: Int = 0 - const val INVALID_MIN_COST_LOTTO_PAID_MESSAGE: String = "로또 구입 비용은 최소 1,000원 이상 이어야 합니다" - const val INVALID_THOUSAND_UNIT_LOTTO_PAID_MESSAGE: String = "로또 구입 비용은 1,000원 단위로 지불해야 합니다" + private const val INVALID_MIN_COST_LOTTO_PAID_MESSAGE: String = "로또 구입 비용은 최소 1,000원 이상 이어야 합니다" + private const val INVALID_THOUSAND_UNIT_LOTTO_PAID_MESSAGE: String = "로또 구입 비용은 1,000원 단위로 지불해야 합니다" } diff --git a/src/test/kotlin/lotto/domain/LottoPurchaseCalculatorTest.kt b/src/test/kotlin/lotto/domain/LottoPurchaseCalculatorTest.kt index e2a3af6d0d..f8a60ae033 100644 --- a/src/test/kotlin/lotto/domain/LottoPurchaseCalculatorTest.kt +++ b/src/test/kotlin/lotto/domain/LottoPurchaseCalculatorTest.kt @@ -1,4 +1,36 @@ package lotto.domain +import io.kotest.assertions.throwables.shouldThrowWithMessage +import io.kotest.matchers.equals.shouldBeEqual +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource + class LottoPurchaseCalculatorTest { + @ParameterizedTest + @CsvSource( + "1000, 1", + "11000, 11", + "5000, 5", + ) + fun `로또 구입 비용을 토대로 최대 몇장의 로또를 구입할 수 있는지 계산할 수 있다`( + amountPaid: Int, + purchasedLottoTicketCount: Int, + ) { + LottoPurchaseCalculator.getMaxPurchasedLottoTicketCount(amountPaid) shouldBeEqual purchasedLottoTicketCount + } + + @Test + fun `최소한의 로또 구입 비용을 지불하지 않으면 에러가 발생한다`() { + shouldThrowWithMessage(message = "로또 구입 비용은 최소 1,000원 이상 이어야 합니다") { + LottoPurchaseCalculator.getMaxPurchasedLottoTicketCount(999) + } + } + + @Test + fun `로또 구입 비용이 1,000원 단위가 아닐 시 에러가 발생한다`() { + shouldThrowWithMessage(message = "로또 구입 비용은 1,000원 단위로 지불해야 합니다") { + LottoPurchaseCalculator.getMaxPurchasedLottoTicketCount(1500) + } + } } From 69907e7575fcfda52295cb575fca512346077dbf Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:42:45 +0900 Subject: [PATCH 09/18] =?UTF-8?q?=EC=9D=BC=EA=B8=89=20=EC=BB=AC=EB=A0=89?= =?UTF-8?q?=EC=85=98=20LottoTickets=20=EC=B6=94=EA=B0=80=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/lotto/domain/LottoWinnerNumbers.kt | 6 +- .../lotto/domain/LottoWinnerNumbersTest.kt | 118 ++++++++++++++---- 2 files changed, 98 insertions(+), 26 deletions(-) diff --git a/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt b/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt index 91c8bc9b77..387928fa37 100644 --- a/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt +++ b/src/main/kotlin/lotto/domain/LottoWinnerNumbers.kt @@ -5,15 +5,15 @@ data class LottoWinnerNumbers(val lottoNumbers: LottoNumbers, val bonusNumber: L require(!lottoNumbers.contains(bonusNumber)) { INVALID_WINNER_NUMBERS_MESSAGE } } - fun resultLottoPayout(purchasedLottoTickets: PurchasedLottoTickets): PurchasedLottoResults { + fun resultLottoPayout(lottoTickets: LottoTickets): PurchasedLottoResults { val rankCounts: Map = - purchasedLottoTickets.purchasedLottoTickets + lottoTickets.lottoTickets .map { lottoTicket -> lottoTicket.checkLottoWinnerRank(this) } .groupingBy { it } .eachCount() return PurchasedLottoResults( - purchasedCount = purchasedLottoTickets.purchasedCount, + purchasedCount = lottoTickets.lottoTickets.size, firstRankCount = rankCounts[LottoWinnerRank.FIRST] ?: 0, secondRankCount = rankCounts[LottoWinnerRank.SECOND] ?: 0, thirdRankCount = rankCounts[LottoWinnerRank.THIRD] ?: 0, diff --git a/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt b/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt index 73c37c6aff..40cfb20d4f 100644 --- a/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt +++ b/src/test/kotlin/lotto/domain/LottoWinnerNumbersTest.kt @@ -4,6 +4,7 @@ import io.kotest.assertions.throwables.shouldThrowWithMessage import io.kotest.matchers.equals.shouldBeEqual import lotto.domain.LottoNumber.Companion.INVALID_LOTTO_NUMBER_MESSAGE import lotto.domain.LottoNumbers.Companion.INVALID_LOTTO_NUMBER_COUNT_MESSAGE +import lotto.domain.LottoTicket.ManualLottoTicket import lotto.domain.LottoWinnerNumbers.Companion.INVALID_WINNER_NUMBERS_MESSAGE import lotto.util.createLottoNumbers import org.junit.jupiter.api.Test @@ -36,13 +37,12 @@ class LottoWinnerNumbersTest { } } - @MethodSource("구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공") + @MethodSource("당첨 로또 번호, 보너스 번호, 구매한 로또 티켓, 매칭 결과 및 수익률 제공") @ParameterizedTest - fun `구매한 로또 번호가 당첨 번호와 몇개가 일치하는지와 수익률 등 결과 확인 (3개부터)`( - purchasedCount: Int, - lottoNumbers: Set, - winnerNumbers: Set, + fun `구매한 로또 번호가 당첨 번호와 몇개가 일치하는지와 수익률 등 결과 확인`( + winnerNumbers: LottoNumbers, bonusNumber: Int, + purchasedLottoTickets: LottoTickets, firstRankCount: Int, secondRankCount: Int, thirdRankCount: Int, @@ -50,15 +50,7 @@ class LottoWinnerNumbersTest { fifthRankCount: Int, profitMargin: Double, ) { - val purchasedLottoTickets = - PurchasedLottoTickets(purchasedCount = purchasedCount, generateLottoNumbers = { lottoNumbers }) - - val lottoWinnerNumbers = - LottoWinnerNumbers( - lottoNumbers = LottoNumbers(winnerNumbers.map { LottoNumber.of(it) }.toSet()), - bonusNumber = LottoNumber.of(bonusNumber), - ) - + val lottoWinnerNumbers = LottoWinnerNumbers(winnerNumbers, LottoNumber.of(bonusNumber)) val purchasedLottoResults = lottoWinnerNumbers.resultLottoPayout(purchasedLottoTickets) purchasedLottoResults.firstRankCount shouldBeEqual firstRankCount @@ -69,16 +61,96 @@ class LottoWinnerNumbersTest { purchasedLottoResults.getProfitMargin() shouldBeEqual profitMargin } - fun `구매한 로또의 번호 및 당첨 번호, 매칭 결과 및 수익률 제공`(): Stream { + fun `당첨 로또 번호, 보너스 번호, 구매한 로또 티켓, 매칭 결과 및 수익률 제공`(): Stream { return Stream.of( - Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), setOf(11, 15, 16, 17, 18, 19), 3, 0, 0, 0, 0, 0, 0.0), - Arguments.of(25, setOf(1, 2, 3, 4, 5, 6), setOf(4, 15, 16, 17, 18, 19), 7, 0, 0, 0, 0, 0, 0.0), - Arguments.of(35, setOf(1, 2, 3, 4, 5, 6), setOf(4, 5, 16, 17, 18, 19), 20, 0, 0, 0, 0, 0, 0.0), - Arguments.of(5, setOf(1, 2, 3, 4, 5, 6), setOf(4, 5, 6, 7, 8, 9), 21, 0, 0, 0, 0, 5, 5.0), - Arguments.of(8, setOf(11, 12, 13, 14, 15, 16), setOf(13, 14, 15, 16, 17, 18), 22, 0, 0, 0, 8, 0, 50.0), - Arguments.of(3, setOf(21, 22, 23, 24, 25, 26), setOf(21, 22, 23, 24, 25, 1), 2, 0, 0, 3, 0, 0, 1500.0), - Arguments.of(3, setOf(21, 22, 23, 24, 25, 26), setOf(21, 22, 23, 24, 25, 1), 26, 0, 3, 0, 0, 0, 30000.0), - Arguments.of(1, setOf(31, 32, 33, 34, 35, 41), setOf(31, 32, 33, 34, 35, 41), 9, 1, 0, 0, 0, 0, 2000000.0), + Arguments.of( + createLottoNumbers(1, 2, 3, 4, 5, 6), + 7, + LottoTickets(listOf(ManualLottoTicket(createLottoNumbers(1, 2, 3, 4, 5, 6)))), + 1, + 0, + 0, + 0, + 0, + 2000000.0, + ), + Arguments.of( + createLottoNumbers(1, 2, 3, 4, 5, 6), + 7, + LottoTickets(listOf(ManualLottoTicket(createLottoNumbers(1, 2, 3, 4, 5, 7)))), + 0, + 1, + 0, + 0, + 0, + 30000.0, + ), + Arguments.of( + createLottoNumbers(1, 2, 3, 4, 5, 6), + 7, + LottoTickets(listOf(ManualLottoTicket(createLottoNumbers(1, 2, 3, 4, 5, 8)))), + 0, + 0, + 1, + 0, + 0, + 1500.0, + ), + Arguments.of( + createLottoNumbers(1, 2, 3, 4, 5, 6), + 7, + LottoTickets(listOf(ManualLottoTicket(createLottoNumbers(1, 2, 3, 4, 8, 9)))), + 0, + 0, + 0, + 1, + 0, + 50.0, + ), + Arguments.of( + createLottoNumbers(1, 2, 3, 4, 5, 6), + 7, + LottoTickets(listOf(ManualLottoTicket(createLottoNumbers(1, 2, 3, 8, 9, 10)))), + 0, + 0, + 0, + 0, + 1, + 5.0, + ), + Arguments.of( + createLottoNumbers(1, 2, 3, 4, 5, 6), + 7, + LottoTickets(listOf(ManualLottoTicket(createLottoNumbers(1, 2, 8, 9, 10, 11)))), + 0, + 0, + 0, + 0, + 0, + 0.0, + ), + Arguments.of( + createLottoNumbers(1, 2, 3, 4, 5, 6), + 7, + LottoTickets(listOf(ManualLottoTicket(createLottoNumbers(1, 8, 9, 10, 11, 12)))), + 0, + 0, + 0, + 0, + 0, + 0.0, + ), + Arguments.of( + createLottoNumbers(1, 2, 3, 4, 5, 6), + 7, + LottoTickets(listOf(ManualLottoTicket(createLottoNumbers(8, 9, 10, 11, 12, 13)))), + 0, + 0, + 0, + 0, + 0, + 0.0, + ), ) } } From 7c6c04fbf0e375ab57cfef45cc6c8baf1fb25f0b Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:44:14 +0900 Subject: [PATCH 10/18] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20Pu?= =?UTF-8?q?rchasedLottoTickets=20=EC=82=AD=EC=A0=9C=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/domain/PurchasedLottoResults.kt | 6 +++--- src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt b/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt index e1e60d4935..8440b0a800 100644 --- a/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt +++ b/src/main/kotlin/lotto/domain/PurchasedLottoResults.kt @@ -1,8 +1,6 @@ package lotto.domain -import lotto.domain.LottoTicketIssuer.DEFAULT_LOTTO_PRICE -import lotto.domain.PurchasedLottoTickets.Companion.INVALID_PURCHASED_COUNT_MESSAGE -import lotto.domain.PurchasedLottoTickets.Companion.PURCHASED_COUNT_MIN_VALUE +import lotto.domain.LottoPurchaseCalculator.DEFAULT_LOTTO_PRICE data class PurchasedLottoResults( val purchasedCount: Int, @@ -38,6 +36,8 @@ data class PurchasedLottoResults( companion object { const val LOTTO_MATCH_COUNT_MIN_VALUE: Int = 0 + const val PURCHASED_COUNT_MIN_VALUE: Int = 1 + const val INVALID_PURCHASED_COUNT_MESSAGE: String = "구입한 로또 개수가 올바르지 않습니다" const val INVALID_LOTTO_MATCH_COUNT_MESSAGE: String = "로또 당첨 번호 매치 결과는 0 이상 이어야합니다" const val INVALID_PURCHASED_COUNT_LOTTO_MATCH_COUNT_MESSAGE: String = "당첨된 내역의 합이 구매한 개수보다 많을 수 없습니다" } diff --git a/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt b/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt index 1777be765c..ddaebe7ed9 100644 --- a/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt +++ b/src/test/kotlin/lotto/domain/PurchasedLottoResultsTest.kt @@ -3,7 +3,6 @@ package lotto.domain import io.kotest.assertions.throwables.shouldThrowWithMessage import lotto.domain.PurchasedLottoResults.Companion.INVALID_LOTTO_MATCH_COUNT_MESSAGE import lotto.domain.PurchasedLottoResults.Companion.INVALID_PURCHASED_COUNT_LOTTO_MATCH_COUNT_MESSAGE -import lotto.domain.PurchasedLottoTickets.Companion.INVALID_PURCHASED_COUNT_MESSAGE import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.junit.jupiter.params.ParameterizedTest @@ -13,7 +12,7 @@ import org.junit.jupiter.params.provider.CsvSource class PurchasedLottoResultsTest { @Test fun `로또 구매 개수가 1개 미만 일 경우 에러가 발생한다`() { - shouldThrowWithMessage(message = INVALID_PURCHASED_COUNT_MESSAGE) { + shouldThrowWithMessage(message = "구입한 로또 개수가 올바르지 않습니다") { PurchasedLottoResults( purchasedCount = 0, firstRankCount = 0, From 47ff7e366a0652a9116f044a44c0349213a20713 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:45:06 +0900 Subject: [PATCH 11/18] =?UTF-8?q?LottoNumberGenerator=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/lotto/domain/LottoNumberGeneratorTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/kotlin/lotto/domain/LottoNumberGeneratorTest.kt b/src/test/kotlin/lotto/domain/LottoNumberGeneratorTest.kt index 5062f8dac5..cff7ae0e36 100644 --- a/src/test/kotlin/lotto/domain/LottoNumberGeneratorTest.kt +++ b/src/test/kotlin/lotto/domain/LottoNumberGeneratorTest.kt @@ -6,6 +6,6 @@ import org.junit.jupiter.api.Test class LottoNumberGeneratorTest { @Test fun `로또 번호 자동 생성은 1부터 45사이의 6개의 숫자로 이루어져야한다`() { - (1..45).toSet().containsAll(generateLottoNumbers()) shouldBeEqual true + (1..45).toSet().containsAll(LottoNumberGenerator.generatorRandomNumber()) shouldBeEqual true } } From feb0e89831fc6da342a609b1160343fbe68a3525 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:46:21 +0900 Subject: [PATCH 12/18] =?UTF-8?q?=EC=9E=90=EB=8F=99=20=EB=A1=9C=EB=98=90?= =?UTF-8?q?=20=EB=B0=9C=EA=B8=89=20=EA=B8=B0=EB=8A=A5=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20AutoLottoIssuer=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/domain/AutoLottoIssuer.kt | 12 +++++++++++- src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/lotto/domain/AutoLottoIssuer.kt b/src/main/kotlin/lotto/domain/AutoLottoIssuer.kt index cbf56bf83c..6cb688deb7 100644 --- a/src/main/kotlin/lotto/domain/AutoLottoIssuer.kt +++ b/src/main/kotlin/lotto/domain/AutoLottoIssuer.kt @@ -1,4 +1,14 @@ package lotto.domain -class AutoLottoIssuer { +object AutoLottoIssuer { + fun issueAutoLottoTickets( + autoLottoCount: Int, + generateLottoNumbers: () -> LottoNumbers, + ): LottoTickets { + val autoLottoTickets = mutableListOf() + + repeat(autoLottoCount) { autoLottoTickets.add(LottoTicket.AutoLottoTicket { generateLottoNumbers() }) } + + return LottoTickets(autoLottoTickets) + } } diff --git a/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt b/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt index 55a19a40ab..6bfa0664b0 100644 --- a/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt +++ b/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt @@ -1,4 +1,13 @@ package lotto.domain +import io.kotest.matchers.equals.shouldBeEqual +import lotto.util.createLottoNumbers +import org.junit.jupiter.api.Test + class AutoLottoIssuerTest { + @Test + fun `정해진 개수 만큼 자동 로또를 생성 할 수 있다`() { + val lottoTickets = AutoLottoIssuer.issueAutoLottoTickets(3) { createLottoNumbers(1, 2, 3, 4, 5, 6) } + lottoTickets.lottoTickets.size shouldBeEqual 3 + } } From 9da2ccd35f29397bd26848dff0c4729019115990 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:47:51 +0900 Subject: [PATCH 13/18] =?UTF-8?q?=EC=88=98=EB=8F=99=20=EB=A1=9C=EB=98=90?= =?UTF-8?q?=20=EA=B5=AC=EC=9E=85=20view=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?= =?UTF-8?q?=20=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8=20split=20util=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/view/ManualLottoView.kt | 9 +++---- .../view/util/SplitInputNumbersCommand.kt | 27 ++++++++++++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/lotto/view/ManualLottoView.kt b/src/main/kotlin/lotto/view/ManualLottoView.kt index 24fd902953..2bfb30ec9b 100644 --- a/src/main/kotlin/lotto/view/ManualLottoView.kt +++ b/src/main/kotlin/lotto/view/ManualLottoView.kt @@ -1,10 +1,9 @@ -package lotto.view.util +package lotto.view import lotto.domain.LottoNumbers -import lotto.domain.LottoTicket -import lotto.domain.LottoTicket2 +import lotto.domain.LottoTicket.ManualLottoTicket import lotto.domain.LottoTickets -import lotto.view.WinnerLottoNumberView +import lotto.view.util.splitInputNumbersCommand object ManualLottoView { fun inputManualLottoCount(maxPurchaseLottoCount: Int): Int { @@ -26,7 +25,7 @@ object ManualLottoView { val lottoNumbersList = mutableListOf() repeat(manualLottoCount) { lottoNumbersList.add(inputManualLottoNumbers()) } - val lottoTickets = lottoNumbersList.map { LottoTicket2(it) } + val lottoTickets = lottoNumbersList.map { ManualLottoTicket(it) } return LottoTickets(lottoTickets) } diff --git a/src/main/kotlin/lotto/view/util/SplitInputNumbersCommand.kt b/src/main/kotlin/lotto/view/util/SplitInputNumbersCommand.kt index 30bb93d5b7..466e8deb8f 100644 --- a/src/main/kotlin/lotto/view/util/SplitInputNumbersCommand.kt +++ b/src/main/kotlin/lotto/view/util/SplitInputNumbersCommand.kt @@ -1,4 +1,29 @@ package lotto.view.util -class SplitInputNumbersCommand { +import lotto.domain.LottoNumber +import lotto.domain.LottoNumbers + +fun splitInputNumbersCommand(inputNumbersCommand: String): LottoNumbers { + require(inputNumbersCommand.isNotBlank()) { INVALID_BLANK_NUMBERS_MESSAGE } + require(inputNumbersCommand.contains(NUMBERS_DELIMITER)) { + INVALID_DELIMITER_NUMBERS_MESSAGE + } + + val lottoNumbers = + inputNumbersCommand.split(NUMBERS_DELIMITER) + .map { lottoNumberStringToInt(numberString = it.trim()) } + .toSet() + + return LottoNumbers(lottoNumbers) } + +private fun lottoNumberStringToInt(numberString: String): LottoNumber { + val lottoNumberOrNull = numberString.toIntOrNull() + requireNotNull(lottoNumberOrNull) { INVALID_NUMBERS_TO_INT_MESSAGE } + return LottoNumber.of(lottoNumberOrNull) +} + +const val INVALID_BLANK_NUMBERS_MESSAGE: String = "입력된 로또 번호가 공백입니다" +const val INVALID_DELIMITER_NUMBERS_MESSAGE: String = "로또 번호 구분자가 올바르지 않습니다" +const val NUMBERS_DELIMITER: String = "," +const val INVALID_NUMBERS_TO_INT_MESSAGE: String = "로또 번호가 숫자로 입력되지 않았습니다" From b7023611ff1c714d674fa79ccecb3bf41aa9fda0 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:49:07 +0900 Subject: [PATCH 14/18] =?UTF-8?q?=EC=88=98=EB=8F=99=20=EA=B5=AC=EB=A7=A4?= =?UTF-8?q?=20=EB=B0=98=EC=98=81=EC=97=90=20=EB=94=B0=EB=A5=B8=20PurchaseL?= =?UTF-8?q?ottoView=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/lotto/view/PurchaseLottoView.kt | 15 ++++++ .../lotto/view/WinnerLottoNumberView.kt | 50 ++++--------------- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/main/kotlin/lotto/view/PurchaseLottoView.kt b/src/main/kotlin/lotto/view/PurchaseLottoView.kt index f3c10d8979..65a5006e43 100644 --- a/src/main/kotlin/lotto/view/PurchaseLottoView.kt +++ b/src/main/kotlin/lotto/view/PurchaseLottoView.kt @@ -1,11 +1,26 @@ package lotto.view +import lotto.domain.LottoTickets + object PurchaseLottoView { fun inputPurchaseCost(): Int { println("구입금액을 입력해 주세요.") val inputCost: String? = readlnOrNull() requireNotNull(inputCost) { "구입금액이 입력되지 않았습니다" } requireNotNull(inputCost.toIntOrNull()) { "구입금액이 올바르게 입력되지 않았습니다" } + return inputCost.toInt() } + + fun displayPurchasedLottosView( + manualLottoTickets: LottoTickets, + autoLottoTickets: LottoTickets, + ) { + val manualLottoCount = manualLottoTickets.lottoTickets.size + val autoLottoCount = autoLottoTickets.lottoTickets.size + println("\n수동으로 ${manualLottoCount}장, 자동으로 ${autoLottoCount}개를 구매했습니다.") + + manualLottoTickets.lottoTickets.forEach { println(it.lottoNumbers.getNumbers()) } + autoLottoTickets.lottoTickets.forEach { println(it.lottoNumbers.getNumbers()) } + } } diff --git a/src/main/kotlin/lotto/view/WinnerLottoNumberView.kt b/src/main/kotlin/lotto/view/WinnerLottoNumberView.kt index 0902ce0418..2265279c67 100644 --- a/src/main/kotlin/lotto/view/WinnerLottoNumberView.kt +++ b/src/main/kotlin/lotto/view/WinnerLottoNumberView.kt @@ -1,56 +1,28 @@ package lotto.view +import lotto.domain.LottoNumber +import lotto.domain.LottoNumbers +import lotto.view.util.splitInputNumbersCommand + object WinnerLottoNumberView { - fun inputWinningLottoNumbers(): Set { + fun inputWinningLottoNumbers(): LottoNumbers { println("\n지난 주 당첨 번호를 입력해 주세요.") val inputWinnerNumbersCommand: String? = readlnOrNull() requireNotNull(inputWinnerNumbersCommand) { INVALID_NULL_OR_BLANK_WINNER_NUMBERS_MESSAGE } - val splitInputWinnerNumbers = splitInputWinnerNumbersCommand(inputWinnerNumbersCommand) - require(splitInputWinnerNumbers.size == 6) { INVALID_WINNER_NUMBERS_COUNT_MESSAGE } - return splitInputWinnerNumbers + return splitInputNumbersCommand(inputWinnerNumbersCommand) } - fun inputBonusNumber(): Int { + fun inputBonusNumber(): LottoNumber { println("보너스 볼을 입력해 주세요.") val inputBonusNumberCommand: String? = readlnOrNull() requireNotNull(inputBonusNumberCommand) { INVALID_NULL_OR_BLANK_BONUS_NUMBERS_MESSAGE } val inputBonusNumber = inputBonusNumberCommand.toIntOrNull() requireNotNull(inputBonusNumber) { INVALID_BONUS_NUMBERS_MESSAGE } - return inputBonusNumber - } - - private fun splitInputWinnerNumbersCommand(inputWinnerNumbersCommand: String): Set { - require(inputWinnerNumbersCommand.isNotBlank()) { INVALID_BLANK_WINNER_NUMBERS_MESSAGE } - require(inputWinnerNumbersCommand.contains(WINNER_NUMBERS_DELIMITER)) { - INVALID_DELIMITER_WINNER_NUMBERS_MESSAGE - } - - return inputWinnerNumbersCommand.split(WINNER_NUMBERS_DELIMITER) - .map { inputWinnerNumber -> lottoNumberStringToInt(numberString = inputWinnerNumber.trim()) } - .toSet() - } - - private fun lottoNumberStringToInt(numberString: String): Int { - val lottoNumberOrNull = numberString.toIntOrNull() - - requireNotNull(lottoNumberOrNull) { INVALID_WINNER_NUMBERS_TO_INT_MESSAGE } - require((LOTTO_NUMBER_MIN_VALUE..LOTTO_NUMBER_MAX_VALUE).toSet().contains(lottoNumberOrNull)) { - INVALID_WINNER_NUMBERS_LOTTO_RANGE_MESSAGE - } - - return lottoNumberOrNull + return LottoNumber.of(inputBonusNumber) } - const val INVALID_NULL_OR_BLANK_WINNER_NUMBERS_MESSAGE: String = "입력된 로또 당첨 번호가 없습니다" - const val INVALID_NULL_OR_BLANK_BONUS_NUMBERS_MESSAGE: String = "입력된 보너스 번호가 없습니다" - const val INVALID_BONUS_NUMBERS_MESSAGE: String = "입력된 보너스 번호가 올바르지 않습니다" - const val INVALID_BLANK_WINNER_NUMBERS_MESSAGE: String = "입력된 로또 당첨 번호가 공백입니다" - const val INVALID_DELIMITER_WINNER_NUMBERS_MESSAGE: String = "로또 당첨 번호 구분자가 올바르지 않습니다" - const val WINNER_NUMBERS_DELIMITER: String = "," - const val INVALID_WINNER_NUMBERS_TO_INT_MESSAGE: String = "로또 당첨 번호가 숫자로 입력되지 않았습니다" - const val INVALID_WINNER_NUMBERS_LOTTO_RANGE_MESSAGE: String = "로또 당첨 번호가 1~45 사이의 숫자가 아닙니다" - const val LOTTO_NUMBER_MIN_VALUE: Int = 1 - const val LOTTO_NUMBER_MAX_VALUE: Int = 45 - const val INVALID_WINNER_NUMBERS_COUNT_MESSAGE: String = "로또 당첨 번호가 중복되지 않은 6개로 입력되지 않았습니다" + private const val INVALID_NULL_OR_BLANK_WINNER_NUMBERS_MESSAGE: String = "입력된 로또 당첨 번호가 없습니다" + private const val INVALID_NULL_OR_BLANK_BONUS_NUMBERS_MESSAGE: String = "입력된 보너스 번호가 없습니다" + private const val INVALID_BONUS_NUMBERS_MESSAGE: String = "입력된 보너스 번호가 올바르지 않습니다" } From 13016fd401508ad445314fdd81e08701941181b7 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Sat, 14 Dec 2024 02:50:32 +0900 Subject: [PATCH 15/18] =?UTF-8?q?Controller=20=EC=88=98=EB=8F=99=20?= =?UTF-8?q?=EA=B5=AC=EB=A7=A4=20=EB=A1=9C=EB=98=90=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EA=B8=B0=EC=A1=B4?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 ++-- .../lotto/application/LottoApplication.kt | 7 ++- .../lotto/controller/LottoController.kt | 49 +++++++++++++------ 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index bfe63c4bc2..a7573d364b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ - 로또 1장의 가격은 1,000원이다. - 2등을 위해 추가 번호를 하나 더 추첨한다. - 당첨 통계에 2등도 추가해야 한다. - +- 현재 로또 생성기는 자동 생성 기능만 제공한다. 사용자가 수동으로 추첨 번호를 입력할 수 있도록 해야 한다. +- 입력한 금액, 자동 생성 숫자, 수동 생성 번호를 입력하도록 해야 한다. +- ## 기능 설계 - [x] 로또 번호는 1부터 45사이 값이 아니면 에러가 발생한다 - [x] 로또 번호는 value class로 관리된다 @@ -13,9 +15,9 @@ - [x] 비용을 지불해 한번에 여러장 로또를 구입할 수 있다 - [x] 로또 구입 비용이 1,000원 미만일 경우 에러가 발생한다 - [x] 로또 구입 비용이 1,000원 단위가 아닐 경우 에러가 발생한다 - - [x] 로또 구입 비용에 대해 몇 장의 로또가 구입 됐는지 확인활 수 있다 -- [x] 로또 번호가 1부터 45사이의 숫자가 아니면 에러가 발생한다 -- [x] 로또 번호를 6개로 지정할 경우가 아니면 에러가 발생한다 (예를 들어 5개 또는 7개) + - [x] 로또 구입 비용에 대해 몇 장의 로또가 구입될 수 있는지 확인활 수 있다 +- [x] 로또 번호를 수동으로 부여할 수 있다 +- [x] 수동 로또를 여러개 구입할 수 있다 - [x] 로또 번호를 자동으로 부여한다 - [x] 로또 번호는 1부터 45사이의 중복되지 않는 숫자 6개로 이루어져야한다 - [x] 로또 당첨 번호를 입력할 수 있다 diff --git a/src/main/kotlin/lotto/application/LottoApplication.kt b/src/main/kotlin/lotto/application/LottoApplication.kt index baa98f27d7..3d60941df9 100644 --- a/src/main/kotlin/lotto/application/LottoApplication.kt +++ b/src/main/kotlin/lotto/application/LottoApplication.kt @@ -3,7 +3,10 @@ package lotto.application import lotto.controller.LottoController fun main() { - val purchasedLottoTickets = LottoController.purchaseLotto() + val maxPurchaseLottoCount = LottoController.getMaxPurchaseLottoCountFromPayment() + val manualLottoTickets = LottoController.purchaseManualLotto(maxPurchaseLottoCount) + val totalLottoTickets = LottoController.createAutoLotto(maxPurchaseLottoCount, manualLottoTickets) val lottoWinnerNumbers = LottoController.createWinningLottoNumbers() - LottoController.resultPayout(purchasedLottoTickets = purchasedLottoTickets, lottoWinnerNumbers = lottoWinnerNumbers) + + LottoController.resultPayout(lottoTickets = totalLottoTickets, lottoWinnerNumbers = lottoWinnerNumbers) } diff --git a/src/main/kotlin/lotto/controller/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt index c472431573..3523e55620 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -1,40 +1,59 @@ package lotto.controller -import lotto.domain.LottoNumber -import lotto.domain.LottoNumbers -import lotto.domain.LottoTicketIssuer +import lotto.domain.AutoLottoIssuer +import lotto.domain.LottoNumberGenerator +import lotto.domain.LottoPurchaseCalculator +import lotto.domain.LottoTickets import lotto.domain.LottoWinnerNumbers -import lotto.domain.PurchasedLottoTickets -import lotto.domain.generateLottoNumbers import lotto.view.LottoPayoutView -import lotto.view.PurchaseLottoResultView +import lotto.view.ManualLottoView import lotto.view.PurchaseLottoView import lotto.view.WinnerLottoNumberView object LottoController { - fun purchaseLotto(): PurchasedLottoTickets { + fun getMaxPurchaseLottoCountFromPayment(): Int { val amountPaid = PurchaseLottoView.inputPurchaseCost() + return LottoPurchaseCalculator.getMaxPurchasedLottoTicketCount(amountPaid) + } + + fun purchaseManualLotto(maxPurchaseLottoCount: Int): LottoTickets { + val manualLottoCount = ManualLottoView.inputManualLottoCount(maxPurchaseLottoCount) + return ManualLottoView.repeatInputManualLottoNumbers(manualLottoCount) + } - val purchasedLottoTickets = - LottoTicketIssuer.issueTickets(amountPaid = amountPaid, generateLottoNumbers = { generateLottoNumbers() }) + fun createAutoLotto( + maxPurchaseLottoCount: Int, + manualLottoTickets: LottoTickets, + ): LottoTickets { + val autoLottoCount = maxPurchaseLottoCount - manualLottoTickets.lottoTickets.size - PurchaseLottoResultView.displayPurchaseLottoResults(purchasedLottoTickets = purchasedLottoTickets) + val autoLottoTickets = + AutoLottoIssuer.issueAutoLottoTickets(autoLottoCount) { + LottoNumberGenerator.generateAutoLottoNumbers() + } - return purchasedLottoTickets + PurchaseLottoView.displayPurchasedLottosView( + manualLottoTickets = manualLottoTickets, + autoLottoTickets = autoLottoTickets, + ) + + val combinedManualLottoAndAutoLotto = manualLottoTickets.lottoTickets.plus(autoLottoTickets.lottoTickets) + + return LottoTickets(combinedManualLottoAndAutoLotto) } fun createWinningLottoNumbers(): LottoWinnerNumbers { val inputLottoNumbers = WinnerLottoNumberView.inputWinningLottoNumbers() - val lottoNumbers = LottoNumbers(inputLottoNumbers.map { LottoNumber.of(it) }.toSet()) val inputBonusNumber = WinnerLottoNumberView.inputBonusNumber() - return LottoWinnerNumbers(lottoNumbers = lottoNumbers, bonusNumber = LottoNumber.of(inputBonusNumber)) + + return LottoWinnerNumbers(lottoNumbers = inputLottoNumbers, bonusNumber = inputBonusNumber) } fun resultPayout( - purchasedLottoTickets: PurchasedLottoTickets, + lottoTickets: LottoTickets, lottoWinnerNumbers: LottoWinnerNumbers, ) { - val purchasedLottoResults = lottoWinnerNumbers.resultLottoPayout(purchasedLottoTickets) + val purchasedLottoResults = lottoWinnerNumbers.resultLottoPayout(lottoTickets) return LottoPayoutView.displayWinningStatistics(purchasedLottoResults = purchasedLottoResults) } } From d56c98a3aea0c161a99eb73cae8ab73e9b0302d1 Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Tue, 17 Dec 2024 01:06:33 +0900 Subject: [PATCH 16/18] =?UTF-8?q?=EB=A6=AC=EB=A5=98=20=EB=B0=98=EC=98=81?= =?UTF-8?q?=20->=20collection=EC=97=90=EC=84=9C=20=EB=8D=94=20=EC=A7=81?= =?UTF-8?q?=EA=B4=80=EC=A0=81=EC=9D=B8=20kotest=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt b/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt index 6bfa0664b0..8e0768aa23 100644 --- a/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt +++ b/src/test/kotlin/lotto/domain/AutoLottoIssuerTest.kt @@ -1,5 +1,6 @@ package lotto.domain +import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.equals.shouldBeEqual import lotto.util.createLottoNumbers import org.junit.jupiter.api.Test @@ -8,6 +9,6 @@ class AutoLottoIssuerTest { @Test fun `정해진 개수 만큼 자동 로또를 생성 할 수 있다`() { val lottoTickets = AutoLottoIssuer.issueAutoLottoTickets(3) { createLottoNumbers(1, 2, 3, 4, 5, 6) } - lottoTickets.lottoTickets.size shouldBeEqual 3 + lottoTickets.lottoTickets.shouldHaveSize(3) } } From 7ab86bbcbaffc257b4a4c199643561914c7d183f Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Tue, 17 Dec 2024 02:00:28 +0900 Subject: [PATCH 17/18] =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81,?= =?UTF-8?q?=20AutoLottoTicket=20=ED=81=B4=EB=9E=98=EC=8A=A4=20-=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=8D=BC=ED=8B=B0=20=EC=84=A0=EC=96=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/domain/LottoTicket.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/lotto/domain/LottoTicket.kt b/src/main/kotlin/lotto/domain/LottoTicket.kt index e4d491c015..722213bb6d 100644 --- a/src/main/kotlin/lotto/domain/LottoTicket.kt +++ b/src/main/kotlin/lotto/domain/LottoTicket.kt @@ -11,7 +11,7 @@ sealed class LottoTicket { class ManualLottoTicket(override val lottoNumbers: LottoNumbers) : LottoTicket() - class AutoLottoTicket(private val generateLottoNumbers: () -> LottoNumbers) : LottoTicket() { + class AutoLottoTicket(generateLottoNumbers: () -> LottoNumbers) : LottoTicket() { override val lottoNumbers: LottoNumbers = generateLottoNumbers() } } From a80a788b49019775dc9220d48eeca704e16491de Mon Sep 17 00:00:00 2001 From: Pablo730 Date: Tue, 17 Dec 2024 02:38:51 +0900 Subject: [PATCH 18/18] =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= =?UTF-8?q?=20-=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=ED=99=94=20=EB=A1=9C=EC=A7=81=20=ED=99=9C=EC=9A=A9=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EA=B0=84=EA=B2=B0=ED=95=98=EA=B2=8C=20=ED=91=9C?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/view/ManualLottoView.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/kotlin/lotto/view/ManualLottoView.kt b/src/main/kotlin/lotto/view/ManualLottoView.kt index 2bfb30ec9b..611d2be2e6 100644 --- a/src/main/kotlin/lotto/view/ManualLottoView.kt +++ b/src/main/kotlin/lotto/view/ManualLottoView.kt @@ -22,8 +22,7 @@ object ManualLottoView { fun repeatInputManualLottoNumbers(manualLottoCount: Int): LottoTickets { println("\n수동으로 구매할 번호를 입력해 주세요.") - val lottoNumbersList = mutableListOf() - repeat(manualLottoCount) { lottoNumbersList.add(inputManualLottoNumbers()) } + val lottoNumbersList = List(manualLottoCount) { inputManualLottoNumbers() } val lottoTickets = lottoNumbersList.map { ManualLottoTicket(it) }