Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

πŸš€ 4단계 - 둜또(μˆ˜λ™) #1137

Open
wants to merge 13 commits into
base: aimbe
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
πŸš€ 3단계 - 둜또(2λ“±)
## κ΅¬ν˜„ κΈ°λŠ₯ λͺ©λ‘

- [x] 2등을 μœ„ν•΄ μΆ”κ°€ 번호λ₯Ό ν•˜λ‚˜ 더 μΆ”μ²¨ν•œλ‹€.
- [x] 당첨 톡계에 2등을 μΆ”κ°€ν•œλ‹€.
- [x] ν˜„μž¬ 둜또 μƒμ„±κΈ°λŠ” μžλ™ 생성 κΈ°λŠ₯만 μ œκ³΅ν•œλ‹€. μ‚¬μš©μžκ°€ μˆ˜λ™μœΌλ‘œ 좔첨 번호λ₯Ό μž…λ ₯ν•  수 μžˆλ„λ‘ ν•΄μ•Ό ν•œλ‹€
- [x] μž…λ ₯ν•œ κΈˆμ•‘, μžλ™ 생성 숫자, μˆ˜λ™ 생성 번호λ₯Ό μž…λ ₯ν•˜λ„λ‘ ν•΄μ•Ό ν•œλ‹€.
13 changes: 9 additions & 4 deletions src/main/kotlin/lotto/controller/LottoController.kt
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package lotto.controller

import lotto.domain.LottoPrice
import lotto.domain.LottoPurchaseManager
import lotto.service.LottoService
import lotto.view.InputView
import lotto.view.ResultView

