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

πŸš€ 2단계 - 둜또(μžλ™) #994

Open
wants to merge 2 commits into
base: dajeongda
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
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# kotlin-lotto

# 둜또
## κΈ°λŠ₯ μš”κ΅¬ 사항
- 둜또 κ΅¬μž… κΈˆμ•‘μ„ μž…λ ₯ν•˜λ©΄ κ΅¬μž… κΈˆμ•‘μ— ν•΄λ‹Ήν•˜λŠ” 둜또λ₯Ό λ°œκΈ‰ν•΄μ•Ό ν•œλ‹€.
- 둜또 1μž₯의 가격은 1000원이닀.

## κΈ°λŠ₯ λͺ©λ‘
- [x] 둜또 μƒμ„±κΈ°λŠ” 1~45κΉŒμ§€ μ€‘λ³΅λ˜μ§€ μ•Šμ€ 숫자 6개λ₯Ό μƒμ„±ν•œλ‹€.
- [x] 둜또 μƒ΅μ—μ„œλŠ” λͺ‡μž₯을 μ‚΄ 건지 λ°›μ•„μ„œ ν•΄λ‹Ήν•˜λŠ” 만큼 둜또λ₯Ό μ‚°λ‹€.
- [x] 6개 μˆ«μžκ°€ λͺ¨λ‘ 맞으면 1등이고, 20얡을 λ°›λŠ”λ‹€.
- [x] 5개 μˆ«μžκ°€ 맞으면 2등이고, 150λ§Œμ›μ„ λ°›λŠ”λ‹€.
- [x] 4개 μˆ«μžκ°€ 맞으면 3등이고, 5λ§Œμ›μ„ λ°›λŠ”λ‹€.
- [x] 3개 μˆ«μžκ°€ 맞으면 4등이고 5μ²œμ›μ„ λ°›λŠ”λ‹€.
- [] 둜또 수읡 κ³„μ‚°κΈ°λŠ” κ²°κ³Όλ₯Ό λ°›μ•„μ„œ μˆ˜μ΅μ„ κ³„μ‚°ν•œλ‹€.

# λ¬Έμžμ—΄ 계산기
## κΈ°λŠ₯ μš”κ΅¬ 사항
- μ‰Όν‘œ(,) λ˜λŠ” 콜둠(:)을 κ΅¬λΆ„μžλ‘œ κ°€μ§€λŠ” λ¬Έμžμ—΄μ„ μ „λ‹¬ν•˜λŠ” 경우 κ΅¬λΆ„μžλ₯Ό κΈ°μ€€μœΌλ‘œ λΆ„λ¦¬ν•œ 각 숫자의 합을 λ°˜ν™˜
- (예: β€œβ€ => 0, "1,2" => 3, "1,2,3" => 6, β€œ1,2:3” => 6)
Expand Down
32 changes: 32 additions & 0 deletions src/main/kotlin/lotto/BenefitCalculator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package lotto

import java.math.RoundingMode
import java.text.DecimalFormat

class BenefitCalculator {
fun calculate(result: Map<Int, Int>): String {
val spend = result.map { it.value }.sum() * LOTTO_PRICE
val benefit = result.map {
when (it.key) {
1 -> WINNER_REWARD * it.value
2 -> SECOND_REWARD * it.value
3 -> THIRD_REWARD * it.value
4 -> FORTH_REWARD * it.value
else -> 0
}
}.sum()

val rate = benefit.toDouble() / spend
df.roundingMode = RoundingMode.FLOOR
return df.format(rate)
}

companion object {
private const val WINNER_REWARD = 2000000000
private const val SECOND_REWARD = 1500000
private const val THIRD_REWARD = 50000
private const val FORTH_REWARD = 5000
private const val LOTTO_PRICE = 1000
Comment on lines +25 to +29
Copy link
Member

Choose a reason for hiding this comment

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

둜또 λ“±μˆ˜λ₯Ό 도메인 객체둜 ν‘œν˜„ν•΄λ³΄λŠ” 건 μ–΄λ–¨κΉŒμš”? enum λ“±μœΌλ‘œ κ΅¬ν˜„ν•΄λ³΄μ…”λ„ μ’‹κ² μ–΄μš” :)

private val df = DecimalFormat("0.00")
}
}
52 changes: 52 additions & 0 deletions src/main/kotlin/lotto/LottoGame.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package lotto

import lotto.view.InputView
import lotto.view.ResultView

class LottoGame {
fun match(
userLotto: Set<Int>,
Comment on lines +7 to +8
Copy link
Member

Choose a reason for hiding this comment

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

Intμ—λŠ” 1~45 λΌλŠ” 둜또 번호λ₯Ό μ œν•œν•˜κΈ°μ—λŠ” λ„ˆλ¬΄ λ²”μš©μ μΈ μžλ£Œν˜•μ΄λΌ μƒκ°ν•΄μš”.
둜또 번호λ₯Ό λ‚˜νƒ€λ‚΄λŠ” 도메인 객체λ₯Ό λ§Œλ“€μ–΄λ³΄λŠ” 건 μ–΄λ–¨κΉŒμš”?

winningLotto: Set<Int>,
): Int {
val matchCount = userLotto.intersect(winningLotto.toSet()).size
return rank(matchCount)
}

private fun rank(
matchCount: Int,
): Int {
return when (matchCount) {
6 -> 1
5 -> 2
4 -> 3
3 -> 4
else -> 0
}
}
}

