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

[로또] 김소윤 미션 제출합니다. #165

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
9 changes: 9 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 미션 - 로또
## 구현 할 기능 목록

1. 사용자로 부터 로또 구입 금액을 입력받는다
2. 입력 받은 로또 구입 금액이 1000원으로 나누어 떨어지면 몫을 출력하고 컴퓨터가 앞서 계산한 몫만큼 임의의 수 6개로 이루어진 로또를 발행한다.
3. 사용자로부터 당첨번호를(중복되지 않는 숫자 6개를 구분자 ,와 함께) 입력 받는다.
4. 사용자로부터 보너스 번호 1개를 입력받는다.
5. 컴퓨터를 통해 발행된 로또들과 사용자로부터 입력받은 당첨 번호와 보너스번호를 비교해 5등부터 1등까지의 개수를 계산한다.
6. 수익율을 계산한다.
9 changes: 8 additions & 1 deletion src/main/kotlin/lotto/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package lotto

fun main() {
TODO("프로그램 구현")
try {
LottoGame().start()
} catch (exception: IllegalArgumentException) {

}
}



11 changes: 10 additions & 1 deletion src/main/kotlin/lotto/Lotto.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@ package lotto
class Lotto(private val numbers: List<Int>) {
init {
require(numbers.size == 6)
require(isDuplicateNum()) { println(IS_DUPLICATE_NUM) }
require(checkNotIn1to45()) { println(NOT_IN_ONE_TO_FOURTY_FIVE) }
}

// TODO: 추가 기능 구현
private fun isDuplicateNum(): Boolean = numbers.size == numbers.distinct().size
private fun checkNotIn1to45(): Boolean = numbers.all { it in 1..45 }

companion object {
const val IS_DUPLICATE_NUM = "[ERROR] 로또 번호는 중복되는 숫자가 없어야 합니다."
const val NOT_IN_ONE_TO_FOURTY_FIVE = "[EROOR] 로또 번호는 1부터 45 사이의 숫자여야 합니다."
}
}

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

import camp.nextstep.edu.missionutils.Randoms
import lotto.view.Input
import lotto.view.Output
import java.math.BigDecimal
import java.math.BigInteger

class LottoGame {
private var matchCountList = mutableListOf(0, 0, 0, 0, 0)

fun start() {
val money = Input().inputMoney().toInt()
val lottoCount = getLottoCount(money)
val lottoList = getLotto(lottoCount)
Output().outputLottos(lottoList)

val winningNum = Input().inputWinningNum()
val bonusNum = Input().inputBonusNum()

lottoList.forEach { checkLottoAndWinningNumMatch(it, winningNum, bonusNum) }

Output().outputMatchCount(matchCountList)

val profitability = getProfitability(money)
Output().outputProfitability(profitability)

}


private fun getLottoCount(money: Int): Int = money / 1000

private fun getLotto(lottoCount: Int): List<List<Int>> {
val lottoList = List(lottoCount) {
Randoms.pickUniqueNumbersInRange(1, 45, 6).sorted()
}
lottoList.forEach { Lotto(it) }
return lottoList
}

private fun checkLottoAndWinningNumMatch(lotto: List<Int>, winningNum: String, bonusNum: String) {
val winningNumList = winningNum.split(",").map { it.toInt() }.toSet()
val bonusNumToInt = bonusNum.toInt()
val match = lotto.intersect(winningNumList).size

when (match) {
3 -> matchCountList[0]++
4 -> matchCountList[1]++
5 -> if (lotto.contains(bonusNumToInt)) matchCountList[3]++ else matchCountList[2]++
6 -> matchCountList[4]++
}
}

private fun getProfitability(money: Int): BigDecimal {
val priceList = listOf(5000, 50000, 1500000, 30000000, 2000000000)
var sum = BigInteger("0")
for (i in matchCountList.indices) {
val temp = BigInteger(matchCountList[i].toString()) * BigInteger(priceList[i].toString())
sum += temp
}

val tempProfitability = BigDecimal(sum).divide(BigDecimal(money.toString()))
return tempProfitability.multiply(BigDecimal("100")).setScale(1, BigDecimal.ROUND_HALF_UP)
}
}
21 changes: 21 additions & 0 deletions src/main/kotlin/lotto/domain/BonusNum.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package lotto.domain

import lotto.Lotto

class BonusNum(private val bonusNum: String) {
init {
require(isNum()) { println(IS_NOT_NUM) }
require(checkNotIn1to45()) { println(NOT_IN_ONE_TO_FOURTY_FIVE) }
}

private fun isNum(): Boolean = bonusNum.all { number -> number.isDigit() }
private fun checkNotIn1to45(): Boolean = bonusNum.toInt() in 1..45



companion object {
private const val IS_NOT_NUM = "[ERROR] 숫자로 입력해야 합니다."
private const val NOT_IN_ONE_TO_FOURTY_FIVE = "[EROOR] 1부터 45 사이의 숫자여야 합니다."
}
}

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

