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

[로또] 김유정 미션 제출합니다. #188

Open
wants to merge 3 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
25 changes: 25 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 📚 3주차 미션 - 로또

## 구현할 기능 목록
### 공통
- 입력
- [x] 잘못 입력시 다시 입력받기
- 출력
- [x] 예외처리(IllegalArgumentException)
- [x] 에러 메세지 `[ERROR]` 붙여서 출력

### 1. 로또 구입해서 발행하기
- 입력
- [x] 1000 단위의 숫자
- 출력
- [x] 구매한 개수만큼 로또 발행

### 2. 당첨 번호와 보너스 번호 입력받기
- 입력
- [x] 쉼표로 구분된 중복없는 6개 숫자
- [x] 보너스 번호 1개 입력받기

### 3. 당첨 결과 출력하기
- 출력
- [x] 각 등수마다 당첨 개수 출력
- [x] 수익률 계산 후 출력
6 changes: 4 additions & 2 deletions src/main/kotlin/lotto/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package lotto

import lotto.controller.GameController

fun main() {
TODO("프로그램 구현")
}
GameController().start()
}
9 changes: 0 additions & 9 deletions src/main/kotlin/lotto/Lotto.kt

This file was deleted.

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

import camp.nextstep.edu.missionutils.Console
import lotto.global.InformationMessage
import lotto.service.LottoService
import lotto.service.WinningService
import lotto.service.RankService

class GameController {
private val lottoService = LottoService()
private val winningService = WinningService()
private val rankService = RankService()

fun start() {
println(InformationMessage.PURCHASE_AMOUNT.message)
purchase()

println("\n${InformationMessage.WINNING_NUMBER.message}")
winningNumber()

println("\n${InformationMessage.BONUS_NUMBER.message}")
bonusNumber()

println("\n${InformationMessage.WINNING_STATISTIC.message}")
checkLottoNumber()
}

private fun purchase() {
try {
val input = Console.readLine()
val count = lottoService.purchaseLotto(input)
println("\n$count${InformationMessage.PURCHASE_SUCCESS.message}")
lottoService.createLotto(count)
} catch (e: IllegalArgumentException) {
println(e.message)
purchase()
}
}

private fun winningNumber() {
try {
val input = Console.readLine()
winningService.winningNumber(input)
} catch (e: IllegalArgumentException) {
println(e.message)
winningNumber()
}
}

private fun bonusNumber() {
try {
val input = Console.readLine()
winningService.bonusNumber(input)
} catch (e: IllegalArgumentException) {
println(e.message)
bonusNumber()
}
}

private fun checkLottoNumber() {
val winningNumber = winningService.getLotto()
val bonusNumber = winningService.getBonus()
val lottos = lottoService.getLotto()

val matches = rankService.rateRank(winningNumber, bonusNumber, lottos)
println(InformationMessage.place(matches))

calculateReturn(matches)
}

private fun calculateReturn(matches: MutableList<Int>) {
val price = lottoService.getPrice()
println(InformationMessage.returnRate(rankService.calculateReturn(price, matches)))
}
}
7 changes: 7 additions & 0 deletions src/main/kotlin/lotto/global/Config.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package lotto.global

object Config {
const val LOTTO_RANGE = 45
const val NUMBER_DRAW = 6
const val LOTTO_PRICE = 1000
}
10 changes: 10 additions & 0 deletions src/main/kotlin/lotto/global/Error.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package lotto.global

enum class Error(val message: String) {
PURCHASE_AMOUNT("${Config.LOTTO_PRICE}원 단위의 숫자를 입력해주세요"),
NOT_NUMBER("숫자를 입력해주세요"),
NUMBER_RANGE("1~${Config.LOTTO_RANGE}의 숫자만 입력해주세요"),
NUMBER_NUMBER("${Config.NUMBER_DRAW}개의 숫자를 입력해주세요");

fun message() = "[ERROR] $message"
}
20 changes: 20 additions & 0 deletions src/main/kotlin/lotto/global/InformationMessage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package lotto.global