fun main() {
val inputView = InputView()
val resultView = ResultView()
val shop = LottoShop()
val game = LottoGame()
val money = inputView.get("κ΅¬μž…κΈˆμ•‘μ„ μž…λ ₯ν•΄ μ£Όμ„Έμš”.")
// μ–Όλ§ˆλ₯Ό μ‚΄ 수 μžˆλ‹€.
val count = money / 1000
val lottos = shop.buy(count)
println("${count}개λ₯Ό κ΅¬λ§€ν–ˆμŠ΅λ‹ˆλ‹€.")
lottos.forEach {
println(it)
}
val winningLotto = inputView.getWinningLotto("μ§€λ‚œ μ£Ό 당첨 번호λ₯Ό μž…λ ₯ν•΄ μ£Όμ„Έμš”.")
// 맞좰 λ³Έλ‹€.
val result = lottos.groupingBy {
game.match(it, winningLotto)
}.eachCount()

val benefitCalculator = BenefitCalculator()
val benefit = benefitCalculator.calculate(result)
resultView.show(result, benefit)
}


18 changes: 18 additions & 0 deletions src/main/kotlin/lotto/LottoGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package lotto

import kotlin.random.Random

class LottoGenerator {
fun generate(): Set<Int> {
val numbers = mutableSetOf<Int>()
while (numbers.size < LIMIT_SIZE) {
numbers.add(Random.nextInt(MAXIMUM))
}
return numbers
}

companion object {
private const val MAXIMUM = 45
private const val LIMIT_SIZE = 6
}
}
13 changes: 13 additions & 0 deletions src/main/kotlin/lotto/LottoShop.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package lotto

class LottoShop {
fun buy(count: Int): List<Set<Int>> {
Comment on lines +3 to +4
Copy link
Member

Choose a reason for hiding this comment

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

μ»¬λ ‰μ…˜μ˜ μžλ£Œν˜• νƒ€μž…μ΄ 겹쳐져있으면 μ–΄λ–€ 값을 μ˜λ―Έν•˜λŠ”μ§€ μ‰½κ²Œ μ•Œμ•„λ³΄κΈ° μ–΄λ €μ›Œμ§„λ‹€κ³  μƒκ°ν•΄μš”.
ν•œ μ»¬λ ‰μ…˜μ„ 객체둜 λ¬Άμ–΄ 의미λ₯Ό λ‹΄μ•„λ³΄λŠ” 건 μ–΄λ–¨κΉŒμš”?

val lottoGenerator = LottoGenerator()
val lottos = mutableListOf<Set<Int>>()
repeat(count) {
lottos.add(lottoGenerator.generate())
}

return lottos
}
}
14 changes: 14 additions & 0 deletions src/main/kotlin/lotto/view/InputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package lotto.view

class InputView {
fun get(prompt: String): Int {
print(prompt)
return readln().toInt()
}

fun getWinningLotto(prompt: String): Set<Int> {
print(prompt)
return readln().split(",").map { it.toInt() }.toSet()
}

}
23 changes: 23 additions & 0 deletions src/main/kotlin/lotto/view/ResultView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package lotto.view

class ResultView {
fun show(result: Map<Int, Int>, benefit: String) {
println("당첨 톡계")
println("---------")
(1..4).reversed().forEach {
showOne(it, result.getOrDefault(it, 0))
}

val bep = if (benefit.toDouble() > 1.0) "이읡" else "손해"
println("총 수읡λ₯ μ€ ${benefit}μž…λ‹ˆλ‹€. (기쀀이 1이기 λ•Œλ¬Έμ— 결과적으둜 ${bep}λΌλŠ” μ˜λ―Έμž„)")
}

private fun showOne(rank: Int, count: Int) {
when (rank) {
1 -> println("6개 일치 (2000000000원) - ${count}개")
2 -> println("5개 일치 (1500000원) - ${count}개")
3 -> println("4개 일치 (50000원) - ${count}개")
4 -> println("3개 일치 (5000원) - ${count}개")
}
}
}
22 changes: 22 additions & 0 deletions src/test/kotlin/lotto/BenefitCalculatorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package lotto

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

class BenefitCalculatorTest {

@Test
fun `14μž₯ 쀑에 4λ“± 1μž₯ 미당첨 13μž₯일 경우 수읡λ₯ μ€ 0,35이닀`() {
val calculator = BenefitCalculator()
val result = mapOf(
1 to 0,
2 to 0,
3 to 0,
4 to 1,
0 to 13
)

val actual = calculator.calculate(result)
assertThat(actual).isEqualTo("0.35")
}
}
77 changes: 77 additions & 0 deletions src/test/kotlin/lotto/LottoGameTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package lotto

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

