Skip to content

Commit ea6e757

Browse files
committed
fix: 피드백 반영
1 parent f3cdfb4 commit ea6e757

File tree

11 files changed

+79
-78
lines changed

11 files changed

+79
-78
lines changed

docs/step2.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
- [x] 로또 구매 결과를 출력한다.
1616
- [x] 지난 주 당첨 번호 6자리를 입력받는다.
1717
- [x] 콤마(`,`)와 공백(` `)으로 각 숫자를 구분
18-
- [ ] 수익률 통계를 제공한다.
19-
- [ ] 일치하는 로또 개수를 제공한다.
18+
- [x] 수익률 통계를 제공한다.
19+
- [x] 일치하는 로또 개수를 제공한다.

src/main/kotlin/lotto/LottoApplication.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ fun main() {
1111
val randomNumberListGenerator = RandomLottoNumberListGenerator()
1212
val amount = InputView.purchaseAmount()
1313

14-
val numberOfLotto = Cashier.purchaseLotto(amount)
15-
val userLottos = List(numberOfLotto) { Lotto.createLotto(randomNumberListGenerator.generate()) }
14+
val userLottos = Cashier.purchaseLotto(amount, randomNumberListGenerator)
1615
OutputView.printPurchaseResult(userLottos)
1716

1817
val winningNumbers = InputView.winningNumbers()
1918
val winningLotto = Lotto.createLotto(winningNumbers)
2019

21-
val lottoStatistics = Statistics.of(userLottos, winningLotto)
22-
OutputView.printLottoStatistics(lottoStatistics, amount)
20+
val statisticsList = Statistics.of(userLottos, winningLotto)
21+
val earningRatio = Statistics.calculateEarningRatio(statisticsList, amount)
22+
OutputView.printLottoStatistics(statisticsList, earningRatio)
2323
}

src/main/kotlin/lotto/constant/LottoRankConstant.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package lotto.constant
22

3-
const val FIRST_RANK_NUMBER = 1
4-
const val THIRD_RANK_NUMBER = 3
5-
const val FOURTH_RANK_NUMBER = 4
6-
const val FIFTH_RANK_NUMBER = 5
7-
const val NO_RANK_NUMBER = 0
3+
const val MINIMUM_NUMBER = 1
4+
const val MAXIMUM_NUMBER = 45
5+
const val FIRST_RANK = 1
6+
const val SECOND_RANK = 2
7+
const val THIRD_RANK = 3
8+
const val FOURTH_RANK = 4
9+
const val FIFTH_RANK = 5
10+
const val NO_RANK = 0
811
const val MATCH_COUNT_SIX = 6
912
const val MATCH_COUNT_FIVE = 5
1013
const val MATCH_COUNT_FOUR = 4
Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
package lotto.domain
22

