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

[로또 게임] 황연진 미션 제출합니다. #168

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 기능 구현 목록

- 로또 구입 금액을 입력한다.
- 1,000원 단위로 떨어지지 않는 값을 입력할 경우 예외 처리
- 1,000원 이하를 입력할 경우 예외 처리
- 숫자를 입력하지 않을 경우 예외 처리

- 구입 금액에 해당하는 만큼 로또를 발행하며, 이 때 숫자의 범위는 1부터 45이내다.
- 발행한 로또 수량과 번호를 출력한다. 이 때, 번호는 오름차순으로 정렬

- 당첨 번호를 입력한다.
- 번호를 쉼표 기준으로 입력하지 않을 경우 예외 처리
- 1~45 사이의 값을 입력하지 않을 경우 예외 처리
- 숫자를 입력하지 않을 경우 예외 처리
- 값이 중복될 경우 예외 처리
- 번호를 6개 입력하지 않았을 경우 예외 처리

- 보너스 번호를 입력한다.
- 1~45 사이의 값을 입력하지 않을 경우 예외 처리
- 값이 당첨 번호와 중복될 경우 예외 처리
- 숫자를 입력하지 않을 경우 예외 처리

- 당첨 번호와 로또의 숫자를 비교하여 당첨된 로또의 개수를 계산한다.
- 1등: 6개 번호 일치 / 2,000,000,000원
- 2등: 5개 번호 + 보너스 번호 일치 / 30,000,000원
- 3등: 5개 번호 일치 / 1,500,000원
- 4등: 4개 번호 일치 / 50,000원
- 5등: 3개 번호 일치 / 5,000원

- 구매 금액과 당첨 금액을 비교하여 수익률을 계산한다. 이 때, 수익률은 소수점 둘째 자리에서 반올림한다.


### 주의사항
- 사용자가 잘못된 값을 입력할 경우 에러 메세지를 출력한 후 입력을 다시 받는다.
2 changes: 1 addition & 1 deletion src/main/kotlin/lotto/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package lotto

fun main() {
TODO("프로그램 구현")
LottoGame().play()
}
57 changes: 57 additions & 0 deletions src/main/kotlin/lotto/CompareLotto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package lotto

import lotto.model.LottoType

class CompareLotto {
private val resultPrice = listOf(
"3개 일치 (5,000원) - ",
"4개 일치 (50,000원) - ",
"5개 일치 (1,500,000원) - ",
"5개 일치, 보너스 볼 일치 (30,000,000원) - ",
"6개 일치 (2,000,000,000원) - "
)

fun compareLotto(
lottos: List<Lotto>,
lottoNumber: List<Int>,
bonusNumber: Int
): MutableList<Int> {
val winningLottosNumber = MutableList(LottoType.entries.size) { 0 }

lottos.forEach { lotto ->
val index = when (lotto.compareLottoNumber(lottoNumber)) {
in 0..2 -> null
3 -> LottoType.THREE
4 -> LottoType.FOUR
5 -> if (lotto.containBonusNumber(bonusNumber)) LottoType.FIVE_BONUS else LottoType.FIVE
6 -> LottoType.SIX
else -> throw IllegalArgumentException("유효하지 않은 비교 개수입니다.")
}
index?.also {
winningLottosNumber[it.ordinal]++
}
}

return winningLottosNumber
}

fun calculateRateOfReturn(winningLottosNumber: MutableList<Int>, price: Int): Double {
var profit = 0.0
val priceList = listOf(5000, 50000, 1500000, 30000000, 2000000000)
winningLottosNumber.forEachIndexed { index, count ->
profit += priceList[index] * count
}
return profit / price * 100
}

fun printResult(winningLottosNumber: MutableList<Int>) {
winningLottosNumber.forEachIndexed { index, count ->
println("${resultPrice[index]}${count}개")
}
}

fun printRateOfReturnResult(rateOfReturn: Double) {
val num = String.format("%.1f", rateOfReturn)
println("총 수익률은 ${num}%입니다.")
}
}
32 changes: 32 additions & 0 deletions src/main/kotlin/lotto/Input.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package lotto

