diff --git a/README.md b/README.md index 0ef22f5718..cbabd2a9b6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,79 @@ # kotlin-lotto +# ๐Ÿš€ 4๋‹จ๊ณ„ - ๋กœ๋˜(์ˆ˜๋™) + +## ๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ +- ํ˜„์žฌ ๋กœ๋˜ ์ƒ์„ฑ๊ธฐ๋Š” ์ž๋™ ์ƒ์„ฑ ๊ธฐ๋Šฅ๋งŒ ์ œ๊ณตํ•œ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ˆ˜๋™์œผ๋กœ ์ถ”์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค. +- ์ž…๋ ฅํ•œ ๊ธˆ์•ก, ์ž๋™ ์ƒ์„ฑ ์ˆซ์ž, ์ˆ˜๋™ ์ƒ์„ฑ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค. + +## ์‹คํ–‰ ๊ฒฐ๊ณผ +``` +๊ตฌ์ž…๊ธˆ์•ก์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”. +14000 + +์ˆ˜๋™์œผ๋กœ ๊ตฌ๋งคํ•  ๋กœ๋˜ ์ˆ˜๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”. +3 + +์ˆ˜๋™์œผ๋กœ ๊ตฌ๋งคํ•  ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”. +8, 21, 23, 41, 42, 43 +3, 5, 11, 16, 32, 38 +7, 11, 16, 35, 36, 44 + +์ˆ˜๋™์œผ๋กœ 3์žฅ, ์ž๋™์œผ๋กœ 11๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค. +[8, 21, 23, 41, 42, 43] +[3, 5, 11, 16, 32, 38] +[7, 11, 16, 35, 36, 44] +[1, 8, 11, 31, 41, 42] +[13, 14, 16, 38, 42, 45] +[7, 11, 30, 40, 42, 43] +[2, 13, 22, 32, 38, 45] +[23, 25, 33, 36, 39, 41] +[1, 3, 5, 14, 22, 45] +[5, 9, 38, 41, 43, 44] +[2, 8, 9, 18, 19, 21] +[13, 14, 18, 21, 23, 35] +[17, 21, 29, 37, 42, 45] +[3, 8, 27, 30, 35, 44] + +์ง€๋‚œ ์ฃผ ๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”. +1, 2, 3, 4, 5, 6 +๋ณด๋„ˆ์Šค ๋ณผ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”. +7 + +๋‹น์ฒจ ํ†ต๊ณ„ +--------- +3๊ฐœ ์ผ์น˜ (5000์›)- 1๊ฐœ +4๊ฐœ ์ผ์น˜ (50000์›)- 0๊ฐœ +5๊ฐœ ์ผ์น˜ (1500000์›)- 0๊ฐœ +5๊ฐœ ์ผ์น˜, ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜(30000000์›) - 0๊ฐœ +6๊ฐœ ์ผ์น˜ (2000000000์›)- 0๊ฐœ +์ด ์ˆ˜์ต๋ฅ ์€ 0.35์ž…๋‹ˆ๋‹ค.(๊ธฐ์ค€์ด 1์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ณผ์ ์œผ๋กœ ์†ํ•ด๋ผ๋Š” ์˜๋ฏธ์ž„) +``` + +## ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ ์‚ฌํ•ญ +- ๋ชจ๋“  ์›์‹œ๊ฐ’๊ณผ ๋ฌธ์ž์—ด์„ ํฌ์žฅํ•œ๋‹ค. +- ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค. +- ๋ชจ๋“  ๊ธฐ๋Šฅ์„ TDD๋กœ ๊ตฌํ˜„ํ•ด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค. ๋‹จ, UI(System.out, System.in) ๋กœ์ง์€ ์ œ์™ธ +- Enum ํด๋ž˜์Šค๋ฅผ ์ ์šฉํ•ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ตฌํ˜„ํ•œ๋‹ค. +- ์ผ๊ธ‰ ์ปฌ๋ ‰์…˜์„ ์“ด๋‹ค. +- indent(์ธ๋ดํŠธ, ๋“ค์—ฌ์“ฐ๊ธฐ) depth๋ฅผ 2๋ฅผ ๋„˜์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. 1๊นŒ์ง€๋งŒ ํ—ˆ์šฉํ•œ๋‹ค. +- ์˜ˆ๋ฅผ ๋“ค์–ด while๋ฌธ ์•ˆ์— if๋ฌธ์ด ์žˆ์œผ๋ฉด ๋“ค์—ฌ์“ฐ๊ธฐ๋Š” 2์ด๋‹ค. +- ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์„œ๋“œ)๊ฐ€ ํ•œ ๊ฐ€์ง€ ์ผ๋งŒ ์ž˜ ํ•˜๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. +- ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์ „์— README.md ํŒŒ์ผ์— ๊ตฌํ˜„ํ•  ๊ธฐ๋Šฅ ๋ชฉ๋ก์„ ์ •๋ฆฌํ•ด ์ถ”๊ฐ€ํ•œ๋‹ค. +- git์˜ commit ๋‹จ์œ„๋Š” ์•ž ๋‹จ๊ณ„์—์„œ README.md ํŒŒ์ผ์— ์ •๋ฆฌํ•œ ๊ธฐ๋Šฅ ๋ชฉ๋ก ๋‹จ์œ„๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค. + +## ํžŒํŠธ +- ๋ชจ๋“  ์›์‹œ๊ฐ’๊ณผ ๋ฌธ์ž์—ด์„ ํฌ์žฅํ•œ๋‹ค. +- ๋กœ๋˜ ์ˆซ์ž ํ•˜๋‚˜๋Š” Int๋‹ค. ์ด ์ˆซ์ž ํ•˜๋‚˜๋ฅผ ์ถ”์ƒํ™”ํ•œ LottoNumber๋ฅผ ์ถ”๊ฐ€ํ•ด ๊ตฌํ˜„ํ•œ๋‹ค. +- ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค. +- ์ฐธ๊ณ ๋กœ ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค. ์žฅ๊ธฐ์ ์œผ๋กœ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์˜ˆ์™ธ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฑธ ์—ฐ์Šตํ•ด ๋ณธ๋‹ค. +- ๋…ผ๋ฆฌ์ ์ธ ์˜ค๋ฅ˜์ผ ๋•Œ๋งŒ ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค. +- ๋…ผ๋ฆฌ์ ์ธ ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋ฉด ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€ ๋ง๊ณ  null์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. +- ์‹คํŒจํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ณต์žกํ•ด์„œ null๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์œผ๋ฉด sealed class๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. +- ์ผ๋ฐ˜์ ์ธ ์ฝ”ํ‹€๋ฆฐ ์ฝ”๋“œ์—์„œ try-catch๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. + +--- + # ๐Ÿš€ 3๋‹จ๊ณ„ - ๋กœ๋˜(2๋“ฑ) ## ๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ diff --git a/src/main/kotlin/lotto/README.md b/src/main/kotlin/lotto/README.md index 8fd8e215cd..33cfac6d72 100644 --- a/src/main/kotlin/lotto/README.md +++ b/src/main/kotlin/lotto/README.md @@ -1,5 +1,18 @@ # TODO +## ๊ตฌํ˜„ํ•  '๋กœ๋˜(์ˆ˜๋™)' ๊ธฐ๋Šฅ ๋ชฉ๋ก +- [x] ์ •์ˆ˜๊ฐ’ ํฌ์žฅ ํด๋ž˜์Šค ์ƒ์„ฑ +- [x] ์‹ค์ˆ˜๊ฐ’ ํฌ์žฅ ํด๋ž˜์Šค ์ƒ์„ฑ +- [x] ์ž…๋ ฅ ๋ฌธ์ž์—ด ํฌ์žฅ ํด๋ž˜์Šค ์ƒ์„ฑ +- [x] ์ˆ˜๋™์œผ๋กœ ๊ตฌ๋งคํ•  ๋กœ๋˜ ์ˆ˜ ์ž…๋ ฅ ๊ธฐ๋Šฅ +- [x] ์ˆ˜๋™์œผ๋กœ ๊ตฌ๋งคํ•  ๋กœ๋˜ ๋ฒˆํ˜ธ ์ž…๋ ฅ ๊ธฐ๋Šฅ +- [x] ์ˆ˜๋™ ๋กœ๋˜ ์ƒ์„ฑ ๊ธฐ๋Šฅ +- [x] ์ˆ˜๋™ ๋กœ๋˜, ์ž๋™ ๋กœ๋˜ ์ถœ๋ ฅ ๊ธฐ๋Šฅ +- [x] ์ง€๋ถˆํ•œ ๊ธˆ์•ก ํด๋ž˜์Šค ์ƒ์„ฑ +- [x] ๋กœ๋˜ ๋ฒˆํ˜ธ ํด๋ž˜์Šค ์ƒ์„ฑ +- [x] ์ž…๋ ฅ ๋ฌธ์ž์—ด ํด๋ž˜์Šค ์ƒ์„ฑ +- [x] ์˜ˆ์™ธ ์ผ€์ด์Šค ๊ฒ€ํ† ํ•˜์—ฌ ์ฒ˜๋ฆฌ + ## ๊ตฌํ˜„ํ•  '๋กœ๋˜(2๋“ฑ)' ๊ธฐ๋Šฅ ๋ชฉ๋ก - [x] ๋ณด๋„ˆ์Šค ๋ณผ ์ž…๋ ฅ ๊ธฐ๋Šฅ - [x] ๋‹น์ฒจ ํ†ต๊ณ„์— 2๋“ฑ ๊ฒฐ๊ณผ ์ถ”๊ฐ€ diff --git a/src/main/kotlin/lotto/application/Application.kt b/src/main/kotlin/lotto/application/Application.kt index 7ff75d68ed..9520ed1f59 100644 --- a/src/main/kotlin/lotto/application/Application.kt +++ b/src/main/kotlin/lotto/application/Application.kt @@ -1,9 +1,10 @@ package lotto.application +import lotto.domain.Lotto import lotto.domain.LottoGenerator +import lotto.domain.LottoNumber import lotto.domain.LottoResultService import lotto.domain.LottoShop -import lotto.domain.LuckyNumbers import lotto.util.RandomNumberGenerator import lotto.view.InputView import lotto.view.ResultView @@ -11,17 +12,24 @@ import lotto.view.ResultView class Application { private val inputView = InputView() private val resultView = ResultView() - private val lottoShop = LottoShop(LottoGenerator(RandomNumberGenerator())) + private val lottoGenerator = LottoGenerator(RandomNumberGenerator()) fun run() { val inputPayment = inputView.inputPayment() - val lottoList = lottoShop.buyLotto(inputPayment) - resultView.printLotto(lottoList) + val manualLottoCount = inputView.inputManualLottoCount() + val manualNumberList = inputView.inputManualLottoNumbers(manualLottoCount) + val lottoShop = LottoShop(lottoGenerator, inputPayment) + + val manualLottoList = lottoShop.buyManualLotto(manualNumberList) + val autoLottoList = lottoShop.buyAutoLotto() + resultView.printLottoList(manualLottoList, autoLottoList) + + val lottoList = manualLottoList + autoLottoList val inputLuckyNumbers = inputView.inputLuckyNumbers() val inputBonusNumber = inputView.inputBonusNumber() - val lottoResultService = LottoResultService(LuckyNumbers(inputLuckyNumbers, inputBonusNumber)) + val lottoResultService = LottoResultService(Lotto(inputLuckyNumbers.integerNumberList.map { LottoNumber(it) }), LottoNumber(inputBonusNumber)) val statistics = lottoResultService.inquireStatistics(inputPayment, lottoList) resultView.printLottoStatistics(statistics) } diff --git a/src/main/kotlin/lotto/common/IntegerNumberList.kt b/src/main/kotlin/lotto/common/IntegerNumberList.kt new file mode 100644 index 0000000000..6b4b00c753 --- /dev/null +++ b/src/main/kotlin/lotto/common/IntegerNumberList.kt @@ -0,0 +1,5 @@ +package lotto.common + +class IntegerNumberList( + val integerNumberList: List +) diff --git a/src/main/kotlin/lotto/common/NumberString.kt b/src/main/kotlin/lotto/common/NumberString.kt new file mode 100644 index 0000000000..45f54cc0b7 --- /dev/null +++ b/src/main/kotlin/lotto/common/NumberString.kt @@ -0,0 +1,18 @@ +package lotto.common + +class NumberString( + private val string: String +) { + init { + require(string.isNotBlank()) { "๊ฐ’์ด ๋น„์–ด์žˆ์Šต๋‹ˆ๋‹ค." } + require(isNumber()) { "์ˆซ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. (์ž…๋ ฅ๊ฐ’:$string)" } + } + + private fun isNumber(): Boolean { + return string.toCharArray().all { it in '0'..'9' } + } + + fun toIntegerNumber(): Int { + return string.toInt() + } +} diff --git a/src/main/kotlin/lotto/common/NumberStringList.kt b/src/main/kotlin/lotto/common/NumberStringList.kt new file mode 100644 index 0000000000..2a5e8f1751 --- /dev/null +++ b/src/main/kotlin/lotto/common/NumberStringList.kt @@ -0,0 +1,11 @@ +package lotto.common + +class NumberStringList( + string: String +) { + val list = string.split(",").map { NumberString(it.trim()) } + + fun toIntegerNumberList(): List { + return list.map { it.toIntegerNumber() } + } +} diff --git a/src/main/kotlin/lotto/domain/Lotto.kt b/src/main/kotlin/lotto/domain/Lotto.kt index 3490cb738d..4ccef854fc 100644 --- a/src/main/kotlin/lotto/domain/Lotto.kt +++ b/src/main/kotlin/lotto/domain/Lotto.kt @@ -1,10 +1,20 @@ package lotto.domain class Lotto( - val numbers: List + val lottoNumbers: List ) { init { - require(numbers.size == LOTTO_NUMBERS_SIZE) { "๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” ${LOTTO_NUMBERS_SIZE}๊ฐœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค." } + require(lottoNumbers.size == LOTTO_NUMBERS_SIZE) { "๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” ${LOTTO_NUMBERS_SIZE}๊ฐœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค." } + require(lottoNumbers.toSet().size == LOTTO_NUMBERS_SIZE) { "๋ฒˆํ˜ธ์— ์ค‘๋ณต์ด ์žˆ์Šต๋‹ˆ๋‹ค." } + } + + fun countHitNumbers(luckyLotto: Lotto): Int { + val count = lottoNumbers.count { luckyLotto.lottoNumbers.contains(it) } + return count + } + + fun hasBonusNumber(bonusNumber: LottoNumber): Boolean { + return lottoNumbers.contains(bonusNumber) } companion object { diff --git a/src/main/kotlin/lotto/domain/LottoGenerator.kt b/src/main/kotlin/lotto/domain/LottoGenerator.kt index 02ca2248b7..578b0679e3 100644 --- a/src/main/kotlin/lotto/domain/LottoGenerator.kt +++ b/src/main/kotlin/lotto/domain/LottoGenerator.kt @@ -1,5 +1,6 @@ package lotto.domain +import lotto.common.IntegerNumberList import lotto.util.NumberGenerator class LottoGenerator( @@ -9,7 +10,15 @@ class LottoGenerator( return List(size) { Lotto(randomNumber()) } } - private fun randomNumber(): List { + private fun randomNumber(): List { return numberGenerator.generate(Lotto.LOTTO_START_NUMBER, Lotto.LOTTO_END_NUMBER, Lotto.LOTTO_NUMBERS_SIZE) + .map { LottoNumber(it) } + } + + fun generate(numberList: List): List { + return numberList.map { + val lottoNumberList = it.integerNumberList.map { number -> LottoNumber(number) } + Lotto(lottoNumberList) + } } } diff --git a/src/main/kotlin/lotto/domain/LottoNumber.kt b/src/main/kotlin/lotto/domain/LottoNumber.kt new file mode 100644 index 0000000000..3a6cd962b7 --- /dev/null +++ b/src/main/kotlin/lotto/domain/LottoNumber.kt @@ -0,0 +1,19 @@ +package lotto.domain + +data class LottoNumber( + val number: Int +) { + + init { + require(number in LOTTO_MIN_NUMBER..LOTTO_MAX_NUMBER) { "๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” ${LOTTO_MIN_NUMBER}์™€ $LOTTO_MAX_NUMBER ์‚ฌ์ด ๊ฐ’ ์ด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค." } + } + + companion object { + const val LOTTO_MIN_NUMBER = 1 + const val LOTTO_MAX_NUMBER = 45 + } + + override fun toString(): String { + return "$number" + } +} diff --git a/src/main/kotlin/lotto/domain/LottoRank.kt b/src/main/kotlin/lotto/domain/LottoRank.kt index f0be7906b7..5c632eadb1 100644 --- a/src/main/kotlin/lotto/domain/LottoRank.kt +++ b/src/main/kotlin/lotto/domain/LottoRank.kt @@ -2,30 +2,30 @@ package lotto.domain enum class LottoRank( val hitCount: Int, - val hasBonusNumber: Boolean, - val prizeMoney: Int + val prizeMoney: Money, + val hasBonusNumber: Boolean = false ) { - FIRST(6, false, 2000000000), - SECOND(5, true, 30000000), - THIRD(5, false, 1500000), - FOURTH(4, false, 50000), - FIFTH(3, false, 5000), - MISS(0, false, 0); + FIRST(hitCount = 6, prizeMoney = Money(2000000000)), + SECOND(hitCount = 5, prizeMoney = Money(30000000), hasBonusNumber = true), + THIRD(hitCount = 5, prizeMoney = Money(1500000)), + FOURTH(hitCount = 4, prizeMoney = Money(50000)), + FIFTH(hitCount = 3, prizeMoney = Money(5000)), + MISS(hitCount = 0, prizeMoney = Money(0)); - companion object { - fun from(hitCount: Int, hasBonusNumber: Boolean): LottoRank { - return values().find { it.hitCount == hitCount && isHitBonusNumber(it, hasBonusNumber) } ?: return MISS + private fun isHitBonusNumber(it: LottoRank, hasBonusNumber: Boolean): Boolean { + if (it.hasBonusNumber) { + return hasBonusNumber } + return true + } - private fun isHitBonusNumber(it: LottoRank, hasBonusNumber: Boolean): Boolean { - if (it.hasBonusNumber) { - return hasBonusNumber - } - return true + companion object { + fun from(hitCount: Int, hasBonusNumber: Boolean): LottoRank { + return values().find { it.hitCount == hitCount && it.isHitBonusNumber(it, hasBonusNumber) } ?: return MISS } fun winRanks(): List { - return values().filter { it.prizeMoney > 0 }.reversed() + return values().filter { it.prizeMoney.amount > 0 }.reversed() } } } diff --git a/src/main/kotlin/lotto/domain/LottoResultService.kt b/src/main/kotlin/lotto/domain/LottoResultService.kt index 5e390438ff..737e41e058 100644 --- a/src/main/kotlin/lotto/domain/LottoResultService.kt +++ b/src/main/kotlin/lotto/domain/LottoResultService.kt @@ -1,12 +1,26 @@ package lotto.domain class LottoResultService( - private val luckyNumbers: LuckyNumbers, + private val luckyLotto: Lotto, + private val bonusNumber: LottoNumber ) { - fun inquireStatistics(payment: Int, lottoList: List): LottoStatisticsTotal { - val lottoWinner = LottoWinner(luckyNumbers) - val winLottoList = lottoWinner.findWinLottoList(lottoList) + fun inquireStatistics(payment: Payment, lottoList: List): LottoStatisticsTotal { + val winLottoList = findWinLottoList(lottoList) val lottoStatisticsService = LottoStatisticsService(payment, winLottoList) return lottoStatisticsService.statistics() } + + private fun findWinLottoList(lottoList: List): List { + return lottoList + .map { rank(it, bonusNumber) } + .filter { hasPrize(it) } + } + + private fun rank(lotto: Lotto, bonusNumber: LottoNumber): LottoRank { + val hitCount = lotto.countHitNumbers(luckyLotto) + val hasBonusNumber = lotto.hasBonusNumber(bonusNumber) + return LottoRank.from(hitCount, hasBonusNumber) + } + + private fun hasPrize(lottoRank: LottoRank) = lottoRank.prizeMoney.isPositive() } diff --git a/src/main/kotlin/lotto/domain/LottoShop.kt b/src/main/kotlin/lotto/domain/LottoShop.kt index 550fb1302d..1d3b747979 100644 --- a/src/main/kotlin/lotto/domain/LottoShop.kt +++ b/src/main/kotlin/lotto/domain/LottoShop.kt @@ -1,15 +1,33 @@ package lotto.domain +import lotto.common.IntegerNumberList + class LottoShop( - private val lottoGenerator: LottoGenerator + private val lottoGenerator: LottoGenerator, + private var payment: Payment ) { - fun buyLotto(inputPayment: Int): List { - val lottoCount = calculateLottoCount(inputPayment) - return lottoGenerator.generate(lottoCount) + fun buyAutoLotto(): List { + val totalLottoCount = calculateLottoCount(payment) + return lottoGenerator.generate(totalLottoCount) + } + + fun buyManualLotto(manualNumberList: List): List { + val totalLottoCount = calculateLottoCount(payment) + val manualLottoCount = manualNumberList.size + + require(manualLottoCount <= totalLottoCount) { "์ˆ˜๋™ ๋กœ๋˜ ๊ฐœ์ˆ˜๊ฐ€ ์ง€๋ถˆ ๊ธˆ์•ก๋ณด๋‹ค ๋งŽ์•„ ๋กœ๋˜๋ฅผ ๊ตฌ์ž…ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." } + + val change = payment.charge(manualLottoCount * LOTTO_PRICE) + updatePayment(change) + return lottoGenerator.generate(manualNumberList) + } + + private fun calculateLottoCount(payment: Payment): Int { + return payment.amount / LOTTO_PRICE } - private fun calculateLottoCount(payment: Int): Int { - return payment / LOTTO_PRICE + private fun updatePayment(newPayment: Payment) { + this.payment = newPayment } companion object { diff --git a/src/main/kotlin/lotto/domain/LottoStatistics.kt b/src/main/kotlin/lotto/domain/LottoStatistics.kt index f0172ef29c..faf3faa3b3 100644 --- a/src/main/kotlin/lotto/domain/LottoStatistics.kt +++ b/src/main/kotlin/lotto/domain/LottoStatistics.kt @@ -5,11 +5,10 @@ import lotto.util.NumberUtil class LottoStatistics( private val winLottoList: List ) { - private val prizeList: List = winLottoList.map { it.prizeMoney } - private val totalPrize: Int = prizeList.sum() + private val totalPrize: Int = winLottoList.sumOf { it.prizeMoney.amount } - fun earningRate(inputPayment: Int): Double { - val earningRate = totalPrize.toDouble() / inputPayment.toDouble() + fun earningRate(inputPayment: Payment): Double { + val earningRate = totalPrize.toDouble() / inputPayment.amount.toDouble() return NumberUtil.floor(earningRate, EARNING_RATE_DECIMAL_PLACE) } @@ -25,6 +24,6 @@ class LottoStatistics( } companion object { - private const val EARNING_RATE_DECIMAL_PLACE = 2 + private const val EARNING_RATE_DECIMAL_PLACE = 2.0 } } diff --git a/src/main/kotlin/lotto/domain/LottoStatisticsService.kt b/src/main/kotlin/lotto/domain/LottoStatisticsService.kt index acc58d1051..f6f5dbb6a1 100644 --- a/src/main/kotlin/lotto/domain/LottoStatisticsService.kt +++ b/src/main/kotlin/lotto/domain/LottoStatisticsService.kt @@ -1,7 +1,7 @@ package lotto.domain class LottoStatisticsService( - private val payment: Int, + private val payment: Payment, private val winLottoList: List ) { fun statistics(): LottoStatisticsTotal { diff --git a/src/main/kotlin/lotto/domain/LottoWinner.kt b/src/main/kotlin/lotto/domain/LottoWinner.kt deleted file mode 100644 index f8379ff532..0000000000 --- a/src/main/kotlin/lotto/domain/LottoWinner.kt +++ /dev/null @@ -1,13 +0,0 @@ -package lotto.domain - -class LottoWinner( - private val luckyNumbers: LuckyNumbers -) { - fun findWinLottoList(lottoList: List): List { - return lottoList - .map { luckyNumbers.rank(it.numbers) } - .filter { hasPrize(it) } - } - - private fun hasPrize(lottoRank: LottoRank) = lottoRank.prizeMoney > 0 -} diff --git a/src/main/kotlin/lotto/domain/LuckyNumbers.kt b/src/main/kotlin/lotto/domain/LuckyNumbers.kt deleted file mode 100644 index 384d90683d..0000000000 --- a/src/main/kotlin/lotto/domain/LuckyNumbers.kt +++ /dev/null @@ -1,30 +0,0 @@ -package lotto.domain - -class LuckyNumbers( - private val luckyNumbers: List, - private val bonusNumber: Int -) { - init { - require(luckyNumbers.size == LUCKY_NUMBER_SIZE) { "๋‹น์ฒจ ๋ฒˆํ˜ธ๋Š” ${LUCKY_NUMBER_SIZE}๊ฐœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค." } - require(luckyNumbers.toSet().size == LUCKY_NUMBER_SIZE) { "๋‹น์ฒจ ๋ฒˆํ˜ธ์— ์ค‘๋ณต์ด ์žˆ์Šต๋‹ˆ๋‹ค." } - require(!luckyNumbers.contains(bonusNumber)) { "๋ณด๋„ˆ์Šค๋ณผ์€ ๋‹น์ฒจ๋ฒˆํ˜ธ์™€ ์ค‘๋ณต๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." } - } - - fun rank(numbers: List): LottoRank { - val hitCount = countHitNumbers(numbers) - val hasBonusNumber = containsBonusNumber(numbers) - return LottoRank.from(hitCount, hasBonusNumber) - } - - private fun countHitNumbers(numbers: List): Int { - return numbers.count { number -> luckyNumbers.contains(number) } - } - - private fun containsBonusNumber(numbers: List): Boolean { - return numbers.contains(bonusNumber) - } - - companion object { - const val LUCKY_NUMBER_SIZE = 6 - } -} diff --git a/src/main/kotlin/lotto/domain/Money.kt b/src/main/kotlin/lotto/domain/Money.kt new file mode 100644 index 0000000000..dea49b576f --- /dev/null +++ b/src/main/kotlin/lotto/domain/Money.kt @@ -0,0 +1,13 @@ +package lotto.domain + +data class Money( + val amount: Int +) { + fun isPositive(): Boolean { + return amount > 0 + } + + override fun toString(): String { + return "$amount" + } +} diff --git a/src/main/kotlin/lotto/domain/Payment.kt b/src/main/kotlin/lotto/domain/Payment.kt new file mode 100644 index 0000000000..fd86ab0255 --- /dev/null +++ b/src/main/kotlin/lotto/domain/Payment.kt @@ -0,0 +1,14 @@ +package lotto.domain + +data class Payment( + var amount: Int +) { + init { + require(amount >= 0) { "์ง€๋ถˆ์•ก์€ ์Œ์ˆ˜๊ฐ€ ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." } + } + + fun charge(charge: Int): Payment { + require(amount >= charge) { "์ž”์•ก ๋ถ€์กฑ์œผ๋กœ ๊ธˆ์•ก์„ ์ฐจ๊ฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." } + return Payment(amount.minus(charge)) + } +} diff --git a/src/main/kotlin/lotto/util/NumberUtil.kt b/src/main/kotlin/lotto/util/NumberUtil.kt index 77a445ef60..9c2bd66be7 100644 --- a/src/main/kotlin/lotto/util/NumberUtil.kt +++ b/src/main/kotlin/lotto/util/NumberUtil.kt @@ -1,15 +1,14 @@ package lotto.util -import kotlin.math.floor import kotlin.math.pow object NumberUtil { - fun floor(number: Double, decimalPlace: Int): Double { - if (decimalPlace == -1) { + fun floor(number: Double, decimalPlace: Double): Double { + if (decimalPlace < 0) { return number } - val pow = 10.0.pow(decimalPlace.toDouble()) - val floor = floor(number * pow) + val pow = 10.0.pow(decimalPlace) + val floor = kotlin.math.floor(number * pow) return floor / pow } } diff --git a/src/main/kotlin/lotto/util/RandomNumberGenerator.kt b/src/main/kotlin/lotto/util/RandomNumberGenerator.kt index fb80a9364e..3818b02baf 100644 --- a/src/main/kotlin/lotto/util/RandomNumberGenerator.kt +++ b/src/main/kotlin/lotto/util/RandomNumberGenerator.kt @@ -1,9 +1,10 @@ package lotto.util -class RandomNumberGenerator: NumberGenerator { +class RandomNumberGenerator : NumberGenerator { override fun generate(start: Int, end: Int, size: Int): List { val range = start..end val shuffled = range.shuffled() - return shuffled.subList(0, size) + val subList = shuffled.subList(0, size) + return subList.map { it } } } diff --git a/src/main/kotlin/lotto/util/StringValidator.kt b/src/main/kotlin/lotto/util/StringValidator.kt deleted file mode 100644 index cd1e8221fe..0000000000 --- a/src/main/kotlin/lotto/util/StringValidator.kt +++ /dev/null @@ -1,16 +0,0 @@ -package lotto.util - -object StringValidator { - fun validateNumber(string: String) { - val isNumeric = string.toCharArray().all { it in '0'..'9' } - if (!isNumeric) { - throw IllegalArgumentException("์ˆซ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. (์ž…๋ ฅ๊ฐ’:$string)") - } - } - - fun validateNotBlank(string: String) { - if (string.isBlank()) { - throw IllegalArgumentException("๊ฐ’์ด ๋น„์–ด์žˆ์Šต๋‹ˆ๋‹ค.") - } - } -} diff --git a/src/main/kotlin/lotto/view/InputView.kt b/src/main/kotlin/lotto/view/InputView.kt index 1053b55a6f..c173d0f256 100644 --- a/src/main/kotlin/lotto/view/InputView.kt +++ b/src/main/kotlin/lotto/view/InputView.kt @@ -1,50 +1,53 @@ package lotto.view -import lotto.util.StringValidator +import lotto.common.IntegerNumberList +import lotto.common.NumberString +import lotto.common.NumberStringList +import lotto.domain.Payment class InputView { - fun inputPayment(): Int { + fun inputPayment(): Payment { println(INPUT_PAYMENT_GUIDE) - val payment = readln() - validatePaymentInput(payment) - return payment.toInt() + val payment = NumberString(readln()) + return Payment(payment.toIntegerNumber()) } - private fun validatePaymentInput(payment: String) { - StringValidator.validateNotBlank(payment) - StringValidator.validateNumber(payment) + fun inputManualLottoCount(): Int { + println(INPUT_MANUAL_LOTTO_COUNT_GUIDE) + return inputNumber() } - fun inputLuckyNumbers(): List { - println(INPUT_LUCKY_NUMBERS_GUIDE) - val luckyNumberString = readln() - val luckyNumbers = splitNumbers(luckyNumberString) - validateLuckyNumbersInput(luckyNumbers) - return convert(luckyNumbers) + fun inputManualLottoNumbers(count: Int): List { + println(INPUT_MANUAL_LOTTO_NUMBERS_GUIDE) + return List(count) { + inputNumberList() + } } - private fun splitNumbers(input: String) = input.split(",").map { it.trim() } - - private fun validateLuckyNumbersInput(split: List) { - split.forEach { - StringValidator.validateNotBlank(it) - StringValidator.validateNumber(it) - } + fun inputLuckyNumbers(): IntegerNumberList { + println(INPUT_LUCKY_NUMBERS_GUIDE) + return inputNumberList() } - private fun convert(split: List): List { - return split.map { it.toInt() } + private fun inputNumberList(): IntegerNumberList { + val numberList = NumberStringList(readln()).toIntegerNumberList() + return IntegerNumberList(numberList) } fun inputBonusNumber(): Int { println(INPUT_BONUS_BALL) - val bonusBallNumberString = readln() - return bonusBallNumberString.toInt() + return inputNumber() + } + + private fun inputNumber(): Int { + return NumberString(readln()).toIntegerNumber() } private companion object { const val INPUT_PAYMENT_GUIDE = "# ๊ตฌ์ž…๊ธˆ์•ก์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”." + const val INPUT_MANUAL_LOTTO_COUNT_GUIDE = "# ์ˆ˜๋™์œผ๋กœ ๊ตฌ๋งคํ•  ๋กœ๋˜ ์ˆ˜๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”." + const val INPUT_MANUAL_LOTTO_NUMBERS_GUIDE = "# ์ˆ˜๋™์œผ๋กœ ๊ตฌ๋งคํ•  ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”." const val INPUT_LUCKY_NUMBERS_GUIDE = "# ์ง€๋‚œ ์ฃผ ๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”." const val INPUT_BONUS_BALL = "# ๋ณด๋„ˆ์Šค ๋ณผ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”." } diff --git a/src/main/kotlin/lotto/view/ResultView.kt b/src/main/kotlin/lotto/view/ResultView.kt index d38089efaa..ce1dc5c555 100644 --- a/src/main/kotlin/lotto/view/ResultView.kt +++ b/src/main/kotlin/lotto/view/ResultView.kt @@ -7,14 +7,21 @@ import lotto.domain.LottoStatisticsTotal class ResultView { - fun printLotto(lottoList: List) { - println("${lottoList.size}๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.") - lottoList.forEach { - println(it.numbers) + fun printLottoList(manualLottoList: List, autoLottoList: List) { + println("์ˆ˜๋™์œผ๋กœ ${manualLottoList.size}๊ฐœ, ์ž๋™์œผ๋กœ ${autoLottoList.size}๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.") + manualLottoList.forEach { + printLotto(it) + } + autoLottoList.forEach { + printLotto(it) } emptyLine() } + private fun printLotto(lotto: Lotto) { + println(lotto.lottoNumbers) + } + fun printLottoStatistics(statisticsResult: LottoStatisticsTotal) { emptyLine() println(STATISTICS_GUIDE) @@ -41,7 +48,7 @@ class ResultView { private fun printEarningRate(earningRate: Double) { print("์ด ์ˆ˜์ต๋ฅ ์€ ${earningRate}์ž…๋‹ˆ๋‹ค. ") - if (earningRate > 1) { + if (earningRate >= 1.0) { println("(๊ธฐ์ค€์ด 1์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด์ต์ž…๋‹ˆ๋‹ค.)") return } diff --git a/src/main/kotlin/stringCalculator/StringAddCalculator.kt b/src/main/kotlin/stringCalculator/StringAddCalculator.kt index 00554ff064..48286c9c95 100644 --- a/src/main/kotlin/stringCalculator/StringAddCalculator.kt +++ b/src/main/kotlin/stringCalculator/StringAddCalculator.kt @@ -23,7 +23,8 @@ class StringAddCalculator { return split(numberString, delimiter) } - private fun split(string: String, delimiter: Regex = DEFAULT_DELIMITER_REGEX): List = string.split(delimiter) + private fun split(string: String, delimiter: Regex = DEFAULT_DELIMITER_REGEX): List = + string.split(delimiter) private fun split(string: String, delimiter: String): List { if (delimiter.isEmpty()) { diff --git a/src/test/kotlin/lotto/common/NumberStringListTest.kt b/src/test/kotlin/lotto/common/NumberStringListTest.kt new file mode 100644 index 0000000000..74c446d2fd --- /dev/null +++ b/src/test/kotlin/lotto/common/NumberStringListTest.kt @@ -0,0 +1,38 @@ +package lotto.common + +import io.kotest.assertions.throwables.shouldThrowExactly +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe + +class NumberStringListTest : StringSpec({ + + "์ˆซ์ž ์•„๋‹๋•Œ ์—๋Ÿฌ ๋ฐœ์ƒ ํ…Œ์ŠคํŠธ" { + val exception = shouldThrowExactly { + NumberStringList("1,a") + } + exception.message shouldBe "์ˆซ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. (์ž…๋ ฅ๊ฐ’:a)" + } + + "๋นˆ ๋ฌธ์ž์—ด ์ผ ๋•Œ ์—๋Ÿฌ ํ…Œ์ŠคํŠธ" { + val exception = shouldThrowExactly { + NumberStringList("1,") + } + exception.message shouldBe "๊ฐ’์ด ๋น„์–ด์žˆ์Šต๋‹ˆ๋‹ค." + } + + "๊ณต๋ฐฑ ๋ฌธ์ž์—ด ์ผ ๋•Œ ์—๋Ÿฌ ํ…Œ์ŠคํŠธ" { + val exception = shouldThrowExactly { + NumberStringList("1, ") + } + exception.message shouldBe "๊ฐ’์ด ๋น„์–ด์žˆ์Šต๋‹ˆ๋‹ค." + } + + "์ˆซ์ž ๋ฆฌ์ŠคํŠธ ๋ณ€ํ™˜ ํ…Œ์ŠคํŠธ" { + // given + val numberStringList = NumberStringList("1,2,3,4,5") + // when + val numberList = numberStringList.toIntegerNumberList() + // then + numberList shouldBe listOf(1, 2, 3, 4, 5) + } +}) diff --git a/src/test/kotlin/lotto/util/StringValidatorTest.kt b/src/test/kotlin/lotto/common/NumberStringTest.kt similarity index 73% rename from src/test/kotlin/lotto/util/StringValidatorTest.kt rename to src/test/kotlin/lotto/common/NumberStringTest.kt index 45130c6e26..ea121ec8bb 100644 --- a/src/test/kotlin/lotto/util/StringValidatorTest.kt +++ b/src/test/kotlin/lotto/common/NumberStringTest.kt @@ -1,27 +1,28 @@ -package lotto.util +package lotto.common import io.kotest.assertions.throwables.shouldThrowExactly import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe -class StringValidatorTest : StringSpec({ +class NumberStringTest : StringSpec({ + "์ˆซ์ž ์•„๋‹๋•Œ ์—๋Ÿฌ ๋ฐœ์ƒ ํ…Œ์ŠคํŠธ" { val exception = shouldThrowExactly { - StringValidator.validateNumber("1!") + NumberString("1!") } exception.message shouldBe "์ˆซ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. (์ž…๋ ฅ๊ฐ’:1!)" } "๋นˆ ๋ฌธ์ž์—ด ์ผ ๋•Œ ์—๋Ÿฌ ํ…Œ์ŠคํŠธ" { val exception = shouldThrowExactly { - StringValidator.validateNotBlank("") + NumberString("") } exception.message shouldBe "๊ฐ’์ด ๋น„์–ด์žˆ์Šต๋‹ˆ๋‹ค." } - "๊ณต๋ฐฑ ๋ฌธ์ž์—ด ์—๋Ÿฌ ํ…Œ์ŠคํŠธ" { + "๊ณต๋ฐฑ ๋ฌธ์ž์—ด ์ผ ๋•Œ ์—๋Ÿฌ ํ…Œ์ŠคํŠธ" { val exception = shouldThrowExactly { - StringValidator.validateNotBlank(" ") + NumberString(" ") } exception.message shouldBe "๊ฐ’์ด ๋น„์–ด์žˆ์Šต๋‹ˆ๋‹ค." } diff --git a/src/test/kotlin/lotto/domain/LottoShopTest.kt b/src/test/kotlin/lotto/domain/LottoShopTest.kt index e7547dfbf0..ca474cdf1e 100644 --- a/src/test/kotlin/lotto/domain/LottoShopTest.kt +++ b/src/test/kotlin/lotto/domain/LottoShopTest.kt @@ -3,24 +3,50 @@ package lotto.domain import io.kotest.core.spec.style.StringSpec import io.kotest.data.forAll import io.kotest.data.row +import io.kotest.matchers.equality.shouldBeEqualToComparingFields import io.kotest.matchers.shouldBe +import lotto.common.IntegerNumberList import lotto.util.RandomNumberGenerator class LottoShopTest : StringSpec({ val lottoShop = LottoShop(LottoGenerator(RandomNumberGenerator())) - "๋กœ๋˜ ๊ตฌ๋งค ํ…Œ์ŠคํŠธ" { + "๋กœ๋˜ ๊ตฌ๋งค ๊ฐœ์ˆ˜ ๊ฒ€์ฆ ํ…Œ์ŠคํŠธ" { forAll( // given - row("0์›์„ ๋‚ด๋ฉด 0๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.", 0, 0), - row("5000์›์„ ๋‚ด๋ฉด 5๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.", 5000, 5), - row("5500์›์„ ๋‚ด๋ฉด 5๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.", 5500, 5) + row("0์›์„ ๋‚ด๋ฉด 0๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.", Payment(0), 0), + row("5000์›์„ ๋‚ด๋ฉด 5๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.", Payment(5000), 5), + row("5500์›์„ ๋‚ด๋ฉด 5๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.", Payment(5500), 5) ) { title, payment, expectedSize -> // when - val actual = lottoShop.buyLotto(payment) + val actual = lottoShop.buyAutoLotto(payment) // then actual.size shouldBe expectedSize } } + + "์ˆ˜๋™ ๋กœ๋˜ ๊ตฌ๋งค ํ…Œ์ŠคํŠธ" { + val manualNumberList = IntegerNumberList( + listOf( + 1, + 2, + 3, + 4, + 5, + 6 + ) + ) + val result = lottoShop.buyManualLotto(Payment(1000), listOf(manualNumberList)) + result[0] shouldBeEqualToComparingFields Lotto( + listOf( + LottoNumber(1), + LottoNumber(2), + LottoNumber(3), + LottoNumber(4), + LottoNumber(5), + LottoNumber(6) + ) + ) + } }) diff --git a/src/test/kotlin/lotto/domain/LottoStatisticsServiceTest.kt b/src/test/kotlin/lotto/domain/LottoStatisticsServiceTest.kt index 2415d14d82..baea82e0a1 100644 --- a/src/test/kotlin/lotto/domain/LottoStatisticsServiceTest.kt +++ b/src/test/kotlin/lotto/domain/LottoStatisticsServiceTest.kt @@ -10,7 +10,7 @@ class LottoStatisticsServiceTest : StringSpec({ "๋‹น์ฒจ์ž ํ†ต๊ณ„ ํ†ตํ•ฉ ๊ฒฐ๊ณผ ํ…Œ์ŠคํŠธ" { // given - val payment = 15000 + val payment = Payment(15000) forAll( row( LottoRank.FOURTH, diff --git a/src/test/kotlin/lotto/domain/LottoStatisticsTest.kt b/src/test/kotlin/lotto/domain/LottoStatisticsTest.kt index caef33336c..5b837b7d9c 100644 --- a/src/test/kotlin/lotto/domain/LottoStatisticsTest.kt +++ b/src/test/kotlin/lotto/domain/LottoStatisticsTest.kt @@ -8,9 +8,9 @@ import io.kotest.matchers.shouldBe class LottoStatisticsTest : StringSpec({ "๋กœ๋˜ ์ˆ˜์ต๋ฅ  ๊ณ„์‚ฐ ํ…Œ์ŠคํŠธ" { forAll( - row(listOf(LottoRank.FOURTH, LottoRank.FIFTH), 100000, 0.55), - row(listOf(LottoRank.FIFTH), 5000, 1.0), - row(listOf(LottoRank.FOURTH), 5000, 10), + row(listOf(LottoRank.FOURTH, LottoRank.FIFTH), Payment(100000), 0.55), + row(listOf(LottoRank.FIFTH), Payment(5000), 1.0), + row(listOf(LottoRank.FOURTH), Payment(5000), 10.0), ) { prizeList, payment, expectedEarningRate -> // given val lottoStatistics = LottoStatistics(prizeList) diff --git a/src/test/kotlin/lotto/domain/LottoTest.kt b/src/test/kotlin/lotto/domain/LottoTest.kt index 0b14972c5e..f7289d29b8 100644 --- a/src/test/kotlin/lotto/domain/LottoTest.kt +++ b/src/test/kotlin/lotto/domain/LottoTest.kt @@ -7,10 +7,96 @@ import io.kotest.matchers.shouldBe class LottoTest : StringSpec({ "๋กœ๋˜ ๋ฒˆํ˜ธ๊ฐ€ 6๊ฐœ๋ฅผ ๋„˜์œผ๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ ํ…Œ์ŠคํŠธ" { - val numbers = listOf(1, 2, 3, 4, 5, 6, 7) + val numbers = listOf( + LottoNumber(1), + LottoNumber(2), + LottoNumber(3), + LottoNumber(4), + LottoNumber(5), + LottoNumber(6), + LottoNumber(7) + ) val exception = shouldThrowExactly { Lotto(numbers) } exception.message shouldBe "๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค." } + + "๋กœ๋˜ ๋ฒˆํ˜ธ ์ค‘๋ณต ์—๋Ÿฌ ํ…Œ์ŠคํŠธ" { + val numbers = listOf( + LottoNumber(1), + LottoNumber(2), + LottoNumber(3), + LottoNumber(4), + LottoNumber(5), + LottoNumber(1) + ) + val exception = shouldThrowExactly { + Lotto(numbers) + } + exception.message shouldBe "๋ฒˆํ˜ธ์— ์ค‘๋ณต์ด ์žˆ์Šต๋‹ˆ๋‹ค." + } + + "๋‹น์ฒจ ๋ฒˆํ˜ธ ๊ฐœ์ˆ˜ ์นด์šดํŠธ ํ…Œ์ŠคํŠธ" { + // given + val numbers = listOf( + LottoNumber(1), + LottoNumber(2), + LottoNumber(3), + LottoNumber(4), + LottoNumber(5), + LottoNumber(6) + ) + val lotto = Lotto(numbers) + + val luckyNumbers = listOf( + LottoNumber(2), + LottoNumber(4), + LottoNumber(6), + LottoNumber(8), + LottoNumber(10), + LottoNumber(12) + ) + val luckyLotto = Lotto(luckyNumbers) + // when + val actual = lotto.countHitNumbers(luckyLotto) + // then + actual shouldBe 3 + } + + "๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ํฌํ•จ๋˜๋ฉด containsBonusNumber์—์„œ true๋ฅผ ๋ฐ˜ํ™˜" { + // given + val numbers = listOf( + LottoNumber(1), + LottoNumber(2), + LottoNumber(3), + LottoNumber(4), + LottoNumber(5), + LottoNumber(6) + ) + val lotto = Lotto(numbers) + val bonusNumber = LottoNumber(1) + // when + val actual = lotto.hasBonusNumber(bonusNumber) + // then + actual shouldBe true + } + + "๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ํฌํ•จ ์•ˆ๋˜๋ฉด containsBonusNumber์—์„œ false๋ฅผ ๋ฐ˜ํ™˜" { + // given + val numbers = listOf( + LottoNumber(1), + LottoNumber(2), + LottoNumber(3), + LottoNumber(4), + LottoNumber(5), + LottoNumber(6) + ) + val lotto = Lotto(numbers) + val bonusNumber = LottoNumber(7) + // when + val actual = lotto.hasBonusNumber(bonusNumber) + // then + actual shouldBe false + } }) diff --git a/src/test/kotlin/lotto/domain/LottoWinnerTest.kt b/src/test/kotlin/lotto/domain/LottoWinnerTest.kt deleted file mode 100644 index 5d831b3461..0000000000 --- a/src/test/kotlin/lotto/domain/LottoWinnerTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -package lotto.domain - -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.collections.shouldContainInOrder -import io.kotest.matchers.shouldBe - -class LottoWinnerTest : StringSpec({ - - "๋‹น์ฒจ ๋กœ๋˜ ์„ ํƒ ํ…Œ์ŠคํŠธ" { - // given - val luckyNumbers = listOf(1, 3, 5, 7, 9, 11) - val bonusNumber = 13 - val lottoWinner = LottoWinner(LuckyNumbers(luckyNumbers, bonusNumber)) - - val fourthWinLotto = Lotto(listOf(5, 7, 9, 11, 12, 13)) - val secondWinLotto = Lotto(listOf(3, 5, 7, 9, 11, 13)) - val thirdWinLotto = Lotto(listOf(3, 5, 7, 9, 11, 15)) - val notWintLotto = Lotto(listOf(2, 4, 6, 8, 10, 13)) - // when - val result = lottoWinner.findWinLottoList(listOf(fourthWinLotto, notWintLotto, secondWinLotto, thirdWinLotto)) - // then - result.size shouldBe 3 - result shouldContainInOrder listOf(LottoRank.FOURTH, LottoRank.SECOND, LottoRank.THIRD) - } -}) diff --git a/src/test/kotlin/lotto/domain/LuckyNumbersTest.kt b/src/test/kotlin/lotto/domain/LuckyNumbersTest.kt deleted file mode 100644 index aabdad0046..0000000000 --- a/src/test/kotlin/lotto/domain/LuckyNumbersTest.kt +++ /dev/null @@ -1,52 +0,0 @@ -package lotto.domain - -import io.kotest.assertions.throwables.shouldThrowExactly -import io.kotest.core.spec.style.StringSpec -import io.kotest.data.forAll -import io.kotest.data.row -import io.kotest.matchers.shouldBe - -class LuckyNumbersTest : StringSpec({ - "๋‹น์ฒจ ๋ฒˆํ˜ธ๊ฐ€ 6๊ฐœ๋ฅผ ๋„˜์œผ๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ ํ…Œ์ŠคํŠธ" { - val numbers = listOf(1, 2, 3, 4, 5, 6, 7) - val exception = shouldThrowExactly { - LuckyNumbers(luckyNumbers = numbers, bonusNumber = 10) - } - exception.message shouldBe "๋‹น์ฒจ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค." - } - - "๋‹น์ฒจ ๋ฒˆํ˜ธ๊ฐ€ ์ค‘๋ณต์ด๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ ํ…Œ์ŠคํŠธ" { - val numbers = listOf(1, 2, 3, 4, 6, 6) - val exception = shouldThrowExactly { - LuckyNumbers(luckyNumbers = numbers, bonusNumber = 10) - } - exception.message shouldBe "๋‹น์ฒจ ๋ฒˆํ˜ธ์— ์ค‘๋ณต์ด ์žˆ์Šต๋‹ˆ๋‹ค." - } - - "๋ณด๋„ˆ์Šค๋ณผ ์ค‘๋ณต ์—๋Ÿฌ ํ…Œ์ŠคํŠธ" { - val numbers = listOf(1, 2, 3, 4, 5, 6) - val exception = shouldThrowExactly { - LuckyNumbers(luckyNumbers = numbers, bonusNumber = 6) - } - exception.message shouldBe "๋ณด๋„ˆ์Šค๋ณผ์€ ๋‹น์ฒจ๋ฒˆํ˜ธ์™€ ์ค‘๋ณต๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." - } - - "๋กœ๋˜ Hit Count ๊ณ„์‚ฐ ํ…Œ์ŠคํŠธ" { - forAll( - // given - row("0๊ฐœ ์ผ์น˜ํ•˜๋Š” ๋กœ๋˜", LuckyNumbers(luckyNumbers = listOf(1, 3, 5, 7, 9, 11), bonusNumber = 13), listOf(2, 4, 6, 8, 10, 12), LottoRank.MISS), - row("3๊ฐœ ์ผ์น˜ํ•˜๋Š” ๋กœ๋˜", LuckyNumbers(luckyNumbers = listOf(1, 3, 5, 7, 9, 11), bonusNumber = 13), listOf(7, 8, 9, 10, 11, 12), LottoRank.FIFTH), - row( - "5๊ฐœ ์ผ์น˜+๋ณด๋„ˆ์Šค๋ฒˆํ˜ธ ์ผ์น˜ํ•˜๋Š” ๋กœ๋˜", - LuckyNumbers(luckyNumbers = listOf(1, 3, 5, 7, 9, 11), bonusNumber = 13), - listOf(1, 3, 5, 7, 9, 13), - LottoRank.SECOND - ) - ) { title, luckyNumbers, lottoNumbers, expectedRank -> - // when - val actual = luckyNumbers.rank(lottoNumbers) - // then - actual shouldBe expectedRank - } - } -}) diff --git a/src/test/kotlin/lotto/domain/MoneyTest.kt b/src/test/kotlin/lotto/domain/MoneyTest.kt new file mode 100644 index 0000000000..3605234f0e --- /dev/null +++ b/src/test/kotlin/lotto/domain/MoneyTest.kt @@ -0,0 +1,24 @@ +package lotto.domain + +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe + +class MoneyTest : StringSpec({ + "์–‘์ˆ˜๊ฐ’์„ ๊ฐ€์กŒ์„๋•Œ isPositive ์—์„œ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค." { + // given + val integer = Money(1) + // when + val actual = integer.isPositive() + // then + actual shouldBe true + } + + "์Œ์ˆ˜๊ฐ’์„ ๊ฐ€์กŒ์„๋•Œ isPositive ์—์„œ false๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค." { + // given + val integer = Money(-1) + // when + val actual = integer.isPositive() + // then + actual shouldBe false + } +}) diff --git a/src/test/kotlin/lotto/domain/PaymentTest.kt b/src/test/kotlin/lotto/domain/PaymentTest.kt new file mode 100644 index 0000000000..c953b5283a --- /dev/null +++ b/src/test/kotlin/lotto/domain/PaymentTest.kt @@ -0,0 +1,34 @@ +package lotto.domain + +import io.kotest.assertions.throwables.shouldThrowExactly +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe + +class PaymentTest : StringSpec({ + "์ˆซ์ž ์•„๋‹๋•Œ ์—๋Ÿฌ ๋ฐœ์ƒ ํ…Œ์ŠคํŠธ" { + val exception = shouldThrowExactly { + Payment(-1) + } + exception.message shouldBe "์ง€๋ถˆ์•ก์€ ์Œ์ˆ˜๊ฐ€ ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + } + + "์ง€๋ถˆ๊ธˆ ์ฐจ๊ฐ ํ…Œ์ŠคํŠธ" { + // given + val payment = Payment(1000) + // when + payment.charge(100) + // then + payment.amount shouldBe 900 + } + + "์ž”์•ก ๋ถ€์กฑ์œผ๋กœ ์ง€๋ถˆ๊ธˆ ์ฐจ๊ฐ ์—๋Ÿฌ ํ…Œ์ŠคํŠธ" { + // given + val payment = Payment(1000) + // when + val exception = shouldThrowExactly { + payment.charge(1100) + } + // then + exception.message shouldBe "์ž”์•ก ๋ถ€์กฑ์œผ๋กœ ๊ธˆ์•ก์„ ์ฐจ๊ฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + } +}) diff --git a/src/test/kotlin/lotto/util/NumberUtilTest.kt b/src/test/kotlin/lotto/util/NumberUtilTest.kt index 2eadd4a249..5e6558654c 100644 --- a/src/test/kotlin/lotto/util/NumberUtilTest.kt +++ b/src/test/kotlin/lotto/util/NumberUtilTest.kt @@ -10,9 +10,9 @@ class NumberUtilTest : StringSpec({ "์†Œ์ˆซ์  ์ง€์ • ์ž๋ฆฌ์ˆ˜ ์ดํ•˜ ๋ฒ„๋ฆผ ํ…Œ์ŠคํŠธ" { forAll( // given - row(1.2345, 0, 1.0), - row(1.2345, 3, 1.234), - row(1.2345, -1, 1.2345) + row(1.2345, 0.0, 1.0), + row(1.2345, 3.0, 1.234), + row(1.2345, -1.0, 1.2345) ) { number, decimalPlace, expectedResult -> // when val actualResult = NumberUtil.floor(number, decimalPlace) diff --git a/src/test/kotlin/lotto/util/NumberGeneratorTest.kt b/src/test/kotlin/lotto/util/RandomNumberGeneratorTest.kt similarity index 92% rename from src/test/kotlin/lotto/util/NumberGeneratorTest.kt rename to src/test/kotlin/lotto/util/RandomNumberGeneratorTest.kt index 2decea957d..665c4f3e38 100644 --- a/src/test/kotlin/lotto/util/NumberGeneratorTest.kt +++ b/src/test/kotlin/lotto/util/RandomNumberGeneratorTest.kt @@ -4,7 +4,7 @@ import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.ints.shouldBeInRange -class NumberGeneratorTest : StringSpec({ +class RandomNumberGeneratorTest : StringSpec({ val numberGenerator = RandomNumberGenerator()