enum class InformationMessage(val message: String) {
PURCHASE_AMOUNT("구입금액을 입력해 주세요."),
PURCHASE_SUCCESS("개를 구매했습니다."),
WINNING_NUMBER("당첨 번호를 입력해 주세요."),
BONUS_NUMBER("보너스 번호를 입력해 주세요."),
WINNING_STATISTIC("당첨 통계\n---");

companion object {
fun place(numbers: MutableList<Int>) = "${WINNING_NUMBER.message}\n" +
"3개 일치 (5,000원) - ${numbers[4]}개\n" +
"4개 일치 (50,000원) - ${numbers[3]}개\n" +
"5개 일치 (1,500,000원) - ${numbers[2]}개\n" +
"5개 일치, 보너스 볼 일치 (30,000,000원) - ${numbers[1]}개\n" +
"6개 일치 (2,000,000,000원) - ${numbers[0]}개"

fun returnRate(percent: Double) = "총 수익률은 ${percent}%입니다."
}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/lotto/global/Prize.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package lotto.global

enum class Prize(val rank: Int, val amount: Int) {
FIRST(1, 2000000000),
SECOND(2, 30000000),
THIRD(3, 1500000),
FOURTH(4, 50000),
FIFTH(5, 5000);

fun calculation(number: Int) = amount * number

companion object {
private val map = Prize.values().associateBy { it.rank }
fun from(rank: Int) = Prize.values().first { it.rank == rank }
}
}
13 changes: 13 additions & 0 deletions src/main/kotlin/lotto/model/Lotto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package lotto.model

import lotto.global.Config

class Lotto(private val numbers: List<Int>) {
init {
require(numbers.size == Config.NUMBER_DRAW)
require(numbers.toSet().size == Config.NUMBER_DRAW)
numbers.forEach { require(it in 1..Config.LOTTO_RANGE) }
}

fun getLotto() = numbers
}
40 changes: 40 additions & 0 deletions src/main/kotlin/lotto/service/LottoService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package lotto.service

import camp.nextstep.edu.missionutils.Randoms
import lotto.global.Config
import lotto.global.Error
import lotto.model.Lotto

class LottoService {
private var price = Config.LOTTO_PRICE
private var lottos: MutableList<Lotto> = mutableListOf()

fun purchaseLotto(price: String): Int {
require(price.matches(Regex("^[0-9]*$"))) { Error.NOT_NUMBER.message() }
require(
(price.toDouble() / Config.LOTTO_PRICE).toString().matches(Regex("^[0-9]+.0$"))
) { Error.PURCHASE_AMOUNT.message() }
this.price = price.toInt()
return this.price / Config.LOTTO_PRICE
}

fun createLotto(count: Int) {
for (i in 0..<count) {
val random = makeRandomNumber()
println(random)
lottos.add(Lotto(random))
}
}

private fun makeRandomNumber(): MutableList<Int> {
return Randoms.pickUniqueNumbersInRange(1, Config.LOTTO_RANGE, Config.NUMBER_DRAW)
}

fun getPrice(): Int {
return price
}

fun getLotto(): MutableList<Lotto> {
return lottos
}
}
47 changes: 47 additions & 0 deletions src/main/kotlin/lotto/service/RankService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package lotto.service

import lotto.global.Prize
import lotto.model.Lotto
import kotlin.math.round

class RankService {
fun rateRank(
winningNumber: MutableSet<Int>,
bonusNumber: Int,
lottos: MutableList<Lotto>
): MutableList<Int> {
val matches: MutableList<Int> = mutableListOf(0, 0, 0, 0, 0)

lottos.forEach { it: Lotto ->
when (checkSameNumber(it.getLotto(), winningNumber)) {
3 -> matches[4]++
4 -> matches[3]++
5 -> if (!it.getLotto().contains(bonusNumber)) {
matches[2]++
} else {
matches[1]++
}

6 -> matches[0]++
}
}
return matches
}

fun checkSameNumber(numbers: List<Int>, winningNumber: MutableSet<Int>): Int {
var matchCount = 0
for (number in numbers) {
if (winningNumber.contains(number)) {
matchCount++
}
}
return matchCount
}

fun calculateReturn(price: Int, matches: MutableList<Int>): Double {
var totalPrize = 0
for (i in 1..5) totalPrize += Prize.from(i).calculation(matches[i - 1])
val d = totalPrize.toDouble() / price.toDouble() * 100
return round(d * 100) / 100
}
}
42 changes: 42 additions & 0 deletions src/main/kotlin/lotto/service/WinningService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package lotto.service

import lotto.global.Config
import lotto.global.Error

class WinningService {
private var lottoNumber: MutableSet<Int> = mutableSetOf()
private var bonusNumber: Int = 0

fun winningNumber(winningNumber: String) {
winningNumber.split(",").forEach {
val number = try {
it.toInt()
} catch (e: NumberFormatException) {
throw IllegalArgumentException(Error.NOT_NUMBER.message())
}
require(number in (1..Config.LOTTO_RANGE)) { Error.NUMBER_RANGE.message() }
lottoNumber.add(number)
}
require(lottoNumber.size == 6) { Error.NUMBER_NUMBER.message() }

lottoNumber = lottoNumber.toSortedSet()
}

fun bonusNumber(bonusNumber: String) {
val number = try {
bonusNumber.toInt()
} catch (e: NumberFormatException) {
throw IllegalArgumentException(Error.NOT_NUMBER.message())
}
require(number in (1..Config.LOTTO_RANGE)) { Error.NUMBER_RANGE.message() }
this.bonusNumber = number
}

fun getLotto(): MutableSet<Int> {
return lottoNumber
}

fun getBonus(): Int {
return bonusNumber
}
}
1 change: 1 addition & 0 deletions src/test/kotlin/lotto/LottoTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package lotto

import lotto.model.Lotto
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows

Expand Down
24 changes: 24 additions & 0 deletions src/test/kotlin/lotto/service/LottoServiceTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package lotto.service

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows

class LottoServiceTest {
@Test
fun `로또 구입 금액이 1000 단위의 숫자가 아니면 ERROR`() {
assertThrows<IllegalArgumentException> {
LottoService().purchaseLotto("300")
}
assertThrows<IllegalArgumentException> {
LottoService().purchaseLotto("3000d")
}
}

@Test
fun `구입 금액에 따른 로또 개수 확인`() {
val input = "123000"
val result = 123
assertThat(LottoService().purchaseLotto(input)).isEqualTo(result)
}
}
28 changes: 28 additions & 0 deletions src/test/kotlin/lotto/service/RankServiceTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package lotto.service

import lotto.model.Lotto
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

class RankServiceTest {
@Test
fun `로또 당첨 확인`() {
val input = RankService().rateRank(WINNING_NUMBER, BONUS_NUMBER, FIRST)
val result = mutableListOf(1, 0, 0, 0, 0)
assertThat(input).isEqualTo(result)
}

@Test
fun `로또 당첨 확인 2등`() {
val input = RankService().rateRank(WINNING_NUMBER, BONUS_NUMBER, SECOND)
val result = mutableListOf(0, 1, 0, 0, 0)
assertThat(input).isEqualTo(result)
}

companion object {
private val WINNING_NUMBER = mutableSetOf(1, 2, 3, 4, 5, 6)
private const val BONUS_NUMBER = 7
private val FIRST = mutableListOf(Lotto(listOf(1, 2, 3, 4, 5, 6)))
private val SECOND = mutableListOf(Lotto(listOf(1, 2, 3, 4, 5, 7)))
}
}
Loading