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

[로또] 홍성우 미션 제출합니다. #171

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
33 changes: 33 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## 구현할 기능
### 1️⃣ 로또 class
- 생성자로 `numbers` List 를 가져온다.
- `numbers`를 오름차순으로 정렬한다.

### 2️⃣ 입력
- 로또 구입 금액을 얻고, 횟수를 전달
- 입력 예외 처리 : 1000으로 나누어 떨어지지 않을 경우
- 당첨 번호 & 보너스 번호 입력
- 당첨 번호를 오름차순으로 정렬함.
- 예외 처리
- 당첨 번호가 1 ~ 45를 벗어날 경우
- 번호 개수가 6개 이상 또는 6개 미만인 경우
- 자연수가 아닐 경우
- 중복된 수가 있을 경우

### 3️⃣ 당첨번호 결정

### 4️⃣ 수익률 계산
- 전체 수익을 얻는다.
- 수익률을 계산한다. (전체 수익/넣은 금액)
- 소수점 둘째 자리에서 반올림 한다.

### 5️⃣ 수익률 & 로또 결과 출력
- 계산한 수익률을 얻어서 출력한다.
- 당첨 통계를 아래와 같이 보여준다.
```
3개 일치 (5,000원) - 1개
4개 일치 (50,000원) - 0개
5개 일치 (1,500,000원) - 0개
5개 일치, 보너스 볼 일치 (30,000,000원) - 0개
6개 일치 (2,000,000,000원) - 0개
```
4 changes: 3 additions & 1 deletion src/main/kotlin/lotto/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package lotto

fun main() {
TODO("프로그램 구현")
val lottoRunner = LottoOperator()

lottoRunner.lottoRun()
}
26 changes: 26 additions & 0 deletions src/main/kotlin/lotto/CalculateIncomeRate.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package lotto

const val MATCH_3_INCOME = 5000
const val MATCH_4_INCOME = 50000
const val MATCH_5_INCOME = 1500000
const val MATCH_Bonus_INCOME = 30000000
const val MATCH_6_INCOME = 2000000000


class CalculateIncomeRate(getInputMoney: PurchasedLottos) {
private var totalIncome = 0
private val inputMoney = getInputMoney.getInputManager().getInputMoney()

fun calculateTotalIncomeRate(): Double = calculateTotalIncome().toDouble() / inputMoney.toDouble()
fun calculateTotalIncome(): Int {
totalIncome += MatchCatalog.Match3.getMatchCount() * MATCH_3_INCOME
totalIncome += MatchCatalog.Match4.getMatchCount() * MATCH_4_INCOME
totalIncome += MatchCatalog.Match5.getMatchCount() * MATCH_5_INCOME
totalIncome += MatchCatalog.MatchBonus.getMatchCount() * MATCH_Bonus_INCOME
totalIncome += MatchCatalog.Match6.getMatchCount() * MATCH_6_INCOME

return totalIncome
}

fun getTotalIncome() = totalIncome
}
43 changes: 43 additions & 0 deletions src/main/kotlin/lotto/CompareLottoNumber.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package lotto

class CompareLottoNumber(private val purchasedLottoTicket: PurchasedLottos) {
private var countMatch = IDX_ZERO
private val bonusNumber = purchasedLottoTicket.getBonusNumber()

private fun printState() {
println("당첨 통계")
println("---")
}

fun compareWinningLottoAndPurchasedLotto() {
printState()

val userLottos = purchasedLottoTicket.getPurchasedLottos()
val winningLottoNumber = purchasedLottoTicket.getWinning()

for (i in IDX_ZERO until userLottos.size) {
checkMatching(userLottos[i], winningLottoNumber)
}
}

private fun checkMatching(purchasedLotto: Lotto, winningLotto: List<Int>) {
countMatch = purchasedLotto.getNumbers().count { it in winningLotto }
when {
countMatch == 3 -> MatchCatalog.Match3.matchCountPlus()
countMatch == 4 -> MatchCatalog.Match4.matchCountPlus()
(countMatch == 5 && checkBonusNumber(purchasedLotto)) -> MatchCatalog.MatchBonus.matchCountPlus()
countMatch == 5 -> MatchCatalog.Match5.matchCountPlus()
countMatch == 6 -> MatchCatalog.Match6.matchCountPlus()
}
}

private fun checkBonusNumber(lotto: Lotto): Boolean {
val lottoNumber = lotto.getNumbers()
for (i in IDX_ZERO until lottoNumber.size) {
if (lottoNumber[i] == bonusNumber) {
return true
}
}
return false
}
}
10 changes: 10 additions & 0 deletions src/main/kotlin/lotto/DecidePurchasedLottoNumber.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package lotto