fun main() {
val purchaseAmount = InputView().readPurchaseAmount()
val lottos = LottoService().purchase(LottoPrice(purchaseAmount))
ResultView().printPurchaseResult(lottos)
val purchaseAmount = LottoPrice(InputView().readPurchaseAmount())

val manualCount = InputView().readManualLottoCount()
val manualLottos = InputView().readManualLottoNumbers(manualCount)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Viewκ°€ Model에 μ˜μ‘΄ν•˜κ³ μžˆλŠ” 것 κ°™μ•„μš”. πŸ€”
View λ‹¨μ—μ„œλŠ” μž…λ ₯ κ°’μœΌλ‘œ List<List<Int>>의 κ²°κ³Όλ₯Ό κ°€μ Έμ˜€κ³ , 이 κ²°κ³ΌλŠ” Controllerμ—μ„œ λ³€ν™˜ν•΄μ£Όλ„λ‘ ν•΄μ£Όλ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μΆ”κ°€μ μœΌλ‘œ 이 μˆ˜λ™(으둜 μž…λ ₯ 받은) 둜또λ₯Ό μƒμ„±ν•΄μ£ΌλŠ” 역할은 μ–΄λ–€ κ°μ²΄μ—κ²Œ μœ„μž„ν• μ§€λ„ κ³ λ―Όν•΄λ³΄μ‹œλ©΄ 쒋을 것 κ°™μ•„μš”. πŸ˜ƒ


val lottos = LottoService(LottoPurchaseManager()).purchase(purchaseAmount, manualLottos)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ν˜„μž¬ LottoService 객체λ₯Ό λ‘λ²ˆ μƒμ„±ν•΄μ„œ μ‚¬μš©ν•˜κ³ μžˆλŠ”λ°μš”.
LottoService κ°μ²΄λŠ” ν•œλ²ˆ μƒμ„±ν•œ 뒀에 μž¬μ‚¬μš©ν•˜λ©΄ μ–΄λ–¨κΉŒμš”?

ResultView().printPurchaseResult(manualCount, lottos)

val winningNumbers = InputView().readWinningNumbers()
val bonusBall = InputView().readBonusBall(winningNumbers)
val winningResult = LottoService().checkWinning(lottos, winningNumbers, bonusBall)
val winningResult = LottoService(LottoPurchaseManager()).checkWinning(lottos, winningNumbers, bonusBall)

ResultView().printWinningStatistics(winningResult)
ResultView().printProfitRate(winningResult.calculateProfitRate(purchaseAmount))
Expand Down
5 changes: 2 additions & 3 deletions src/main/kotlin/lotto/domain/LottoFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ package lotto.domain
import Lottos

object LottoFactory {
fun create(price: LottoPrice): Lottos {
val purchaseCount = price.calculatePurchaseCount()
val tickets = (1..purchaseCount).map { LottoRandomGenerator.randomGenerate() }
fun create(count: Int): Lottos {
val tickets = (1..count).map { LottoRandomGenerator.randomGenerate() }
return Lottos(tickets)
}
}
5 changes: 4 additions & 1 deletion src/main/kotlin/lotto/domain/LottoPrice.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package lotto.domain

@JvmInline
value class LottoPrice(val money: Int) {
value class LottoPrice(private val money: Int) {
init {
require(money >= LottoConstants.LOTTO_PRICE) { "둜또 κ΅¬μž… κΈˆμ•‘μ€ 1000원 이상이어야 ν•©λ‹ˆλ‹€." }
}

val value: Int
get() = money

fun calculatePurchaseCount(): Int {
return money / LottoConstants.LOTTO_PRICE
}
Expand Down
17 changes: 17 additions & 0 deletions src/main/kotlin/lotto/domain/LottoPurchaseManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lotto.domain

import Lottos

class LottoPurchaseManager {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LottoPurchaseManager의 경우 λ³„λ„μ˜ μƒνƒœ 값을 가지지 μ•ŠλŠ”λ°, object class둜 선언해도 λ˜μ§€ μ•Šμ„κΉŒμš”? πŸ€”

fun purchase(
price: LottoPrice,
manualLottos: Lottos,
): Lottos {
val totalCount = price.calculatePurchaseCount()
val autoCount = totalCount - manualLottos.size
require(autoCount >= 0) { "μˆ˜λ™ ꡬ맀 κ°œμˆ˜κ°€ 총 ꡬ맀 κ°€λŠ₯ 개수λ₯Ό μ΄ˆκ³Όν–ˆμŠ΅λ‹ˆλ‹€." }

val autoLottos = LottoFactory.create(autoCount)
return Lottos(manualLottos + autoLottos)
}
}
13 changes: 11 additions & 2 deletions src/main/kotlin/lotto/domain/Lottos.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@ class Lottos(private val tickets: List<Lotto>) {
): Map<Rank, Int> {
return tickets
.map { it.match(winningNumber, bonusBall) }
.groupBy { it }
.mapValues { it.value.size }
.groupingBy {
it
}.eachCount()
}

operator fun plus(lotto: Lottos): List<Lotto> {
return tickets + lotto.tickets
}
Comment on lines +27 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ•„λž˜μ™€ 같이 리턴 νƒ€μž…μ„ Lottos둜 변경해보면 μ–΄λ–¨κΉŒμš”? πŸ˜ƒ

Suggested change
operator fun plus(lotto: Lottos): List<Lotto> {
return tickets + lotto.tickets
}
operator fun plus(lotto: Lottos): Lottos {
return Lottos(tickets + lotto.tickets)
}


companion object {
fun from(lottos: List<Lotto>): Lottos = Lottos(lottos)
}
}
4 changes: 2 additions & 2 deletions src/main/kotlin/lotto/domain/WinningResult.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ class WinningResult(private val winningStatistics: Map<Rank, Int>) {
}
}

fun calculateProfitRate(purchaseAmount: Int): Double {
return calculateTotalPrize().toDouble() / purchaseAmount
fun calculateProfitRate(purchaseAmount: LottoPrice): Double {
return calculateTotalPrize().toDouble() / purchaseAmount.value
}

fun getWinningCount(rank: Rank): Int {
Expand Down
11 changes: 7 additions & 4 deletions src/main/kotlin/lotto/service/LottoService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ package lotto.service

import Lottos
import lotto.domain.Lotto
import lotto.domain.LottoFactory
import lotto.domain.LottoNumber
import lotto.domain.LottoPrice
import lotto.domain.LottoPurchaseManager
import lotto.domain.WinningLotto
import lotto.domain.WinningResult

class LottoService {
fun purchase(price: LottoPrice): Lottos {
return LottoFactory.create(price)
class LottoService(private val purchaseManager: LottoPurchaseManager) {
fun purchase(
price: LottoPrice,
manualLottos: Lottos,
): Lottos {
return purchaseManager.purchase(price, manualLottos)
}

fun checkWinning(
Expand Down
20 changes: 20 additions & 0 deletions src/main/kotlin/lotto/view/InputView.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package lotto.view

import Lottos
import lotto.domain.Lotto
import lotto.domain.LottoNumber

Expand Down Expand Up @@ -29,4 +30,23 @@ class InputView {
require(!winningNumbers.numbers.contains(bonusBallNumber)) { "λ³΄λ„ˆμŠ€ 볼은 당첨 λ²ˆν˜Έμ™€ 쀑볡될 수 μ—†μŠ΅λ‹ˆλ‹€." }
return bonusBallNumber
}

fun readManualLottoCount(): Int {
println("\nμˆ˜λ™μœΌλ‘œ ꡬ맀할 둜또 수λ₯Ό μž…λ ₯ν•΄ μ£Όμ„Έμš”.")
return readln().toInt()
}

fun readManualLottoNumbers(count: Int): Lottos {
println("\nμˆ˜λ™μœΌλ‘œ ꡬ맀할 번호λ₯Ό μž…λ ₯ν•΄ μ£Όμ„Έμš”.")

val manualLottos =
(1..count).map {
val numbers =
readln().split(",")
.map { it.trim().toInt() }
.map { LottoNumber(it) }
Lotto(numbers)
}
return Lottos.from(manualLottos)
Comment on lines +42 to +50
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(이미 μœ„μ—μ„œ μ–ΈκΈ‰ν–ˆμ—ˆμ§€λ§Œ) μ‹€μ œλ‘œ μž…λ ₯ 받은 값을 Domain Model인 Lotto 그리고 Lottos둜 λ³€κ²½ν•˜λŠ” λ‘œμ§μ€ Controller에 μœ„μΉ˜μ‹œν‚€λ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€. πŸ˜‰

}
}
10 changes: 7 additions & 3 deletions src/main/kotlin/lotto/view/ResultView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import lotto.domain.Rank
import lotto.domain.WinningResult

class ResultView {
fun printPurchaseResult(lottos: Lottos) {
println("${lottos.size}개λ₯Ό κ΅¬λ§€ν–ˆμŠ΅λ‹ˆλ‹€.")
lottos.lottos.forEach { println(it) }
fun printPurchaseResult(
manualCount: Int,
lottos: Lottos,
) {
val autoCount = lottos.size - manualCount
println("\nμˆ˜λ™μœΌλ‘œ ${manualCount}μž₯, μžλ™μœΌλ‘œ ${autoCount}μž₯을 κ΅¬λ§€ν–ˆμŠ΅λ‹ˆλ‹€.")
lottos.lottos.forEach { println(it.numbers.map { num -> num.number }) }
}

fun printWinningStatistics(winningResult: WinningResult) {
Expand Down
28 changes: 21 additions & 7 deletions src/test/kotlin/lotto/LottoGameTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Lottos
import lotto.domain.Lotto
import lotto.domain.LottoNumber
import lotto.domain.LottoPrice
import lotto.domain.LottoPurchaseManager
import lotto.domain.Rank
import lotto.service.LottoService
import org.assertj.core.api.Assertions.assertThat
Expand All @@ -17,12 +18,25 @@ class LottoGameTest {
}

@ParameterizedTest
@CsvSource("1000", "2000", "3000")
fun `κ΅¬λ§€ν•œ 둜또 만큼 λžœλ€ν•œ 번호λ₯Ό μƒμ„±ν•œλ‹€`(money: Int) {
@CsvSource(
"2000, 1",
"3000, 2",
)
fun `μˆ˜λ™κ³Ό μžλ™ 둜또λ₯Ό ν•©μ³μ„œ ꡬ맀 κΈˆμ•‘λ§ŒνΌ 둜또λ₯Ό μƒμ„±ν•œλ‹€`(
money: Int,
manualCount: Int,
) {
val lottoPrice = LottoPrice(money)
val purchasedLottos = LottoService().purchase(lottoPrice)
val manualLottos =
List(manualCount) {
Lotto(createLottoNumbers(1, 2, 3, 4, 5, 6))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createLottoNumbers κ°€ μ•„λ‹ˆλΌ μ²˜μŒλΆ€ν„° createLotto λ©”μ„œλ“œλ₯Ό λ§Œλ“€λ©΄ 일일이 Lotto둜 λž©ν•‘ν•˜λŠ” λ‘œμ§λ“€μ„ 쀄일 수 μžˆμ„ 것 κ°™μ•„μš”. πŸ˜ƒ

}

val purchasedLottos = LottoService(LottoPurchaseManager()).purchase(lottoPrice, Lottos(manualLottos))

assertThat(purchasedLottos.size).isEqualTo(lottoPrice.calculatePurchaseCount())
assertThat(purchasedLottos.lottos.take(manualCount))
.containsExactlyElementsOf(manualLottos)

purchasedLottos.lottos.forEach {
assertThat(it.numbers.distinct().size).isEqualTo(6)
Expand Down Expand Up @@ -58,7 +72,7 @@ class LottoGameTest {
val winningNumbers = Lotto(createLottoNumbers(1, 2, 3, 4, 5, 6))
val bonusNumber = LottoNumber(7)

val winningResult = LottoService().checkWinning(lottos, winningNumbers, bonusNumber)
val winningResult = LottoService(LottoPurchaseManager()).checkWinning(lottos, winningNumbers, bonusNumber)

assertThat(winningResult.getWinningCount(Rank.NONE)).isEqualTo(0)
}
Expand All @@ -77,7 +91,7 @@ class LottoGameTest {
val winningNumbers = Lotto(createLottoNumbers(1, 2, 3, 4, 5, 6))
val bonusNumber = LottoNumber(7)

val winningResult = LottoService().checkWinning(lottos, winningNumbers, bonusNumber)
val winningResult = LottoService(LottoPurchaseManager()).checkWinning(lottos, winningNumbers, bonusNumber)

assertThat(winningResult.getWinningCount(Rank.FIRST)).isEqualTo(1)
assertThat(winningResult.getWinningCount(Rank.SECOND)).isEqualTo(1)
Expand All @@ -96,7 +110,7 @@ class LottoGameTest {
val winningNumbers = Lotto(createLottoNumbers(1, 2, 3, 4, 5, 6))
val bonusNumber = LottoNumber(7)

val winningResult = LottoService().checkWinning(lottos, winningNumbers, bonusNumber)
val winningResult = LottoService(LottoPurchaseManager()).checkWinning(lottos, winningNumbers, bonusNumber)

assertThat(winningResult.getWinningCount(Rank.FIFTH)).isEqualTo(0)
assertThat(winningResult.getWinningCount(Rank.FOURTH)).isEqualTo(0)
Expand All @@ -118,7 +132,7 @@ class LottoGameTest {
val winningNumbers = Lotto(createLottoNumbers(1, 2, 3, 4, 5, 6))
val bonusNumber = LottoNumber(7)

val winningResult = LottoService().checkWinning(lottos, winningNumbers, bonusNumber)
val winningResult = LottoService(LottoPurchaseManager()).checkWinning(lottos, winningNumbers, bonusNumber)

assertThat(winningResult.getWinningCount(Rank.FIRST)).isEqualTo(1)
assertThat(winningResult.getWinningCount(Rank.SECOND)).isEqualTo(1)
Expand Down
3 changes: 2 additions & 1 deletion src/test/kotlin/lotto/WinningResultTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package lotto

import lotto.domain.LottoPrice
import lotto.domain.Rank
import lotto.domain.WinningResult
import org.assertj.core.api.Assertions.assertThat
Expand Down Expand Up @@ -47,7 +48,7 @@ class WinningResultTest {
@Test
fun `수읡λ₯ μ„ κ³„μ‚°ν•œλ‹€`() {
val winningStatistics = mapOf(Rank.FOURTH to 1)
val purchaseAmount = 10000
val purchaseAmount = LottoPrice(10000)
val winningResult = WinningResult(winningStatistics)
val profitRate = winningResult.calculateProfitRate(purchaseAmount)
assertThat(profitRate).isEqualTo(0.5)
Expand Down
47 changes: 47 additions & 0 deletions src/test/kotlin/lotto/domain/RankTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package lotto.domain

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

class RankTest {
@Test
fun `6개 λ§žμΆ”λ©΄ 1등이닀`() {
val rank = Rank.from(matchCount = 6, matchBonus = false)
assertThat(rank).isEqualTo(Rank.FIRST)
}

@Test
fun `5κ°œμ™€ λ³΄λ„ˆμŠ€ 볼을 λ§žμΆ”λ©΄ 2등이닀`() {
val rank = Rank.from(matchCount = 5, matchBonus = true)
assertThat(rank).isEqualTo(Rank.SECOND)
}

@Test
fun `5개 λ§žμΆ”κ³  λ³΄λ„ˆμŠ€ 볼을 λͺ» λ§žμΆ”λ©΄ 3등이닀`() {
val rank = Rank.from(matchCount = 5, matchBonus = false)
assertThat(rank).isEqualTo(Rank.THIRD)
}

@Test
fun `4개 λ§žμΆ”λ©΄ 4등이닀`() {
val rank = Rank.from(matchCount = 4, matchBonus = false)
assertThat(rank).isEqualTo(Rank.FOURTH)
}

@Test
fun `3개 λ§žμΆ”λ©΄ 5등이닀`() {
val rank = Rank.from(matchCount = 3, matchBonus = false)
assertThat(rank).isEqualTo(Rank.FIFTH)
}

@Test
fun `2개 μ΄ν•˜ λ§žμΆ”λ©΄ 미당첨이닀`() {
val rank2 = Rank.from(matchCount = 2, matchBonus = false)
val rank1 = Rank.from(matchCount = 1, matchBonus = false)
val rank0 = Rank.from(matchCount = 0, matchBonus = false)

assertThat(rank2).isEqualTo(Rank.NONE)
assertThat(rank1).isEqualTo(Rank.NONE)
assertThat(rank0).isEqualTo(Rank.NONE)
}
Comment on lines +37 to +46
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ν•˜λ‚˜μ˜ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ§€λ§Œ λ‹€μ–‘ν•œ μΈμžμ— λŒ€ν•œ ν…ŒμŠ€νŠΈλŠ” Parameterized Testλ₯Ό ν™œμš©ν•΄μ„œ 쑰금 더 κΉ”λ”ν•˜κ²Œ λ³€κ²½ν•΄λ³Ό 수 μžˆμ„ 것 κ°™μ•„μš”. πŸ˜ƒ

}