-
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
Step2, 로또(자동) #1138
base: minsu-lee
Are you sure you want to change the base?
Step2, 로또(자동) #1138
Changes from all commits
b3db155
431acdc
3967140
29b3ad6
f36c917
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 |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package calculator.model.input | ||
|
||
data class DelimiterAndNumbers( | ||
val delimiter: String?, | ||
val numbers: String, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package lotto | ||
|
||
import lotto.model.price.Lotto2024Price | ||
import lotto.model.process.LottoMachineProcess | ||
import lotto.model.rank.LottoWinningRank | ||
import lotto.view.keyboard.MachineKeyboard | ||
import lotto.view.monitor.LottoMonitor | ||
|
||
fun main() { | ||
val price = Lotto2024Price() | ||
val lottoRank = LottoWinningRank() | ||
val process = LottoMachineProcess(price, lottoRank) | ||
val keyboard = MachineKeyboard() | ||
val monitor = LottoMonitor() | ||
val machine = LottoMachine(process, keyboard, monitor) | ||
machine.issuanceLottoNumber() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package lotto | ||
|
||
import lotto.model.process.MachineProcess | ||
import lotto.view.keyboard.Keyboard | ||
import lotto.view.monitor.Monitor | ||
|
||
class LottoMachine( | ||
private val process: MachineProcess, | ||
private val keyboard: Keyboard, | ||
private val monitor: Monitor, | ||
) : Machine { | ||
override fun issuanceLottoNumber() { | ||
monitor.displayLottoPurchaseAmount() | ||
val totalPurchaseAmount = keyboard.inputLottoPrice() | ||
val lottoCount = process.calculateLottoCount(totalPurchaseAmount) | ||
monitor.displayLottoPurchasesCount(lottoCount) | ||
|
||
val lottoTickets = process.generateLottoTickets(lottoCount) | ||
monitor.displayIssuedLottoTickets(lottoTickets) | ||
|
||
monitor.displayInputLastWeekLottoWinningNumbers() | ||
val lastWeekNumbers = keyboard.inputLastWeekWinningNumbers() | ||
val lottoStatistics = | ||
process.calculateWinningStatistics( | ||
lottoTickets, | ||
lastWeekNumbers, | ||
totalPurchaseAmount, | ||
) | ||
monitor.displayLottoStatistics(lottoStatistics) | ||
Comment on lines
+13
to
+29
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,5 @@ | ||
package lotto | ||
|
||
interface Machine { | ||
fun issuanceLottoNumber() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package lotto.model.number | ||
|
||
class LottoNumbers( | ||
private val lottoNumbers: List<Int>, | ||
) : List<Int> by lottoNumbers { | ||
init { | ||
require(lottoNumbers.size == DEFAULT_LOTTO_COUNT) { | ||
"로또 번호는 ${DEFAULT_LOTTO_COUNT}개여야 합니다." | ||
} | ||
require(lottoNumbers.all { it in LOTTO_MIN_NUMBER..LOTTO_MAX_NUMBER }) { | ||
"로또 번호는 $LOTTO_MIN_NUMBER ~ $LOTTO_MAX_NUMBER 사이여야 합니다." | ||
} | ||
require(lottoNumbers.distinct().size == lottoNumbers.size) { | ||
"로또 번호는 중복될 수 없습니다." | ||
} | ||
} | ||
|
||
override fun toString(): String { | ||
return "$lottoNumbers" | ||
} | ||
|
||
companion object { | ||
const val LOTTO_MIN_NUMBER = 1 | ||
const val LOTTO_MAX_NUMBER = 45 | ||
const val DEFAULT_LOTTO_COUNT = 6 | ||
private val NUMBERS = (LOTTO_MIN_NUMBER..LOTTO_MAX_NUMBER) | ||
|
||
fun issuanceLottoNumbers(lottoCount: Int = DEFAULT_LOTTO_COUNT): LottoNumbers { | ||
val lottoNumbers = | ||
NUMBERS.shuffled().take(lottoCount) | ||
.sorted() | ||
return LottoNumbers(lottoNumbers) | ||
} | ||
|
||
fun issuanceLottoTickets( | ||
ticketCount: Int, | ||
lottoCount: Int = DEFAULT_LOTTO_COUNT, | ||
): List<LottoNumbers> { | ||
return List(ticketCount) { | ||
issuanceLottoNumbers(lottoCount) | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package lotto.model.price | ||
|
||
class Lotto2024Price( | ||
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. 클래스명에 년도를 명시해야하는 이유가 있을까요? |
||
override val price: Int = 1000, | ||
) : LottoPrice { | ||
init { | ||
require(price > 0) { | ||
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. 로또를 1원 이상 천원 미만 입력하게 되면 어떻게 될까요? |
||
"로또 금액 설정이 잘못되었습니다" | ||
} | ||
} | ||
|
||
override fun calculateLottoCount(purchaseAmount: Int): Int { | ||
return purchaseAmount.div(price) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package lotto.model.price | ||
|
||
interface LottoPrice { | ||
val price: Int | ||
|
||
fun calculateLottoCount(purchaseAmount: Int): Int | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package lotto.model.process | ||
|
||
import lotto.model.number.LottoNumbers | ||
import lotto.model.price.LottoPrice | ||
import lotto.model.rank.LottoRank | ||
import lotto.model.statistics.DefaultLottoStatistics | ||
import lotto.model.statistics.LottoStatistics | ||
|
||
class LottoMachineProcess( | ||
private val lottoPrice: LottoPrice, | ||
private val lottoRank: LottoRank, | ||
) : MachineProcess { | ||
override fun calculateLottoCount(purchaseAmount: Int): Int { | ||
return lottoPrice.calculateLottoCount(purchaseAmount) | ||
} | ||
|
||
override fun generateLottoTickets(lottoCount: Int): List<LottoNumbers> { | ||
return LottoNumbers.issuanceLottoTickets(lottoCount) | ||
} | ||
|
||
override fun calculateWinningStatistics( | ||
lottoTickets: List<LottoNumbers>, | ||
winningNumbers: List<Int>, | ||
totalPurchaseAmount: Int, | ||
): LottoStatistics { | ||
val winningRank = | ||
lottoRank.calculateWinningCounts( | ||
lottoTickets, | ||
winningNumbers, | ||
) | ||
return DefaultLottoStatistics(winningRank, totalPurchaseAmount) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package lotto.model.process | ||
|
||
import lotto.model.number.LottoNumbers | ||
import lotto.model.statistics.LottoStatistics | ||
|
||
interface MachineProcess { | ||
fun calculateLottoCount(purchaseAmount: Int): Int | ||
|
||
fun generateLottoTickets(lottoCount: Int): List<LottoNumbers> | ||
|
||
fun calculateWinningStatistics( | ||
lottoTickets: List<LottoNumbers>, | ||
winningNumbers: List<Int>, | ||
totalPurchaseAmount: Int, | ||
): LottoStatistics | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package lotto.model.rank | ||
|
||
import lotto.model.number.LottoNumbers | ||
|
||
interface LottoRank { | ||
fun calculateWinningCounts( | ||
lottoTickets: List<LottoNumbers>, | ||
winningNumbers: List<Int>, | ||
): Map<Int, Int> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package lotto.model.rank | ||
|
||
import lotto.model.number.LottoNumbers | ||
|
||
class LottoWinningRank : LottoRank { | ||
override fun calculateWinningCounts( | ||
lottoTickets: List<LottoNumbers>, | ||
winningNumbers: List<Int>, | ||
): Map<Int, Int> { | ||
return lottoTickets.groupingBy { lottoNumbers -> | ||
val winningCounts = matchWinningLottoNumbersCount(lottoNumbers, winningNumbers) | ||
winningCounts | ||
}.eachCount().filter { it.key >= 3 } | ||
} | ||
|
||
private fun matchWinningLottoNumbersCount( | ||
lottoNumbers: LottoNumbers, | ||
winningNumbers: List<Int>, | ||
): Int { | ||
val winningSets = winningNumbers.toSet() | ||
return lottoNumbers.count(winningSets::contains) | ||
} | ||
|
||
companion object { | ||
val DEFAULT_RANK_PRICE = | ||
mapOf( | ||
6 to 2_000_000_000, | ||
5 to 1_500_000, | ||
4 to 50_000, | ||
3 to 5_000, | ||
) | ||
Comment on lines
+25
to
+31
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. 로또 번호가 일치하는 것에 대한 금액을 enum으로 관리해보면 어떨까요? |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package lotto.model.statistics | ||
|
||
import lotto.model.rank.LottoWinningRank | ||
|
||
class DefaultLottoStatistics( | ||
override val winningRank: Map<Int, Int>, | ||
private val totalPurchaseAmount: Int, | ||
) : LottoStatistics { | ||
override val profitRate: Double | ||
|
||
init { | ||
profitRate = calculateProfitRate() | ||
} | ||
|
||
private fun calculateProfitRate(): Double { | ||
val totalPrize = calculateTotalPrize() | ||
return if (totalPrize > 0) { | ||
totalPrize.toDouble().div(totalPurchaseAmount) | ||
} else { | ||
0.0 | ||
} | ||
} | ||
|
||
private fun calculateTotalPrize(): Long { | ||
return winningRank.map { (key, count) -> | ||
(LottoWinningRank.DEFAULT_RANK_PRICE[key]?.toLong() ?: 0).times(count) | ||
}.sum() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package lotto.model.statistics | ||
|
||
interface LottoStatistics { | ||
val winningRank: Map<Int, Int> | ||
val profitRate: Double | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package lotto.view.keyboard | ||
|
||
interface Keyboard { | ||
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. Keyboard 인터페이스를 구현하는 곳은 MarchineKeyboard 클래스만 존재하네요. |
||
fun inputLottoPrice(): Int | ||
|
||
fun inputLastWeekWinningNumbers(): List<Int> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package lotto.view.keyboard | ||
|
||
class MachineKeyboard : Keyboard { | ||
override fun inputLottoPrice(): Int { | ||
val input = readlnOrNull()?.toIntOrNull() | ||
require(input != null && input > 0) { "구입금액이 잘못 입력되었습니다" } | ||
return input | ||
} | ||
|
||
override fun inputLastWeekWinningNumbers(): List<Int> { | ||
val input = readlnOrNull() | ||
require(!input.isNullOrEmpty()) { "당첨 번호 입력이 잘못되었습니다." } | ||
return parseLottoNumbers(input) | ||
} | ||
|
||
private fun parseLottoNumbers(input: String): List<Int> { | ||
return input.split(",") | ||
.map(::validateAndParseNumber) | ||
} | ||
|
||
private fun validateAndParseNumber(numberString: String): Int { | ||
val number = numberString.trim().toIntOrNull() | ||
require(number != null) { "당첨 번호 입력이 잘못되었습니다." } | ||
return number | ||
} | ||
} |
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.
숫자가 -1이 아닌 음수값이 오면 어떻게 될까요?