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

[로또] 조민지 미션 제출합니다. #184

Open
wants to merge 8 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
48 changes: 48 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# 📌 미션- 로또
- 사용자가 요구하는 수량의 로또를 발행하고, 발행한 로또를 당첨번호와 비교하여 당첨통계 및 수익률을 고지하는 프로젝트
---
# 🔷 기능 정의서

## view
### - Input
- 로또 구입 금액을 입력받는다.
- 1000단위가 아니면 예외처리
- 0 또는 음수일 경우 예외처리
- 문자열 입력 시 예외처리
- 당첨번호를 입력받는다.
- 중복된 숫자 있으면 예외처리
- 1 ~ 45 가 아니면 예외처리
- 문자열 입력 시 예외처리
- 입력된 숫자가 6개가 아니면 예외처리
- 각 숫자는 , 로 구분
- 보너스 번호를 입력 받는다.
- 당첨 번호와 중복되면 예외처리
- 1 ~ 45 가 아니면 예외처리
- 문자열 입력 시 예외처리

### - Output
- '구입 금액 입력해주세요' 문구
- 'n개를 구매했습니다.'구입한 수량 문구
- 발행된 로또 번호 출력
- '당첨 번호를 입력해주세요.' 문구
- '보너스 번호를 입력해주세요.' 문구
- 당첨 내역 출력
- 수익률은 소수점 둘째 자리에서 반올림

- 예외 상황 시 '[ERROR]'로 시작하는 에러 문구

---

##
- 사용자가 지불한 금액에 해당하는 로또 발행 수량 반환
- 로또 발행기
- 입력 받은 수량만큼 로또 발행
- 로또 번호 생성기
- 중복되지 않는 수 6개 + 보너스 번호 1개
- 1~45 사이의 랜덤 숫자 발행기
- 중복되는 숫자는 예외처리
- 당첨 번호와 발행 번호 비교기
- 몇 개가 일치하는지 계산
- 등수 계산
- 수익률 계산
- 입력값 검증
7 changes: 6 additions & 1 deletion src/main/kotlin/lotto/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package lotto

import lotto.controller.Controller

fun main() {
TODO("프로그램 구현")

val controller = Controller()
controller.start()

}
9 changes: 0 additions & 9 deletions src/main/kotlin/lotto/Lotto.kt

This file was deleted.

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

import lotto.domain.Lotto
import lotto.domain.LottoSalesOffice
import lotto.domain.WinnerDecider
import lotto.view.InputView
import lotto.view.OutputView