import camp.nextstep.edu.missionutils.Console.readLine
import lotto.exception.BonusValidation
import lotto.exception.ErrorConstants
import lotto.exception.LottoValidation
import lotto.exception.PriceValidation

class Input {

fun inputPurchasePrice(): Int {
println("구입금액을 입력해 주세요.")
val price = readLine()
PriceValidation(price)
return price.toInt()
}

fun inputLottoNumber(): List<Int> {
println("당첨 번호를 입력해 주세요.")
val number = readLine()
LottoValidation(number)
return number.split(",").map { it.toInt() }
}

fun inputLottoBonusNumber(lotto: List<Int>): Int {
println("보너스 번호를 입력해 주세요.")
val bonusNumber = readLine()
BonusValidation(lotto, bonusNumber)
return bonusNumber.toInt()
}

}
16 changes: 15 additions & 1 deletion src/main/kotlin/lotto/Lotto.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,19 @@ class Lotto(private val numbers: List<Int>) {
require(numbers.size == 6)
}

// TODO: 추가 기능 구현
private fun sortLotto(): List<Int> {
return numbers.sorted()
}

fun compareLottoNumber(lottoNumber: List<Int>): Int {
return numbers.intersect(lottoNumber.toSet()).size
}

fun containBonusNumber(bonusNumber: Int): Boolean {
return numbers.contains(bonusNumber)
}

fun printLotto() {
println("${sortLotto()}")
}
}
61 changes: 61 additions & 0 deletions src/main/kotlin/lotto/LottoGame.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package lotto

class LottoGame {

fun play() {
val input = Input()
val lottoManager = LottoManager()
val compareLotto = CompareLotto()

val price = getPrice(input)
lottoManager.createLottoes(price)
lottoManager.printLottoes(price)

val lottoNumbers = getLottoNumber(input)
val bonusNumber = getBonusNumber(input, lottoNumbers)

val lottoResult = compareLotto.compareLotto(lottoManager.lottoes, lottoNumbers, bonusNumber)
val rateOfReturnResult = compareLotto.calculateRateOfReturn(lottoResult, price)
compareLotto.printResult(lottoResult)
compareLotto.printRateOfReturnResult(rateOfReturnResult)
}

private fun getPrice(input: Input): Int {
var price: Int
while (true) {
try {
price = input.inputPurchasePrice()
break
} catch (e: IllegalArgumentException) {
println(e.message)
}
}
return price
}

private fun getLottoNumber(input: Input): List<Int> {
var lotto: List<Int>
while (true) {
try {
lotto = input.inputLottoNumber()
break
} catch (e: IllegalArgumentException) {
println(e.message)
}
}
return lotto
}

private fun getBonusNumber(input: Input, lottoNumbers: List<Int>): Int {
var bonus: Int
while (true) {
try {
bonus = input.inputLottoBonusNumber(lottoNumbers)
break
} catch (e: IllegalArgumentException) {
println(e.message)
}
}
return bonus
}
}
30 changes: 30 additions & 0 deletions src/main/kotlin/lotto/LottoManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package lotto

import camp.nextstep.edu.missionutils.Randoms

class LottoManager {

private val _lottoes = mutableListOf<Lotto>()
val lottoes: List<Lotto>
get() = _lottoes

fun createLottoes(price: Int) {
val lottoNumbers = price / 1000
repeat(lottoNumbers) {
_lottoes.add(Lotto(getLotto()))
}
}

private fun getLotto(): MutableList<Int> {
return Randoms.pickUniqueNumbersInRange(1, 45, 6)
}

fun printLottoes(price: Int) {
val lottoNumbers = price / 1000
println("${lottoNumbers}개를 구매했습니다.")
lottoes.forEach { lotto ->
lotto.printLotto()
}
println()
}
}
32 changes: 32 additions & 0 deletions src/main/kotlin/lotto/exception/BonusValidation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package lotto.exception

