Skip to content

Commit 481f265

Browse files
authored
Step4 - 로또 (수동) (#974)
* docs: 당첨 로또 기능 목록 추가, 당첨 여부 검증 변경 예정 * feat: 당첨 번호 일치 갯수 반환, 보너스 번호 일치 검증 구현 * Refactor: 당첨 여부 검증 역할 이동 (LottoMachine -> LottoRanking), LottoRanking 인터페이스 구현 코드 정리 * docs: 당첨번호 기능 목록 추가 * Feat: 당첨 번호 & 보너스 번호 중복 검증 로직 구현 * docs: 로또 계산기 기능 목록 추가 chore: test클래스 패키지 이동, 코드 컨벤션 * Feat: 로또 계산기 - 수익률 계산 로직 구현 Refactor: 당첨 통계 역할 이동 (LottoMachine -> LottoCalculator) * Refactor: 로또 구매 함수 로직 개선
1 parent bb1bb09 commit 481f265

File tree

12 files changed

+169
-75
lines changed

12 files changed

+169
-75
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@
3838
로또 (Data)
3939
- [O] 로또 번호의 조합을 가지고 있는다.
4040

41+
당첨 로또
42+
- [O] 당첨 번호 일치 개수 반환
43+
- [O] 보너스 번호 일치 검증
44+
- [] 당첨번호 & 보너스 번호 중복
45+
46+
로또 계산기
47+
- [O] 수익률 반환
48+
- [O] 게임 횟수 반환
49+
4150
로또 머신 (object)
4251
- [O] 입력받은 번호로 구성된 로또로 생성한다.
4352
- [O] 당첨 번호 생성(with 보너스 번호)

src/main/kotlin/lotto/LottoMain.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package lotto
22

3-
import lotto.data.LottoNumber
43
import lotto.domain.LottoMachine
54
import lotto.domain.RandomLogic
65
import lotto.service.LottoGame

src/main/kotlin/lotto/data/LottoRanking.kt

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,34 @@
11
package lotto.data
22

33
enum class LottoRanking(val matchingNumberCnt: Int, val price: Int) : Prize {
4-
FirstPlace(6, 2_000_000_000) {
5-
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
6-
return winningStatus.first.price * winningStatus.second
7-
}
8-
},
9-
SecondPlace(5, 30_000_000) {
10-
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
11-
return winningStatus.first.price * winningStatus.second
12-
}
13-
},
14-
ThirdPlace(5, 1_500_000) {
15-
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
16-
return winningStatus.first.price * winningStatus.second
17-
}
18-
},
19-
FourthPlace(4, 50_000) {
20-
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
21-
return winningStatus.first.price * winningStatus.second
22-
}
23-
},
24-
FifthPlace(3, 5_000) {
25-
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
26-
return winningStatus.first.price * winningStatus.second
4+
FirstPlace(6, 2_000_000_000),
5+
SecondPlace(5, 30_000_000),
6+
ThirdPlace(5, 1_500_000),
7+
FourthPlace(4, 50_000),
8+
FifthPlace(3, 5_000),
9+
None(0, 0);
10+
11+
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
12+
return winningStatus.first.price * winningStatus.second
13+
}
14+
15+
companion object {
16+
fun findLottoRanking(matchingNumberCnt: Int, hasBonusNumber: Boolean): LottoRanking {
17+
return if (matchingNumberCnt == SecondPlace.matchingNumberCnt) {
18+
determineRankingWithBonusNumber(hasBonusNumber)
19+
} else {
20+
LottoRanking.values().find { it.matchingNumberCnt == matchingNumberCnt } ?: None
21+
}
2722
}
28-
},
29-
None(0, 0) {
30-
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
31-
return winningStatus.first.price * winningStatus.second
23+
24+
private fun determineRankingWithBonusNumber(isContainBonusNumber: Boolean): LottoRanking {
25+
return if (isContainBonusNumber) {
26+
SecondPlace
27+
} else {
28+
ThirdPlace
29+
}
3230
}
33-
};
31+
}
3432
}
3533

