Skip to content

Commit bb1bb09

Browse files
authored
Step3 - 로또(2등) (#959)
* refactor: 로또 자료구조 변경, domain패키치 추가, 테스트 코드 표현 변경(오류 -> 예외) * Refactor: 로또 번호 랜덤 로직 추상화 * Refactor: 당첨 도메인 추가 * Docs: 보너스 볼 추가로 인한 기능목록 수정(README.md) * Refactor: Lotto클래스로 로또 번호 중복 로직 역할 이동, 랜덤 로직 리팩토링, 로또 번호 반환 자료구조 변경 * Feat: 보너스 번호가 포함된 당첨 로또 데이터 추가. * Refactor: 당첨 여부 검증, 당첨 통계 기능 리펙터링(with 보너스 번호) * Feat: 보너스 볼 입력 로직 구현 Refactor: 당첨 통계 output로직 수정, 당첨 로또 생성 로직 수정 * Refactor: 랜덤 번호 생성 자료구조 변경(정렬 기능 추가)
1 parent 2dad94c commit bb1bb09

19 files changed

+283
-165
lines changed

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,20 @@
3939
- [O] 로또 번호의 조합을 가지고 있는다.
4040

4141
로또 머신 (object)
42-
4342
- [O] 입력받은 번호로 구성된 로또로 생성한다.
43+
- [O] 당첨 번호 생성(with 보너스 번호)
4444
- [O] 당첨 여부 검증
4545
- [O] 수익률 반환
4646

47-
4847
로또 게임 (class)
4948
- [O] 입력받은 금액의 최대 수량만큼 로또를 구해한다.
5049
- [O] 당첨 통계를 낸다.
5150

52-
5351
inputView (object)
5452

5553
- [O] 입력된 금액 포맷 검증
5654
- [O] 숫자 포맷 검증
5755
- [O] 금액 범위는 1,000원 이상 100,000원 이하의 정수
58-
- [O] 지난 당첨 번호 포맷 검증
56+
- [] 지난 당첨 번호 포맷 검증
5957
- [O] 콤마(,)를 기준으로 나눈다
6058
- [O] 숫자 포맷 검증

src/main/kotlin/lotto/LottoGame.kt

Lines changed: 0 additions & 38 deletions
This file was deleted.

src/main/kotlin/lotto/LottoMachine.kt

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/main/kotlin/lotto/LottoMain.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
package lotto
22

3+
import lotto.data.LottoNumber
4+
import lotto.domain.LottoMachine
5+
import lotto.domain.RandomLogic
6+
import lotto.service.LottoGame
37
import lotto.view.InputView
48
import lotto.view.OutputView
59

610
fun main() {
711

812
val cash = InputView.inputCash()
9-
val lottoGame = LottoGame()
10-
13+
val lottoGame = LottoGame(RandomLogic())
1114
val purchaseLottoList = lottoGame.buyLotto(cash.toInt())
1215

1316
OutputView.showLottoList(purchaseLottoList)
1417

1518
val winningNumberList = InputView.inputWinningNumber()
19+
val bonusNumber = InputView.inputBonusNumber()
1620

17-
val winningStatus = lottoGame.getWinningStats(winningNumberList, purchaseLottoList)
18-
21+
val winningLotto = LottoMachine.createWinningLotto(winningNumberList, bonusNumber)
22+
val winningStatus = lottoGame.getWinningStats(winningLotto, purchaseLottoList)
1923
val winningRate = LottoMachine.createWinningRate(cash.toInt(), winningStatus)
2024

2125
OutputView.showWinningStatus(winningStatus, winningRate)
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
package lotto.data
22

3-
import java.util.TreeSet
3+
data class Lotto(val selectNumbers: Set<LottoNumber>) {
4+
init {
5+
validateDuplication(selectNumbers)
6+
}
47

5-
data class Lotto(val selectNumbers: TreeSet<LottoNumber>)
8+
private fun validateDuplication(lottoNumbers: Set<LottoNumber>) {
9+
require(lottoNumbers.size == LOTTO_NUMBER_LENGTH) { ERR_MSG_OUT_OF_LOTTO_LENGTH }
10+
}
11+
12+
companion object {
13+
private const val LOTTO_NUMBER_LENGTH = 6
14+
private const val ERR_MSG_OUT_OF_LOTTO_LENGTH = "번호는 6개로 구성되어야 합니다."
15+
}
16+
}
Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,34 @@
11
package lotto.data
22

3-
import java.util.TreeSet
3+
import lotto.domain.RandomLogicInterface
44

55
class LottoNumber private constructor(private val number: Int) : Comparable<LottoNumber> {
66

7+
override fun compareTo(other: LottoNumber): Int {
8+
return this.number.compareTo(other.number)
9+
}
10+
11+
override fun toString(): String {
12+
return number.toString()
13+
}
14+
715
companion object {
816
private const val MIN_NUMBER = 1
917
private const val MAX_NUMBER = 45
10-
private const val SUB_LIST_START_POSITION = 0
11-
private const val LOTTO_NUMBER_LENGTH = 6
1218
private const val ERR_MSG_OUT_OF_LOTTO_RANGE = "로또의 범위를 넘어서는 번호입니다."
13-
private const val ERR_MSG_OUT_OF_LOTTO_LENGTH = "번호는 6개로 구성되어야 합니다."
1419

1520
private val NUMBERS: Map<Int, LottoNumber> = (MIN_NUMBER..MAX_NUMBER).associateWith(::LottoNumber)
1621

17-
fun createLottoNumbers(numbers: List<Int>): TreeSet<LottoNumber> {
18-
val lottoNumbers = TreeSet(numbers.map(::from))
19-
validateDuplication(lottoNumbers)
20-
21-
return lottoNumbers
22-
}
23-
24-
fun createRandomLotto(): TreeSet<LottoNumber> {
25-
val randomNumberList = (MIN_NUMBER..MAX_NUMBER).shuffled()
26-
.subList(SUB_LIST_START_POSITION, SUB_LIST_START_POSITION + LOTTO_NUMBER_LENGTH)
27-
28-
return TreeSet(randomNumberList.map(::from))
22+
fun createLottoNumbers(numbers: List<Int>): Set<LottoNumber> {
23+
return LinkedHashSet(numbers.map(::from))
2924
}
3025

31-
private fun validateDuplication(lottoNumbers: TreeSet<LottoNumber>) {
32-
require(lottoNumbers.size == LOTTO_NUMBER_LENGTH) { ERR_MSG_OUT_OF_LOTTO_LENGTH }
26+
fun createRandomLottoNumber(lottoCreation: RandomLogicInterface): Set<LottoNumber> {
27+
return lottoCreation.createAutoLotto(NUMBERS)
3328
}
3429

35-
private fun from(value: Int): LottoNumber {
30+
fun from(value: Int): LottoNumber {
3631
return NUMBERS[value] ?: throw IllegalArgumentException(ERR_MSG_OUT_OF_LOTTO_RANGE)
3732
}
3833
}
39-
40-
override fun compareTo(other: LottoNumber): Int {
41-
return this.number.compareTo(other.number)
42-
}
43-
44-
override fun toString(): String {
45-
return number.toString()
46-
}
4734
}
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
package lotto.data
22

33
enum class LottoRanking(val matchingNumberCnt: Int, val price: Int) : Prize {
4-
FirstPlace(6, 2000000000) {
4+
FirstPlace(6, 2_000_000_000) {
55
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
66
return winningStatus.first.price * winningStatus.second
77
}
88
},
9-
SecondPlace(5, 1500000) {
9+
SecondPlace(5, 30_000_000) {
1010
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
1111
return winningStatus.first.price * winningStatus.second
1212
}
1313
},
14-
ThirdPlace(4, 50000) {
14+
ThirdPlace(5, 1_500_000) {
1515
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
1616
return winningStatus.first.price * winningStatus.second
1717
}
1818
},
19-
FourthPlace(3, 5000) {
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) {
2025
override fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int {
2126
return winningStatus.first.price * winningStatus.second
2227
}
@@ -28,6 +33,6 @@ enum class LottoRanking(val matchingNumberCnt: Int, val price: Int) : Prize {
2833
};
2934
}
3035

31-
interface Prize {
36+
fun interface Prize {
3237
fun findPrize(winningStatus: Pair<LottoRanking, Int>): Int
3338
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package lotto.data
2+
3+
data class WinningLotto(val lotto: Lotto, val bonusNumber: LottoNumber)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package lotto.domain
2+
3+
import lotto.data.Lotto
4+
import lotto.data.LottoNumber
5+
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
12+
import lotto.data.WinningLotto
13+
14+
object LottoMachine {
15+
16+
fun createSelectLotto(lottoNumbers: Set<LottoNumber>): Lotto {
17+
return Lotto(lottoNumbers)
18+
}
19+
20+
fun createWinningLotto(winningNumbers: List<Int>, bonusNumber: Int): WinningLotto {
21+
val winningLotto = LottoNumber.createLottoNumbers(winningNumbers)
22+
val bonusLottoNumber = LottoNumber.from(bonusNumber)
23+
return WinningLotto(Lotto(winningLotto), bonusLottoNumber)
24+
}
25+
26+
fun checkLotto(purchaseLotto: Lotto, winningLotto: WinningLotto): LottoRanking {
27+
val intersectNumber = winningLotto.lotto.selectNumbers.intersect(purchaseLotto.selectNumbers)
28+
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+
}
38+
}
39+
40+
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) }
56+
}
57+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package lotto.domain
2+
3+
import lotto.data.LottoNumber
4+
import java.util.TreeSet
5+
6+
class RandomLogic : RandomLogicInterface {
7+
8+
override fun createAutoLotto(numbers: Map<Int, LottoNumber>): Set<LottoNumber> {
9+
10+
return TreeSet(numbers.values.shuffled().subList(SUB_LIST_START_POSITION, LOTTO_NUMBER_LENGTH))
11+
}
12+
13+
companion object {
14+
private const val SUB_LIST_START_POSITION = 0
15+
private const val LOTTO_NUMBER_LENGTH = 6
16+
}
17+
}

0 commit comments

Comments
 (0)