class LottoGameTest {

@Test
fun `1등은 6개 일치` () {
val lottoGame = LottoGame()
val userLotto = setOf(1, 2, 3, 4, 5, 6)
val winningLotto = setOf(1, 2, 3, 4, 5, 6)
val actual = lottoGame.match(userLotto, winningLotto)

actual shouldBe 1
}

@Test
fun `2등은 5개 일치`() {
val lottoGame = LottoGame()
val userLotto = setOf(1, 2, 3, 4, 5, 6)
val winningLotto = setOf(1, 2, 3, 4, 5, 7)
val actual = lottoGame.match(userLotto, winningLotto)

actual shouldBe 2
}

@Test
fun `3등은 4개 일치`() {
val lottoGame = LottoGame()
val userLotto = setOf(1, 2, 3, 4, 5, 6)
val winningLotto = setOf(1, 2, 3, 4, 7, 8)
val actual = lottoGame.match(userLotto, winningLotto)

actual shouldBe 3
}

@Test
fun `4등은 3개 일치`() {
val lottoGame = LottoGame()
val userLotto = setOf(1, 2, 3, 4, 5, 6)
val winningLotto = setOf(1, 2, 3, 7, 8, 9)
val actual = lottoGame.match(userLotto, winningLotto)

actual shouldBe 4
}

@Test
fun `2개 경우 일치 ν•˜λ©΄ 0`(userLotto: Set<Int>) {
val lottoGame = LottoGame()
val userLotto = setOf(1, 2, 12, 13, 14, 15)
val winningLotto = setOf(1, 2, 3, 7, 8, 9)
val actual = lottoGame.match(userLotto, winningLotto)

actual shouldBe 4
}

@Test
fun `1개 경우 일치 ν•˜λ©΄ 0`(userLotto: Set<Int>) {
val lottoGame = LottoGame()
val userLotto = setOf(1, 11, 12, 13, 14, 16)
val winningLotto = setOf(1, 2, 3, 7, 8, 9)
val actual = lottoGame.match(userLotto, winningLotto)

actual shouldBe 4
}

@Test
fun `0개 경우 일치 ν•˜λ©΄ 0`(userLotto: Set<Int>) {
val lottoGame = LottoGame()
val userLotto = setOf(10, 11, 12, 13, 14, 16)
val winningLotto = setOf(1, 2, 3, 7, 8, 9)
val actual = lottoGame.match(userLotto, winningLotto)

actual shouldBe 4
}
Comment on lines +8 to +76
Copy link
Member

Choose a reason for hiding this comment

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

이런 ν˜•νƒœμ˜ ν…ŒμŠ€νŠΈλŠ” @ParameterizedTestλ₯Ό ν™œμš©ν•΄λ³΄λŠ” 건 μ–΄λ–¨κΉŒμš”?

}
22 changes: 22 additions & 0 deletions src/test/kotlin/lotto/LottoGeneratorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package lotto

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

class LottoGeneratorTest {

@Test
fun `둜또 μƒμ„±κΈ°λŠ” 숫자 6개λ₯Ό μƒμ„±ν•œλ‹€`() {
val lottoGenerator = LottoGenerator()
val lotto = lottoGenerator.generate()
lotto.size shouldBe 6
}

@Test
fun `둜또 μƒμ„±κΈ°λŠ” μˆ«μžκ°€ κ²ΉμΉ˜μ§€ μ•ŠλŠ”λ‹€`() {
val lottoGenerator = LottoGenerator()
val lotto = lottoGenerator.generate()
lotto.distinct().size shouldBe 6
}

}
15 changes: 15 additions & 0 deletions src/test/kotlin/lotto/LottoShopTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package lotto

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

class LottoShopTest {

@Test
fun `둜또 nμž₯ 사기`() {
val lottoShop = LottoShop()
val count = 5
val lottos = lottoShop.buy(5)
lottos.size shouldBe count
}
Comment on lines +8 to +14
Copy link
Member

Choose a reason for hiding this comment

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

λͺ‡ μž₯을 μƒ€λŠ”μ§€ κ²€μ¦ν•˜λŠ” 것은 ν…ŒμŠ€νŠΈμ— 큰 의미λ₯Ό 가지지 λͺ»ν•œλ‹€κ³  μƒκ°ν•΄μš”.
κ°œλ°œμžκ°€ μ œμ–΄ κ°€λŠ₯ν•œ ν˜•νƒœλ‘œ, μ–΄λ–€ 티켓이 λ°˜ν™˜λ˜μ—ˆλŠ”μ§€κΉŒμ§€ ν…ŒμŠ€νŠΈν•  수 있게 λ§Œλ“€μ–΄λ³΄λŠ” 건 μ–΄λ–¨κΉŒμš”?

}