From 27bba58774a248695231f5794298405f9f472236 Mon Sep 17 00:00:00 2001 From: baek0318 Date: Tue, 28 Nov 2023 23:24:26 +0900 Subject: [PATCH 1/5] =?UTF-8?q?step3=20:=20=EA=B5=AC=EB=A7=A4=ED=95=9C=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EC=A0=95=EB=A0=AC=20=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=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/view/OutputView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/lotto/view/OutputView.kt b/src/main/kotlin/lotto/view/OutputView.kt index 7197fa716..3281fd06c 100644 --- a/src/main/kotlin/lotto/view/OutputView.kt +++ b/src/main/kotlin/lotto/view/OutputView.kt @@ -8,7 +8,7 @@ object OutputView { fun outputBuyResult(lottoCount: Int, lotteries: List) { println("${lottoCount}개를 구매했습니다.") lotteries.forEach { - println(it.numbers) + println(it.numbers.sorted()) } println() } From dfe8dda668f9fbdf5f2e9f009169f2ca20151133 Mon Sep 17 00:00:00 2001 From: baek0318 Date: Thu, 30 Nov 2023 20:10:27 +0900 Subject: [PATCH 2/5] =?UTF-8?q?step3=20:=20MatchCount=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/domain/Earning.kt | 4 ++-- src/main/kotlin/lotto/domain/LottoAnswer.kt | 2 +- src/main/kotlin/lotto/domain/LottoResult.kt | 2 +- src/main/kotlin/lotto/domain/LottoService.kt | 2 +- src/main/kotlin/lotto/domain/MatchCount.kt | 25 ++++++++++++++++++++ src/test/kotlin/lotto/EarningTest.kt | 15 +++++++++--- 6 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/lotto/domain/MatchCount.kt diff --git a/src/main/kotlin/lotto/domain/Earning.kt b/src/main/kotlin/lotto/domain/Earning.kt index 723845ae4..43353787d 100644 --- a/src/main/kotlin/lotto/domain/Earning.kt +++ b/src/main/kotlin/lotto/domain/Earning.kt @@ -2,10 +2,10 @@ package lotto.domain @JvmInline value class Earning( - private val strategy: Map + private val strategy: Map ) { - fun calculate(result: Map): Int = result + fun calculate(result: Map): Int = result .filter { strategy.containsKey(it.key) } .map { (strategy[it.key]?.times(it.value) ?: 0) } .reduceOrNull { acc, i -> acc + i } ?: 0 diff --git a/src/main/kotlin/lotto/domain/LottoAnswer.kt b/src/main/kotlin/lotto/domain/LottoAnswer.kt index d7e870eef..353696d61 100644 --- a/src/main/kotlin/lotto/domain/LottoAnswer.kt +++ b/src/main/kotlin/lotto/domain/LottoAnswer.kt @@ -5,7 +5,7 @@ value class LottoAnswer( private val answer: List ) { - fun match(inputLottos: List): Map { + fun match(inputLottos: List): Map { return inputLottos .map { innerMatch(it) } .groupingBy { it } diff --git a/src/main/kotlin/lotto/domain/LottoResult.kt b/src/main/kotlin/lotto/domain/LottoResult.kt index ec9dc1856..71c9882b5 100644 --- a/src/main/kotlin/lotto/domain/LottoResult.kt +++ b/src/main/kotlin/lotto/domain/LottoResult.kt @@ -4,5 +4,5 @@ import java.math.BigDecimal data class LottoResult( val earningRate: BigDecimal, - val earnResult: Map + val earnResult: Map ) diff --git a/src/main/kotlin/lotto/domain/LottoService.kt b/src/main/kotlin/lotto/domain/LottoService.kt index 478d952d7..19550a0b3 100644 --- a/src/main/kotlin/lotto/domain/LottoService.kt +++ b/src/main/kotlin/lotto/domain/LottoService.kt @@ -9,7 +9,7 @@ class LottoService( ) { val lottoCount = lotteries.size - fun play(answer: LottoAnswer, earningStrategy: Map): LottoResult { + fun play(answer: LottoAnswer, earningStrategy: Map): LottoResult { val result = answer.match(lotteries) val earning = Earning(earningStrategy).calculate(result) val earningRate = EarningRate { earningRate -> diff --git a/src/main/kotlin/lotto/domain/MatchCount.kt b/src/main/kotlin/lotto/domain/MatchCount.kt new file mode 100644 index 000000000..2b23bb185 --- /dev/null +++ b/src/main/kotlin/lotto/domain/MatchCount.kt @@ -0,0 +1,25 @@ +package lotto.domain + +enum class MatchCount( + val matchCount: Int, + val isMatchBonus: Boolean +) { + ZERO(0, false), + ONE(1, false), + TWO(2, false), + THREE(3, false), + FOUR(4, false), + FIVE(5, false), + FIVE_WITH_BONUS(5, true), + SIX(6, false); + + companion object { + fun of(count: Int, isMatchBonus: Boolean): MatchCount { + val matchCount = values().find { it.matchCount == count } ?: throw IllegalArgumentException("해당하는 매치 카운트가 없습니다.") + if (matchCount == FIVE && isMatchBonus) { + return FIVE_WITH_BONUS + } + return matchCount + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/lotto/EarningTest.kt b/src/test/kotlin/lotto/EarningTest.kt index 873bf9408..7861cf21a 100644 --- a/src/test/kotlin/lotto/EarningTest.kt +++ b/src/test/kotlin/lotto/EarningTest.kt @@ -5,14 +5,23 @@ import io.kotest.data.Row2 import io.kotest.data.forAll import io.kotest.matchers.shouldBe import lotto.domain.Earning +import lotto.domain.MatchCount class EarningTest : StringSpec({ "정답 결과에 따라서 알맞은 수익이 발생해야한다" { - val earning = Earning(mapOf(3 to 5000, 4 to 50000, 5 to 1500000, 6 to 2000000000)) + val earning = Earning( + mapOf( + MatchCount.THREE to 5000, + MatchCount.FOUR to 50000, + MatchCount.FIVE to 1500000, + MatchCount.FIVE_WITH_BONUS to 30000000, + MatchCount.SIX to 2000000000 + ) + ) forAll( - Row2(mapOf(3 to 1), 5000), - Row2(mapOf(3 to 1, 4 to 2), 105000) + Row2(mapOf(MatchCount.THREE to 1), 5000), + Row2(mapOf(MatchCount.THREE to 1, MatchCount.FOUR to 2), 105000) ) { lottoResult, actual -> val result = earning.calculate(lottoResult) result shouldBe actual From 058c26a5c882f53821e3307cac12c1e6ca92e3c7 Mon Sep 17 00:00:00 2001 From: baek0318 Date: Thu, 30 Nov 2023 20:11:01 +0900 Subject: [PATCH 3/5] =?UTF-8?q?step3=20:=20=EB=B3=B4=EB=84=88=EC=8A=A4=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=B6=94=EA=B0=80=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/lotto/Main.kt | 12 ++++++++++-- src/main/kotlin/lotto/domain/LottoAnswer.kt | 18 ++++++++++++------ src/main/kotlin/lotto/view/InputView.kt | 5 +++++ src/main/kotlin/lotto/view/OutputView.kt | 14 +++++++++++--- src/test/kotlin/lotto/LottoAnswerTest.kt | 13 +++++++++++-- .../kotlin/lotto/TestNumberGeneratorFive.kt | 7 +++++++ 6 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 src/test/kotlin/lotto/TestNumberGeneratorFive.kt diff --git a/src/main/kotlin/lotto/Main.kt b/src/main/kotlin/lotto/Main.kt index 2fb1e2905..b083f1233 100644 --- a/src/main/kotlin/lotto/Main.kt +++ b/src/main/kotlin/lotto/Main.kt @@ -2,6 +2,7 @@ package lotto import lotto.domain.LottoAnswer import lotto.domain.LottoService +import lotto.domain.MatchCount import lotto.view.InputView import lotto.view.OutputView @@ -11,8 +12,15 @@ fun main() { OutputView.outputBuyResult(service.lottoCount, service.lotteries) val answer = InputView.getLottoAnswer() - val lottoAnswer = LottoAnswer(answer) - val earningStrategy = mapOf(3 to 5000, 4 to 50000, 5 to 1500000, 6 to 2000000000) + val bonusNumber = InputView.getBonusNumber() + val lottoAnswer = LottoAnswer(answer, bonusNumber) + val earningStrategy = mapOf( + MatchCount.THREE to 5000, + MatchCount.FOUR to 50000, + MatchCount.FIVE to 1500000, + MatchCount.FIVE_WITH_BONUS to 30000000, + MatchCount.SIX to 2000000000 + ) val result = service.play(lottoAnswer, earningStrategy) OutputView.outputLottoResult(result, earningStrategy) diff --git a/src/main/kotlin/lotto/domain/LottoAnswer.kt b/src/main/kotlin/lotto/domain/LottoAnswer.kt index 353696d61..78c24707a 100644 --- a/src/main/kotlin/lotto/domain/LottoAnswer.kt +++ b/src/main/kotlin/lotto/domain/LottoAnswer.kt @@ -1,8 +1,8 @@ package lotto.domain -@JvmInline -value class LottoAnswer( - private val answer: List +data class LottoAnswer( + private val answer: List, + private val bonusNumber: Int ) { fun match(inputLottos: List): Map { @@ -12,8 +12,14 @@ value class LottoAnswer( .eachCount() } - private fun innerMatch(inputLotto: Lotto): Int { - return inputLotto.numbers.count { outer -> isAnswerNumberMatch(outer) } + private fun innerMatch(inputLotto: Lotto): MatchCount { + val count = inputLotto.numbers.count { outer -> isAnswerNumberMatch(outer) } + val isBonusMatch = isBonusMatch(inputLotto) + return MatchCount.of(count, isBonusMatch) + } + + private fun isBonusMatch(inputLotto: Lotto): Boolean { + return inputLotto.numbers.find { bonusNumber == it } != null } private fun isAnswerNumberMatch(outer: Int): Boolean { @@ -21,6 +27,6 @@ value class LottoAnswer( } companion object { - fun create(answer: List) = LottoAnswer(answer) + fun create(answer: List, bonusNumber: Int) = LottoAnswer(answer, bonusNumber) } } diff --git a/src/main/kotlin/lotto/view/InputView.kt b/src/main/kotlin/lotto/view/InputView.kt index a39d954d6..fee26e860 100644 --- a/src/main/kotlin/lotto/view/InputView.kt +++ b/src/main/kotlin/lotto/view/InputView.kt @@ -11,4 +11,9 @@ object InputView { println("지난 주 당첨 번호를 입력해 주세요.") return readln().split(", ").map { it.toInt() } } + + fun getBonusNumber(): Int { + println("보너스 볼을 입력해 주세요.") + return readln().toInt() + } } diff --git a/src/main/kotlin/lotto/view/OutputView.kt b/src/main/kotlin/lotto/view/OutputView.kt index 3281fd06c..59efe5f05 100644 --- a/src/main/kotlin/lotto/view/OutputView.kt +++ b/src/main/kotlin/lotto/view/OutputView.kt @@ -2,6 +2,7 @@ package lotto.view import lotto.domain.Lotto import lotto.domain.LottoResult +import lotto.domain.MatchCount object OutputView { @@ -13,14 +14,21 @@ object OutputView { println() } - fun outputLottoResult(result: LottoResult, strategy: Map) { + fun outputLottoResult(result: LottoResult, strategy: Map) { println() println("당첨 통계") println("---------") strategy.entries - .sortedBy { it.key } - .map { "${it.key}개 일치 (${it.value}원)- ${result.earnResult[it.key] ?: 0}개" } + .sortedBy { it.key.matchCount } + .map { outputLottoResultSeperate(it.key, it.value, result.earnResult) } .forEach { println(it) } println("총 수익률은 ${result.earningRate}입니다.") } + + private fun outputLottoResultSeperate(matchCount: MatchCount, amount: Int, earnResult: Map): String{ + if (matchCount.isMatchBonus) { + return "${matchCount.matchCount}개 일치, 보너스 볼 일치(${amount}원)- ${earnResult[matchCount] ?: 0}개" + } + return "${matchCount.matchCount}개 일치 (${amount}원)- ${earnResult[matchCount] ?: 0}개" + } } diff --git a/src/test/kotlin/lotto/LottoAnswerTest.kt b/src/test/kotlin/lotto/LottoAnswerTest.kt index 17e142463..03db62478 100644 --- a/src/test/kotlin/lotto/LottoAnswerTest.kt +++ b/src/test/kotlin/lotto/LottoAnswerTest.kt @@ -4,12 +4,21 @@ import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe import lotto.domain.Lotto import lotto.domain.LottoAnswer +import lotto.domain.MatchCount class LottoAnswerTest : StringSpec({ "정답지와 3개가 일치하는 로또가 1개만 존재할 경우 { 3 : 1 } 결과가 나와야 한다" { - val answer = LottoAnswer.create(listOf(1, 2, 3, 4, 5, 6)) + val bonusNumber = 0 + val answer = LottoAnswer.create(listOf(1, 2, 3, 4, 5, 6), bonusNumber) val inputLotto = Lotto.create(TestNumberGenerator) - answer.match(listOf(inputLotto)) shouldBe mapOf(3 to 1) + answer.match(listOf(inputLotto)) shouldBe mapOf(MatchCount.THREE to 1) + } + + "정답지와 5개가 일치하고 보너스 번호가 일치하는 로또가 존재할 경우 { FIVE_WITH_BONUS : 1} 결과가 나와야 한다" { + val bonusNumber = 7 + val answer = LottoAnswer.create(listOf(1, 2, 3, 4, 5, 6), bonusNumber) + val inputLotto = Lotto.create(TestNumberGeneratorFive) + answer.match(listOf(inputLotto)) shouldBe mapOf( MatchCount.FIVE_WITH_BONUS to 1) } }) diff --git a/src/test/kotlin/lotto/TestNumberGeneratorFive.kt b/src/test/kotlin/lotto/TestNumberGeneratorFive.kt new file mode 100644 index 000000000..5d962dd10 --- /dev/null +++ b/src/test/kotlin/lotto/TestNumberGeneratorFive.kt @@ -0,0 +1,7 @@ +package lotto + +import lotto.domain.strategy.NumberGenerator + +object TestNumberGeneratorFive: NumberGenerator { + override fun generate(size: Int): List = listOf(1, 2, 3, 4, 5, 7) +} \ No newline at end of file From 17f51f63069b700d2af3c78977516f71eacb0de5 Mon Sep 17 00:00:00 2001 From: baek0318 Date: Thu, 30 Nov 2023 20:11:06 +0900 Subject: [PATCH 4/5] =?UTF-8?q?step3=20:=20=EB=B3=B4=EB=84=88=EC=8A=A4=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=B6=94=EA=B0=80=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=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 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 36f6adee5..5a4fa3398 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,10 @@ ## lotto ### 기능 구현 사항 -1. 금액에 맞게 로또를 뽑아야한다 (ex. 14000원 14개를 뽑아야함) -2. 1 ~ 45 사이의 숫자를 랜덤으로 6개를 만들어서 로또를 만들어야한다 -3. 정답지와 얼마나 일치하는지에 대한 결과를 만들어야 한다 -4. 수익률 계산을 해야한다 -5. 수익이 얼마가 발생했는지 알아야 한다 \ No newline at end of file +- 금액에 맞게 로또를 뽑아야한다 (ex. 14000원 14개를 뽑아야함) +- 1 ~ 45 사이의 숫자를 랜덤으로 6개를 만들어서 로또를 만들어야한다 +- 정답지와 얼마나 일치하는지에 대한 결과를 만들어야 한다 + - 당첨번호를 맞출때 보너스 번호가 맞는지도 확인해야함 +- 수익률 계산을 해야한다 +- 수익이 얼마가 발생했는지 알아야 한다 + - 당첨번호 5개 일치 + 보너스 번호 일치인 경우에 대해서 수익을 계산해야한다 \ No newline at end of file From e99f9ca619818e99db97c04b418f1bd9cb4a68cd Mon Sep 17 00:00:00 2001 From: baek0318 Date: Thu, 30 Nov 2023 20:13:14 +0900 Subject: [PATCH 5/5] =?UTF-8?q?step3=20:=20kotlin=20lint=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/domain/MatchCount.kt | 2 +- src/main/kotlin/lotto/view/OutputView.kt | 2 +- src/test/kotlin/lotto/LottoAnswerTest.kt | 2 +- src/test/kotlin/lotto/TestNumberGeneratorFive.kt | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/lotto/domain/MatchCount.kt b/src/main/kotlin/lotto/domain/MatchCount.kt index 2b23bb185..d3c0ec4f2 100644 --- a/src/main/kotlin/lotto/domain/MatchCount.kt +++ b/src/main/kotlin/lotto/domain/MatchCount.kt @@ -22,4 +22,4 @@ enum class MatchCount( return matchCount } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/lotto/view/OutputView.kt b/src/main/kotlin/lotto/view/OutputView.kt index 59efe5f05..3ae1ce463 100644 --- a/src/main/kotlin/lotto/view/OutputView.kt +++ b/src/main/kotlin/lotto/view/OutputView.kt @@ -25,7 +25,7 @@ object OutputView { println("총 수익률은 ${result.earningRate}입니다.") } - private fun outputLottoResultSeperate(matchCount: MatchCount, amount: Int, earnResult: Map): String{ + private fun outputLottoResultSeperate(matchCount: MatchCount, amount: Int, earnResult: Map): String { if (matchCount.isMatchBonus) { return "${matchCount.matchCount}개 일치, 보너스 볼 일치(${amount}원)- ${earnResult[matchCount] ?: 0}개" } diff --git a/src/test/kotlin/lotto/LottoAnswerTest.kt b/src/test/kotlin/lotto/LottoAnswerTest.kt index 03db62478..0854df505 100644 --- a/src/test/kotlin/lotto/LottoAnswerTest.kt +++ b/src/test/kotlin/lotto/LottoAnswerTest.kt @@ -19,6 +19,6 @@ class LottoAnswerTest : StringSpec({ val bonusNumber = 7 val answer = LottoAnswer.create(listOf(1, 2, 3, 4, 5, 6), bonusNumber) val inputLotto = Lotto.create(TestNumberGeneratorFive) - answer.match(listOf(inputLotto)) shouldBe mapOf( MatchCount.FIVE_WITH_BONUS to 1) + answer.match(listOf(inputLotto)) shouldBe mapOf(MatchCount.FIVE_WITH_BONUS to 1) } }) diff --git a/src/test/kotlin/lotto/TestNumberGeneratorFive.kt b/src/test/kotlin/lotto/TestNumberGeneratorFive.kt index 5d962dd10..ea36a7366 100644 --- a/src/test/kotlin/lotto/TestNumberGeneratorFive.kt +++ b/src/test/kotlin/lotto/TestNumberGeneratorFive.kt @@ -2,6 +2,6 @@ package lotto import lotto.domain.strategy.NumberGenerator -object TestNumberGeneratorFive: NumberGenerator { +object TestNumberGeneratorFive : NumberGenerator { override fun generate(size: Int): List = listOf(1, 2, 3, 4, 5, 7) -} \ No newline at end of file +}