-
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] 2단계 - 로또(자동) #1139
[Step2] 2단계 - 로또(자동) #1139
Changes from all commits
5c1ed42
e3cc483
5c3dfeb
d2aab97
ba57c9f
0c33d33
6409a30
bc7f21a
ad6bd13
173cd00
2e5c4cb
38e7331
1aff168
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 |
---|---|---|
@@ -1 +1,17 @@ | ||
# kotlin-lotto | ||
# kotlin-lotto | ||
## 기능 요구 사항 | ||
### 1. 입력 | ||
- [ ] 구입 금액을 입력받는다. | ||
- [ ] 지난 주 당첨 번호를 입력받는다. | ||
|
||
### 2. 로또 발급 | ||
- [ ] 구입 금액에 따라 로또를 발급한다. (1장 = 1000원) | ||
- [ ] 각 로또는 1~45 사이의 중복되지 않는 6개의 숫자로 구성된다. | ||
|
||
### 3. 당첨 검증 | ||
- [ ] 각 로또의 숫자와 당첨 번호를 비교하여 일치하는 개수를 확인한다. | ||
- [ ] 일치 개수에 따라 당첨금을 계산한다. | ||
|
||
### 4. 결과 출력 | ||
- [ ] 당첨 내역을 출력한다. (3개, 4개, 5개, 6개 일치) | ||
- [ ] 수익률을 계산하여 출력한다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package lotto | ||
|
||
import lotto.domain.Lotto | ||
import lotto.domain.LottoCalculator | ||
import lotto.domain.LottoTicket | ||
import lotto.ui.InputView | ||
import lotto.ui.ResultView | ||
|
||
fun main() { | ||
val inputView = InputView() | ||
val resultView = ResultView() | ||
|
||
val amount = inputView.getMoney() | ||
val lottoTicket = LottoTicket.makeTicket(amount) | ||
resultView.printTickets(lottoTicket.getTickets()) | ||
|
||
val winningLotto = Lotto(inputView.getWinningNumbers()) | ||
|
||
val calculator = LottoCalculator() | ||
val results = calculator.calculateResults(lottoTicket, winningLotto) | ||
val profitRate = calculator.calculateProfit(results) | ||
|
||
resultView.printResults(results, profitRate) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package lotto.domain | ||
|
||
data class Lotto(val numbers: List<Int>) { | ||
init { | ||
require(numbers.size == 6) { "Invalid input" } | ||
require(numbers.all { it in 1..45 }) { "Out of Range" } | ||
} | ||
|
||
fun getMatchedNumberCount(winningLotto: Lotto): Int { | ||
return numbers.count { it in winningLotto } | ||
} | ||
|
||
operator fun contains(number: Int): Boolean { | ||
return numbers.contains(number) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package lotto.domain | ||
|
||
class LottoCalculator { | ||
fun calculateResults( | ||
tickets: LottoTicket, | ||
winningNumbers: Lotto, | ||
): LottoResult { | ||
return LottoResult( | ||
tickets.getTickets() | ||
.groupingBy { it.getMatchedNumberCount(winningNumbers) } | ||
.eachCount(), | ||
) | ||
} | ||
|
||
fun calculateProfit(lottoResult: LottoResult): Double { | ||
val totalPrize = | ||
lottoResult.getResults().entries.sumOf { (match, count) -> | ||
when (match) { | ||
3 -> 5000 * count | ||
4 -> 50000 * count | ||
5 -> 1500000 * count | ||
6 -> 2000000000 * count | ||
else -> 0 | ||
} | ||
} | ||
Comment on lines
+17
to
+25
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 클래스를 활용해 보시고 이전과 어떻게 달라졌는지 직접 확인해보시면 더욱 의미있을 것 같아요!
|
||
|
||
return totalPrize.toDouble() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package lotto.domain | ||
|
||
class LottoMaker(private val numberGenerator: () -> List<Int>) { | ||
fun makeLotto(): Lotto { | ||
return Lotto(numberGenerator().sorted()) | ||
} | ||
|
||
companion object { | ||
private const val START_NUMBER = 1 | ||
private const val END_NUMBER = 45 | ||
private const val LOTTO_COUNT = 6 | ||
|
||
fun defaultMaker(): LottoMaker { | ||
return LottoMaker({ (START_NUMBER..END_NUMBER).shuffled().take(LOTTO_COUNT).sorted() }) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package lotto.domain | ||
|
||
data class LottoResult(private val result: Map<Int, Int>) { | ||
fun getResults(): Map<Int, Int> { | ||
return result | ||
} | ||
|
||
fun getMatchCount(match: Int): Int { | ||
return result.getOrDefault(match, 0) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package lotto.domain | ||
|
||
class LottoTicket(private val tickets: List<Lotto>) { | ||
fun size(): Int = tickets.size | ||
|
||
fun getTickets(): List<Lotto> = tickets | ||
|
||
companion object { | ||
fun makeTicket(amount: Int): LottoTicket { | ||
val lottoMaker = LottoMaker.defaultMaker() | ||
val lottoCount = amount / 1000 | ||
return LottoTicket(List(lottoCount) { lottoMaker.makeLotto() }) | ||
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. 리뷰를 잘 반영해서 도메인 로직을 도메인 객체에 잘 위임해주셨어요! 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,15 @@ | ||
package lotto.ui | ||
|
||
class InputView { | ||
fun getMoney(): Int { | ||
println("구입금액을 입력해주세요") | ||
val money = readln() | ||
requireNotNull(money.toInt()) | ||
return money.toInt() | ||
} | ||
|
||
fun getWinningNumbers(): List<Int> { | ||
println("지난 주 당첨 번호를 입력해 주세요.") | ||
return readln().split(",").map { it.trim().toInt() }.toList() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package lotto.ui | ||
|
||
import lotto.domain.Lotto | ||
import lotto.domain.LottoResult | ||
|
||
class ResultView { | ||
fun printTickets(tickets: List<Lotto>) { | ||
println("${tickets.size}개를 구매했습니다.") | ||
tickets.forEach { println(it.numbers) } | ||
} | ||
|
||
fun printResults( | ||
results: LottoResult, | ||
profit: Double, | ||
) { | ||
println("당첨 통계") | ||
println("---------") | ||
results.getResults().forEach { (matchCount, count) -> | ||
println("$matchCount 개 일치 - $count 개") | ||
} | ||
println("총 수익률은 $profit 입니다.") | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package lotto.domain | ||
|
||
import org.junit.jupiter.api.Assertions.assertEquals | ||
import org.junit.jupiter.api.Test | ||
|
||
class LottoCalculatorTest { | ||
private val calculator = LottoCalculator() | ||
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. LottoCalculator는 커밋되지 않은 것 같아요! 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. 빠졌었네요ㅠ 추가로 커밋했습니다! |
||
|
||
@Test | ||
fun testLottoCalculator() { | ||
val tickets = | ||
LottoTicket( | ||
listOf( | ||
Lotto(listOf(1, 2, 3, 4, 5, 6)), | ||
Lotto(listOf(1, 2, 3, 7, 8, 9)), | ||
Lotto(listOf(10, 11, 12, 13, 14, 15)), | ||
) | ||
) | ||
val winningLotto = Lotto(listOf(1, 2, 3, 4, 5, 6)) | ||
|
||
val results = calculator.calculateResults(tickets, winningLotto) | ||
assertEquals(1, results.getMatchCount(6)) | ||
assertEquals(1, results.getMatchCount(3)) | ||
assertEquals(1, results.getMatchCount(0)) | ||
} | ||
|
||
@Test | ||
fun testCalculateProfit() { | ||
val results = | ||
LottoResult( | ||
mapOf( | ||
6 to 1, | ||
5 to 2, | ||
4 to 1, | ||
3 to 2, | ||
) | ||
) | ||
|
||
val profit = calculator.calculateProfit(results) | ||
assertEquals( | ||
2000000000.0 * 1 + 1500000.0 * 2 + 50000.0 * 1 + 5000.0 * 2, | ||
profit | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package lotto.domain | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class LottoMakerTest { | ||
@Test | ||
fun `Lotto - size should be 6`() { | ||
val fixedNumbers = listOf(1, 2, 3, 4, 5, 6) | ||
val lottoMaker = LottoMaker { fixedNumbers } | ||
val lotto = lottoMaker.makeLotto() | ||
|
||
lotto.numbers.size shouldBe 6 | ||
} | ||
|
||
@Test | ||
fun `Lotto - should be same with list`() { | ||
val fixedNumbers = listOf(1, 2, 3, 4, 5, 6) | ||
val lottoMaker = LottoMaker { fixedNumbers } | ||
val lotto = lottoMaker.makeLotto() | ||
|
||
lotto.numbers shouldBe fixedNumbers | ||
} | ||
|
||
@Test | ||
fun `Lotto - should be in range(1-45)`() { | ||
val lottoMaker = LottoMaker.defaultMaker() | ||
val lotto = lottoMaker.makeLotto() | ||
lotto.numbers.all { it in 1..45 } shouldBe true | ||
} | ||
} |
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.
LottoCalculator라는 이름만 보고도 현재 하고 있는 행동(수익률 계산, 로또 결과 판단)을 예측할 수 있을까요?
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.
여러 가지 해결 방법이 있겠지만, 잘 Wrapping해주신 LottoResult를 외부에서 생성해주지 말고, 객체 스스로 판단하여 Result를 생성할 수 있도록 만드는 것도 하나의 방법이 될 수 있을 것 같아요 🙂