import camp.nextstep.edu.missionutils.Randoms

class DecidePurchasedLottoNumber {
fun randomLottoNumberGenerator(): List<Int> {
val numbers = Randoms.pickUniqueNumbersInRange(1, 45, 6)
return numbers.sorted()
}
}
103 changes: 103 additions & 0 deletions src/main/kotlin/lotto/InputManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package lotto

import camp.nextstep.edu.missionutils.Console

const val ONE_LOTTO_PRICE = 1000
const val MIN_NUMBER = 1
const val MAX_NUMBER = 45
const val LOTTO_SIZE = 6
const val IDX_ZERO = 0

class InputManager {
private lateinit var winningNumber: List<Int>
private var inputMoney: Int = ONE_LOTTO_PRICE
private var bonusNumber: Int = MIN_NUMBER

fun playerInsertMoney(): Int {
setInputMoney()
return inputMoney
}

fun playerInputNumbers() {
setWinningNumber()
setBonusNumber()
}

private fun setInputMoney() {
println("구입금액을 입력해 주세요.")
while (true) {
try {
inputMoney = Console.readLine().toInt()
checkInputNumberRange()
break
} catch (e: IllegalArgumentException) {
println(e.message)
println("다시 입력해주세요.")
}
}
println("${inputMoney / ONE_LOTTO_PRICE}개를 구매했습니다.")
println()
}

fun getBonusNumber() = bonusNumber
fun getWinningNumber() = winningNumber

fun getInputMoney() = inputMoney
private fun setWinningNumber() {
println("당첨 번호를 입력해 주세요.")
while (true) {
try {
winningNumber = Console.readLine().split(",").map { it.toInt() }
checkWinningNumberRange()
winningNumber.sorted()
break
} catch (e: IllegalArgumentException) {
println(e.message)
println("다시 입력해주세요.")
}
}
println()
}

private fun setBonusNumber() {
println("보너스 번호를 입력해 주세요.")
while (true) {
try {
bonusNumber = Console.readLine().toInt()
checkBonusNumberRange()
break
} catch (e: IllegalArgumentException) {
println(e.message)
println("다시 입력해주세요.")
}
}
println()
}

private fun checkInputNumberRange() {
if (inputMoney % ONE_LOTTO_PRICE != 0) {
throw IllegalArgumentException("[ERROR] 로또 구입 금액은 1000원 단위에 맞춰서 넣어주세요.")
}
}

private fun checkWinningNumberRange() {
if (winningNumber.size != LOTTO_SIZE) {
throw IllegalArgumentException("[ERROR] 로또 번호는 6개여야 합니다.")
}
if (winningNumber.toSet().size != LOTTO_SIZE) {
throw IllegalArgumentException("[ERROR] 중복되는 수는 넣을 수 없습니다.")
}
winningNumber.toList()
for (i in winningNumber.indices) {
if (winningNumber[i].toInt() !in MIN_NUMBER..MAX_NUMBER) {
throw IllegalArgumentException("[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.")
}
}
}

private fun checkBonusNumberRange() {
if (bonusNumber !in MIN_NUMBER..MAX_NUMBER) {
throw IllegalArgumentException("[ERROR] 보너스 번호는 1부터 45 사이의 숫자입니다.")
}
}
}
4 changes: 2 additions & 2 deletions src/main/kotlin/lotto/Lotto.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package lotto