3+
import lotto.stretagy.LottoNumberListGenerator
4+
35
class Cashier {
46
companion object {
57
private const val LOTTO_PRICE = 1000
68

7-
fun purchaseLotto(amount: Int): Int {
9+
fun purchaseLotto(
10+
amount: Int,
11+
lottoNumberListGenerator: LottoNumberListGenerator,
12+
): List<Lotto> {
813
require(amount >= LOTTO_PRICE)
9-
return amount / LOTTO_PRICE
14+
val numberOfLotto = calculateNumberOfLotto(amount)
15+
return List(numberOfLotto) { Lotto.createLotto(lottoNumberListGenerator.generate()) }
1016
}
1117

12-
fun exchange() {
18+
private fun calculateNumberOfLotto(amount: Int): Int {
19+
return amount / LOTTO_PRICE
1320
}
1421
}
1522
}

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,8 @@ package lotto.domain
22

33
class Lotto private constructor(val lottoNumbers: Set<LottoNumber>) {
44
companion object {
5-
private const val NUMBER_OF_SELECT = 6
6-
75
fun createLotto(numbers: List<Int>): Lotto {
8-
val lottoNumbers =
9-
numbers
10-
.take(NUMBER_OF_SELECT)
11-
.sorted()
12-
.map { LottoNumber.from(it) }
13-
.toSet()
6+
val lottoNumbers = numbers.map { LottoNumber.from(it) }.toSet()
147

158
return Lotto(lottoNumbers)
169
}

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

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,21 @@
11
package lotto.domain
22

3-
class LottoNumber private constructor(val number: Int) {
3+
@JvmInline
4+
value class LottoNumber(val number: Int) {
45
companion object {
56
private const val MINIMUM_NUMBER = 1
67
private const val MAXIMUM_NUMBER = 45
8+
private const val CANNOT_CREATE_LOTTO_NUMBER_MESSAGE = "Lotto number must be between %s and %s."
79

810
private val NUMBERS: Map<Int, LottoNumber> = (MINIMUM_NUMBER..MAXIMUM_NUMBER).associateWith { LottoNumber(it) }
911

1012
fun from(number: Int): LottoNumber {
11-
return NUMBERS[number] ?: throw IllegalArgumentException()
13+
return NUMBERS[number] ?: throw IllegalArgumentException(
14+
CANNOT_CREATE_LOTTO_NUMBER_MESSAGE.format(MINIMUM_NUMBER, MAXIMUM_NUMBER),
15+
)
1216
}
1317
}
1418

15-
override fun equals(other: Any?): Boolean {
16-
if (this === other) return true
17-
if (javaClass != other?.javaClass) return false
18-
19-
other as LottoNumber
20-
21-
return number == other.number
22-
}
23-
24-
override fun hashCode(): Int {
25-
return number
26-
}
27-
2819
override fun toString(): String {
2920
return number.toString()
3021
}

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package lotto.domain
22

3-
import lotto.constant.FIFTH_RANK_NUMBER
4-
import lotto.constant.FIRST_RANK_NUMBER
5-
import lotto.constant.FOURTH_RANK_NUMBER
3+
import lotto.constant.FIFTH_RANK
4+
import lotto.constant.FIRST_RANK
5+
import lotto.constant.FOURTH_RANK
66
import lotto.constant.MATCH_COUNT_FIVE
77
import lotto.constant.MATCH_COUNT_FOUR
88
import lotto.constant.MATCH_COUNT_SIX
99
import lotto.constant.MATCH_COUNT_THREE
10-
import lotto.constant.NO_RANK_NUMBER
11-
import lotto.constant.THIRD_RANK_NUMBER
10+
import lotto.constant.NO_RANK
11+
import lotto.constant.THIRD_RANK
1212

1313
class Match {
1414
companion object {
@@ -19,17 +19,17 @@ class Match {
1919
val lottoNumbers: Set<LottoNumber> = userLotto.lottoNumbers
2020
val winningLottoNumbers: Set<LottoNumber> = winningLotto.lottoNumbers
2121

22-
val matchCount = lottoNumbers.filter { winningLottoNumbers.contains(it) }.size
22+
val matchCount = lottoNumbers.intersect(winningLottoNumbers).size
2323
return rank(matchCount)
2424
}
2525

2626
private fun rank(matchCount: Int): Int {
2727
return when (matchCount) {
28-
MATCH_COUNT_SIX -> FIRST_RANK_NUMBER
29-
MATCH_COUNT_FIVE -> THIRD_RANK_NUMBER
30-
MATCH_COUNT_FOUR -> FOURTH_RANK_NUMBER
31-
MATCH_COUNT_THREE -> FIFTH_RANK_NUMBER
32-
else -> NO_RANK_NUMBER
28+
MATCH_COUNT_SIX -> FIRST_RANK
29+
MATCH_COUNT_FIVE -> THIRD_RANK
30+
MATCH_COUNT_FOUR -> FOURTH_RANK
31+
MATCH_COUNT_THREE -> FIFTH_RANK
32+
else -> NO_RANK
3333
}
3434
}
3535
}
Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
package lotto.domain
22

3+
import lotto.constant.FIFTH_RANK
4+
import lotto.constant.FIRST_RANK
5+
import lotto.constant.FOURTH_RANK
6+
import lotto.constant.SECOND_RANK
7+
import lotto.constant.THIRD_RANK
8+
39
data class Statistics(val rank: Int, val matchCount: Int) {
410
fun earnings(): Long {
511
return earningPriceByRanking() * matchCount
612
}
713

814
private fun earningPriceByRanking(): Long =
915
when (rank) {
10-
RANK_FIRST -> FIRST_RANK_EARNING
11-
RANK_SECOND -> SECOND_RANK_EARNING
12-
RANK_THIRD -> THIRD_RANK_EARNING
13-
RANK_FOURTH -> FOURTH_RANK_EARNING
14-
RANK_FIFTH -> FIFTH_RANK_EARNING
16+
FIRST_RANK -> FIRST_RANK_EARNING
17+
SECOND_RANK -> SECOND_RANK_EARNING
18+
THIRD_RANK -> THIRD_RANK_EARNING
19+
FOURTH_RANK -> FOURTH_RANK_EARNING
20+
FIFTH_RANK -> FIFTH_RANK_EARNING
1521
else -> NO_RANK_EARNING
1622
}
1723

1824
companion object {
19-
private const val RANK_FIRST = 1
20-
private const val RANK_SECOND = 2
21-
private const val RANK_THIRD = 3
22-
private const val RANK_FOURTH = 4
23-
private const val RANK_FIFTH = 5
24-
2525
private const val FIRST_RANK_EARNING = 2_000_000_000L
2626
private const val SECOND_RANK_EARNING = 1_500_000L
2727
private const val THIRD_RANK_EARNING = 50_000L
@@ -34,10 +34,12 @@ data class Statistics(val rank: Int, val matchCount: Int) {
3434
winningLotto: Lotto,
3535
): List<Statistics> {
3636
val groupByRanking: Map<Int, List<Lotto>> =
37-
(5 downTo 1).associateWith { emptyList<Lotto>() } +
37+
(FIFTH_RANK downTo FIRST_RANK).associateWith { emptyList<Lotto>() } +
3838
userLottos.groupBy { Match.lottoNumber(it, winningLotto) }
3939

40-
return groupByRanking.map { Statistics(it.key, it.value.size) }.sortedByDescending { it.rank }
40+
val statistics: List<Statistics> =
41+
groupByRanking.map { Statistics(it.key, it.value.size) }.sortedByDescending { it.rank }
42+
return getRankedLottos(statistics)
4143
}
4244

4345
fun calculateEarningRatio(
@@ -46,5 +48,9 @@ data class Statistics(val rank: Int, val matchCount: Int) {
4648
): Double {
4749
return statisticsList.sumOf { it.earnings() }.toDouble() / amount
4850
}
51+
52+
private fun getRankedLottos(statisticsList: List<Statistics>): List<Statistics> {
53+
return statisticsList.filter { it.rank in FIRST_RANK..FIFTH_RANK && it.rank != SECOND_RANK }
54+
}
4955
}
5056
}
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package lotto.stretagy
22

3+
import lotto.constant.MAXIMUM_NUMBER
4+
import lotto.constant.MINIMUM_NUMBER
5+
36
class RandomLottoNumberListGenerator : LottoNumberListGenerator {
47
override fun generate(): List<Int> {
58
return (MINIMUM_NUMBER..MAXIMUM_NUMBER).shuffled()
9+
.take(NUMBER_OF_SELECT)
10+
.sorted()
611
}
712

813
companion object {
9-
private const val MINIMUM_NUMBER = 1
10-
private const val MAXIMUM_NUMBER = 45
14+
private const val NUMBER_OF_SELECT = 6
1115
}
1216
}

src/main/kotlin/lotto/view/InputView.kt

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ package lotto.view
22

33
class InputView {
44
companion object {
5+
private const val PURCHASE_INFORMATION_MESSAGE = "구입금액을 입력해 주세요."
6+
private const val WINNING_NUMBER_DELIMITERS = ","
7+
private const val REPLACEMENT_SOURCE = " "
8+
private const val REPLACEMENT_TARGET = ""
9+
private const val WINNING_NUMBER_INPUT_MESSAGE = "지난 주 당첨 번호를 입력해 주세요."
10+
private const val ERROR_INVALID_NUMBER = "유효한 숫자를 입력해주세요."
11+
private const val ERROR_WRONG_NUMBER_COUNT = "정확히 6개의 숫자를 입력해야 합니다."
12+
513
fun purchaseAmount(): Int {
614
println(PURCHASE_INFORMATION_MESSAGE)
715
return readln().toIntOrNull()
@@ -12,18 +20,8 @@ class InputView {
1220
println(WINNING_NUMBER_INPUT_MESSAGE)
1321
return readln().replace(REPLACEMENT_SOURCE, REPLACEMENT_TARGET)
1422
.split(WINNING_NUMBER_DELIMITERS)
15-
.also { if (it.size != 6) throw IllegalArgumentException(ERROR_WRONG_NUMBER_COUNT) }
23+
.also { require(it.size == 6) { ERROR_WRONG_NUMBER_COUNT } }
1624
.map { it.toIntOrNull() ?: throw IllegalArgumentException(ERROR_INVALID_NUMBER) }
1725
}
18-
19-
private const val PURCHASE_INFORMATION_MESSAGE = "구입금액을 입력해 주세요."
20-
private const val WINNING_NUMBER_DELIMITERS = ","
21-
private const val REPLACEMENT_SOURCE = " "
22-
private const val REPLACEMENT_TARGET = ""
23-
24-
private const val WINNING_NUMBER_INPUT_MESSAGE = "지난 주 당첨 번호를 입력해 주세요."
25-
26-
private const val ERROR_INVALID_NUMBER = "유효한 숫자를 입력해주세요."
27-
private const val ERROR_WRONG_NUMBER_COUNT = "정확히 6개의 숫자를 입력해야 합니다."
2826
}
2927
}

src/main/kotlin/lotto/view/OutputView.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,12 @@ class OutputView {
3232

3333
fun printLottoStatistics(
3434
statisticsList: List<Statistics>,
35-
amount: Int,
35+
earningRatio: Double,
3636
) {
3737
println(LOTTO_STATISTICS_TITLE)
3838
println(LOTTO_STATISTICS_SEPARATOR)
39-
statisticsList.filter { it.rank in 1..5 && it.rank != 2 }
40-
.forEach { printLottoResult(it) }
41-
val earningRatio = Statistics.calculateEarningRatio(statisticsList, amount)
39+
statisticsList.forEach { printLottoResult(it) }
40+
4241
println(EARNING_RATIO_MESSAGE.format(earningRatio, getProfitStatus(earningRatio)))
4342
}
4443

0 commit comments

Comments
 (0)