3634
fun interface Prize {
Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
11
package lotto.data
22

3-
data class WinningLotto(val lotto: Lotto, val bonusNumber: LottoNumber)
3+
data class WinningLotto(val lotto: Lotto, val bonusNumber: LottoNumber) {
4+
5+
init {
6+
validateWinningLotto()
7+
}
8+
9+
fun countMatchingNumbers(lotto: Lotto): Int {
10+
return this.lotto.selectNumbers.intersect(lotto.selectNumbers).size
11+
}
12+
13+
fun hasBonusNumber(lotto: Lotto): Boolean {
14+
return lotto.selectNumbers.contains(bonusNumber)
15+
}
16+
17+
private fun validateWinningLotto() {
18+
validateDuplicationBonusNumber()
19+
}
20+
21+
private fun validateDuplicationBonusNumber() {
22+
require(!lotto.selectNumbers.contains(bonusNumber)) { "당첨 번호 구성과 보너스 번호가 중복됩니다." }
23+
}
24+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package lotto.domain
2+
3+
import lotto.data.LottoRanking
4+
5+
object LottoCalculator {
6+
7+
private const val GAME_COST = 1000
8+
9+
fun calculateWinningRate(cash: Int, winningStatus: Map<LottoRanking, Int>): Float {
10+
val totalPrice = winningStatus.toList().sumOf { it.first.findPrize(it) }
11+
12+
return totalPrice / cash.toFloat()
13+
}
14+
15+
fun getTimes(cash: Int): Int {
16+
return cash / GAME_COST
17+
}
18+
}

src/main/kotlin/lotto/domain/LottoMachine.kt

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ package lotto.domain
33
import lotto.data.Lotto
44
import lotto.data.LottoNumber
55
import lotto.data.LottoRanking
6-
import lotto.data.LottoRanking.FifthPlace
7-
import lotto.data.LottoRanking.FirstPlace
8-
import lotto.data.LottoRanking.FourthPlace
9-
import lotto.data.LottoRanking.None
10-
import lotto.data.LottoRanking.SecondPlace
11-
import lotto.data.LottoRanking.ThirdPlace
126
import lotto.data.WinningLotto
137

148
object LottoMachine {
@@ -24,34 +18,13 @@ object LottoMachine {
2418
}
2519

2620
fun checkLotto(purchaseLotto: Lotto, winningLotto: WinningLotto): LottoRanking {
27-
val intersectNumber = winningLotto.lotto.selectNumbers.intersect(purchaseLotto.selectNumbers)
21+
val matchingNumberCnt = winningLotto.countMatchingNumbers(purchaseLotto)
22+
val hasBonusNumber = winningLotto.hasBonusNumber(purchaseLotto)
2823

29-
return when (intersectNumber.size) {
30-
FirstPlace.matchingNumberCnt -> FirstPlace
31-
SecondPlace.matchingNumberCnt, ThirdPlace.matchingNumberCnt -> {
32-
checkSecondPlace(purchaseLotto, winningLotto.bonusNumber)
33-
}
34-
FourthPlace.matchingNumberCnt -> FourthPlace
35-
FifthPlace.matchingNumberCnt -> FifthPlace
36-
else -> None
37-
}
24+
return LottoRanking.findLottoRanking(matchingNumberCnt, hasBonusNumber)
3825
}
3926

4027
fun createWinningRate(cash: Int, winningStatus: Map<LottoRanking, Int>): Float {
41-
val totalPrice = createTotalWinningPrice(winningStatus)
42-
43-
return totalPrice / cash.toFloat()
44-
}
45-
46-
private fun checkSecondPlace(purchaseLotto: Lotto, bonusLottoNumber: LottoNumber): LottoRanking {
47-
return if (purchaseLotto.selectNumbers.contains(bonusLottoNumber)) {
48-
SecondPlace
49-
} else {
50-
ThirdPlace
51-
}
52-
}
53-
54-
private fun createTotalWinningPrice(winningStatus: Map<LottoRanking, Int>): Int {
55-
return winningStatus.toList().sumOf { it.first.findPrize(it) }
28+
return LottoCalculator.calculateWinningRate(cash, winningStatus)
5629
}
5730
}

src/main/kotlin/lotto/service/LottoGame.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,30 @@ import lotto.data.Lotto
44
import lotto.data.LottoNumber
55
import lotto.data.LottoRanking
66
import lotto.data.WinningLotto
7+
import lotto.domain.LottoCalculator
78
import lotto.domain.LottoMachine
89
import lotto.domain.RandomLogicInterface
910
import lotto.domain.WinningDomain
1011

1112
class LottoGame(private val randomLogic: RandomLogicInterface) {
1213

1314
fun buyLotto(cash: Int): List<Lotto> {
14-
val lottoList = mutableListOf<Lotto>()
15-
val times = cash / GAME_COST
15+
val times = LottoCalculator.getTimes(cash)
16+
17+
return createLotto(times)
18+
}
1619

20+
private fun createLotto(times: Int): List<Lotto> {
21+
val lottoList = mutableListOf<Lotto>()
1722
repeat(times) {
1823
val lottoNumberCombination = LottoNumber.createRandomLottoNumber(randomLogic)
1924
lottoList.add(LottoMachine.createSelectLotto(lottoNumberCombination))
2025
}
21-
2226
return lottoList
2327
}
2428

2529
fun getWinningStats(winningLotto: WinningLotto, purchaseLottoList: List<Lotto>): Map<LottoRanking, Int> {
2630

2731
return WinningDomain.checkWinningResult(winningLotto, purchaseLottoList)
2832
}
29-
30-
companion object {
31-
private const val GAME_COST = 1000
32-
}
3333
}

src/test/kotlin/lotto/LottoNumberTest.kt renamed to src/test/kotlin/lotto/data/LottoNumberTest.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
package lotto
1+
package lotto.data
22

3-
import lotto.data.LottoNumber
43
import org.assertj.core.api.Assertions.assertThat
54
import org.junit.jupiter.api.Test
65

src/test/kotlin/lotto/LottoTest.kt renamed to src/test/kotlin/lotto/data/LottoTest.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
package lotto
1+
package lotto.data
22

3-
import lotto.data.Lotto
4-
import lotto.data.LottoNumber
53
import org.assertj.core.api.Assertions
64
import org.junit.jupiter.api.Test
75

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package lotto.data
2+
3+
import org.assertj.core.api.Assertions.assertThat
4+
import org.junit.jupiter.api.Test
5+
6+
class WinningLottoTest {
7+
8+
@Test
9+
fun `당첨 번호와 일치하는 번호 수 반환`() {
10+
// given : 당첨로또와 로또를 받는다.
11+
val lotto1 = Lotto(LottoNumber.createLottoNumbers(listOf(1, 2, 3, 4, 5, 6)))
12+
val lotto2 = Lotto(LottoNumber.createLottoNumbers(listOf(1, 2, 3, 4, 5, 7)))
13+
14+
// 당첨번호 [1,2,3,4,5,7] + 보너스 번호 [6]
15+
val wLotto1 = Lotto(LottoNumber.createLottoNumbers(listOf(1, 2, 3, 4, 5, 7)))
16+
val winningLotto = WinningLotto(wLotto1, LottoNumber.from(6))
17+
18+
// when : 검증 로직을 실행한다.
19+
val actual1 = winningLotto.countMatchingNumbers(lotto1)
20+
val actual2 = winningLotto.countMatchingNumbers(lotto2)
21+
22+
// then : 일치하는 번호의 개수를 반환한다.
23+
assertThat(actual1).isEqualTo(5)
24+
assertThat(actual2).isEqualTo(6)
25+
}
26+
27+
@Test
28+
fun `보너스 번호 일치 검증`() {
29+
// given : 당첨로또와 로또를 받는다.
30+
val lotto1 = Lotto(LottoNumber.createLottoNumbers(listOf(1, 2, 3, 4, 5, 6)))
31+
val lotto2 = Lotto(LottoNumber.createLottoNumbers(listOf(1, 2, 3, 4, 5, 7)))
32+
33+
// 당첨번호 [1,2,3,4,5,7] + 보너스 번호 [6]
34+
val wLotto1 = Lotto(LottoNumber.createLottoNumbers(listOf(1, 2, 3, 4, 5, 7)))
35+
val winningLotto = WinningLotto(wLotto1, LottoNumber.from(6))
36+
37+
// when : 보너스 번호 일치 검증 로직을 호출한다.
38+
val actual1 = winningLotto.hasBonusNumber(lotto1)
39+
val actual2 = winningLotto.hasBonusNumber(lotto2)
40+
41+
// then :
42+
assertThat(actual1).isTrue()
43+
assertThat(actual2).isFalse()
44+
}
45+
46+
@Test
47+
fun `보너스 번호 중복 검증`() {
48+
// given : 당첨 번호로 구성된 로또와 이와 중복되는 보너스 번호를 받는다.
49+
val lotto = Lotto(LottoNumber.createLottoNumbers(listOf(1, 2, 3, 4, 5, 6)))
50+
val bonusLottoNumber = LottoNumber.from(6)
51+
52+
// when :
53+
val actual = runCatching { WinningLotto(lotto, bonusLottoNumber) }.exceptionOrNull()
54+
55+
// then :
56+
assertThat(actual).isInstanceOf(IllegalArgumentException::class.java)
57+
}
58+
}

0 commit comments

Comments
 (0)