-
Notifications
You must be signed in to change notification settings - Fork 357
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단계 - 로또(수동) #589
base: 0923kdh
Are you sure you want to change the base?
4단계 - 로또(수동) #589
Changes from all commits
e1b19c9
3996fc9
ac84773
b986fd3
1c8d75d
6bb4ae4
974b688
69bce82
c2bb815
acf1301
2926629
2da6a89
ef9e487
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,3 +37,4 @@ | |
* 구매한 n장의 로또에 대해 당첨 통계를 관리할 수 있다. | ||
* 보너스 볼을 입력을 수 있다. | ||
* 보너스 볼을 포함하여 당첨 통계를 낼 수 있다. | ||
* 수동으로 로또 번호를 입력받을 수 있다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,21 @@ | ||
package lotto | ||
|
||
import lotto.domain.LottoMachine | ||
import lotto.domain.LottoTicketBundle | ||
import lotto.domain.StatisticalResultExtractor | ||
import lotto.domain.WinningNumbers | ||
import lotto.domain.strategy.LottoAutoGenerateStrategy | ||
import lotto.domain.strategy.LottoManualGenerateStrategy | ||
import lotto.view.InputView | ||
import lotto.view.OutputView | ||
|
||
fun main() { | ||
val ticketAmount = InputView.getPurchaseAmount() | ||
val lottoTicketBundle = LottoTicketBundle(ticketAmount).lottoTickets | ||
InputView.getNumberOfPurchases(lottoTicketBundle.size) | ||
val winningNumber = InputView.getWinningNumber() | ||
val lottoWinning = WinningNumberExtractor.process( | ||
lottoTicketBundle, WinningNumbers(winningNumber.first, winningNumber.second) | ||
) | ||
OutputView.printOutput(StatisticalResultExtractor(lottoWinning), lottoTicketBundle.size) | ||
val manualTicketCount = InputView.getManualTicketCount() | ||
val ticketCount = LottoMachine.calculateTicketCount(ticketAmount, manualTicketCount) | ||
InputView.printManualTicketNumber(ticketCount.manualTicketCount) | ||
val lottoTicketBundle = LottoTicketBundle(ticketCount, listOf(LottoAutoGenerateStrategy(), LottoManualGenerateStrategy())) | ||
InputView.printNumberOfPurchases(ticketCount) | ||
val winningBallResult = InputView.getWinningBalls() | ||
val lottoWinningResult = LottoMachine.process(lottoTicketBundle, winningBallResult) | ||
OutputView.printOutput(StatisticalResultExtractor(lottoWinningResult), lottoTicketBundle.lottoTickets.size) | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package lotto.domain | ||
|
||
import lotto.common.LottoTicketPolicy | ||
|
||
object LottoMachine { | ||
fun calculateTicketCount(amount: Int, manualTicketCount: Int): LottoTicketCount { | ||
val autoTicketCount = (amount / LottoTicketPolicy.PRICE) - manualTicketCount | ||
|
||
return LottoTicketCount(autoTicketCount, manualTicketCount) | ||
} | ||
|
||
fun process(lottoTicketBundle: LottoTicketBundle, winningBallResult: WinningBallResult): LottoWinningResult { | ||
val resultMap = mutableMapOf<LottoTicketResult, Int>() | ||
lottoTicketBundle.lottoTickets.groupingBy { ticket -> | ||
val intersectNumbers = ticket.intersect(winningBallResult.winningBalls) | ||
val isBonusBallMatched = winningBallResult.bonusBall in ticket | ||
LottoTicketResult(intersectNumbers.size, isBonusBallMatched) | ||
}.eachCountTo(resultMap) | ||
|
||
return LottoWinningResult(resultMap.toSortedMap(getTicketResultComparator())) | ||
} | ||
|
||
private fun getTicketResultComparator(): Comparator<LottoTicketResult> = | ||
Comparator.comparing(LottoTicketResult::matchCount) | ||
.thenComparing(LottoTicketResult::isBonusBallMatched) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package lotto.domain | ||
|
||
import lotto.common.LottoTicketPolicy.END_NUMBER | ||
import lotto.common.LottoTicketPolicy.START_NUMBER | ||
|
||
@JvmInline | ||
value class LottoNumber( | ||
private val number: Int, | ||
) { | ||
init { | ||
require(number in START_NUMBER..END_NUMBER) { "로또 번호는 1~45 사이의 숫자만 가능합니다." } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,19 @@ | ||
package lotto | ||
package lotto.domain | ||
|
||
import lotto.common.LottoTicketPolicy.END_NUMBER | ||
import lotto.common.LottoTicketPolicy.MAX_LOTTO_NUMBER_SIZE | ||
import lotto.common.LottoTicketPolicy.START_NUMBER | ||
import lotto.utils.RandomNumberGenerator | ||
|
||
object LottoNumberSelector { | ||
fun select(): Set<Int> { | ||
val lottoNumbers = mutableSetOf<Int>() | ||
fun select(): Set<LottoNumber> { | ||
val lottoNumbers = mutableSetOf<LottoNumber>() | ||
while (lottoNumbers.size < MAX_LOTTO_NUMBER_SIZE) { | ||
lottoNumbers.add(generateRandomNumber()) | ||
lottoNumbers.add(generateLottoNumber()) | ||
} | ||
|
||
return lottoNumbers | ||
} | ||
|
||
private fun generateRandomNumber() = RandomNumberGenerator.generate(START_NUMBER..END_NUMBER) | ||
private fun generateLottoNumber() = LottoNumber(RandomNumberGenerator.generate(START_NUMBER..END_NUMBER)) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
package lotto.domain | ||
|
||
import lotto.LottoNumberSelector | ||
|
||
data class LottoTicket( | ||
val numbers: Set<Int> = LottoNumberSelector.select(), | ||
) : Set<Int> by numbers | ||
val numbers: Set<LottoNumber>, | ||
) : Set<LottoNumber> by numbers | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저번 리뷰 때 kotlin delegate 패턴에 대한 단점을 물어봤었죠~ 제가 생각하는 delegate 패턴의 단점은 바로 delegate에 대한 대상의 API를 모두 사용할 수 있다라고 생각해요. 일반적인 객체는 객체 캡슐화에 대해서 내부에서는 사용하고 외부에서는 필요한 메서드만 사용할 수 있지만, delegate를 해버리는 순간 의미없는, 사용하지 않는 메서드까지 모두 외부에서 사용할 수 있기 때문에 외부에서 내부적인 부분까지 사용할 수 있어 객체간의 협력이 깨질 수도 있다고 생각해요~ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,19 @@ | ||
package lotto.domain | ||
|
||
import lotto.common.LottoTicketPolicy | ||
import lotto.domain.strategy.LottoGenerateStrategy | ||
import lotto.domain.strategy.TicketGenerateType | ||
|
||
class LottoTicketBundle(amount: Int) { | ||
private val count = amount / LottoTicketPolicy.PRICE | ||
val lottoTickets: List<LottoTicket> = List(count) { | ||
LottoTicket() | ||
class LottoTicketBundle( | ||
lottoTicketCount: LottoTicketCount, | ||
lottoGenerateStrategies: List<LottoGenerateStrategy>, | ||
) { | ||
private val lottoGenerateStrategyMap = lottoGenerateStrategies.associateBy { it.ticketGenerateType } | ||
|
||
val lottoTickets: List<LottoTicket> = List(lottoTicketCount.autoTicketCount) { | ||
val autoGenerateStrategy = lottoGenerateStrategyMap.getValue(TicketGenerateType.AUTO) | ||
autoGenerateStrategy.generate() | ||
} + List(lottoTicketCount.manualTicketCount) { | ||
val manualGenerateStrategy = lottoGenerateStrategyMap.getValue(TicketGenerateType.MANUAL) | ||
manualGenerateStrategy.generate() | ||
Comment on lines
+12
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package lotto.domain | ||
|
||
data class LottoTicketCount( | ||
val autoTicketCount: Int, | ||
val manualTicketCount: Int, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package lotto.domain | ||
|
||
data class LottoTicketResult( | ||
val matchCount: Int, | ||
val isBonusBallMatched: Boolean, | ||
) |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package lotto.domain | ||
|
||
data class LottoWinningResult( | ||
val result: Map<LottoTicketResult, Int>, | ||
) { | ||
fun totalAmount(): Long { | ||
return result.entries.sumOf { | ||
WinningAmount.from(it.key.matchCount, it.key.isBonusBallMatched).amount * it.value | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,17 @@ | ||
package lotto.domain | ||
|
||
import lotto.TicketResult | ||
import lotto.common.LottoTicketPolicy | ||
|
||
class StatisticalResultExtractor( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
private val lottoWinning: LottoWinning, | ||
private val lottoWinningResult: LottoWinningResult, | ||
) { | ||
fun getMatchCount(winningAmount: WinningAmount): Int { | ||
val ticketResult = TicketResult(winningAmount.count, winningAmount.isBonusBallMatched) | ||
return lottoWinning.result[ticketResult] ?: ZERO_COUNT | ||
val lottoTicketResult = LottoTicketResult(winningAmount.count, winningAmount.isBonusBallMatched) | ||
return lottoWinningResult.result[lottoTicketResult] ?: ZERO_COUNT | ||
} | ||
|
||
fun getTotalRateOfReturn(ticketCount: Int): Double { | ||
return lottoWinning.totalAmount() / (ticketCount * LottoTicketPolicy.PRICE).toDouble() | ||
return lottoWinningResult.totalAmount() / (ticketCount * LottoTicketPolicy.PRICE).toDouble() | ||
} | ||
|
||
companion object { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package lotto.domain | ||
|
||
data class WinningBallResult( | ||
val winningBalls: WinningBalls, | ||
val bonusBall: LottoNumber, | ||
) { | ||
init { | ||
require(!winningBalls.contains(bonusBall)) { "보너스 볼은 당첨 번호와 중복될 수 없습니다." } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package lotto.domain | ||
|
||
data class WinningBalls( | ||
val balls: Set<LottoNumber>, | ||
) : Set<LottoNumber> by balls { | ||
init { | ||
require(balls.size == 6) { "당첨 번호는 중복이 없어야 합니다." } | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package lotto.domain.strategy | ||
|
||
import lotto.domain.LottoNumber | ||
import lotto.domain.LottoNumberSelector | ||
import lotto.domain.LottoTicket | ||
|
||
interface LottoGenerateStrategy { | ||
val ticketGenerateType: TicketGenerateType | ||
fun generate(): LottoTicket | ||
} | ||
|
||
class LottoAutoGenerateStrategy : LottoGenerateStrategy { | ||
override val ticketGenerateType = TicketGenerateType.AUTO | ||
override fun generate(): LottoTicket { | ||
return LottoTicket(LottoNumberSelector.select()) | ||
} | ||
} | ||
|
||
class LottoManualGenerateStrategy : LottoGenerateStrategy { | ||
override val ticketGenerateType = TicketGenerateType.MANUAL | ||
override fun generate(): LottoTicket { | ||
val manualLottoNumberStr = readln() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. view에 대한 영역이 아닐까요? |
||
val manualLottoNumber = manualLottoNumberStr.split(", ").map { LottoNumber(it.toInt()) }.toSet() | ||
|
||
return LottoTicket(manualLottoNumber) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package lotto.domain.strategy | ||
|
||
enum class TicketGenerateType { | ||
AUTO, | ||
MANUAL, | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이렇게도 표현이 가능해보이네요~ 😊
그리고 LottoTicketResult를 만드는 부분에 대해서 LottoMachine에서 모두 해결하는 것보다는, LottoTicketResult에게 LottoTicketBundle과 WinningBallResult를 넘겨서 좀 더 객체 협력을 만드는 게 좋지 않을까요?