class Lotto(private val numbers: List<Int>) {
init {
require(numbers.size == 6)
require(numbers.size == LOTTO_SIZE)
}

// TODO: 추가 기능 구현
fun getNumbers() = numbers
}
13 changes: 13 additions & 0 deletions src/main/kotlin/lotto/LottoOperator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package lotto

class LottoOperator {
private var purchasingLottos = PurchasedLottos()
private var comparingLottoNumber = CompareLottoNumber(purchasingLottos)
private var printResult = PrintResult(purchasingLottos)

fun lottoRun() {
purchasingLottos.purchasingLotto()
comparingLottoNumber.compareWinningLottoAndPurchasedLotto()
printResult.printResult()
}
}
10 changes: 10 additions & 0 deletions src/main/kotlin/lotto/MatchCatalog.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package lotto

enum class MatchCatalog(private var matchCount: Int) {
Match3(0), Match4(0),
Match5(0), MatchBonus(0),
Match6(0);

fun matchCountPlus() = matchCount++
fun getMatchCount() = matchCount
}
14 changes: 14 additions & 0 deletions src/main/kotlin/lotto/PrintResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package lotto

class PrintResult(purchasedLottos: PurchasedLottos) {
private var calculateIncomeRate = CalculateIncomeRate(purchasedLottos)

fun printResult() {
println("3개 일치 (${MATCH_3_INCOME}원) - ${MatchCatalog.Match3.getMatchCount()}개")
println("4개 일치 (${MATCH_4_INCOME}원) - ${MatchCatalog.Match4.getMatchCount()}개")
println("5개 일치 (${MATCH_5_INCOME}원) - ${MatchCatalog.Match5.getMatchCount()}개")
println("5개 일치, 보너스 볼 일치 (${MATCH_Bonus_INCOME}원) - ${MatchCatalog.MatchBonus.getMatchCount()}개")
println("6개 일치 (${MATCH_6_INCOME}원) - ${MatchCatalog.Match6.getMatchCount()}개")
println("총 수익률은 ${calculateIncomeRate.calculateTotalIncomeRate()}%입니다.")
}
}
43 changes: 43 additions & 0 deletions src/main/kotlin/lotto/PurchasedLottos.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package lotto

class PurchasedLottos {
private var inputManager = InputManager()
private var purchasedLottos = mutableListOf<Lotto>()
private var decidePurchasedLottoNumber = DecidePurchasedLottoNumber()
private var lottoCount: Int = IDX_ZERO
private var bonusNumber = inputManager.getBonusNumber()

fun purchasingLotto() {
initLottoCount()
makePurchasedLottos()
printPurchasedLottoList()
inputManager.playerInputNumbers()
}

private fun initLottoCount() {
lottoCount = calculateLottoCount()
}

private fun makePurchasedLottos() {
for (i in IDX_ZERO until lottoCount) {
val temporalLotto = Lotto(decidePurchasedLottoNumber.randomLottoNumberGenerator())
purchasedLottos.add(temporalLotto)
}
}

private fun printPurchasedLottoList() {
for (i in IDX_ZERO until purchasedLottos.size) {
println("${purchasedLottos[i].getNumbers()}")
}
println()
}

private fun calculateLottoCount(): Int = inputManager.playerInsertMoney() / ONE_LOTTO_PRICE

fun getWinning() = inputManager.getWinningNumber()

fun getInputManager() = inputManager

fun getPurchasedLottos() = purchasedLottos
fun getBonusNumber() = bonusNumber
}
9 changes: 9 additions & 0 deletions src/test/kotlin/lotto/ApplicationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest
import camp.nextstep.edu.missionutils.test.NsTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows

class ApplicationTest : NsTest() {

Expand Down Expand Up @@ -50,6 +51,14 @@ class ApplicationTest : NsTest() {
}
}

@Test
fun `로또 번호의 개수가 6개가 넘어가면 예외가 발생한다`() {
assertThrows<IllegalArgumentException> {
Lotto(listOf(1, 2, 3, 4, 5, 6, 7))
}
}


override fun runMain() {
main()
}
Expand Down