class BonusValidation(private val lotto: List<Int>, private val bonus: String) {

init {
validateBonusRange()
validateBonusNumber()
validateBonusDuplicate()
}

private fun validateBonusRange() {
require(bonus.toInt() in 1..45) {
ErrorConstants.INVALID_LOTTO_RANGE_ERROR
}
}

private fun validateBonusNumber() {
try {
bonus.toInt()
} catch (e: NumberFormatException) {
throw IllegalArgumentException(ErrorConstants.INVALID_PRICE_FORMAT_ERROR)
}
}

private fun validateBonusDuplicate() {
repeat(lotto.size) {
require(lotto[it] != bonus.toInt()) {
ErrorConstants.DUPLICATE_LOTTO_ERROR
}
}
}
}
10 changes: 10 additions & 0 deletions src/main/kotlin/lotto/exception/ErrorConstants.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package lotto.exception

object ErrorConstants {
const val INVALID_PRICE_FORMAT_ERROR = "[ERROR] 숫자만 입력 가능합니다."
const val INVALID_PRICE_UNIT_ERROR = "[ERROR] 1,000원 단위의 값을 입력해주세요."
const val INVALID_PRICE_RANGE_ERROR = "[ERROR] 1,000원 이상의 값을 입력해주세요."
const val INVALID_LOTTO_FORMAT_ERROR = "[ERROR] 번호를 쉼표 기준으로 입력해주세요."
const val INVALID_LOTTO_RANGE_ERROR = "[ERROR] 1~45 사이의 숫자만 가능합니다."
const val DUPLICATE_LOTTO_ERROR = "[ERROR] 중복된 숫자는 입력할 수 없습니다."
}
42 changes: 42 additions & 0 deletions src/main/kotlin/lotto/exception/LottoValidation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package lotto.exception

class LottoValidation(private val lotto: String) {
private val input: List<String> = lotto.split(",")

init {
validateLottoComma()
validateLottoRange()
validateLottoNumber()
validateLottoDuplication()
}

private fun validateLottoComma() {
require(lotto.contains(",")) {
ErrorConstants.INVALID_LOTTO_FORMAT_ERROR
}
}

private fun validateLottoRange() {
repeat(input.size) {
require(input[it].toInt() in 1..45) {
ErrorConstants.INVALID_LOTTO_RANGE_ERROR
}
}
}

private fun validateLottoNumber() {
repeat(input.size) {
try {
input[it].toInt()
} catch (e: NumberFormatException) {
throw IllegalArgumentException(ErrorConstants.INVALID_PRICE_FORMAT_ERROR)
}
}
}

private fun validateLottoDuplication() {
require(input.toSet().size == input.size) {
ErrorConstants.DUPLICATE_LOTTO_ERROR
}
}
}
28 changes: 28 additions & 0 deletions src/main/kotlin/lotto/exception/PriceValidation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package lotto.exception

class PriceValidation(private val price: String) {

init {
validatePriceDigit()
validatePriceUnit()
validatePricePositive()
}

private fun validatePriceDigit() {
require(price.toIntOrNull() != null) {
ErrorConstants.INVALID_PRICE_FORMAT_ERROR
}
}

private fun validatePriceUnit() {
require(price.toInt() % 1000 == 0) {
ErrorConstants.INVALID_PRICE_UNIT_ERROR
}
}

private fun validatePricePositive() {
require(price.toInt() >= 1000) {
ErrorConstants.INVALID_PRICE_RANGE_ERROR
}
}
}
5 changes: 5 additions & 0 deletions src/main/kotlin/lotto/model/LottoType.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package lotto.model

enum class LottoType {
THREE, FOUR, FIVE, FIVE_BONUS, SIX
}