class Money(private val money: String) {
init {
require(isNum()) { println(IS_NOT_NUM) }
require(isMultiplesOfThousand()) { println(IS_NOT_MULTIPLES_OF_THOUSAND) }
}

private fun isNum(): Boolean = money.all { number -> number.isDigit() }

private fun isMultiplesOfThousand(): Boolean = money.toInt() % 1000 == 0

companion object {
private const val IS_NOT_NUM = "[ERROR] 금액은 숫자여야 합니다."
private const val IS_NOT_MULTIPLES_OF_THOUSAND = "[ERROR] 구입 금액은 1000원으로 나누어 떨어져야 합니다."
}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/lotto/domain/WinningNum.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package lotto.domain

class WinningNum(private val winningNum: String) {
init {
require(isValidFormat()) { println(IS_VALID_FORMAT) }
}

private fun isValidFormat(): Boolean =
winningNum.split(",").map { it.trim() }.all { it.matches(Regex("""^\d+(,\d+)*$""")) }


companion object {
private const val IS_VALID_FORMAT = "[ERROR] 당첨 번호 입력 시 콤마와 숫자로 이루어진 문자열로 입력해야 합니다."
}
}

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

import camp.nextstep.edu.missionutils.Console
import lotto.Lotto
import lotto.domain.BonusNum
import lotto.domain.Money
import lotto.domain.WinningNum

class Input {
fun inputMoney(): String {
println("구입할 금액을 입력해 주세요.")
val money = Console.readLine()
Money(money)
return money
}

fun inputWinningNum(): String {
println("\n당첨 번호를 입력해 주세요.")
val winningNum = Console.readLine()
WinningNum(winningNum)
Lotto(winningNum.split(",").map { it.toInt() }.toList())
return winningNum
}

fun inputBonusNum(): String {
println("\n보너스 번호를 입력해 주세요.")
val bonusNum = Console.readLine()
BonusNum(bonusNum)
return bonusNum
}
}

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

import java.math.BigDecimal

class Output {

fun outputLottos(lottoList: List<List<Int>>) {
println()
println("${lottoList.size}개를 구매했습니다.")
lottoList.forEach { println(it) }
}

fun outputMatchCount(matchCountList: MutableList<Int>) {
println("\n당첨 통계")
println("---")
println("3개 일치 (5,000원) - ${matchCountList[0]}개")
println("4개 일치 (50,000원) - ${matchCountList[1]}개")
println("5개 일치 (1,500,000원) - ${matchCountList[2]}개")
println("5개 일치, 보너스 볼 일치 (30,000,000원) - ${matchCountList[3]}개")
println("6개 일치 (2,000,000,000원) - ${matchCountList[4]}개")
}

fun outputProfitability(profitability : BigDecimal){
println("총 수익률은 $profitability%입니다.")
}
}

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

import lotto.domain.BonusNum
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows


class BonusNumTest {
@Test
fun `보너스 번호 입력 시 숫자 아닌 경우 예외 발생`() {
assertThrows<IllegalArgumentException> {
BonusNum("10j")
}
}

@Test
fun `보너스 번호 입력 시 1부터 45의 범위에 속하지 않는 경우 예외 발생`() {
assertThrows<IllegalArgumentException> {
BonusNum("48")
}
}

}
9 changes: 7 additions & 2 deletions src/test/kotlin/lotto/LottoTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ class LottoTest {
}
}

// TODO: 이 테스트가 통과할 수 있게 구현 코드 작성
@Test
fun `로또 번호에 중복된 숫자가 있으면 예외가 발생한다`() {
assertThrows<IllegalArgumentException> {
Lotto(listOf(1, 2, 3, 4, 5, 5))
}
}

// 아래에 추가 테스트 작성 가능
@Test
fun `로또 번호가 1부터 45 사이의 숫자가 아닐 경우 예외 발생 `() {
assertThrows<IllegalArgumentException> {
Lotto(listOf(1, 2, 3, 4, 5, 48))
}
}

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

import lotto.domain.Money
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows


class MoneyTest {

@Test
fun `금액이 1000원으로 나누어 떨어지지 않을 경우 테스트`() {
val money = "1100"
assertThrows<IllegalArgumentException> { Money(money) }
}

@Test
fun `금액이 숫자가 아닐 경우 테스트`() {
val money = "1100k"
assertThrows<IllegalArgumentException> { Money(money) }
}


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

import lotto.domain.WinningNum
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows


class WinningNumTest {
@Test
fun `당첨 번호 입력시 숫자와 콤마로 이루어진 문자열이 아닐 경우 예외 발생`() {
assertThrows<IllegalArgumentException> {
WinningNum("4;7,5,3,9,10")
}
}

}