From 0eeefefe729e9076b13844068225696f0e28e5c0 Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 18:21:54 +0900 Subject: [PATCH 01/15] [STEP-2] init --- lotto/build.gradle | 1 + lotto/src/main/kotlin/lotto/Main.kt | 5 +++++ settings.gradle.kts | 1 + 3 files changed, 7 insertions(+) create mode 100644 lotto/build.gradle create mode 100644 lotto/src/main/kotlin/lotto/Main.kt diff --git a/lotto/build.gradle b/lotto/build.gradle new file mode 100644 index 0000000000..c773c5128a --- /dev/null +++ b/lotto/build.gradle @@ -0,0 +1 @@ +dependencies {} diff --git a/lotto/src/main/kotlin/lotto/Main.kt b/lotto/src/main/kotlin/lotto/Main.kt new file mode 100644 index 0000000000..f5e4fa0e3c --- /dev/null +++ b/lotto/src/main/kotlin/lotto/Main.kt @@ -0,0 +1,5 @@ +package lotto + +fun main() { + println("Hello World!") +} diff --git a/settings.gradle.kts b/settings.gradle.kts index b0e6791ad7..aa25adb482 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,3 +3,4 @@ plugins { } rootProject.name = "kotlin-lotto" include("string-calculator") +include("lotto") From b565de4a2197a3b9ddef8c1f660bb9e716454563 Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 19:11:30 +0900 Subject: [PATCH 02/15] =?UTF-8?q?[STEP-2]=20=EA=B8=B0=EB=8A=A5=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 lotto/README.md diff --git a/lotto/README.md b/lotto/README.md new file mode 100644 index 0000000000..ca353f4d95 --- /dev/null +++ b/lotto/README.md @@ -0,0 +1,16 @@ +### Lotto + +- [ ] 로또 구입 금액을 입력하면 구입 금액에 해당하는 로또를 발급해야 한다. +- [ ] 로또 1장의 가격은 1000원이다. + - [ ] 최소 구매금액은 1000원이다. + - [ ] 구매금액의 최소 단위는 1000원이다. +- [ ] 사용자는 지불한 금액만큼의 로또를 가지고 있는다. + - [ ] 사용자는 지불한 금액을 알고 있다. + - [ ] 사용자는 자신이 구매한 로또를 알고 있다. +- [ ] 각 로또마다 6개의 숫자를 가지고 있다. + - [ ] 로또의 숫자들은 무작위로 섞여 있다. +- [ ] 당첨 번호를 입력할 수 있다. +- [ ] 당첨 통계를 낼 수 있다. + - [ ] 3~6개 일치 여부를 판단할 수 있다. + - [ ] 일치한 개수 별로 당첨 금액이 다르게 책정된다. + - [ ] 총 수익률을 계산할 수 있다. From 8985d3998941465ef1a33d8c273a01cf3f04c53d Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 19:15:27 +0900 Subject: [PATCH 03/15] =?UTF-8?q?[STEP-2]=20=EA=B5=AC=EB=A7=A4=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EA=B4=80=EB=A0=A8=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 --- .../lotto/domain/LottoPurchaseAmountTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 lotto/src/test/kotlin/lotto/domain/LottoPurchaseAmountTest.kt diff --git a/lotto/src/test/kotlin/lotto/domain/LottoPurchaseAmountTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoPurchaseAmountTest.kt new file mode 100644 index 0000000000..becbf3cdc6 --- /dev/null +++ b/lotto/src/test/kotlin/lotto/domain/LottoPurchaseAmountTest.kt @@ -0,0 +1,22 @@ +package lotto.domain + +import io.kotest.assertions.throwables.shouldNotThrowAny +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class LottoPurchaseAmountTest { + @Nested + inner class ValidateTest { + @ParameterizedTest + @ValueSource(ints = [1000, 2000, 3000, 4000]) + fun `로또 1장의 최소 구매금액은 1000원이다`(purchaseAmount: Int) { + + } + + @Test + fun `로또 1장의 구매금액의 최소 단위는 1000원이다`() { + } + } +} From 31af8e4d315892dcc01cc68e6ab705a8cb682b63 Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 19:20:13 +0900 Subject: [PATCH 04/15] =?UTF-8?q?[STEP-2]=20=EA=B5=AC=EB=A7=A4=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/README.md | 6 +-- lotto/src/main/kotlin/lotto/Main.kt | 5 ++- .../lotto/domain/LottoPurchaseAmount.kt | 26 +++++++++++++ lotto/src/main/kotlin/lotto/view/InputView.kt | 15 ++++++++ .../lotto/domain/LottoPurchaseAmountTest.kt | 38 +++++++++++++++++-- 5 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt create mode 100644 lotto/src/main/kotlin/lotto/view/InputView.kt diff --git a/lotto/README.md b/lotto/README.md index ca353f4d95..5c79bb11b9 100644 --- a/lotto/README.md +++ b/lotto/README.md @@ -1,9 +1,9 @@ ### Lotto - [ ] 로또 구입 금액을 입력하면 구입 금액에 해당하는 로또를 발급해야 한다. -- [ ] 로또 1장의 가격은 1000원이다. - - [ ] 최소 구매금액은 1000원이다. - - [ ] 구매금액의 최소 단위는 1000원이다. +- [x] 로또 1장의 가격은 1000원이다. + - [x] 최소 구매금액은 1000원이다. + - [x] 구매금액의 최소 단위는 1000원이다. - [ ] 사용자는 지불한 금액만큼의 로또를 가지고 있는다. - [ ] 사용자는 지불한 금액을 알고 있다. - [ ] 사용자는 자신이 구매한 로또를 알고 있다. diff --git a/lotto/src/main/kotlin/lotto/Main.kt b/lotto/src/main/kotlin/lotto/Main.kt index f5e4fa0e3c..79d75ad57a 100644 --- a/lotto/src/main/kotlin/lotto/Main.kt +++ b/lotto/src/main/kotlin/lotto/Main.kt @@ -1,5 +1,8 @@ package lotto +import lotto.domain.LottoPurchaseAmount +import lotto.view.InputView + fun main() { - println("Hello World!") + val lottoPurchaseAmount = LottoPurchaseAmount(InputView.inputPurchaseAmount()) } diff --git a/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt b/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt new file mode 100644 index 0000000000..14bd2812d3 --- /dev/null +++ b/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt @@ -0,0 +1,26 @@ +package lotto.domain + +data class LottoPurchaseAmount( + val amount: Int, +) { + init { + amount.validateMinimum() + amount.validatePurchaseMinUnit() + } + + private fun Int.validateMinimum() { + require(this >= MIN_PURCHASE_AMOUNT) { + "[PurchaseAmount] 구매금액은 ${MIN_PURCHASE_AMOUNT}원 이상이어야 합니다. | 입력금액: $this" + } + } + + private fun Int.validatePurchaseMinUnit() { + require(this % MIN_PURCHASE_AMOUNT == 0) { + "[PurchaseAmount] 구매금액은 ${MIN_PURCHASE_AMOUNT}원 단위이어야 합니다. | 입력금액: $this" + } + } + + companion object { + private const val MIN_PURCHASE_AMOUNT = 1000 + } +} diff --git a/lotto/src/main/kotlin/lotto/view/InputView.kt b/lotto/src/main/kotlin/lotto/view/InputView.kt new file mode 100644 index 0000000000..fd3aee594d --- /dev/null +++ b/lotto/src/main/kotlin/lotto/view/InputView.kt @@ -0,0 +1,15 @@ +package lotto.view + +object InputView { + fun inputPurchaseAmount() = input("구입금액을 입력해 주세요.") + .toIntOrThrow() + + private fun input(message: String): String { + println(message) + return readln() + } + + private fun String.toIntOrThrow(): Int = runCatching { + this.toInt() + }.getOrElse { throw IllegalArgumentException("[InputView] 값을 Int로 변환하는데 실패했습니다. | '$this'") } +} diff --git a/lotto/src/test/kotlin/lotto/domain/LottoPurchaseAmountTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoPurchaseAmountTest.kt index becbf3cdc6..c1c82a8fec 100644 --- a/lotto/src/test/kotlin/lotto/domain/LottoPurchaseAmountTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/LottoPurchaseAmountTest.kt @@ -1,8 +1,10 @@ package lotto.domain import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.assertions.throwables.shouldThrowExactly +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.Nested -import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource @@ -12,11 +14,41 @@ class LottoPurchaseAmountTest { @ParameterizedTest @ValueSource(ints = [1000, 2000, 3000, 4000]) fun `로또 1장의 최소 구매금액은 1000원이다`(purchaseAmount: Int) { + val lottoPurchaseAmount = shouldNotThrowAny { + LottoPurchaseAmount(purchaseAmount) + } + lottoPurchaseAmount.amount shouldBe purchaseAmount + } + @ParameterizedTest + @ValueSource(ints = [200, 400, 600, 800, 999]) + fun `로또를 1000원 미만으로 구매하려는 경우 예외가 발생한다`(purchaseAmount: Int) { + val exception = shouldThrowExactly { + LottoPurchaseAmount(purchaseAmount) + } + exception.message shouldContain "구매금액은 ${MIN_PURCHASE_AMOUNT}원 이상이어야 합니다" } - @Test - fun `로또 1장의 구매금액의 최소 단위는 1000원이다`() { + @ParameterizedTest + @ValueSource(ints = [1000, 2000, 3000, 4000]) + fun `로또 1장의 구매금액의 최소 단위는 1000원이다`(purchaseAmount: Int) { + val lottoPurchaseAmount = shouldNotThrowAny { + LottoPurchaseAmount(purchaseAmount) + } + lottoPurchaseAmount.amount shouldBe purchaseAmount } + + @ParameterizedTest + @ValueSource(ints = [1001, 2010, 3100, 4111]) + fun `로또 1장의 구매금액이 1000원 단위가 아닌 경우 예외가 발생한다`(purchaseAmount: Int) { + val exception = shouldThrowExactly { + LottoPurchaseAmount(purchaseAmount) + } + exception.message shouldContain "구매금액은 ${MIN_PURCHASE_AMOUNT}원 단위이어야 합니다" + } + } + + companion object { + private const val MIN_PURCHASE_AMOUNT = 1000 } } From 2a910cb24b93331d4922730e8a20e33b8ce281d3 Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 19:29:12 +0900 Subject: [PATCH 05/15] =?UTF-8?q?[STEP-2]=20=EC=9C=A0=EC=A0=80=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=AA=A9=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/test/kotlin/lotto/domain/UserTest.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lotto/src/test/kotlin/lotto/domain/UserTest.kt diff --git a/lotto/src/test/kotlin/lotto/domain/UserTest.kt b/lotto/src/test/kotlin/lotto/domain/UserTest.kt new file mode 100644 index 0000000000..1ab605cf20 --- /dev/null +++ b/lotto/src/test/kotlin/lotto/domain/UserTest.kt @@ -0,0 +1,20 @@ +package lotto.domain + +import org.junit.jupiter.api.Test + +class UserTest { + @Test + fun `사용자는 구매금액을 가지고 있는다`() { + + } + + @Test + fun `사용자는 로또를 가지고 있는다`() { + + } + + @Test + fun `사용자는 당첨금액을 알고 있다`() { + + } +} From 9180d3448b653f97367732e557b6b86867c6bed0 Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 19:32:11 +0900 Subject: [PATCH 06/15] =?UTF-8?q?[STEP-2]=20=EC=9C=A0=EC=A0=80=EB=8A=94=20?= =?UTF-8?q?=EA=B5=AC=EB=A7=A4=EA=B8=88=EC=95=A1=EC=9D=84=20=EC=95=8C?= =?UTF-8?q?=EA=B3=A0=20=EC=9E=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/README.md | 2 +- lotto/src/main/kotlin/lotto/Main.kt | 2 ++ lotto/src/main/kotlin/lotto/domain/User.kt | 5 +++++ lotto/src/test/kotlin/lotto/domain/UserTest.kt | 9 ++++++++- 4 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 lotto/src/main/kotlin/lotto/domain/User.kt diff --git a/lotto/README.md b/lotto/README.md index 5c79bb11b9..68fdd41c51 100644 --- a/lotto/README.md +++ b/lotto/README.md @@ -5,7 +5,7 @@ - [x] 최소 구매금액은 1000원이다. - [x] 구매금액의 최소 단위는 1000원이다. - [ ] 사용자는 지불한 금액만큼의 로또를 가지고 있는다. - - [ ] 사용자는 지불한 금액을 알고 있다. + - [x] 사용자는 지불한 금액을 알고 있다. - [ ] 사용자는 자신이 구매한 로또를 알고 있다. - [ ] 각 로또마다 6개의 숫자를 가지고 있다. - [ ] 로또의 숫자들은 무작위로 섞여 있다. diff --git a/lotto/src/main/kotlin/lotto/Main.kt b/lotto/src/main/kotlin/lotto/Main.kt index 79d75ad57a..f05efb19cb 100644 --- a/lotto/src/main/kotlin/lotto/Main.kt +++ b/lotto/src/main/kotlin/lotto/Main.kt @@ -1,8 +1,10 @@ package lotto import lotto.domain.LottoPurchaseAmount +import lotto.domain.User import lotto.view.InputView fun main() { val lottoPurchaseAmount = LottoPurchaseAmount(InputView.inputPurchaseAmount()) + val user = User(lottoPurchaseAmount) } diff --git a/lotto/src/main/kotlin/lotto/domain/User.kt b/lotto/src/main/kotlin/lotto/domain/User.kt new file mode 100644 index 0000000000..6d5d8737e5 --- /dev/null +++ b/lotto/src/main/kotlin/lotto/domain/User.kt @@ -0,0 +1,5 @@ +package lotto.domain + +class User( + val lottoPurchaseAmount: LottoPurchaseAmount, +) diff --git a/lotto/src/test/kotlin/lotto/domain/UserTest.kt b/lotto/src/test/kotlin/lotto/domain/UserTest.kt index 1ab605cf20..87ed7c04c2 100644 --- a/lotto/src/test/kotlin/lotto/domain/UserTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/UserTest.kt @@ -1,20 +1,27 @@ package lotto.domain +import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test class UserTest { @Test fun `사용자는 구매금액을 가지고 있는다`() { + val lottoPurchaseAmount = LottoPurchaseAmount(1000) + val user = User(lottoPurchaseAmount) + + user.lottoPurchaseAmount shouldBe lottoPurchaseAmount } @Test fun `사용자는 로또를 가지고 있는다`() { - } @Test fun `사용자는 당첨금액을 알고 있다`() { + } + @Test + fun `사용자는 지불한 금액만큼의 로또를 가지고 있는다`() { } } From c767b0fa6355f24dacaacab04056ade2357680e2 Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 19:54:38 +0900 Subject: [PATCH 07/15] =?UTF-8?q?[STEP-2]=20=EB=A1=9C=EB=98=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/README.md | 8 ++--- lotto/src/main/kotlin/lotto/domain/Lotto.kt | 16 ++++++++++ .../lotto/domain/LottoPurchaseAmount.kt | 2 ++ lotto/src/main/kotlin/lotto/domain/User.kt | 5 +++- .../src/test/kotlin/lotto/domain/LottoTest.kt | 29 +++++++++++++++++++ .../src/test/kotlin/lotto/domain/UserTest.kt | 11 +++---- 6 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 lotto/src/main/kotlin/lotto/domain/Lotto.kt create mode 100644 lotto/src/test/kotlin/lotto/domain/LottoTest.kt diff --git a/lotto/README.md b/lotto/README.md index 68fdd41c51..470f2165fa 100644 --- a/lotto/README.md +++ b/lotto/README.md @@ -4,11 +4,11 @@ - [x] 로또 1장의 가격은 1000원이다. - [x] 최소 구매금액은 1000원이다. - [x] 구매금액의 최소 단위는 1000원이다. -- [ ] 사용자는 지불한 금액만큼의 로또를 가지고 있는다. +- [x] 사용자는 지불한 금액만큼의 로또를 가지고 있는다. - [x] 사용자는 지불한 금액을 알고 있다. - - [ ] 사용자는 자신이 구매한 로또를 알고 있다. -- [ ] 각 로또마다 6개의 숫자를 가지고 있다. - - [ ] 로또의 숫자들은 무작위로 섞여 있다. +- [x] 각 로또마다 6개의 숫자를 가지고 있다. + - [x] 로또의 숫자들은 무작위로 섞여 있다. + - [x] 로또의 숫자는 1~45 까지 이다. - [ ] 당첨 번호를 입력할 수 있다. - [ ] 당첨 통계를 낼 수 있다. - [ ] 3~6개 일치 여부를 판단할 수 있다. diff --git a/lotto/src/main/kotlin/lotto/domain/Lotto.kt b/lotto/src/main/kotlin/lotto/domain/Lotto.kt new file mode 100644 index 0000000000..0836c9d45b --- /dev/null +++ b/lotto/src/main/kotlin/lotto/domain/Lotto.kt @@ -0,0 +1,16 @@ +package lotto.domain + +data class Lotto( + val values: List = generateLotto() +) { + companion object { + private const val MIN_LOTTO_NUMBER = 1 + private const val MAX_LOTTO_NUMBER = 45 + private const val LOTTO_NUMBER_COUNT = 6 + + private fun generateLotto(): List { + return (MIN_LOTTO_NUMBER..MAX_LOTTO_NUMBER).shuffled() + .take(LOTTO_NUMBER_COUNT) + } + } +} diff --git a/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt b/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt index 14bd2812d3..1c85156ad7 100644 --- a/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt +++ b/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt @@ -8,6 +8,8 @@ data class LottoPurchaseAmount( amount.validatePurchaseMinUnit() } + fun calculateLottoCount(): Int = amount / MIN_PURCHASE_AMOUNT + private fun Int.validateMinimum() { require(this >= MIN_PURCHASE_AMOUNT) { "[PurchaseAmount] 구매금액은 ${MIN_PURCHASE_AMOUNT}원 이상이어야 합니다. | 입력금액: $this" diff --git a/lotto/src/main/kotlin/lotto/domain/User.kt b/lotto/src/main/kotlin/lotto/domain/User.kt index 6d5d8737e5..2aadbe2ac6 100644 --- a/lotto/src/main/kotlin/lotto/domain/User.kt +++ b/lotto/src/main/kotlin/lotto/domain/User.kt @@ -2,4 +2,7 @@ package lotto.domain class User( val lottoPurchaseAmount: LottoPurchaseAmount, -) +) { + private val lottoCount = lottoPurchaseAmount.calculateLottoCount() + val lotteries: List = List(lottoCount) { Lotto() } +} diff --git a/lotto/src/test/kotlin/lotto/domain/LottoTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoTest.kt new file mode 100644 index 0000000000..d30fab705a --- /dev/null +++ b/lotto/src/test/kotlin/lotto/domain/LottoTest.kt @@ -0,0 +1,29 @@ +package lotto.domain + +import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe +import org.junit.jupiter.api.Test + +class LottoTest{ + + @Test + fun `각 로또마다 6개의 숫자를 가지고 있다`() { + val lotto = Lotto() + + lotto.values.size shouldBe 6 + } + + @Test + fun `로또의 숫자들은 무작위로 섞여 있다`() { + val lotto = Lotto() + + lotto.values.sorted() shouldNotBe lotto.values + } + + @Test + fun `로또의 숫자는 1~45 까지 이다`() { + val lotto = Lotto() + + lotto.values.all { it in 1..45 } shouldBe true + } +} diff --git a/lotto/src/test/kotlin/lotto/domain/UserTest.kt b/lotto/src/test/kotlin/lotto/domain/UserTest.kt index 87ed7c04c2..6719ccee7a 100644 --- a/lotto/src/test/kotlin/lotto/domain/UserTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/UserTest.kt @@ -14,14 +14,15 @@ class UserTest { } @Test - fun `사용자는 로또를 가지고 있는다`() { - } + fun `사용자는 지불한 금액만큼의 로또를 가지고 있는다`() { + val lottoPurchaseAmount = LottoPurchaseAmount(1000) - @Test - fun `사용자는 당첨금액을 알고 있다`() { + val user = User(lottoPurchaseAmount) + + user.lotteries.size shouldBe lottoPurchaseAmount.calculateLottoCount() } @Test - fun `사용자는 지불한 금액만큼의 로또를 가지고 있는다`() { + fun `사용자는 당첨금액을 알고 있다`() { } } From 4743ea7f4c9b6e9a5a14772083b0a752fb55a05a Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 19:54:47 +0900 Subject: [PATCH 08/15] =?UTF-8?q?[STEP-2]=20=EB=A1=9C=EB=98=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/README.md | 2 +- lotto/src/main/kotlin/lotto/Main.kt | 4 ++-- .../main/kotlin/lotto/domain/{User.kt => LottoUser.kt} | 2 +- .../lotto/domain/{UserTest.kt => LottoUserTest.kt} | 10 +++++----- 4 files changed, 9 insertions(+), 9 deletions(-) rename lotto/src/main/kotlin/lotto/domain/{User.kt => LottoUser.kt} (92%) rename lotto/src/test/kotlin/lotto/domain/{UserTest.kt => LottoUserTest.kt} (62%) diff --git a/lotto/README.md b/lotto/README.md index 470f2165fa..bb978aca15 100644 --- a/lotto/README.md +++ b/lotto/README.md @@ -1,6 +1,6 @@ ### Lotto -- [ ] 로또 구입 금액을 입력하면 구입 금액에 해당하는 로또를 발급해야 한다. +- [x] 로또 구입 금액을 입력하면 구입 금액에 해당하는 로또를 발급해야 한다. - [x] 로또 1장의 가격은 1000원이다. - [x] 최소 구매금액은 1000원이다. - [x] 구매금액의 최소 단위는 1000원이다. diff --git a/lotto/src/main/kotlin/lotto/Main.kt b/lotto/src/main/kotlin/lotto/Main.kt index f05efb19cb..81bb357464 100644 --- a/lotto/src/main/kotlin/lotto/Main.kt +++ b/lotto/src/main/kotlin/lotto/Main.kt @@ -1,10 +1,10 @@ package lotto import lotto.domain.LottoPurchaseAmount -import lotto.domain.User +import lotto.domain.LottoUser import lotto.view.InputView fun main() { val lottoPurchaseAmount = LottoPurchaseAmount(InputView.inputPurchaseAmount()) - val user = User(lottoPurchaseAmount) + val lottoUser = LottoUser(lottoPurchaseAmount) } diff --git a/lotto/src/main/kotlin/lotto/domain/User.kt b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt similarity index 92% rename from lotto/src/main/kotlin/lotto/domain/User.kt rename to lotto/src/main/kotlin/lotto/domain/LottoUser.kt index 2aadbe2ac6..dc05ee9665 100644 --- a/lotto/src/main/kotlin/lotto/domain/User.kt +++ b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt @@ -1,6 +1,6 @@ package lotto.domain -class User( +class LottoUser( val lottoPurchaseAmount: LottoPurchaseAmount, ) { private val lottoCount = lottoPurchaseAmount.calculateLottoCount() diff --git a/lotto/src/test/kotlin/lotto/domain/UserTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt similarity index 62% rename from lotto/src/test/kotlin/lotto/domain/UserTest.kt rename to lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt index 6719ccee7a..3d838eed19 100644 --- a/lotto/src/test/kotlin/lotto/domain/UserTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt @@ -3,23 +3,23 @@ package lotto.domain import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test -class UserTest { +class LottoUserTest { @Test fun `사용자는 구매금액을 가지고 있는다`() { val lottoPurchaseAmount = LottoPurchaseAmount(1000) - val user = User(lottoPurchaseAmount) + val lottoUser = LottoUser(lottoPurchaseAmount) - user.lottoPurchaseAmount shouldBe lottoPurchaseAmount + lottoUser.lottoPurchaseAmount shouldBe lottoPurchaseAmount } @Test fun `사용자는 지불한 금액만큼의 로또를 가지고 있는다`() { val lottoPurchaseAmount = LottoPurchaseAmount(1000) - val user = User(lottoPurchaseAmount) + val lottoUser = LottoUser(lottoPurchaseAmount) - user.lotteries.size shouldBe lottoPurchaseAmount.calculateLottoCount() + lottoUser.lotteries.size shouldBe lottoPurchaseAmount.calculateLottoCount() } @Test From 5e85811d6010c619824a41644b35ba8d844dbb3c Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 23:29:42 +0900 Subject: [PATCH 09/15] =?UTF-8?q?[STEP-2]=20=EB=8B=B9=EC=B2=A8=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/README.md | 2 +- lotto/src/main/kotlin/lotto/Main.kt | 3 +++ .../main/kotlin/lotto/domain/CorrectNumbers.kt | 15 +++++++++++++++ .../kotlin/lotto/domain/CorrectNumbersTest.kt | 18 ++++++++++++++++++ .../src/test/kotlin/lotto/domain/LottoTest.kt | 2 +- 5 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 lotto/src/main/kotlin/lotto/domain/CorrectNumbers.kt create mode 100644 lotto/src/test/kotlin/lotto/domain/CorrectNumbersTest.kt diff --git a/lotto/README.md b/lotto/README.md index bb978aca15..127691dd83 100644 --- a/lotto/README.md +++ b/lotto/README.md @@ -9,7 +9,7 @@ - [x] 각 로또마다 6개의 숫자를 가지고 있다. - [x] 로또의 숫자들은 무작위로 섞여 있다. - [x] 로또의 숫자는 1~45 까지 이다. -- [ ] 당첨 번호를 입력할 수 있다. +- [x] 당첨 번호를 입력할 수 있다. - [ ] 당첨 통계를 낼 수 있다. - [ ] 3~6개 일치 여부를 판단할 수 있다. - [ ] 일치한 개수 별로 당첨 금액이 다르게 책정된다. diff --git a/lotto/src/main/kotlin/lotto/Main.kt b/lotto/src/main/kotlin/lotto/Main.kt index 81bb357464..b363548d2a 100644 --- a/lotto/src/main/kotlin/lotto/Main.kt +++ b/lotto/src/main/kotlin/lotto/Main.kt @@ -1,5 +1,6 @@ package lotto +import lotto.domain.CorrectNumbers import lotto.domain.LottoPurchaseAmount import lotto.domain.LottoUser import lotto.view.InputView @@ -7,4 +8,6 @@ import lotto.view.InputView fun main() { val lottoPurchaseAmount = LottoPurchaseAmount(InputView.inputPurchaseAmount()) val lottoUser = LottoUser(lottoPurchaseAmount) + + val correctNumbers = CorrectNumbers(InputView.inputCorrectNumbers()) } diff --git a/lotto/src/main/kotlin/lotto/domain/CorrectNumbers.kt b/lotto/src/main/kotlin/lotto/domain/CorrectNumbers.kt new file mode 100644 index 0000000000..f953557cf2 --- /dev/null +++ b/lotto/src/main/kotlin/lotto/domain/CorrectNumbers.kt @@ -0,0 +1,15 @@ +package lotto.domain + +data class CorrectNumbers( + val values: Set, +) { + init { + require(values.size == CORRECT_NUMBER_COUNT) { + "[CorrectNumbers] 당첨 번호의 개수가 6개가 아닙니다. | 당첨번호: '$values'" + } + } + + companion object { + private const val CORRECT_NUMBER_COUNT = 6 + } +} diff --git a/lotto/src/test/kotlin/lotto/domain/CorrectNumbersTest.kt b/lotto/src/test/kotlin/lotto/domain/CorrectNumbersTest.kt new file mode 100644 index 0000000000..f077242877 --- /dev/null +++ b/lotto/src/test/kotlin/lotto/domain/CorrectNumbersTest.kt @@ -0,0 +1,18 @@ +package lotto.domain + +import io.kotest.assertions.throwables.shouldThrowExactly +import io.kotest.matchers.string.shouldContain +import org.junit.jupiter.api.Test + +class CorrectNumbersTest { + + @Test + fun `당첨번호는 6개가 아닌 경우 예외가 발생한다`() { + val inputs = List(5) { it }.toSet() + + val correctNumbers = shouldThrowExactly { + CorrectNumbers(inputs) + } + correctNumbers.message shouldContain "당첨 번호의 개수가 6개가 아닙니다" + } +} diff --git a/lotto/src/test/kotlin/lotto/domain/LottoTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoTest.kt index d30fab705a..ce792acbf3 100644 --- a/lotto/src/test/kotlin/lotto/domain/LottoTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/LottoTest.kt @@ -4,7 +4,7 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import org.junit.jupiter.api.Test -class LottoTest{ +class LottoTest { @Test fun `각 로또마다 6개의 숫자를 가지고 있다`() { From 672ed89f00a114545429c1da861038dd3189a2ae Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sat, 23 Nov 2024 23:58:37 +0900 Subject: [PATCH 10/15] =?UTF-8?q?[STEP-2]=20=EB=8B=B9=EC=B2=A8=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=A7=9E=EC=B6=98=20?= =?UTF-8?q?=EA=B0=9C=EC=88=98=EB=A5=BC=20=EB=A1=9C=EB=98=90=EA=B0=80=20?= =?UTF-8?q?=EA=B0=80=EC=A7=80=EA=B3=A0=20=EC=9E=88=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/README.md | 3 +- lotto/src/main/kotlin/lotto/Main.kt | 9 ++-- lotto/src/main/kotlin/lotto/domain/Lotto.kt | 19 ++++++-- .../src/main/kotlin/lotto/domain/LottoUser.kt | 9 ++++ lotto/src/main/kotlin/lotto/view/InputView.kt | 11 +++++ .../kotlin/lotto/domain/CorrectNumbersTest.kt | 1 - .../src/test/kotlin/lotto/domain/LottoTest.kt | 44 ++++++++++++++++++- .../test/kotlin/lotto/domain/LottoUserTest.kt | 18 ++++++++ 8 files changed, 105 insertions(+), 9 deletions(-) diff --git a/lotto/README.md b/lotto/README.md index 127691dd83..45932549b7 100644 --- a/lotto/README.md +++ b/lotto/README.md @@ -10,7 +10,8 @@ - [x] 로또의 숫자들은 무작위로 섞여 있다. - [x] 로또의 숫자는 1~45 까지 이다. - [x] 당첨 번호를 입력할 수 있다. + - [x] 당첨 번호에 따른 맞춘 개수를 로또가 가지고 있는다. - [ ] 당첨 통계를 낼 수 있다. - - [ ] 3~6개 일치 여부를 판단할 수 있다. + - [x] 3~6개 일치 여부를 판단할 수 있다. - [ ] 일치한 개수 별로 당첨 금액이 다르게 책정된다. - [ ] 총 수익률을 계산할 수 있다. diff --git a/lotto/src/main/kotlin/lotto/Main.kt b/lotto/src/main/kotlin/lotto/Main.kt index b363548d2a..139a071d1d 100644 --- a/lotto/src/main/kotlin/lotto/Main.kt +++ b/lotto/src/main/kotlin/lotto/Main.kt @@ -3,11 +3,14 @@ package lotto import lotto.domain.CorrectNumbers import lotto.domain.LottoPurchaseAmount import lotto.domain.LottoUser -import lotto.view.InputView +import lotto.view.InputView.inputCorrectNumbers +import lotto.view.InputView.inputPurchaseAmount fun main() { - val lottoPurchaseAmount = LottoPurchaseAmount(InputView.inputPurchaseAmount()) + val lottoPurchaseAmount = LottoPurchaseAmount(inputPurchaseAmount()) val lottoUser = LottoUser(lottoPurchaseAmount) - val correctNumbers = CorrectNumbers(InputView.inputCorrectNumbers()) + val correctNumbers = CorrectNumbers(inputCorrectNumbers()) + + lottoUser.checkLotteries(correctNumbers) } diff --git a/lotto/src/main/kotlin/lotto/domain/Lotto.kt b/lotto/src/main/kotlin/lotto/domain/Lotto.kt index 0836c9d45b..7a57f533f1 100644 --- a/lotto/src/main/kotlin/lotto/domain/Lotto.kt +++ b/lotto/src/main/kotlin/lotto/domain/Lotto.kt @@ -1,16 +1,29 @@ package lotto.domain data class Lotto( - val values: List = generateLotto() + val values: Set = generateLotto(), + private var correctCount: Int? = null, ) { + val markedCorrectCount + get() = correctCount ?: error("[Lotto] 마킹이 되지 않은 로또입니다.") + + fun markCorrectCount(correctCount: Int) { + if (this.correctCount != null) { + error("[Lotto] 이미 당첨 개수 마킹이 완료된 로또입니다. | 로또 당첨개수: '$this', 마킹 시도한 당첨개수: $correctCount") + } + this.correctCount = correctCount + } + companion object { private const val MIN_LOTTO_NUMBER = 1 private const val MAX_LOTTO_NUMBER = 45 private const val LOTTO_NUMBER_COUNT = 6 - private fun generateLotto(): List { - return (MIN_LOTTO_NUMBER..MAX_LOTTO_NUMBER).shuffled() + private fun generateLotto(): Set { + return (MIN_LOTTO_NUMBER..MAX_LOTTO_NUMBER) + .shuffled() .take(LOTTO_NUMBER_COUNT) + .toSet() } } } diff --git a/lotto/src/main/kotlin/lotto/domain/LottoUser.kt b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt index dc05ee9665..f714d5a81a 100644 --- a/lotto/src/main/kotlin/lotto/domain/LottoUser.kt +++ b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt @@ -5,4 +5,13 @@ class LottoUser( ) { private val lottoCount = lottoPurchaseAmount.calculateLottoCount() val lotteries: List = List(lottoCount) { Lotto() } + + fun checkLotteries(correctNumbers: CorrectNumbers) { + lotteries.forEach { lotto -> + val lottoNumbers = lotto.values + val correctCount = lottoNumbers.intersect(correctNumbers.values).size + + lotto.markCorrectCount(correctCount) + } + } } diff --git a/lotto/src/main/kotlin/lotto/view/InputView.kt b/lotto/src/main/kotlin/lotto/view/InputView.kt index fd3aee594d..0c2bef8b15 100644 --- a/lotto/src/main/kotlin/lotto/view/InputView.kt +++ b/lotto/src/main/kotlin/lotto/view/InputView.kt @@ -1,9 +1,15 @@ package lotto.view object InputView { + private const val CORRECT_NUMBER_DELIMITER = "," + fun inputPurchaseAmount() = input("구입금액을 입력해 주세요.") .toIntOrThrow() + fun inputCorrectNumbers() = input("지난 주 당첨 번호를 입력해 주세요.") + .toIntsOrThrow() + .toSet() + private fun input(message: String): String { println(message) return readln() @@ -12,4 +18,9 @@ object InputView { private fun String.toIntOrThrow(): Int = runCatching { this.toInt() }.getOrElse { throw IllegalArgumentException("[InputView] 값을 Int로 변환하는데 실패했습니다. | '$this'") } + + private fun String.toIntsOrThrow(): List { + return this.split(CORRECT_NUMBER_DELIMITER) + .map { it.trim().toIntOrThrow() } + } } diff --git a/lotto/src/test/kotlin/lotto/domain/CorrectNumbersTest.kt b/lotto/src/test/kotlin/lotto/domain/CorrectNumbersTest.kt index f077242877..dbfdc4f19d 100644 --- a/lotto/src/test/kotlin/lotto/domain/CorrectNumbersTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/CorrectNumbersTest.kt @@ -5,7 +5,6 @@ import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.Test class CorrectNumbersTest { - @Test fun `당첨번호는 6개가 아닌 경우 예외가 발생한다`() { val inputs = List(5) { it }.toSet() diff --git a/lotto/src/test/kotlin/lotto/domain/LottoTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoTest.kt index ce792acbf3..919a282860 100644 --- a/lotto/src/test/kotlin/lotto/domain/LottoTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/LottoTest.kt @@ -1,11 +1,13 @@ package lotto.domain +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.assertions.throwables.shouldThrowExactly import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe +import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.Test class LottoTest { - @Test fun `각 로또마다 6개의 숫자를 가지고 있다`() { val lotto = Lotto() @@ -26,4 +28,44 @@ class LottoTest { lotto.values.all { it in 1..45 } shouldBe true } + + @Test + fun `correctCount가 null이면 마킹할 수 있다`() { + val lotto = Lotto() + + shouldNotThrowAny { + lotto.markCorrectCount(1) + } + } + + @Test + fun `correctCount가 null이면 markedCorrectCount을 조회할 수 없다`() { + val lotto = Lotto() + + val exception = shouldThrowExactly { + lotto.markedCorrectCount + } + exception.message shouldContain "마킹이 되지 않은 로또입니다" + } + + @Test + fun `correctCount가 null이 아닌 경우 예외가 발생한다`() { + val lotto = Lotto() + lotto.markCorrectCount(1) + + val exception = shouldThrowExactly { + lotto.markCorrectCount(1) + } + exception.message shouldContain "이미 당첨 개수 마킹이 완료된 로또입니다" + } + + @Test + fun `correctCount가 null이 아니면 markedCorrectCount을 조회할 수 있다`() { + val lotto = Lotto() + lotto.markCorrectCount(1) + + shouldNotThrowAny { + lotto.markedCorrectCount + } + } } diff --git a/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt index 3d838eed19..72b815b09f 100644 --- a/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt @@ -1,5 +1,6 @@ package lotto.domain +import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test @@ -22,6 +23,23 @@ class LottoUserTest { lottoUser.lotteries.size shouldBe lottoPurchaseAmount.calculateLottoCount() } + @Test + fun `사용자는 로또별 당첨금액을 체크할 수 있다`() { + val lottoPurchaseAmount = LottoPurchaseAmount(10000) + val lottoUser = LottoUser(lottoPurchaseAmount) + val inputs = List(6) { it }.toSet() + + val correctNumbers = CorrectNumbers(inputs) + + lottoUser.checkLotteries(correctNumbers) + + lottoUser.lotteries.forEach { + shouldNotThrowAny { + it.markedCorrectCount + } + } + } + @Test fun `사용자는 당첨금액을 알고 있다`() { } From 5c49d4a513a9e956355b22b4f4f8954edd5b3fc8 Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sun, 24 Nov 2024 11:57:53 +0900 Subject: [PATCH 11/15] =?UTF-8?q?[STEP-2]=20=EC=9D=BC=EC=B9=98=ED=95=9C=20?= =?UTF-8?q?=EA=B0=9C=EC=88=98=20=EB=B3=84=EB=A1=9C=20=EB=8B=B9=EC=B2=A8=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=EC=9D=B4=20=EB=8B=A4=EB=A5=B4=EA=B2=8C=20?= =?UTF-8?q?=EC=B1=85=EC=A0=95=EB=90=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 2 ++ lotto/README.md | 2 +- lotto/src/main/kotlin/lotto/domain/Lotto.kt | 5 ++++ .../domain/enums/LottoCompensationStrategy.kt | 26 +++++++++++++++++++ .../src/test/kotlin/lotto/domain/LottoTest.kt | 23 ++++++++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 lotto/src/main/kotlin/lotto/domain/enums/LottoCompensationStrategy.kt diff --git a/.editorconfig b/.editorconfig index bef9fbc308..72dd48ac3b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,3 +11,5 @@ ktlint_standard_multiline-expression-wrapping = disabled ktlint_standard_function-signature = disabled ktlint_standard_filename = disabled ktlint_standard_property-naming = disabled +ktlint_standard_enum-entry-name-case = disabled +ktlint_standard_no-semi = disabled diff --git a/lotto/README.md b/lotto/README.md index 45932549b7..c62e333757 100644 --- a/lotto/README.md +++ b/lotto/README.md @@ -13,5 +13,5 @@ - [x] 당첨 번호에 따른 맞춘 개수를 로또가 가지고 있는다. - [ ] 당첨 통계를 낼 수 있다. - [x] 3~6개 일치 여부를 판단할 수 있다. - - [ ] 일치한 개수 별로 당첨 금액이 다르게 책정된다. + - [x] 일치한 개수 별로 당첨 금액이 다르게 책정된다. - [ ] 총 수익률을 계산할 수 있다. diff --git a/lotto/src/main/kotlin/lotto/domain/Lotto.kt b/lotto/src/main/kotlin/lotto/domain/Lotto.kt index 7a57f533f1..4317c6edc3 100644 --- a/lotto/src/main/kotlin/lotto/domain/Lotto.kt +++ b/lotto/src/main/kotlin/lotto/domain/Lotto.kt @@ -1,5 +1,7 @@ package lotto.domain +import lotto.domain.enums.LottoCompensationStrategy + data class Lotto( val values: Set = generateLotto(), private var correctCount: Int? = null, @@ -7,6 +9,9 @@ data class Lotto( val markedCorrectCount get() = correctCount ?: error("[Lotto] 마킹이 되지 않은 로또입니다.") + val compensation + get() = LottoCompensationStrategy.getCompensationByCorrectCount(markedCorrectCount) + fun markCorrectCount(correctCount: Int) { if (this.correctCount != null) { error("[Lotto] 이미 당첨 개수 마킹이 완료된 로또입니다. | 로또 당첨개수: '$this', 마킹 시도한 당첨개수: $correctCount") diff --git a/lotto/src/main/kotlin/lotto/domain/enums/LottoCompensationStrategy.kt b/lotto/src/main/kotlin/lotto/domain/enums/LottoCompensationStrategy.kt new file mode 100644 index 0000000000..0c87a9f8d3 --- /dev/null +++ b/lotto/src/main/kotlin/lotto/domain/enums/LottoCompensationStrategy.kt @@ -0,0 +1,26 @@ +package lotto.domain.enums + +private const val DEFAULT_COMPENSATION_UNIT = "원" + +enum class LottoCompensationStrategy( + val correctCount: Int, + val compensation: Long, + val unit: String, +) { + `3개`(3, 5_000, DEFAULT_COMPENSATION_UNIT), + `4개`(4, 50_000, DEFAULT_COMPENSATION_UNIT), + `5개`(5, 1_500_000, DEFAULT_COMPENSATION_UNIT), + `6개`(6, 2_000_000_000, DEFAULT_COMPENSATION_UNIT), + ; + + companion object { + private const val DEFAULT_COMPENSATION = 0L + + fun findByCorrectCount(correctCount: Int): LottoCompensationStrategy? = + entries.find { it.correctCount == correctCount } + + fun getCompensationByCorrectCount(correctCount: Int): Long = + findByCorrectCount(correctCount)?.compensation + ?: DEFAULT_COMPENSATION + } +} diff --git a/lotto/src/test/kotlin/lotto/domain/LottoTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoTest.kt index 919a282860..2a3fdb5fb8 100644 --- a/lotto/src/test/kotlin/lotto/domain/LottoTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/LottoTest.kt @@ -5,7 +5,10 @@ import io.kotest.assertions.throwables.shouldThrowExactly import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.string.shouldContain +import lotto.domain.enums.LottoCompensationStrategy import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource class LottoTest { @Test @@ -68,4 +71,24 @@ class LottoTest { lotto.markedCorrectCount } } + + @ParameterizedTest + @ValueSource(ints = [0, 1, 2]) + fun `맞춘 개수가 3개 미만인 경우 당첨금이 0원이다`(correctCount: Int) { + val lotto = Lotto() + lotto.markCorrectCount(correctCount) + + lotto.markedCorrectCount shouldBe correctCount + lotto.compensation shouldBe 0 + } + + @ParameterizedTest + @ValueSource(ints = [3, 4, 5, 6]) + fun `맞춘 개수가 3개 이상인 경우 당첨금이 존재한다`(correctCount: Int) { + val lotto = Lotto() + lotto.markCorrectCount(correctCount) + + lotto.markedCorrectCount shouldBe correctCount + lotto.compensation shouldBe LottoCompensationStrategy.findByCorrectCount(correctCount)?.compensation + } } From 48cfead6d8b6fedf8bb12a45e80b27607bb7e98b Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sun, 24 Nov 2024 12:03:46 +0900 Subject: [PATCH 12/15] =?UTF-8?q?[STEP-2]=20=EB=A1=9C=EB=98=90=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=B6=9C=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/src/main/kotlin/lotto/Main.kt | 5 +++++ .../kotlin/lotto/domain/LottoPurchaseAmount.kt | 4 ++-- lotto/src/main/kotlin/lotto/view/ResultView.kt | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 lotto/src/main/kotlin/lotto/view/ResultView.kt diff --git a/lotto/src/main/kotlin/lotto/Main.kt b/lotto/src/main/kotlin/lotto/Main.kt index 139a071d1d..7f05f7b362 100644 --- a/lotto/src/main/kotlin/lotto/Main.kt +++ b/lotto/src/main/kotlin/lotto/Main.kt @@ -5,10 +5,15 @@ import lotto.domain.LottoPurchaseAmount import lotto.domain.LottoUser import lotto.view.InputView.inputCorrectNumbers import lotto.view.InputView.inputPurchaseAmount +import lotto.view.ResultView.printLotteries +import lotto.view.ResultView.printLottoPurchaseAmount fun main() { val lottoPurchaseAmount = LottoPurchaseAmount(inputPurchaseAmount()) + printLottoPurchaseAmount(lottoPurchaseAmount) + val lottoUser = LottoUser(lottoPurchaseAmount) + printLotteries(lottoUser) val correctNumbers = CorrectNumbers(inputCorrectNumbers()) diff --git a/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt b/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt index 1c85156ad7..24e6de1c1e 100644 --- a/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt +++ b/lotto/src/main/kotlin/lotto/domain/LottoPurchaseAmount.kt @@ -12,13 +12,13 @@ data class LottoPurchaseAmount( private fun Int.validateMinimum() { require(this >= MIN_PURCHASE_AMOUNT) { - "[PurchaseAmount] 구매금액은 ${MIN_PURCHASE_AMOUNT}원 이상이어야 합니다. | 입력금액: $this" + "[LottoPurchaseAmount] 구매금액은 ${MIN_PURCHASE_AMOUNT}원 이상이어야 합니다. | 입력금액: $this" } } private fun Int.validatePurchaseMinUnit() { require(this % MIN_PURCHASE_AMOUNT == 0) { - "[PurchaseAmount] 구매금액은 ${MIN_PURCHASE_AMOUNT}원 단위이어야 합니다. | 입력금액: $this" + "[LottoPurchaseAmount] 구매금액은 ${MIN_PURCHASE_AMOUNT}원 단위이어야 합니다. | 입력금액: $this" } } diff --git a/lotto/src/main/kotlin/lotto/view/ResultView.kt b/lotto/src/main/kotlin/lotto/view/ResultView.kt new file mode 100644 index 0000000000..50fae221cf --- /dev/null +++ b/lotto/src/main/kotlin/lotto/view/ResultView.kt @@ -0,0 +1,18 @@ +package lotto.view + +import lotto.domain.LottoPurchaseAmount +import lotto.domain.LottoUser + +object ResultView { + fun printLottoPurchaseAmount(purchaseAmount: LottoPurchaseAmount) { + val totalLottoCount = purchaseAmount.calculateLottoCount() + println("${totalLottoCount}개를 구매했습니다.") + } + + fun printLotteries(lottoUser: LottoUser) { + lottoUser.lotteries.forEach { + println(it.values) + } + println() + } +} From 3c7a55ae7a4c6e17af47306458e797159700c28a Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sun, 24 Nov 2024 12:58:32 +0900 Subject: [PATCH 13/15] =?UTF-8?q?[STEP-2]=20=EC=88=98=EC=9D=B5=EB=A5=A0=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/README.md | 3 ++- lotto/src/main/kotlin/lotto/Main.kt | 6 ++++- lotto/src/main/kotlin/lotto/domain/Lotto.kt | 8 ++++--- .../src/main/kotlin/lotto/domain/LottoUser.kt | 14 +++++++++++ .../domain/enums/LottoCompensationStrategy.kt | 4 ++-- .../src/main/kotlin/lotto/view/ResultView.kt | 24 ++++++++++++++++--- 6 files changed, 49 insertions(+), 10 deletions(-) diff --git a/lotto/README.md b/lotto/README.md index c62e333757..d814cbd30f 100644 --- a/lotto/README.md +++ b/lotto/README.md @@ -14,4 +14,5 @@ - [ ] 당첨 통계를 낼 수 있다. - [x] 3~6개 일치 여부를 판단할 수 있다. - [x] 일치한 개수 별로 당첨 금액이 다르게 책정된다. - - [ ] 총 수익률을 계산할 수 있다. + - [x] 당첨된 로또의 개수를 계산할 수 있다. + - [x] 총 수익률을 계산할 수 있다. diff --git a/lotto/src/main/kotlin/lotto/Main.kt b/lotto/src/main/kotlin/lotto/Main.kt index 7f05f7b362..5eda5e2a29 100644 --- a/lotto/src/main/kotlin/lotto/Main.kt +++ b/lotto/src/main/kotlin/lotto/Main.kt @@ -7,15 +7,19 @@ import lotto.view.InputView.inputCorrectNumbers import lotto.view.InputView.inputPurchaseAmount import lotto.view.ResultView.printLotteries import lotto.view.ResultView.printLottoPurchaseAmount +import lotto.view.ResultView.printLottoResult +import lotto.view.ResultView.print수익률 fun main() { val lottoPurchaseAmount = LottoPurchaseAmount(inputPurchaseAmount()) printLottoPurchaseAmount(lottoPurchaseAmount) val lottoUser = LottoUser(lottoPurchaseAmount) - printLotteries(lottoUser) + printLotteries(lottoUser.lotteries) val correctNumbers = CorrectNumbers(inputCorrectNumbers()) lottoUser.checkLotteries(correctNumbers) + printLottoResult(lottoUser.calculateLottoCorrectCount()) + print수익률(lottoUser.수익률) } diff --git a/lotto/src/main/kotlin/lotto/domain/Lotto.kt b/lotto/src/main/kotlin/lotto/domain/Lotto.kt index 4317c6edc3..1dda3cd24b 100644 --- a/lotto/src/main/kotlin/lotto/domain/Lotto.kt +++ b/lotto/src/main/kotlin/lotto/domain/Lotto.kt @@ -3,14 +3,16 @@ package lotto.domain import lotto.domain.enums.LottoCompensationStrategy data class Lotto( - val values: Set = generateLotto(), private var correctCount: Int? = null, + val generate: () -> Set = { generateRandomLotto() } ) { + val values: Set = generate.invoke() + val markedCorrectCount get() = correctCount ?: error("[Lotto] 마킹이 되지 않은 로또입니다.") val compensation - get() = LottoCompensationStrategy.getCompensationByCorrectCount(markedCorrectCount) + get() = LottoCompensationStrategy.getCompensationByCorrectCount(correctCount) fun markCorrectCount(correctCount: Int) { if (this.correctCount != null) { @@ -24,7 +26,7 @@ data class Lotto( private const val MAX_LOTTO_NUMBER = 45 private const val LOTTO_NUMBER_COUNT = 6 - private fun generateLotto(): Set { + private fun generateRandomLotto(): Set { return (MIN_LOTTO_NUMBER..MAX_LOTTO_NUMBER) .shuffled() .take(LOTTO_NUMBER_COUNT) diff --git a/lotto/src/main/kotlin/lotto/domain/LottoUser.kt b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt index f714d5a81a..583d8d8987 100644 --- a/lotto/src/main/kotlin/lotto/domain/LottoUser.kt +++ b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt @@ -1,11 +1,19 @@ package lotto.domain +import lotto.domain.enums.LottoCompensationStrategy +import java.math.BigDecimal + class LottoUser( val lottoPurchaseAmount: LottoPurchaseAmount, ) { private val lottoCount = lottoPurchaseAmount.calculateLottoCount() val lotteries: List = List(lottoCount) { Lotto() } + val compensation: Long + get() = lotteries.sumOf { it.compensation } + val 수익률: BigDecimal + get() = BigDecimal(compensation) / BigDecimal(lottoPurchaseAmount.amount) + fun checkLotteries(correctNumbers: CorrectNumbers) { lotteries.forEach { lotto -> val lottoNumbers = lotto.values @@ -14,4 +22,10 @@ class LottoUser( lotto.markCorrectCount(correctCount) } } + + fun calculateLottoCorrectCount(): Map { + return LottoCompensationStrategy.entries.associateWith { strategy -> + lotteries.count { it.markedCorrectCount == strategy.correctCount } + } + } } diff --git a/lotto/src/main/kotlin/lotto/domain/enums/LottoCompensationStrategy.kt b/lotto/src/main/kotlin/lotto/domain/enums/LottoCompensationStrategy.kt index 0c87a9f8d3..b3ca12c347 100644 --- a/lotto/src/main/kotlin/lotto/domain/enums/LottoCompensationStrategy.kt +++ b/lotto/src/main/kotlin/lotto/domain/enums/LottoCompensationStrategy.kt @@ -16,10 +16,10 @@ enum class LottoCompensationStrategy( companion object { private const val DEFAULT_COMPENSATION = 0L - fun findByCorrectCount(correctCount: Int): LottoCompensationStrategy? = + fun findByCorrectCount(correctCount: Int?): LottoCompensationStrategy? = entries.find { it.correctCount == correctCount } - fun getCompensationByCorrectCount(correctCount: Int): Long = + fun getCompensationByCorrectCount(correctCount: Int?): Long = findByCorrectCount(correctCount)?.compensation ?: DEFAULT_COMPENSATION } diff --git a/lotto/src/main/kotlin/lotto/view/ResultView.kt b/lotto/src/main/kotlin/lotto/view/ResultView.kt index 50fae221cf..90a426a40b 100644 --- a/lotto/src/main/kotlin/lotto/view/ResultView.kt +++ b/lotto/src/main/kotlin/lotto/view/ResultView.kt @@ -1,7 +1,9 @@ package lotto.view +import lotto.domain.Lotto import lotto.domain.LottoPurchaseAmount -import lotto.domain.LottoUser +import lotto.domain.enums.LottoCompensationStrategy +import java.math.BigDecimal object ResultView { fun printLottoPurchaseAmount(purchaseAmount: LottoPurchaseAmount) { @@ -9,10 +11,26 @@ object ResultView { println("${totalLottoCount}개를 구매했습니다.") } - fun printLotteries(lottoUser: LottoUser) { - lottoUser.lotteries.forEach { + fun printLotteries(lotteries: List) { + lotteries.forEach { println(it.values) } println() } + + fun printLottoResult(lottoResults: Map) { + val title = """ + + 당첨 통계 + --------- + """.trimIndent() + println(title) + lottoResults.forEach { (strategy, count) -> + println("${strategy.correctCount}개 일치 (${strategy.compensation}${strategy.unit})- ${count}개") + } + } + + fun print수익률(수익률: BigDecimal) { + println("총 수익률은 ${수익률.setScale(2)}입니다.") + } } From e58758594757a1c359fca60f59f4aa8bf4d8c72f Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sun, 24 Nov 2024 13:17:14 +0900 Subject: [PATCH 14/15] =?UTF-8?q?[STEP-2]=20=EB=8B=B9=EC=B2=A8=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EA=B3=84=EC=82=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/src/main/kotlin/lotto/domain/Lotto.kt | 6 +++--- lotto/src/main/kotlin/lotto/domain/LottoUser.kt | 16 +++++++++++----- .../test/kotlin/lotto/domain/LottoUserTest.kt | 12 ++++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lotto/src/main/kotlin/lotto/domain/Lotto.kt b/lotto/src/main/kotlin/lotto/domain/Lotto.kt index 1dda3cd24b..50b6900c9d 100644 --- a/lotto/src/main/kotlin/lotto/domain/Lotto.kt +++ b/lotto/src/main/kotlin/lotto/domain/Lotto.kt @@ -4,9 +4,9 @@ import lotto.domain.enums.LottoCompensationStrategy data class Lotto( private var correctCount: Int? = null, - val generate: () -> Set = { generateRandomLotto() } + val rolling: () -> Set = { rollingRandom() }, ) { - val values: Set = generate.invoke() + val values: Set = rolling.invoke() val markedCorrectCount get() = correctCount ?: error("[Lotto] 마킹이 되지 않은 로또입니다.") @@ -26,7 +26,7 @@ data class Lotto( private const val MAX_LOTTO_NUMBER = 45 private const val LOTTO_NUMBER_COUNT = 6 - private fun generateRandomLotto(): Set { + private fun rollingRandom(): Set { return (MIN_LOTTO_NUMBER..MAX_LOTTO_NUMBER) .shuffled() .take(LOTTO_NUMBER_COUNT) diff --git a/lotto/src/main/kotlin/lotto/domain/LottoUser.kt b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt index 583d8d8987..67a821260f 100644 --- a/lotto/src/main/kotlin/lotto/domain/LottoUser.kt +++ b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt @@ -5,10 +5,10 @@ import java.math.BigDecimal class LottoUser( val lottoPurchaseAmount: LottoPurchaseAmount, + lottoCount: Int = lottoPurchaseAmount.calculateLottoCount(), + lottoGenerateStrategy: (() -> Set)? = null, ) { - private val lottoCount = lottoPurchaseAmount.calculateLottoCount() - val lotteries: List = List(lottoCount) { Lotto() } - + val lotteries: List = generateLotteries(lottoCount, lottoGenerateStrategy) val compensation: Long get() = lotteries.sumOf { it.compensation } val 수익률: BigDecimal @@ -25,7 +25,13 @@ class LottoUser( fun calculateLottoCorrectCount(): Map { return LottoCompensationStrategy.entries.associateWith { strategy -> - lotteries.count { it.markedCorrectCount == strategy.correctCount } - } + lotteries.count { it.markedCorrectCount == strategy.correctCount } + } + } + + companion object { + private fun generateLotteries(lottoCount: Int, lottoGenerateStrategy: (() -> Set)?) = List(lottoCount) { + lottoGenerateStrategy?.let { Lotto { it.invoke() } } ?: Lotto() + } } } diff --git a/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt index 72b815b09f..b9ac6397f7 100644 --- a/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt @@ -2,6 +2,7 @@ package lotto.domain import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.matchers.shouldBe +import lotto.domain.enums.LottoCompensationStrategy import org.junit.jupiter.api.Test class LottoUserTest { @@ -42,5 +43,16 @@ class LottoUserTest { @Test fun `사용자는 당첨금액을 알고 있다`() { + val lottoPurchaseAmount = LottoPurchaseAmount(10000) + val lottoUser = LottoUser(lottoPurchaseAmount) { + (1..6).toSet() + } + + val inputs = (1..6).toSet() + val correctNumbers = CorrectNumbers(inputs) + + lottoUser.checkLotteries(correctNumbers) + + lottoUser.compensation shouldBe LottoCompensationStrategy.`6개`.compensation * lottoPurchaseAmount.calculateLottoCount() } } From 8c8bc137758c0462b6cb81e749a28565d4bf51b6 Mon Sep 17 00:00:00 2001 From: 0703kyj Date: Sun, 24 Nov 2024 13:24:59 +0900 Subject: [PATCH 15/15] =?UTF-8?q?[STEP-2]=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lotto/README.md | 2 +- lotto/src/main/kotlin/lotto/domain/LottoUser.kt | 1 + lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt | 5 ++++- .../src/main/kotlin/stringcalculator/StringParser.kt | 7 ++++--- .../test/kotlin/stringcalculator/StringParserTest.kt | 11 +++++++++++ 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lotto/README.md b/lotto/README.md index d814cbd30f..e7fb69c837 100644 --- a/lotto/README.md +++ b/lotto/README.md @@ -11,7 +11,7 @@ - [x] 로또의 숫자는 1~45 까지 이다. - [x] 당첨 번호를 입력할 수 있다. - [x] 당첨 번호에 따른 맞춘 개수를 로또가 가지고 있는다. -- [ ] 당첨 통계를 낼 수 있다. +- [x] 당첨 통계를 낼 수 있다. - [x] 3~6개 일치 여부를 판단할 수 있다. - [x] 일치한 개수 별로 당첨 금액이 다르게 책정된다. - [x] 당첨된 로또의 개수를 계산할 수 있다. diff --git a/lotto/src/main/kotlin/lotto/domain/LottoUser.kt b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt index 67a821260f..6c1d370e4d 100644 --- a/lotto/src/main/kotlin/lotto/domain/LottoUser.kt +++ b/lotto/src/main/kotlin/lotto/domain/LottoUser.kt @@ -9,6 +9,7 @@ class LottoUser( lottoGenerateStrategy: (() -> Set)? = null, ) { val lotteries: List = generateLotteries(lottoCount, lottoGenerateStrategy) + val compensation: Long get() = lotteries.sumOf { it.compensation } val 수익률: BigDecimal diff --git a/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt b/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt index b9ac6397f7..be1c53bcd0 100644 --- a/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt +++ b/lotto/src/test/kotlin/lotto/domain/LottoUserTest.kt @@ -1,6 +1,9 @@ package lotto.domain import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.inspectors.shouldForAll +import io.kotest.inspectors.shouldForExactly +import io.kotest.matchers.should import io.kotest.matchers.shouldBe import lotto.domain.enums.LottoCompensationStrategy import org.junit.jupiter.api.Test @@ -34,7 +37,7 @@ class LottoUserTest { lottoUser.checkLotteries(correctNumbers) - lottoUser.lotteries.forEach { + lottoUser.lotteries.shouldForAll { shouldNotThrowAny { it.markedCorrectCount } diff --git a/string-calculator/src/main/kotlin/stringcalculator/StringParser.kt b/string-calculator/src/main/kotlin/stringcalculator/StringParser.kt index dce1d1730c..57b7417fd9 100644 --- a/string-calculator/src/main/kotlin/stringcalculator/StringParser.kt +++ b/string-calculator/src/main/kotlin/stringcalculator/StringParser.kt @@ -3,10 +3,11 @@ package stringcalculator object StringParser { const val 공백 = "" const val 줄바꿈 = "\\n" + private const val DEFAULT_PAYLOAD = "0" - fun String.toCalculateRequest(): StringCalculateRequest { - val payload = this.split(줄바꿈).last() - return StringCalculateRequest(delimiter = Delimiter(this), payload = payload) + fun String?.toCalculateRequest(): StringCalculateRequest { + val payload = this?.split(줄바꿈)?.last() + return StringCalculateRequest(delimiter = Delimiter(this), payload = payload ?: DEFAULT_PAYLOAD) } fun String.splitToInts(delimiter: Delimiter): List { diff --git a/string-calculator/src/test/kotlin/stringcalculator/StringParserTest.kt b/string-calculator/src/test/kotlin/stringcalculator/StringParserTest.kt index 9feba95ba3..34614d5935 100644 --- a/string-calculator/src/test/kotlin/stringcalculator/StringParserTest.kt +++ b/string-calculator/src/test/kotlin/stringcalculator/StringParserTest.kt @@ -4,6 +4,8 @@ import io.kotest.assertions.throwables.shouldThrowExactly import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.NullAndEmptySource import stringcalculator.StringParser.splitToInts import stringcalculator.StringParser.toCalculateRequest @@ -75,4 +77,13 @@ class StringParserTest { exception.message shouldContain "값이 음수거나 Int로 변환하는데 실패했습니다" } + + @ParameterizedTest + @NullAndEmptySource + fun `빈 문자열 또는 null 값을 입력할 경우 0을 반환해야 한다`(input: String?) { + val (delimiter, payload) = input.toCalculateRequest() + val numbers = payload.splitToInts(delimiter) + + numbers.sum() shouldBe 0 + } }