From d24621394868dca8c29c2b1c7cd19c95191cef27 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 00:33:31 +0900 Subject: [PATCH 01/27] =?UTF-8?q?feat:=20=EA=B5=AC=EC=9E=85=EA=B8=88?= =?UTF-8?q?=EC=95=A1=EC=9D=84=20=EC=9E=85=EB=A0=A5=EB=B0=9B=EB=8A=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 35 +++++++++++++++++++++++++++ src/main/kotlin/lotto/LottoMachine.kt | 11 +++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/main/kotlin/lotto/LottoMachine.kt diff --git a/README.md b/README.md index 4fc0ae874..a90c2dc70 100644 --- a/README.md +++ b/README.md @@ -1 +1,36 @@ # kotlin-lotto-precourse + +## 기능 목록 +간단한 로또 발매기를 구현한다. + +### 당첨 기준 +당첨은 1등부터 5등까지 있다. 당첨 기준과 금액은 아래와 같다. +1등: 6개 번호 일치 / 2,000,000,000원 +2등: 5개 번호 + 보너스 번호 일치 / 30,000,000원 +3등: 5개 번호 일치 / 1,500,000원 +4등: 4개 번호 일치 / 50,000원 +5등: 3개 번호 일치 / 5,000원 + +로또 1장의 가격은 1,000원이다. +구입 금액은 1000원 단위로 입력 받으며 1000원으로 나누어 떨어지지 않는 경우 예외처리한다. +사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 로또 게임을 종료한다. +사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다. +Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리한다. + +### 입력 +- 당첨 번호와 보너스 번호를 입력받음 +- 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑음 +- 로또 번호의 숫자 범위는 1~45 +- 당첨 번호를 쉼표(,)를 기준으로 구분 +- 로또 구입 금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 함 +- 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑음 + +### 출력 +- 발행한 로또 수량 및 번호 출력 +- 로또 번호는 오름차순 정렬 +- 당첨 내역 출력 +- 수익률은 소수점 둘째 자리에서 반올림 +- 예외 상황 시 에러 문구를 출력 +ex) 단, 에러 문구는 "[ERROR]"로 시작해야 함 + + diff --git a/src/main/kotlin/lotto/LottoMachine.kt b/src/main/kotlin/lotto/LottoMachine.kt new file mode 100644 index 000000000..5d72a834c --- /dev/null +++ b/src/main/kotlin/lotto/LottoMachine.kt @@ -0,0 +1,11 @@ +package lotto + +import camp.nextstep.edu.missionutils.Console +class LottoMachine() { + + fun payLottoery():Int { + println("구입금액을 입력해주세요.") + val payment = Console.readLine() + return payment.toInt() + } +} \ No newline at end of file From a4cfd44b52cdb95514056d63a0a05df2973ecdef Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 15:13:50 +0900 Subject: [PATCH 02/27] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/LottoMachine.kt | 37 +++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/lotto/LottoMachine.kt b/src/main/kotlin/lotto/LottoMachine.kt index 5d72a834c..9d54c5128 100644 --- a/src/main/kotlin/lotto/LottoMachine.kt +++ b/src/main/kotlin/lotto/LottoMachine.kt @@ -3,9 +3,42 @@ package lotto import camp.nextstep.edu.missionutils.Console class LottoMachine() { - fun payLottoery():Int { + fun payLottoery():String { println("구입금액을 입력해주세요.") val payment = Console.readLine() - return payment.toInt() + return payment } + + fun String.validateInt():Int { + return this.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자를 입력하세요.") + } + + fun Int.validatePositive():Int { + require(this > 0) {"[ERROR] 양수 숫자를 입력하세요."} + return this + } + + fun Int.validateDivisibleBy(divisor: Int):Int { + require(this % divisor == 0) { "[ERROR] ${divisor}원 단위로 입력해 주세요." } + return this + } + + fun String.validateIntList():List { + return this.split(',').map { + it.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자만 입력해 주세요.") + } + } + + fun List.findDuplicates(count: Int): List { + require(this.toSet().size == count) {"[ERROR] 중복되지 않는 숫자로 입력해 주세요."} + return this + } + + fun List.validateCount(count: Int): List { + require(this.size == count) { "갯수에 맞게 입력해 주세요." } + return this + } + + + } \ No newline at end of file From 9704a1db0522991d59ae0014b8a1cfca2f63b63a Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 15:33:04 +0900 Subject: [PATCH 03/27] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/LottoMachine.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/kotlin/lotto/LottoMachine.kt b/src/main/kotlin/lotto/LottoMachine.kt index 9d54c5128..18ef6bb82 100644 --- a/src/main/kotlin/lotto/LottoMachine.kt +++ b/src/main/kotlin/lotto/LottoMachine.kt @@ -1,6 +1,9 @@ package lotto import camp.nextstep.edu.missionutils.Console +import kotlin.math.pow +import kotlin.math.roundToInt + class LottoMachine() { fun payLottoery():String { @@ -39,6 +42,19 @@ class LottoMachine() { return this } + fun Int.validateRange(start: Int, end: Int): Int { + require(this in start..end) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } + return this + } + fun List.validateRange(start: Int, end: Int): List { + require(this.all { it in start..end }) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } + return this + } + fun Double.round(decimalPlaces: Int): Double { + val factor = 10.0.pow(decimalPlaces) + return (this * factor).roundToInt() / factor + } + } \ No newline at end of file From 3b475c90401637ef642f3ea950f456c3ccad23a3 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 15:38:17 +0900 Subject: [PATCH 04/27] =?UTF-8?q?Style:=20=EC=98=88=EC=99=B8=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=EB=A7=8C=20=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/{LottoMachine.kt => Validation.kt} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/main/kotlin/lotto/{LottoMachine.kt => Validation.kt} (98%) diff --git a/src/main/kotlin/lotto/LottoMachine.kt b/src/main/kotlin/lotto/Validation.kt similarity index 98% rename from src/main/kotlin/lotto/LottoMachine.kt rename to src/main/kotlin/lotto/Validation.kt index 18ef6bb82..966d1a077 100644 --- a/src/main/kotlin/lotto/LottoMachine.kt +++ b/src/main/kotlin/lotto/Validation.kt @@ -4,7 +4,7 @@ import camp.nextstep.edu.missionutils.Console import kotlin.math.pow import kotlin.math.roundToInt -class LottoMachine() { +class Validation() { fun payLottoery():String { println("구입금액을 입력해주세요.") @@ -56,5 +56,5 @@ class LottoMachine() { val factor = 10.0.pow(decimalPlaces) return (this * factor).roundToInt() / factor } - + } \ No newline at end of file From 2dc0c80c3974449b8be9d1c48ed055c43ee59104 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 16:14:03 +0900 Subject: [PATCH 05/27] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=EA=B5=AC?= =?UTF-8?q?=EC=9E=85=EA=B8=88=EC=95=A1,=20=EB=8B=B9=EC=B2=A8=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8,=20=EB=B3=B4=EB=84=88=EC=8A=A4=20=EB=B2=88=ED=98=B8?= =?UTF-8?q?=EB=A5=BC=20=EC=9E=85=EB=A0=A5=EB=B0=9B=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/LottoView.kt | 27 +++++++++++++++++++++++++++ src/main/kotlin/lotto/Validation.kt | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/lotto/LottoView.kt diff --git a/src/main/kotlin/lotto/LottoView.kt b/src/main/kotlin/lotto/LottoView.kt new file mode 100644 index 000000000..7fb9d21e7 --- /dev/null +++ b/src/main/kotlin/lotto/LottoView.kt @@ -0,0 +1,27 @@ +package lotto + +import camp.nextstep.edu.missionutils.Console +class LottoView { + fun printLottoPurchaseRequest() = println("구입금액을 입력해 주세요.") + + fun inputLottoPurchaseAmount(): String = Console.readLine() + + fun printLottoCount(count: Int) = println("\n${count}개를 구매했습니다.") + + fun printLottos(lottos: List) { + lottos.forEach { + println(it.toString()) + } + } + + fun printWinningNumberRequest() = println("\n당첨 번호를 입력해 주세요.") + + fun inputWinningNumber(): String = Console.readLine() + + fun printBonusNumberRequest() = println("\n보너스 번호를 입력해 주세요.") + + fun inputBonusNumber(): String = Console.readLine() + + fun printLottoRankHeader() = println("\n당첨 통계\n---") + +} diff --git a/src/main/kotlin/lotto/Validation.kt b/src/main/kotlin/lotto/Validation.kt index 966d1a077..c3a2fdf15 100644 --- a/src/main/kotlin/lotto/Validation.kt +++ b/src/main/kotlin/lotto/Validation.kt @@ -6,7 +6,7 @@ import kotlin.math.roundToInt class Validation() { - fun payLottoery():String { + fun payLottoery(): String { println("구입금액을 입력해주세요.") val payment = Console.readLine() return payment From 65cfd602801367f10ce2aa14d83f95c0c4f69be6 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 17:15:56 +0900 Subject: [PATCH 06/27] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EA=B5=AC?= =?UTF-8?q?=EC=9E=85=20=EA=B8=88=EC=95=A1=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/LottoController.kt | 20 ++++++++++++++++++++ src/main/kotlin/lotto/LottoPurchaseAmount.kt | 18 ++++++++++++++++++ src/main/kotlin/lotto/LottoView.kt | 4 +++- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/lotto/LottoController.kt create mode 100644 src/main/kotlin/lotto/LottoPurchaseAmount.kt diff --git a/src/main/kotlin/lotto/LottoController.kt b/src/main/kotlin/lotto/LottoController.kt new file mode 100644 index 000000000..330955cde --- /dev/null +++ b/src/main/kotlin/lotto/LottoController.kt @@ -0,0 +1,20 @@ +package lotto + +class LottoController(private val lottoView: LottoView) { + fun run() { + val lottoPurchaseAmount = payMoney() + val lottos = purchaseLottos(lottoPurchaseAmount.money) + } + + private fun payMoney(): LottoPurchaseAmount { + return try { + lottoView.printLottoPurchaseRequest() + LottoPurchaseAmount.from(lottoView.inputLottoPurchaseAmount()) + } catch (e: IllegalArgumentException) { + lottoView.printError(e.message) + return payMoney() + } + } + +} + diff --git a/src/main/kotlin/lotto/LottoPurchaseAmount.kt b/src/main/kotlin/lotto/LottoPurchaseAmount.kt new file mode 100644 index 000000000..ecb283e7c --- /dev/null +++ b/src/main/kotlin/lotto/LottoPurchaseAmount.kt @@ -0,0 +1,18 @@ +package lotto + +import lotto.Validation.validateInt +import lotto.Validation.validatePositive +import lotto.Validation.validateDivisibleBy + +class LottoPurchaseAmount private constructor(val money: Int) { + companion object { + fun from(inputLottoPurchaseAmount: String): LottoPurchaseAmount { + return LottoPurchaseAmount( + inputLottoPurchaseAmount + .validateInt() + .validatePositive() + .validateDivisibleBy() + ) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/LottoView.kt b/src/main/kotlin/lotto/LottoView.kt index 7fb9d21e7..8269b3613 100644 --- a/src/main/kotlin/lotto/LottoView.kt +++ b/src/main/kotlin/lotto/LottoView.kt @@ -2,6 +2,8 @@ package lotto import camp.nextstep.edu.missionutils.Console class LottoView { + fun printError(message: String?) = println(message) + fun printLottoPurchaseRequest() = println("구입금액을 입력해 주세요.") fun inputLottoPurchaseAmount(): String = Console.readLine() @@ -23,5 +25,5 @@ class LottoView { fun inputBonusNumber(): String = Console.readLine() fun printLottoRankHeader() = println("\n당첨 통계\n---") - + } From aa56782e7d794d57c6f29465e950d5d0bbfba6f8 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 18:02:19 +0900 Subject: [PATCH 07/27] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=EB=A5=BC=20?= =?UTF-8?q?=EB=B0=9C=ED=96=89=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/Validation.kt | 60 ------------------- .../lotto/{ => controller}/LottoController.kt | 15 ++++- .../lotto/{ => model}/LottoPurchaseAmount.kt | 8 +-- src/main/kotlin/lotto/model/LottoStore.kt | 14 +++++ src/main/kotlin/lotto/util/Validation.kt | 49 +++++++++++++++ src/main/kotlin/lotto/{ => view}/LottoView.kt | 4 +- 6 files changed, 84 insertions(+), 66 deletions(-) delete mode 100644 src/main/kotlin/lotto/Validation.kt rename src/main/kotlin/lotto/{ => controller}/LottoController.kt (53%) rename src/main/kotlin/lotto/{ => model}/LottoPurchaseAmount.kt (74%) create mode 100644 src/main/kotlin/lotto/model/LottoStore.kt create mode 100644 src/main/kotlin/lotto/util/Validation.kt rename src/main/kotlin/lotto/{ => view}/LottoView.kt (95%) diff --git a/src/main/kotlin/lotto/Validation.kt b/src/main/kotlin/lotto/Validation.kt deleted file mode 100644 index c3a2fdf15..000000000 --- a/src/main/kotlin/lotto/Validation.kt +++ /dev/null @@ -1,60 +0,0 @@ -package lotto - -import camp.nextstep.edu.missionutils.Console -import kotlin.math.pow -import kotlin.math.roundToInt - -class Validation() { - - fun payLottoery(): String { - println("구입금액을 입력해주세요.") - val payment = Console.readLine() - return payment - } - - fun String.validateInt():Int { - return this.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자를 입력하세요.") - } - - fun Int.validatePositive():Int { - require(this > 0) {"[ERROR] 양수 숫자를 입력하세요."} - return this - } - - fun Int.validateDivisibleBy(divisor: Int):Int { - require(this % divisor == 0) { "[ERROR] ${divisor}원 단위로 입력해 주세요." } - return this - } - - fun String.validateIntList():List { - return this.split(',').map { - it.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자만 입력해 주세요.") - } - } - - fun List.findDuplicates(count: Int): List { - require(this.toSet().size == count) {"[ERROR] 중복되지 않는 숫자로 입력해 주세요."} - return this - } - - fun List.validateCount(count: Int): List { - require(this.size == count) { "갯수에 맞게 입력해 주세요." } - return this - } - - fun Int.validateRange(start: Int, end: Int): Int { - require(this in start..end) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } - return this - } - - fun List.validateRange(start: Int, end: Int): List { - require(this.all { it in start..end }) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } - return this - } - - fun Double.round(decimalPlaces: Int): Double { - val factor = 10.0.pow(decimalPlaces) - return (this * factor).roundToInt() / factor - } - -} \ No newline at end of file diff --git a/src/main/kotlin/lotto/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt similarity index 53% rename from src/main/kotlin/lotto/LottoController.kt rename to src/main/kotlin/lotto/controller/LottoController.kt index 330955cde..944487092 100644 --- a/src/main/kotlin/lotto/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -1,4 +1,7 @@ -package lotto +package lotto.controller + +import lotto.view.LottoView +import lotto.model.LottoPurchaseAmount class LottoController(private val lottoView: LottoView) { fun run() { @@ -16,5 +19,15 @@ class LottoController(private val lottoView: LottoView) { } } + private fun purchaseLottos(money: Int): List { + val lottoCount = money / LottoStore.LOTTO_TICKET_PRICE + val lottos = mutableListOf() + lottoView.printLottoCount(lottoCount) + repeat(lottoCount) { lottos.add(Lotto.fromList(LottoStore().buy())) } + lottoView.printLottos(lottos) + return lottos + } + + } diff --git a/src/main/kotlin/lotto/LottoPurchaseAmount.kt b/src/main/kotlin/lotto/model/LottoPurchaseAmount.kt similarity index 74% rename from src/main/kotlin/lotto/LottoPurchaseAmount.kt rename to src/main/kotlin/lotto/model/LottoPurchaseAmount.kt index ecb283e7c..d5200819e 100644 --- a/src/main/kotlin/lotto/LottoPurchaseAmount.kt +++ b/src/main/kotlin/lotto/model/LottoPurchaseAmount.kt @@ -1,8 +1,8 @@ -package lotto +package lotto.model -import lotto.Validation.validateInt -import lotto.Validation.validatePositive -import lotto.Validation.validateDivisibleBy +import lotto.util.validateInt +import lotto.util.validatePositive +import lotto.util.validateDivisibleBy class LottoPurchaseAmount private constructor(val money: Int) { companion object { diff --git a/src/main/kotlin/lotto/model/LottoStore.kt b/src/main/kotlin/lotto/model/LottoStore.kt new file mode 100644 index 000000000..56ebb1610 --- /dev/null +++ b/src/main/kotlin/lotto/model/LottoStore.kt @@ -0,0 +1,14 @@ +package lotto.model + +import camp.nextstep.edu.missionutils.Randoms +class LottoStore: Store { + override fun buy(): List { + return Randoms.pickUniqueNumbersInRange(LOTTO_MIN_NUMBER ,LOTTO_MAX_NUMBER,LOTTO_NUMBER_COUNT) + } + + companion object { + const val LOTTO_NUMBER_COUNT = 6 + const val LOTTO_MIN_NUMBER = 1 + const val LOTTO_MAX_NUMBER = 45 + } +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/util/Validation.kt b/src/main/kotlin/lotto/util/Validation.kt new file mode 100644 index 000000000..abdbb1e33 --- /dev/null +++ b/src/main/kotlin/lotto/util/Validation.kt @@ -0,0 +1,49 @@ +package lotto.util + +import kotlin.math.pow +import kotlin.math.roundToInt + +fun String.validateInt(): Int { + return this.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자를 입력하세요.") +} + +fun Int.validatePositive(): Int { + require(this > 0) { "[ERROR] 양수 숫자를 입력하세요." } + return this +} + +fun Int.validateDivisibleBy(divisor: Int): Int { + require(this % divisor == 0) { "[ERROR] ${divisor}원 단위로 입력해 주세요." } + return this +} + +fun String.validateIntList(): List { + return this.split(',').map { + it.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자만 입력해 주세요.") + } +} + +fun List.findDuplicates(count: Int): List { + require(this.toSet().size == count) { "[ERROR] 중복되지 않는 숫자로 입력해 주세요." } + return this +} + +fun List.validateCount(count: Int): List { + require(this.size == count) { "갯수에 맞게 입력해 주세요." } + return this +} + +fun Int.validateRange(start: Int, end: Int): Int { + require(this in start..end) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } + return this +} + +fun List.validateRange(start: Int, end: Int): List { + require(this.all { it in start..end }) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } + return this +} + +fun Double.round(decimalPlaces: Int): Double { + val factor = 10.0.pow(decimalPlaces) + return (this * factor).roundToInt() / factor +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/LottoView.kt b/src/main/kotlin/lotto/view/LottoView.kt similarity index 95% rename from src/main/kotlin/lotto/LottoView.kt rename to src/main/kotlin/lotto/view/LottoView.kt index 8269b3613..6895b14de 100644 --- a/src/main/kotlin/lotto/LottoView.kt +++ b/src/main/kotlin/lotto/view/LottoView.kt @@ -1,6 +1,8 @@ -package lotto +package lotto.view import camp.nextstep.edu.missionutils.Console +import lotto.Lotto + class LottoView { fun printError(message: String?) = println(message) From 8b430ad9f9b33bcf491d6ac1d20ad4ed0c7b4fce Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 18:27:24 +0900 Subject: [PATCH 08/27] =?UTF-8?q?feat:=20Lotto=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EA=B8=B0=EB=B3=B8=20=EA=B8=B0=EB=8A=A5=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 --- src/main/kotlin/lotto/Lotto.kt | 28 +++++++++++++++++++ .../lotto/controller/LottoController.kt | 1 + src/main/kotlin/lotto/model/LottoStore.kt | 1 + 3 files changed, 30 insertions(+) diff --git a/src/main/kotlin/lotto/Lotto.kt b/src/main/kotlin/lotto/Lotto.kt index b97abc385..99a825fe6 100644 --- a/src/main/kotlin/lotto/Lotto.kt +++ b/src/main/kotlin/lotto/Lotto.kt @@ -1,9 +1,37 @@ package lotto +import lotto.model.LottoStore +import lotto.util.* + class Lotto(private val numbers: List) { init { require(numbers.size == 6) { "[ERROR] 로또 번호는 6개여야 합니다." } } // TODO: 추가 기능 구현 + override fun toString(): String { + return numbers.joinToString(prefix = "[", postfix = "]", separator = ", ") { it.toString() } + } + + fun toList(): List { + return numbers + } + + fun IsContain(number: Int): Boolean { + return numbers.contains(number) + } + + companion object { + fun fromInput(inputNumbers: String): Lotto { + return fromList(inputNumbers.validateIntList()) + } + + fun fromList(numbers: List): Lotto { + return numbers + .validateCount(LottoStore.LOTTO_NUMBER_COUNT) + .findDuplicates(LottoStore.LOTTO_NUMBER_COUNT) + .validateRange(LottoStore.LOTTO_MIN_NUMBER, LottoStore.LOTTO_MAX_NUMBER) + .run { Lotto(this) } + } + } } diff --git a/src/main/kotlin/lotto/controller/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt index 944487092..698036e6f 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -2,6 +2,7 @@ package lotto.controller import lotto.view.LottoView import lotto.model.LottoPurchaseAmount +import lotto.model.LottoStore class LottoController(private val lottoView: LottoView) { fun run() { diff --git a/src/main/kotlin/lotto/model/LottoStore.kt b/src/main/kotlin/lotto/model/LottoStore.kt index 56ebb1610..83b8b2858 100644 --- a/src/main/kotlin/lotto/model/LottoStore.kt +++ b/src/main/kotlin/lotto/model/LottoStore.kt @@ -10,5 +10,6 @@ class LottoStore: Store { const val LOTTO_NUMBER_COUNT = 6 const val LOTTO_MIN_NUMBER = 1 const val LOTTO_MAX_NUMBER = 45 + const val LOTTO_TICKET_PRICE = 1000 } } \ No newline at end of file From 01665d04001d540e211c424db29f44bb542e3338 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 18:36:36 +0900 Subject: [PATCH 09/27] =?UTF-8?q?feat:=20=EA=B0=81=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lotto/controller/LottoController.kt | 1 + .../kotlin/lotto/model/LottoPurchaseAmount.kt | 2 +- src/main/kotlin/lotto/model/LottoRanking.kt | 4 +++ src/main/kotlin/lotto/model/LottoResult.kt | 28 +++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/lotto/model/LottoRanking.kt create mode 100644 src/main/kotlin/lotto/model/LottoResult.kt diff --git a/src/main/kotlin/lotto/controller/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt index 698036e6f..c0f986171 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -1,5 +1,6 @@ package lotto.controller +import lotto.Lotto import lotto.view.LottoView import lotto.model.LottoPurchaseAmount import lotto.model.LottoStore diff --git a/src/main/kotlin/lotto/model/LottoPurchaseAmount.kt b/src/main/kotlin/lotto/model/LottoPurchaseAmount.kt index d5200819e..a3f9df484 100644 --- a/src/main/kotlin/lotto/model/LottoPurchaseAmount.kt +++ b/src/main/kotlin/lotto/model/LottoPurchaseAmount.kt @@ -11,7 +11,7 @@ class LottoPurchaseAmount private constructor(val money: Int) { inputLottoPurchaseAmount .validateInt() .validatePositive() - .validateDivisibleBy() + .validateDivisibleBy(LottoStore.LOTTO_TICKET_PRICE) ) } } diff --git a/src/main/kotlin/lotto/model/LottoRanking.kt b/src/main/kotlin/lotto/model/LottoRanking.kt new file mode 100644 index 000000000..bb34686a6 --- /dev/null +++ b/src/main/kotlin/lotto/model/LottoRanking.kt @@ -0,0 +1,4 @@ +package lotto.model + +class LottoRanking(var countByRanking: MutableMap, var totalReturn: Double){ +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/model/LottoResult.kt b/src/main/kotlin/lotto/model/LottoResult.kt new file mode 100644 index 000000000..e4fe3d1db --- /dev/null +++ b/src/main/kotlin/lotto/model/LottoResult.kt @@ -0,0 +1,28 @@ +package lotto.model + +enum class LottoResult(val prize: Int, private val message: String) { + MISS(0, "꽝"), + THREE_MATCH(5000, "3개 일치 (5,000원)"), + FOUR_MATCH(50000, "4개 일치 (50,000원)"), + FIVE_MATCH(1500000, "5개 일치 (1,500,000원)"), + FIVE_MATCH_WITH_BONUS(30000000, "5개 일치, 보너스 볼 일치 (30,000,000원)"), + SIX_MATCH(200000000, "6개 일치 (2,000,000,000원)"); + + fun getMessage(count: Int): String { + return "$message - ${count}개" + } + + companion object { + fun of(countOfMatch: Int, isBonusMatch: Boolean): LottoResult { + return when { + countOfMatch == 6 -> SIX_MATCH + countOfMatch == 5 && isBonusMatch -> FIVE_MATCH_WITH_BONUS + countOfMatch == 5 -> FIVE_MATCH + countOfMatch == 4 -> FOUR_MATCH + countOfMatch == 3 -> THREE_MATCH + else -> MISS + } + } + } +} + From fcc079ce375a195bdf442ffb17e46912165f54c0 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 18:44:43 +0900 Subject: [PATCH 10/27] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=88=98=EC=9D=B5?= =?UTF-8?q?=EB=A5=A0=20=EA=B3=84=EC=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/model/LottoRanking.kt | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/kotlin/lotto/model/LottoRanking.kt b/src/main/kotlin/lotto/model/LottoRanking.kt index bb34686a6..441d86bd4 100644 --- a/src/main/kotlin/lotto/model/LottoRanking.kt +++ b/src/main/kotlin/lotto/model/LottoRanking.kt @@ -1,4 +1,30 @@ package lotto.model +import lotto.model.LottoStore +import lotto.util.round + class LottoRanking(var countByRanking: MutableMap, var totalReturn: Double){ + companion object { + fun of(lottoResults: List): LottoRanking { + val lottoResultBundle = mutableMapOf() + var prize = 0.0 + + LottoResult.entries.forEach { result -> lottoResultBundle[result] = 0 } + + for (result in lottoResults) { + lottoResultBundle[result] = (lottoResultBundle[result] ?: 0) + 1 + prize += result.prize + } + + prize = calculateROI((lottoResults.size * LottoStore.LOTTO_TICKET_PRICE), prize).round(PRECISION) + return LottoRanking(lottoResultBundle, prize) + } + + private fun calculateROI(initialInvestment: Int, profit: Double): Double { + return (profit / initialInvestment) * PERCENT_FACTOR + } + + private const val PERCENT_FACTOR = 100 + private const val PRECISION = 2 + } } \ No newline at end of file From 34dd13aca379611903eb187018d011bc1113a8bd Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 18:48:08 +0900 Subject: [PATCH 11/27] =?UTF-8?q?feat:=20Store=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EC=83=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/model/LottoStore.kt | 4 ++-- src/main/kotlin/lotto/model/Store.kt | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/lotto/model/Store.kt diff --git a/src/main/kotlin/lotto/model/LottoStore.kt b/src/main/kotlin/lotto/model/LottoStore.kt index 83b8b2858..513eb2478 100644 --- a/src/main/kotlin/lotto/model/LottoStore.kt +++ b/src/main/kotlin/lotto/model/LottoStore.kt @@ -2,7 +2,7 @@ package lotto.model import camp.nextstep.edu.missionutils.Randoms class LottoStore: Store { - override fun buy(): List { + override fun sell(): List { return Randoms.pickUniqueNumbersInRange(LOTTO_MIN_NUMBER ,LOTTO_MAX_NUMBER,LOTTO_NUMBER_COUNT) } @@ -12,4 +12,4 @@ class LottoStore: Store { const val LOTTO_MAX_NUMBER = 45 const val LOTTO_TICKET_PRICE = 1000 } -} \ No newline at end of file +} diff --git a/src/main/kotlin/lotto/model/Store.kt b/src/main/kotlin/lotto/model/Store.kt new file mode 100644 index 000000000..55aa9c574 --- /dev/null +++ b/src/main/kotlin/lotto/model/Store.kt @@ -0,0 +1,5 @@ +package lotto.model + +interface Store { + fun sell(): List +} \ No newline at end of file From 590dff4a18211dfa4cc3c4d399197fc1539e7083 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 19:07:10 +0900 Subject: [PATCH 12/27] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=8B=B9?= =?UTF-8?q?=EC=B2=A8=20=EB=B2=88=ED=98=B8=20=EC=B6=94=EC=B2=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/Lotto.kt | 2 +- .../lotto/controller/LottoController.kt | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/lotto/Lotto.kt b/src/main/kotlin/lotto/Lotto.kt index 99a825fe6..12eed3ab4 100644 --- a/src/main/kotlin/lotto/Lotto.kt +++ b/src/main/kotlin/lotto/Lotto.kt @@ -17,7 +17,7 @@ class Lotto(private val numbers: List) { return numbers } - fun IsContain(number: Int): Boolean { + fun isContain(number: Int): Boolean { return numbers.contains(number) } diff --git a/src/main/kotlin/lotto/controller/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt index c0f986171..cd00e07fb 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -4,11 +4,14 @@ import lotto.Lotto import lotto.view.LottoView import lotto.model.LottoPurchaseAmount import lotto.model.LottoStore +import lotto.util.* class LottoController(private val lottoView: LottoView) { fun run() { val lottoPurchaseAmount = payMoney() val lottos = purchaseLottos(lottoPurchaseAmount.money) + val lottoResult = processLottoWinningNumbers() + val bonus = processLottoBonusNumber(lottoResult) } private fun payMoney(): LottoPurchaseAmount { @@ -30,6 +33,30 @@ class LottoController(private val lottoView: LottoView) { return lottos } + private fun processLottoWinningNumbers(): Lotto { + return try { + lottoView.printWinningNumberRequest() + Lotto.fromInput(lottoView.inputWinningNumber()) + } catch (e: IllegalArgumentException) { + lottoView.printError(e.message) + return processLottoWinningNumbers() + } + } + + private fun processLottoBonusNumber(lotto: Lotto): Int { + return try { + lottoView.printBonusNumberRequest() + val bonus = lottoView.inputBonusNumber() + .validateInt() + .validateRange(LottoStore.LOTTO_MIN_NUMBER, LottoStore.LOTTO_MAX_NUMBER) + + if (lotto.isContain(bonus)) throw IllegalArgumentException("[ERROR] 중복되지 않는 숫자로 입력해 주세요.") + bonus + } catch (e: IllegalArgumentException) { + lottoView.printError(e.message) + return processLottoBonusNumber(lotto) + } + } } From 0df59a98747c284d5e2312201b2fd894789cddfc Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 19:13:28 +0900 Subject: [PATCH 13/27] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EA=B3=84=EC=82=B0=EA=B3=BC=20=EC=88=9C=EC=9C=84=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lotto/controller/LottoController.kt | 27 ++++++++++++++++--- src/main/kotlin/lotto/{ => model}/Lotto.kt | 3 +-- src/main/kotlin/lotto/model/LottoRanking.kt | 2 +- src/main/kotlin/lotto/view/LottoView.kt | 6 ++++- src/test/kotlin/lotto/LottoTest.kt | 1 + 5 files changed, 31 insertions(+), 8 deletions(-) rename src/main/kotlin/lotto/{ => model}/Lotto.kt (95%) diff --git a/src/main/kotlin/lotto/controller/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt index cd00e07fb..cb7bc07a4 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -1,9 +1,7 @@ package lotto.controller -import lotto.Lotto +import lotto.model.* import lotto.view.LottoView -import lotto.model.LottoPurchaseAmount -import lotto.model.LottoStore import lotto.util.* class LottoController(private val lottoView: LottoView) { @@ -12,6 +10,8 @@ class LottoController(private val lottoView: LottoView) { val lottos = purchaseLottos(lottoPurchaseAmount.money) val lottoResult = processLottoWinningNumbers() val bonus = processLottoBonusNumber(lottoResult) + val results = checkResults(lottos, lottoResult, bonus) + calculateRanks(results) } private fun payMoney(): LottoPurchaseAmount { @@ -28,7 +28,7 @@ class LottoController(private val lottoView: LottoView) { val lottoCount = money / LottoStore.LOTTO_TICKET_PRICE val lottos = mutableListOf() lottoView.printLottoCount(lottoCount) - repeat(lottoCount) { lottos.add(Lotto.fromList(LottoStore().buy())) } + repeat(lottoCount) { lottos.add(Lotto.fromList(LottoStore().sell())) } lottoView.printLottos(lottos) return lottos } @@ -57,6 +57,25 @@ class LottoController(private val lottoView: LottoView) { return processLottoBonusNumber(lotto) } } + private fun checkResults(myLotto: List, answer: Lotto, bonus: Int): List { + val ranks = mutableListOf() + for (lotto in myLotto) { + val count = lotto.toList().intersect(answer.toList().toSet()).size + val hasBonus = lotto.isContain(bonus) + ranks.add(LottoResult.of(count, hasBonus)) + } + return ranks + } + + private fun calculateRanks(lottoResults: List) { + lottoView.printLottoRankHeader() + val ranks = LottoRanking.of(lottoResults) + for ((rank, count) in ranks.countByRanking) { + if (rank == LottoResult.MISS) continue + lottoView.printLottoRank(rank, count) + } + lottoView.printRevenue(ranks.totalRevenue) + } } diff --git a/src/main/kotlin/lotto/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt similarity index 95% rename from src/main/kotlin/lotto/Lotto.kt rename to src/main/kotlin/lotto/model/Lotto.kt index 12eed3ab4..10b73bc42 100644 --- a/src/main/kotlin/lotto/Lotto.kt +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -1,6 +1,5 @@ -package lotto +package lotto.model -import lotto.model.LottoStore import lotto.util.* class Lotto(private val numbers: List) { diff --git a/src/main/kotlin/lotto/model/LottoRanking.kt b/src/main/kotlin/lotto/model/LottoRanking.kt index 441d86bd4..e9760ed78 100644 --- a/src/main/kotlin/lotto/model/LottoRanking.kt +++ b/src/main/kotlin/lotto/model/LottoRanking.kt @@ -3,7 +3,7 @@ package lotto.model import lotto.model.LottoStore import lotto.util.round -class LottoRanking(var countByRanking: MutableMap, var totalReturn: Double){ +class LottoRanking(var countByRanking: MutableMap, var totalRevenue: Double){ companion object { fun of(lottoResults: List): LottoRanking { val lottoResultBundle = mutableMapOf() diff --git a/src/main/kotlin/lotto/view/LottoView.kt b/src/main/kotlin/lotto/view/LottoView.kt index 6895b14de..839004863 100644 --- a/src/main/kotlin/lotto/view/LottoView.kt +++ b/src/main/kotlin/lotto/view/LottoView.kt @@ -1,7 +1,8 @@ package lotto.view import camp.nextstep.edu.missionutils.Console -import lotto.Lotto +import lotto.model.Lotto +import lotto.model.LottoResult class LottoView { fun printError(message: String?) = println(message) @@ -28,4 +29,7 @@ class LottoView { fun printLottoRankHeader() = println("\n당첨 통계\n---") + fun printLottoRank(rank: LottoResult, count: Int) = println(rank.getMessage(count)) + + fun printRevenue(revenue: Double) = println("총 수익률은 ${revenue}%입니다.") } diff --git a/src/test/kotlin/lotto/LottoTest.kt b/src/test/kotlin/lotto/LottoTest.kt index 122fae572..b82b74cf6 100644 --- a/src/test/kotlin/lotto/LottoTest.kt +++ b/src/test/kotlin/lotto/LottoTest.kt @@ -1,5 +1,6 @@ package lotto +import lotto.model.Lotto import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows From 0285235a9aaa1d9dd4ed18957f0fca5b7215b639 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 19:14:28 +0900 Subject: [PATCH 14/27] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=8B=A4=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/Application.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/kotlin/lotto/Application.kt b/src/main/kotlin/lotto/Application.kt index 151821c9c..2aefd40c6 100644 --- a/src/main/kotlin/lotto/Application.kt +++ b/src/main/kotlin/lotto/Application.kt @@ -1,5 +1,12 @@ package lotto +import lotto.controller.LottoController +import lotto.view.LottoView + fun main() { // TODO: 프로그램 구현 + val lottoView = LottoView() + val lottoController = LottoController(lottoView) + + lottoController.run() } From 7fc54248c8d1823cdf2aee9f12c9dce1fad5bad7 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 19:26:16 +0900 Subject: [PATCH 15/27] =?UTF-8?q?fix:=20=EC=97=90=EB=9F=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=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/controller/LottoController.kt | 4 ++-- src/main/kotlin/lotto/view/LottoView.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/lotto/controller/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt index cb7bc07a4..0e10bd473 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -61,8 +61,8 @@ class LottoController(private val lottoView: LottoView) { val ranks = mutableListOf() for (lotto in myLotto) { val count = lotto.toList().intersect(answer.toList().toSet()).size - val hasBonus = lotto.isContain(bonus) - ranks.add(LottoResult.of(count, hasBonus)) + val isBonus = lotto.isContain(bonus) + ranks.add(LottoResult.of(count, isBonus)) } return ranks } diff --git a/src/main/kotlin/lotto/view/LottoView.kt b/src/main/kotlin/lotto/view/LottoView.kt index 839004863..75e2daa21 100644 --- a/src/main/kotlin/lotto/view/LottoView.kt +++ b/src/main/kotlin/lotto/view/LottoView.kt @@ -31,5 +31,5 @@ class LottoView { fun printLottoRank(rank: LottoResult, count: Int) = println(rank.getMessage(count)) - fun printRevenue(revenue: Double) = println("총 수익률은 ${revenue}%입니다.") + fun printRevenue(revenue: Double) = println("\n총 수익률은 ${revenue}%입니다.") } From e0c22be4624260e783634906c7dc9193760fb94d Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 21:40:46 +0900 Subject: [PATCH 16/27] =?UTF-8?q?fix:=20=EC=A4=91=EB=B3=B5=EB=90=9C=20?= =?UTF-8?q?=EC=88=AB=EC=9E=90=EB=A5=BC=20=ED=99=95=EC=9D=B8=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=A1=9C=EC=A7=81=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/model/Lotto.kt | 16 +++++++++++----- src/main/kotlin/lotto/util/Validation.kt | 5 +++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/lotto/model/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt index 10b73bc42..b4e507fe0 100644 --- a/src/main/kotlin/lotto/model/Lotto.kt +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -7,6 +7,12 @@ class Lotto(private val numbers: List) { require(numbers.size == 6) { "[ERROR] 로또 번호는 6개여야 합니다." } } + init { + numbers + .findDuplicates() + .validateRange(LottoStore.LOTTO_MIN_NUMBER, LottoStore.LOTTO_MAX_NUMBER); + } + // TODO: 추가 기능 구현 override fun toString(): String { return numbers.joinToString(prefix = "[", postfix = "]", separator = ", ") { it.toString() } @@ -26,11 +32,11 @@ class Lotto(private val numbers: List) { } fun fromList(numbers: List): Lotto { - return numbers - .validateCount(LottoStore.LOTTO_NUMBER_COUNT) - .findDuplicates(LottoStore.LOTTO_NUMBER_COUNT) - .validateRange(LottoStore.LOTTO_MIN_NUMBER, LottoStore.LOTTO_MAX_NUMBER) - .run { Lotto(this) } + return Lotto(numbers + .validateCount(LottoStore.LOTTO_NUMBER_COUNT) + .findDuplicates() + .validateRange(LottoStore.LOTTO_MIN_NUMBER, LottoStore.LOTTO_MAX_NUMBER) + ) } } } diff --git a/src/main/kotlin/lotto/util/Validation.kt b/src/main/kotlin/lotto/util/Validation.kt index abdbb1e33..e2e7808ee 100644 --- a/src/main/kotlin/lotto/util/Validation.kt +++ b/src/main/kotlin/lotto/util/Validation.kt @@ -23,8 +23,9 @@ fun String.validateIntList(): List { } } -fun List.findDuplicates(count: Int): List { - require(this.toSet().size == count) { "[ERROR] 중복되지 않는 숫자로 입력해 주세요." } +fun List.findDuplicates(): List { + val duplicates = this.groupingBy { it }.eachCount().filter { it.value > 1 }.keys + require(duplicates.isEmpty()) { "[ERROR] 중복되지 않는 숫자로 입력해 주세요." } return this } From ccceea645f6c59cb670d8e37e920144c50e5e822 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 22:00:43 +0900 Subject: [PATCH 17/27] =?UTF-8?q?Chore:=20=EA=B8=B0=EB=8A=A5=20=EB=AA=85?= =?UTF-8?q?=EC=84=B8=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a90c2dc70..8dd981c17 100644 --- a/README.md +++ b/README.md @@ -11,17 +11,14 @@ 4등: 4개 번호 일치 / 50,000원 5등: 3개 번호 일치 / 5,000원 -로또 1장의 가격은 1,000원이다. -구입 금액은 1000원 단위로 입력 받으며 1000원으로 나누어 떨어지지 않는 경우 예외처리한다. -사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 로또 게임을 종료한다. -사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다. -Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리한다. ### 입력 - 당첨 번호와 보너스 번호를 입력받음 - 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑음 - 로또 번호의 숫자 범위는 1~45 - 당첨 번호를 쉼표(,)를 기준으로 구분 +- 로또 1장의 가격은 1,000원 +- 구입 금액은 1000원 단위로 입력 받으며 1000원으로 나누어 떨어지지 않는 경우 예외처리 - 로또 구입 금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 함 - 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑음 @@ -32,5 +29,13 @@ Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같 - 수익률은 소수점 둘째 자리에서 반올림 - 예외 상황 시 에러 문구를 출력 ex) 단, 에러 문구는 "[ERROR]"로 시작해야 함 +- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받음 + Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리 +- 사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 로또 게임을 종료 - +#### 예외 +- 로또 번호가 숫자가 아닌 경우 +- 로또 번호가 1~45 사이의 범위를 벗어난 경우 +- 로또 리스트 갯수가 맞지 않는 경우 +- 로또 번호의 숫자가 중복되는 경우 +- 로또 구입 금액이 1000원으로 나누어 떨어지지 않는 경우 \ No newline at end of file From 479afa5cd70c203fdb65db20dfe9f867131cd191 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 22:02:39 +0900 Subject: [PATCH 18/27] =?UTF-8?q?Chore:=20=EA=B8=B0=EB=8A=A5=20=EB=AA=85?= =?UTF-8?q?=EC=84=B8=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8dd981c17..a877a447b 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ - 예외 상황 시 에러 문구를 출력 ex) 단, 에러 문구는 "[ERROR]"로 시작해야 함 - 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받음 - Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리 +- Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리 - 사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 로또 게임을 종료 #### 예외 From 2dfdc4d93a7069c4744a0615d1b76d48f0a5b35b Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 22:09:11 +0900 Subject: [PATCH 19/27] =?UTF-8?q?refactor:=20=EA=B8=B0=EB=B3=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=9E=90=EB=A5=BC=20=ED=98=B8=EC=B6=9C?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=EC=9D=84=20=EC=9C=84=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/model/Lotto.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/lotto/model/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt index b4e507fe0..024e65039 100644 --- a/src/main/kotlin/lotto/model/Lotto.kt +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -32,11 +32,8 @@ class Lotto(private val numbers: List) { } fun fromList(numbers: List): Lotto { - return Lotto(numbers - .validateCount(LottoStore.LOTTO_NUMBER_COUNT) - .findDuplicates() - .validateRange(LottoStore.LOTTO_MIN_NUMBER, LottoStore.LOTTO_MAX_NUMBER) - ) + return Lotto(numbers) // 기본 생성자를 호출하여 유효성 검증을 수행 } } } + From 46e71c375ea9baa0d3afd3985463bcd4edc39597 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 22:12:52 +0900 Subject: [PATCH 20/27] =?UTF-8?q?refactor:=20=EB=A7=A4=EC=A7=81=EB=84=98?= =?UTF-8?q?=EB=B2=84=20=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/model/Lotto.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/lotto/model/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt index 024e65039..5c2d419ef 100644 --- a/src/main/kotlin/lotto/model/Lotto.kt +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -15,7 +15,7 @@ class Lotto(private val numbers: List) { // TODO: 추가 기능 구현 override fun toString(): String { - return numbers.joinToString(prefix = "[", postfix = "]", separator = ", ") { it.toString() } + return numbers.joinToString(prefix = PREFIX, postfix = POSTFIX, separator = SEPARATOR) { it.toString() } } fun toList(): List { @@ -27,6 +27,10 @@ class Lotto(private val numbers: List) { } companion object { + private const val PREFIX = "[" + private const val POSTFIX = "]" + private const val SEPARATOR = ", " + fun fromInput(inputNumbers: String): Lotto { return fromList(inputNumbers.validateIntList()) } From 5b4a7c2b727f46d51ce6873896c386543328aa77 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 22:23:59 +0900 Subject: [PATCH 21/27] =?UTF-8?q?refactor:=20=EC=B4=88=EA=B8=B0=ED=99=94?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81,=20=EB=93=B1=EC=88=98=20=EC=B9=B4?= =?UTF-8?q?=EC=9A=B4=ED=8A=B8=20=EC=A6=9D=EA=B0=80=20=EB=B0=8F=20=EC=83=81?= =?UTF-8?q?=EA=B8=88=20=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81,=20?= =?UTF-8?q?=EC=88=98=EC=9D=B5=EB=A5=A0=20=EA=B3=84=EC=82=B0=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=9D=84=20=EA=B0=81=EA=B0=81=20=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/model/LottoRanking.kt | 32 +++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/lotto/model/LottoRanking.kt b/src/main/kotlin/lotto/model/LottoRanking.kt index e9760ed78..dce3b517f 100644 --- a/src/main/kotlin/lotto/model/LottoRanking.kt +++ b/src/main/kotlin/lotto/model/LottoRanking.kt @@ -3,28 +3,42 @@ package lotto.model import lotto.model.LottoStore import lotto.util.round -class LottoRanking(var countByRanking: MutableMap, var totalRevenue: Double){ +class LottoRanking(var countByRanking: MutableMap, var totalRevenue: Double) { companion object { fun of(lottoResults: List): LottoRanking { - val lottoResultBundle = mutableMapOf() - var prize = 0.0 + val lottoResultBundle = initializeResultBundle() // 1. 초기화 + val prize = calculateTotalPrize(lottoResults, lottoResultBundle) // 2. 등수에 해당하는 count 증가 및 상금 계산 + val totalRevenue = calculateROI(lottoResults.size, prize) // 3. 수익률 계산 및 반올림 + return LottoRanking(lottoResultBundle, totalRevenue) + } + private fun initializeResultBundle(): MutableMap { + val lottoResultBundle = mutableMapOf() LottoResult.entries.forEach { result -> lottoResultBundle[result] = 0 } + return lottoResultBundle + } + private fun calculateTotalPrize( + lottoResults: List, + lottoResultBundle: MutableMap + ): Double { + var prize = 0.0 for (result in lottoResults) { lottoResultBundle[result] = (lottoResultBundle[result] ?: 0) + 1 prize += result.prize } - - prize = calculateROI((lottoResults.size * LottoStore.LOTTO_TICKET_PRICE), prize).round(PRECISION) - return LottoRanking(lottoResultBundle, prize) + return prize } - private fun calculateROI(initialInvestment: Int, profit: Double): Double { - return (profit / initialInvestment) * PERCENT_FACTOR + private fun calculateROI(lottoCount: Int, profit: Double): Double { + val initialInvestment = lottoCount * LottoStore.LOTTO_TICKET_PRICE + val roi = (profit / initialInvestment) * PERCENT_FACTOR + return roi.round(PRECISION) } private const val PERCENT_FACTOR = 100 private const val PRECISION = 2 } -} \ No newline at end of file +} + + From ceac4ea84bff743718aac10f144a765afc935c53 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 22:52:12 +0900 Subject: [PATCH 22/27] =?UTF-8?q?feat:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=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/lotto/util/Validation.kt | 23 +++++++++++++++++------ src/test/kotlin/lotto/LottoTest.kt | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/lotto/util/Validation.kt b/src/main/kotlin/lotto/util/Validation.kt index e2e7808ee..52f6c4fc3 100644 --- a/src/main/kotlin/lotto/util/Validation.kt +++ b/src/main/kotlin/lotto/util/Validation.kt @@ -3,6 +3,16 @@ package lotto.util import kotlin.math.pow import kotlin.math.roundToInt +class LottoConstants { + companion object { + const val LOTTO_NUMBER_COUNT = 6 + const val MIN_LOTTO_NUMBER = 1 + const val MAX_LOTTO_NUMBER = 45 + const val DIVISOR = 1000 + const val PRECISION = 2 + } +} + fun String.validateInt(): Int { return this.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자를 입력하세요.") } @@ -12,7 +22,7 @@ fun Int.validatePositive(): Int { return this } -fun Int.validateDivisibleBy(divisor: Int): Int { +fun Int.validateDivisibleBy(divisor: Int = LottoConstants.DIVISOR): Int { require(this % divisor == 0) { "[ERROR] ${divisor}원 단위로 입력해 주세요." } return this } @@ -29,22 +39,23 @@ fun List.findDuplicates(): List { return this } -fun List.validateCount(count: Int): List { +fun List.validateCount(count: Int = LottoConstants.LOTTO_NUMBER_COUNT): List { require(this.size == count) { "갯수에 맞게 입력해 주세요." } return this } -fun Int.validateRange(start: Int, end: Int): Int { +fun Int.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER, end: Int = LottoConstants.MAX_LOTTO_NUMBER): Int { require(this in start..end) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } return this } -fun List.validateRange(start: Int, end: Int): List { +fun List.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER, end: Int = LottoConstants.MAX_LOTTO_NUMBER): List { require(this.all { it in start..end }) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } return this } -fun Double.round(decimalPlaces: Int): Double { +fun Double.round(decimalPlaces: Int = LottoConstants.PRECISION): Double { val factor = 10.0.pow(decimalPlaces) return (this * factor).roundToInt() / factor -} \ No newline at end of file +} + diff --git a/src/test/kotlin/lotto/LottoTest.kt b/src/test/kotlin/lotto/LottoTest.kt index b82b74cf6..209259131 100644 --- a/src/test/kotlin/lotto/LottoTest.kt +++ b/src/test/kotlin/lotto/LottoTest.kt @@ -1,6 +1,7 @@ package lotto import lotto.model.Lotto +import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows @@ -21,4 +22,17 @@ class LottoTest { } // TODO: 추가 기능 구현에 따른 테스트 코드 작성 + @Test + fun `로또 번호의 범위가 1 ~ 45에 해당하지 않으면 예외가 발생한다`() { + assertThrows { + Lotto.fromList(listOf(50, 5, 2, 20, 17, 19)) + } + } + @Test + fun `isContain() 번호 확인 리턴 검증`() { + val lotto = Lotto.fromList(listOf(1, 2, 3, 4, 5, 6)) + assertThat(lotto.isContain(1)).isEqualTo(true) + assertThat(lotto.isContain(2)).isEqualTo(true) + assertThat(lotto.isContain(10)).isEqualTo(false) + } } From 5de360d9e3cef4be80e7860907938242b99d3246 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 22:53:22 +0900 Subject: [PATCH 23/27] =?UTF-8?q?feat:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=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/test/kotlin/lotto/LottoTest.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/kotlin/lotto/LottoTest.kt b/src/test/kotlin/lotto/LottoTest.kt index 209259131..6181574a8 100644 --- a/src/test/kotlin/lotto/LottoTest.kt +++ b/src/test/kotlin/lotto/LottoTest.kt @@ -1,6 +1,7 @@ package lotto import lotto.model.Lotto +import lotto.model.LottoPurchaseAmount import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows @@ -29,10 +30,17 @@ class LottoTest { } } @Test - fun `isContain() 번호 확인 리턴 검증`() { + fun `isContain() 포함된 번호가 맞는지 확인한다`() { val lotto = Lotto.fromList(listOf(1, 2, 3, 4, 5, 6)) assertThat(lotto.isContain(1)).isEqualTo(true) assertThat(lotto.isContain(2)).isEqualTo(true) assertThat(lotto.isContain(10)).isEqualTo(false) } + + @Test + fun `로또 머니가 양수가 아니면 예외가 발생한다`() { + assertThrows { + LottoPurchaseAmount.from("-1000") + } + } } From a8f8497a1c3927c46f74fce1e87475dd62083f22 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 22:54:28 +0900 Subject: [PATCH 24/27] =?UTF-8?q?feat:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=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/test/kotlin/lotto/LottoTest.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/kotlin/lotto/LottoTest.kt b/src/test/kotlin/lotto/LottoTest.kt index 6181574a8..fcf0895c4 100644 --- a/src/test/kotlin/lotto/LottoTest.kt +++ b/src/test/kotlin/lotto/LottoTest.kt @@ -38,9 +38,15 @@ class LottoTest { } @Test - fun `로또 머니가 양수가 아니면 예외가 발생한다`() { + fun `로또 구입금액이 양수가 아니면 예외가 발생한다`() { assertThrows { LottoPurchaseAmount.from("-1000") } } + @Test + fun `로또 구입금액이 1000원 단위로 나누어지지 않으면 예외가 발생한다`() { + assertThrows { + LottoPurchaseAmount.from("1500") + } + } } From 45d39a1e6705000c0bb7e39c560da1112303876d Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 23:51:10 +0900 Subject: [PATCH 25/27] =?UTF-8?q?chore:=20=EC=97=90=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=84=B8=EC=A7=80=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/util/Validation.kt | 6 +++--- src/test/kotlin/lotto/LottoTest.kt | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/lotto/util/Validation.kt b/src/main/kotlin/lotto/util/Validation.kt index 52f6c4fc3..e82f2b80f 100644 --- a/src/main/kotlin/lotto/util/Validation.kt +++ b/src/main/kotlin/lotto/util/Validation.kt @@ -40,17 +40,17 @@ fun List.findDuplicates(): List { } fun List.validateCount(count: Int = LottoConstants.LOTTO_NUMBER_COUNT): List { - require(this.size == count) { "갯수에 맞게 입력해 주세요." } + require(this.size == count) { "[ERROR] 갯수에 맞게 입력해 주세요." } return this } fun Int.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER, end: Int = LottoConstants.MAX_LOTTO_NUMBER): Int { - require(this in start..end) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } + require(this in start..end) { "[ERROR] 1~45 내의 숫자를 입력해 주세요. $start ~ $end" } return this } fun List.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER, end: Int = LottoConstants.MAX_LOTTO_NUMBER): List { - require(this.all { it in start..end }) { "1~45 내의 숫자를 입력해 주세요. $start ~ $end" } + require(this.all { it in start..end }) { "[ERROR] 1~45 내의 숫자를 입력해 주세요. $start ~ $end" } return this } diff --git a/src/test/kotlin/lotto/LottoTest.kt b/src/test/kotlin/lotto/LottoTest.kt index fcf0895c4..de70ca402 100644 --- a/src/test/kotlin/lotto/LottoTest.kt +++ b/src/test/kotlin/lotto/LottoTest.kt @@ -49,4 +49,10 @@ class LottoTest { LottoPurchaseAmount.from("1500") } } + @Test + fun `로또 구입금액이 정수가 아니면 예외가 발생한다`() { + assertThrows { + LottoPurchaseAmount.from("1000j") + } + } } From a363e6bc8108c6b4c313b8a948c7773fdb714ef7 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 23:53:56 +0900 Subject: [PATCH 26/27] =?UTF-8?q?chore:=20=EB=A7=A4=EC=A7=81=EB=84=98?= =?UTF-8?q?=EB=B2=84=20=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/util/Validation.kt | 53 ++++++++++++++---------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/main/kotlin/lotto/util/Validation.kt b/src/main/kotlin/lotto/util/Validation.kt index e82f2b80f..b4c7bb765 100644 --- a/src/main/kotlin/lotto/util/Validation.kt +++ b/src/main/kotlin/lotto/util/Validation.kt @@ -3,59 +3,66 @@ package lotto.util import kotlin.math.pow import kotlin.math.roundToInt -class LottoConstants { - companion object { - const val LOTTO_NUMBER_COUNT = 6 - const val MIN_LOTTO_NUMBER = 1 - const val MAX_LOTTO_NUMBER = 45 - const val DIVISOR = 1000 - const val PRECISION = 2 - } +enum class LottoConstants(val value: Int) { + LOTTO_NUMBER_COUNT(6), + MIN_LOTTO_NUMBER(1), + MAX_LOTTO_NUMBER(45), + DIVISOR(1000), + PRECISION(2) +} + +object ErrorMessages { + const val INVALID_NUMBER = "[ERROR] 숫자를 입력하세요." + const val NON_POSITIVE = "[ERROR] 양수 숫자를 입력하세요." + const val INVALID_DIVISOR = "[ERROR] %d원 단위로 입력해 주세요." + const val INVALID_INPUT = "[ERROR] 숫자만 입력해 주세요." + const val DUPLICATE_NUMBERS = "[ERROR] 중복되지 않는 숫자로 입력해 주세요." + const val INVALID_COUNT = "[ERROR] 갯수에 맞게 입력해 주세요." + const val OUT_OF_RANGE = "[ERROR] %d~%d 내의 숫자를 입력해 주세요." } fun String.validateInt(): Int { - return this.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자를 입력하세요.") + return this.toIntOrNull() ?: throw IllegalArgumentException(ErrorMessages.INVALID_NUMBER) } fun Int.validatePositive(): Int { - require(this > 0) { "[ERROR] 양수 숫자를 입력하세요." } + require(this > 0) { ErrorMessages.NON_POSITIVE } return this } -fun Int.validateDivisibleBy(divisor: Int = LottoConstants.DIVISOR): Int { - require(this % divisor == 0) { "[ERROR] ${divisor}원 단위로 입력해 주세요." } +fun Int.validateDivisibleBy(divisor: Int = LottoConstants.DIVISOR.value): Int { + require(this % divisor == 0) { ErrorMessages.INVALID_DIVISOR.format(divisor) } return this } fun String.validateIntList(): List { return this.split(',').map { - it.toIntOrNull() ?: throw IllegalArgumentException("[ERROR] 숫자만 입력해 주세요.") + it.toIntOrNull() ?: throw IllegalArgumentException(ErrorMessages.INVALID_INPUT) } } fun List.findDuplicates(): List { val duplicates = this.groupingBy { it }.eachCount().filter { it.value > 1 }.keys - require(duplicates.isEmpty()) { "[ERROR] 중복되지 않는 숫자로 입력해 주세요." } + require(duplicates.isEmpty()) { ErrorMessages.DUPLICATE_NUMBERS } return this } -fun List.validateCount(count: Int = LottoConstants.LOTTO_NUMBER_COUNT): List { - require(this.size == count) { "[ERROR] 갯수에 맞게 입력해 주세요." } +fun List.validateCount(count: Int = LottoConstants.LOTTO_NUMBER_COUNT.value): List { + require(this.size == count) { ErrorMessages.INVALID_COUNT } return this } -fun Int.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER, end: Int = LottoConstants.MAX_LOTTO_NUMBER): Int { - require(this in start..end) { "[ERROR] 1~45 내의 숫자를 입력해 주세요. $start ~ $end" } +fun Int.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER.value, end: Int = LottoConstants.MAX_LOTTO_NUMBER.value): Int { + require(this in start..end) { ErrorMessages.OUT_OF_RANGE.format(start, end) } return this } -fun List.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER, end: Int = LottoConstants.MAX_LOTTO_NUMBER): List { - require(this.all { it in start..end }) { "[ERROR] 1~45 내의 숫자를 입력해 주세요. $start ~ $end" } +fun List.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER.value, end: Int = LottoConstants.MAX_LOTTO_NUMBER.value): List { + require(this.all { it in start..end }) { ErrorMessages.OUT_OF_RANGE.format(start, end) } return this } -fun Double.round(decimalPlaces: Int = LottoConstants.PRECISION): Double { +fun Double.round(decimalPlaces: Int = LottoConstants.PRECISION.value): Double { val factor = 10.0.pow(decimalPlaces) return (this * factor).roundToInt() / factor -} - +} \ No newline at end of file From 715c724c065b63822677f4dd7da1b3d9f6159998 Mon Sep 17 00:00:00 2001 From: eden Date: Mon, 4 Nov 2024 23:56:56 +0900 Subject: [PATCH 27/27] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=ED=8F=AC=EB=A7=B7=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/controller/LottoController.kt | 1 + src/main/kotlin/lotto/model/Lotto.kt | 2 +- src/main/kotlin/lotto/model/LottoRanking.kt | 9 ++++----- src/main/kotlin/lotto/model/LottoStore.kt | 5 +++-- src/main/kotlin/lotto/util/Validation.kt | 10 ++++++++-- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/lotto/controller/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt index 0e10bd473..94667a5d4 100644 --- a/src/main/kotlin/lotto/controller/LottoController.kt +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -57,6 +57,7 @@ class LottoController(private val lottoView: LottoView) { return processLottoBonusNumber(lotto) } } + private fun checkResults(myLotto: List, answer: Lotto, bonus: Int): List { val ranks = mutableListOf() for (lotto in myLotto) { diff --git a/src/main/kotlin/lotto/model/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt index 5c2d419ef..a96a8bdce 100644 --- a/src/main/kotlin/lotto/model/Lotto.kt +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -36,7 +36,7 @@ class Lotto(private val numbers: List) { } fun fromList(numbers: List): Lotto { - return Lotto(numbers) // 기본 생성자를 호출하여 유효성 검증을 수행 + return Lotto(numbers) } } } diff --git a/src/main/kotlin/lotto/model/LottoRanking.kt b/src/main/kotlin/lotto/model/LottoRanking.kt index dce3b517f..7a1d64087 100644 --- a/src/main/kotlin/lotto/model/LottoRanking.kt +++ b/src/main/kotlin/lotto/model/LottoRanking.kt @@ -6,9 +6,9 @@ import lotto.util.round class LottoRanking(var countByRanking: MutableMap, var totalRevenue: Double) { companion object { fun of(lottoResults: List): LottoRanking { - val lottoResultBundle = initializeResultBundle() // 1. 초기화 - val prize = calculateTotalPrize(lottoResults, lottoResultBundle) // 2. 등수에 해당하는 count 증가 및 상금 계산 - val totalRevenue = calculateROI(lottoResults.size, prize) // 3. 수익률 계산 및 반올림 + val lottoResultBundle = initializeResultBundle() + val prize = calculateTotalPrize(lottoResults, lottoResultBundle) + val totalRevenue = calculateROI(lottoResults.size, prize) return LottoRanking(lottoResultBundle, totalRevenue) } @@ -19,8 +19,7 @@ class LottoRanking(var countByRanking: MutableMap, var totalRe } private fun calculateTotalPrize( - lottoResults: List, - lottoResultBundle: MutableMap + lottoResults: List, lottoResultBundle: MutableMap ): Double { var prize = 0.0 for (result in lottoResults) { diff --git a/src/main/kotlin/lotto/model/LottoStore.kt b/src/main/kotlin/lotto/model/LottoStore.kt index 513eb2478..e1599554f 100644 --- a/src/main/kotlin/lotto/model/LottoStore.kt +++ b/src/main/kotlin/lotto/model/LottoStore.kt @@ -1,9 +1,10 @@ package lotto.model import camp.nextstep.edu.missionutils.Randoms -class LottoStore: Store { + +class LottoStore : Store { override fun sell(): List { - return Randoms.pickUniqueNumbersInRange(LOTTO_MIN_NUMBER ,LOTTO_MAX_NUMBER,LOTTO_NUMBER_COUNT) + return Randoms.pickUniqueNumbersInRange(LOTTO_MIN_NUMBER, LOTTO_MAX_NUMBER, LOTTO_NUMBER_COUNT) } companion object { diff --git a/src/main/kotlin/lotto/util/Validation.kt b/src/main/kotlin/lotto/util/Validation.kt index b4c7bb765..829932300 100644 --- a/src/main/kotlin/lotto/util/Validation.kt +++ b/src/main/kotlin/lotto/util/Validation.kt @@ -52,12 +52,18 @@ fun List.validateCount(count: Int = LottoConstants.LOTTO_NUMBER_COUNT.value return this } -fun Int.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER.value, end: Int = LottoConstants.MAX_LOTTO_NUMBER.value): Int { +fun Int.validateRange( + start: Int = LottoConstants.MIN_LOTTO_NUMBER.value, + end: Int = LottoConstants.MAX_LOTTO_NUMBER.value +): Int { require(this in start..end) { ErrorMessages.OUT_OF_RANGE.format(start, end) } return this } -fun List.validateRange(start: Int = LottoConstants.MIN_LOTTO_NUMBER.value, end: Int = LottoConstants.MAX_LOTTO_NUMBER.value): List { +fun List.validateRange( + start: Int = LottoConstants.MIN_LOTTO_NUMBER.value, + end: Int = LottoConstants.MAX_LOTTO_NUMBER.value +): List { require(this.all { it in start..end }) { ErrorMessages.OUT_OF_RANGE.format(start, end) } return this }