class Controller {

private val inputView = InputView()
private val outputView = OutputView()
fun start() {
val userLottos = buyLotto()
showUserLottos(userLottos)
showResultBoard(userLottos)


}

private fun buyLotto(): List<Lotto> {
val lottoSalesOffice = LottoSalesOffice()
return lottoSalesOffice.sellLotto(inputMoney().toInt())
}

private fun inputMoney(): String {
outputView.printInputMoney()
return inputView.readInput()
}

private fun showUserLottos(lottos: List<Lotto>) {
for (lotto in lottos) {
println(lotto.showLotto())
}
}


private fun inputWinningLottoNumbers(): String {
outputView.printInputWinningNumbers()
return inputView.readInput()
}

private fun inputBonusNumber(): String {
outputView.printInputBonusNumber()
return inputView.readInput()
}

private fun showResultBoard(userLottos: List<Lotto>) {
val winningLotto = inputWinningLottoNumbers()
val bonusNumber = inputBonusNumber()
val winnerDecider = WinnerDecider(winningLotto, bonusNumber,userLottos)
winnerDecider.makeJudgement()

outputView.printResultBoardHeader()
}

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

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

fun showLotto() = numbers.addCommaAndBracket()

fun compareToBonus(bonus: Int): Boolean = numbers.contains(bonus)

fun comparetoTarget(target: List<Int>): Int {
var count = 0

for (number in numbers) {
if (number in target) {
count++
}
}
return count
}
private fun List<Int>.addCommaAndBracket(): String {
val formatIssuedLotto = this.joinToString(",") { it.toString() }
return "[$formatIssuedLotto]"
}


companion object {
const val MIN_NUMBER = 1
const val MAX_NUMBER = 45
const val LOTTO_LENGTH = 6
const val SINGLE_LOTTO_PRICE = 1000

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

import lotto.validator.Validator

class LottoSalesOffice {

fun sellLotto (money : Int) : List<Lotto> {
Validator(money)
val quantity = money/1000
val lottos = mutableListOf<Lotto>()

repeat(quantity){
val lotto = RandomGenerator().generate()
lottos.add(lotto)
}

return lottos
}



companion object {
private const val SINGLE_LOTTO_PRICE = 1000
}

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

import camp.nextstep.edu.missionutils.Randoms

class RandomGenerator {

fun generate(): Lotto {
val numbers = Randoms.pickUniqueNumbersInRange(
Lotto.MIN_NUMBER,
Lotto.MAX_NUMBER,
Lotto.LOTTO_LENGTH
)
return Lotto(numbers)
}

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

import kotlin.collections.*

class WinnerDecider(
private val winningLottoNumbers: String,
private val bonus: String,
private val userLottos: List<Lotto>
) {

init {
setWinningCount(winningCount)
}
fun makeJudgement() {
val targetNumbers = parseNumbers()
val bonusNumber = parseBonusNumber()
for (lotto in userLottos) {
val matchCount=lotto.comparetoTarget(targetNumbers)
val hasBonusNumber=lotto.compareToBonus(bonusNumber)
calculateRank(matchCount,hasBonusNumber)
}
}

private fun setWinningCount(winningCount : MutableMap<Int,Int>){
winningCount.put(FIRST, COUNT)
winningCount.put(SECOND,COUNT)
winningCount.put(THIRD,COUNT)
winningCount.put(FOURTH,COUNT)
winningCount.put(FIFTH,COUNT)
winningCount.put(NONE,COUNT)

}
private fun calculateRank(matchCount:Int, hasBonusNumber : Boolean){
when (matchCount) {
6 -> winningCount.replace(FIRST,winningCount.getValue(FIRST)+1)
5 -> if(hasBonusNumber) {winningCount.replace(SECOND,winningCount.getValue(SECOND)+1)}
else{winningCount.replace(THIRD,winningCount.getValue(THIRD)+1)}
4 -> winningCount.replace(FOURTH,winningCount.getValue(FOURTH)+1)
3 -> winningCount.replace(FIFTH,winningCount.getValue(FIFTH)+1)
else -> winningCount.replace(NONE,winningCount.getValue(NONE)+1)
}
}

private fun calculateRateOfReturn() {

}

private fun parseNumbers(): List<Int> {
return winningLottoNumbers.split(',').map { it.toInt() }
}

private fun parseBonusNumber(): Int {
return bonus.toInt()
}

companion object {
private const val COUNT = 0
private const val FIRST = 1
private const val SECOND = 2
private const val THIRD = 3
private const val FOURTH = 4
private const val FIFTH = 5
private const val NONE = -999

val winningCount = mutableMapOf<Int, Int>()

}

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

import lotto.domain.Lotto.Companion.SINGLE_LOTTO_PRICE

class Validator (number : Int){

init {
validateNumber(number)
validateThousandMoney(number)
validateZeroOrNegative(number)
validateTooManyLotto(number)
}

private fun validateNumber(money: Int) {
require(money.toString().toIntOrNull() != null) { NOT_NUMBER_ERROR }
}

private fun validateThousandMoney(money: Int) {
require(money % SINGLE_LOTTO_PRICE == 0) { THOUSAND_UNIT_ERROR }
}

private fun validateZeroOrNegative(money: Int) {
require(money > 0) { ZERO_NEGATIVE_ERROR }
}

private fun validateTooManyLotto (money: Int) {
require(money < MAX_MONEY) {TOO_MANY_LOTTO_ERROR}
}

companion object {
private const val NOT_NUMBER_ERROR = "숫자만 입력할 수 있습니다."
private const val THOUSAND_UNIT_ERROR = "1000원 단위의 금액만 입력할 수 있습니다."
private const val ZERO_NEGATIVE_ERROR = "1000원 단위의 양수의 금액만 입력할 수 있습니다."
private const val MAX_MONEY = 50000
private const val TOO_MANY_LOTTO_ERROR = "로또는 한번에 최대 50개까지 구매 가능합니다."
}
}
10 changes: 10 additions & 0 deletions src/main/kotlin/lotto/view/InputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package lotto.view

import camp.nextstep.edu.missionutils.Console
class InputView {

fun readInput(): String = Console.readLine().trim()

fun finish() = Console.close()

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

class OutputView {

fun printInputMoney() = println(Message.InputMoney)

fun printQuantityPurchased(quantity: Int) = println(format(Message.QuantityPurchased, quantity))

fun printInputWinningNumbers() = println(Message.InputWinningNumbers)

fun printInputBonusNumber() = println(Message.InputBonusNumber)

fun printResultBoardHeader() = println(Message.ResultBoardHeader)

fun printRank(number : Int) = println(format(Message.RankForm,number))

fun printPrizeMoneyAndCount( prize : Int, number : Int) = println(format(Message.PrizeMoneyAndCountForm,prize,number))

fun printBonusBallMatch() = println(Message.BonusBallMatch)

fun printRateOfReturn(rate : Int) = println(format(Message.RateOfReturn,rate))

fun printError() = println(Message.Error)


private fun format(message: Message, vararg any: Any): String = message.toString().format(any)


private enum class Message(private val message: String) {
InputMoney("구입금액을 입력해 주세요."),
QuantityPurchased("%d개를 구매했습니다."),
InputWinningNumbers("당첨 번호를 입력해 주세요."),
InputBonusNumber("보너스 번호를 입력해 주세요."),
ResultBoardHeader("당첨 통계 \n---"),
RankForm("%d개 일치"),
PrizeMoneyAndCountForm(" (%s원) - %d개"),
BonusBallMatch(", 보너스 볼 일치"),
RateOfReturn("총 수익률은 %.1f%입니다."),
Error("[ERROR]");

override fun toString(): String = message
}
}
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.domain.Lotto
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows

Expand Down