From c6a5be26956bfc43fcca3e9c26053be1e85348d5 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Thu, 31 Oct 2024 23:36:22 +0900 Subject: [PATCH 01/41] =?UTF-8?q?docs:=20README=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 프로젝트 개요 2. 프로젝트 흐름 3. 기능 요구사항 4. 프로그래밍 요구사항 5. 기능 목록 6. 오류 처리 7. 테스트 --- README.md | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fc0ae874..537b1969f 100644 --- a/README.md +++ b/README.md @@ -1 +1,173 @@ -# kotlin-lotto-precourse +# 3주차 로또 +## 프로젝트 개요 +사용자가 돈을 낸만큼 로또를 발행하고, 당첨 번호를 입력하여 발행된 로또에서 몇개가 당첨됐는지 또 수익률이 몇 퍼센트인지 당첨 통계를 내주는 프로그램 + +## 프로젝트 흐름 +1. 사용자가 금액을 제시하면 해당 금액에 맞게 로또를 구매한다. +2. 사용자는 1~45까지의 중복되지 않는 6개 숫자로 이루어진 로또 당첨 번호를 쉼표(,) 기준으로 제출한다. +3. 이후 제출한 6개의 숫자와 중복되지 않는 보너스 번호를 제출한다. +4. 구매한 로또의 개수의 따라 로또를 발행한다. +5. 발행한 로또의 개수와 로또 번호를 보여준다. +6. 제출 했던 당첨 번호(보너스 번호 포함)와 발행된 로또들과의 당첨 여부를 확인한다. +7. 번호가 몇 개 일치 했는가에 따라 당첨 내역을 출력한다. +8. 당첨 금액과 로또 구매 금액의 비율로 수익률을 구하고 출력한다. + +## 기능 요구 사항 +### 입력 +- 로또 구입 금액 + - 1,000 단위로 입력 + - 1,000으로 나눠 떨어지지 않으면 **예외 처리** +- 로또 번호 + - 번호는 쉼표로 구분 + - 1에서 45까지 중복이 없는 6개의 자연수 +- 보너스 번호 + - 1에서 45까지 당첨 번호와 중복이 없는 자연수 하나 + +### 출력 +- 발행 로또 정보 + - 로또의 수량 + - 오름차순으로 정렬된 로또 번호 +- 당첨 내역 출력 + - 일치 번호가 3개부터 6개까지 몇 개인지 상금과 함께 출력 + - 5개 일치의 경우 + - 2등: 보너스 번호가 일치 + - 3등: 보너스 번호가 불일치 +- 수익률 + - 소수점 둘째 자리에서 반올림한 총 수익률 + +### 예외 상황 +- 예외 상황 시 에러 문구를 출력하고 그 부분부터 입력을 다시 받음 + - `Exception`이 아닌 `IllegalArgumentException`, `IllegalStateException` 등과 같은 명확한 유형으로 처리 + +### 실행 결과 예시 +``` +구입금액을 입력해 주세요. +8000 + +8개를 구매했습니다. +[8, 21, 23, 41, 42, 43] +[3, 5, 11, 16, 32, 38] +[7, 11, 16, 35, 36, 44] +[1, 8, 11, 31, 41, 42] +[13, 14, 16, 38, 42, 45] +[7, 11, 30, 40, 42, 43] +[2, 13, 22, 32, 38, 45] +[1, 3, 5, 14, 22, 45] + +당첨 번호를 입력해 주세요. +1,2,3,4,5,6 + +보너스 번호를 입력해 주세요. +7 + +당첨 통계 +--- +3개 일치 (5,000원) - 1개 +4개 일치 (50,000원) - 0개 +5개 일치 (1,500,000원) - 0개 +5개 일치, 보너스 볼 일치 (30,000,000원) - 0개 +6개 일치 (2,000,000,000원) - 0개 +총 수익률은 62.5%입니다. +``` + +## 프로그래밍 요구 사항 +- 제한 사항 + - `indent depth`는 2까지 허용 + - `method`는 한가지 일만 수행 + - 15라인을 넘기지 않도록 구현 + - 프로그램 실행 시작점은 `Application`의 `main()` + - 프로그램 종료 시 `System.exit()`나 `exitProcess()`를 호출하지 않음 +- 적용 사항 + - `enum class` 적용 + - 주어진 `Lotto class` 사용 + - `number`이외 필드는 추가 불가 + - `number`의 접근 제어자는 `private`로 고정 + - 패키지는 변경 가능 +- 지향 사항 + - `else`사용은 지양 + - `if` 조건절에서 값을 `return`하는 방식으로 구현 + - 테스트는 기능 단위로 작성 + - UI로직은 제외(System.out, System.in, Scanner) + +## 기능 목록 +### 입력 +- 구입 금액 + - 숫자로 입력 +- 로또 번호 + - 쉼표(,)로 연결된 1~45 사이의 6개의 서로 다른 자연수 입력 +- 보너스 번호 + - 1~45 사이의 당첨 번호와 중복이 없는 자연수 하나 + +### 로또 발행 +- 로또의 수량 + - (입력된 금액 // 1000)개 +- 로또 발행 + - 1~45 사이의 6개의 서로 다른 자연수를 난수로 생성 + - `Randoms.pickUniqueNumbersInRange(1, 45, 6)` + - 로또의 수량 만큼 반복 + +### 당첨 통계 +- 당첨 번호 확인 + - 발행된 로또의 번호와 입력한 로또 번호를 비교 + - 일치 번호의 개수에 따라 당첨 등수의 개수 확인 + - 5개가 일치할 경우 + - 남은 한개의 숫자와 입력한 보너스 번호 비교 + - 두 수가 다를 경우: 3등 + - 두 수가 같을 경우: 2등 +- 수익률 + - (총 당첨액 / 총 구매액) * 100을 소수점 둘째 자리에서 반올림 한 % + - 총 당첨액 + - (당첨 금액 * 당첨 갯수)를 모두 더한 값 + - 3개 일치: 5,000 + - 4개 일치: 50,000 + - 5개 일치 + - 3등: 1,500,000 + - 2등: 30,000,000 + - 6개 일치: 2,000,000,000 + - 총 구매액: 입력 구입 금액 + +## 오류 처리 +- 구입 금액 + - 숫자로 입력 + - 숫자가 아닐 경우: "[ERROR] 구입 금액은 숫자여야 합니다." + - 1,000으로 나눠 떨어지지 않을 경우: "[ERROR] 구입 금액은 1,000원 단위여야 합니다." + - 10억원을 넘길 경우: "[ERROR] 구입 금액은 1억원 이하여야 합니다." +- 로또 번호 + - 쉼표(,)로 연결된 1~45 사이의 6개의 서로 다른 자연수 입력 + - 쉼표로 연결 되지 않을 경우: "[ERROR] 로또 번호는 쉼표로 구분해야 합니다." + - 1~45 사이의 수가 아닐 경우: "[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다." + - 6개가 아닐 경우: "[ERROR] 로또 번호는 6개여야 합니다." + - 서로 다르지 않을 경우: "[ERROR] 로또 번호는 중복될 수 없습니다." + - 자연수가 아닐 경우: "[ERROR] 로또 번호는 자연수여야 합니다." +- 보너스 번호 + - 1~45 사이의 당첨 번호와 중복이 없는 자연수 하나 + - 1~45 사이의 수가 아닐 경우: "[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다." + - 당첨 번호와 중복이 있을 경우: "[ERROR] 보너스 번호는 로또 번호와 중복될 수 없습니다." + - 자연수가 아닐 경우: "[ERROR] 보너스 번호는 자연수여야 합니다." + - 하나의 숫자가 아닐 경우: "[ERROR] 보너스 번호는 하나여야 합니다." + +## 테스트 +- 당첨 통계 + - 당첨 번호 확인 + - [ ] 당첨된 로또 분류 기능 + - [ ] 보너스 번호에 따른 2등과 3등 구분 + - 수익률 + - [ ] 총 당첨액 계산 + - [ ] 수익률 계산(소수점 둘째자리에서 반올림) + +- 예외 상황 테스트 + - 구입 금액 + - [ ] 숫자가 아닐 경우 + - [ ] 1,000으로 나눠 떨어지지 않을 경우 + - [ ] 10억을 넘길 경우 + - 로또 번호 + - [ ] 쉼표로 연결 되지 않을 경우 + - [ ] 1~45 사이의 수가 아닐 경우 + - [ ] 6개가 아닐 경우 + - [ ] 서로 다르지 않을 경우 + - [ ] 자연수가 아닐 경우 + - 보너스 번호 + - [ ] 1~45 사이의 수가 아닐 경우 + - [ ] 당첨 번호와 중복이 있을 경우 + - [ ] 자연수가 아닐 경우 + - [ ] 하나의 숫자가 아닐 경우 \ No newline at end of file From 6c413a6f9b622cb9ec1b62988f3f83240007fc32 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Fri, 1 Nov 2024 16:29:22 +0900 Subject: [PATCH 02/41] =?UTF-8?q?feat:=20=EA=B5=AC=EC=9E=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1,=20=EB=A1=9C=EB=98=90=20=EB=B0=9C=ED=96=89=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 사용자에게 입력을 받는 InputView 생성 - 반복되는 Console.readLine()과 println()을 기능별로 나눔 2. LottoFactory를 통해 로또를 생성 - 투입한 금액에 대한 정보 제공 - 생성될 로또의 개수에 대한 정보 제공 - 로또 생성 - 투입 금액에 대한 검증 --- src/main/kotlin/lotto/model/LottoFactory.kt | 46 +++++++++++++++++++++ src/main/kotlin/lotto/view/InputView.kt | 23 +++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/main/kotlin/lotto/model/LottoFactory.kt create mode 100644 src/main/kotlin/lotto/view/InputView.kt diff --git a/src/main/kotlin/lotto/model/LottoFactory.kt b/src/main/kotlin/lotto/model/LottoFactory.kt new file mode 100644 index 000000000..30523b747 --- /dev/null +++ b/src/main/kotlin/lotto/model/LottoFactory.kt @@ -0,0 +1,46 @@ +package lotto.model + +import camp.nextstep.edu.missionutils.Randoms + +// 로또를 발행하는 역할(로또 생성) +// 구입금액을 통해 로또를 발행 -> 발행된 로또 +// 구입금액 제공 +class LottoFactory(private val purchaseAmountInput: String) { + val purchaseAmount: Int + val lottoQuantity: Int + + init { + purchaseAmount = getValidatePurchaseAmount() + lottoQuantity = purchaseAmount / 1000 + } + + private fun createNumber(): List { + val randomNumbers = Randoms.pickUniqueNumbersInRange(1, 45, 6) + return randomNumbers + } + + fun createLotto(): List { + val lottoList: MutableList = emptyList().toMutableList() + repeat(lottoQuantity) { + val numbers = createNumber() + val lotto = Lotto(numbers) + lottoList.add(lotto) + } + return lottoList + } + + private fun getValidatePurchaseAmount(): Int { + validatePurchaseAmount() + val validatedPurchaseAmount = purchaseAmountInput.trim().toInt() + return validatedPurchaseAmount + } + + private fun validatePurchaseAmount() { + require(purchaseAmountInput.isNotEmpty()) { "[ERROR] 구입 금액은 빈 값이 될 수 없습니다." } + + val amount = purchaseAmountInput.trim().toIntOrNull() + require(amount != null) { "[ERROR] 구입 금액은 숫자여야 합니다." } + require(amount % 1000 == 0) { "[ERROR] 구입 금액은 1,000원 단위여야 합니다." } + require(amount <= 1000000000) { "[ERROR] 구입 금액은 1억원 이하여야 합니다." } + } +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/view/InputView.kt b/src/main/kotlin/lotto/view/InputView.kt new file mode 100644 index 000000000..90187e60b --- /dev/null +++ b/src/main/kotlin/lotto/view/InputView.kt @@ -0,0 +1,23 @@ +package lotto.view + +import camp.nextstep.edu.missionutils.Console + +class InputView { + private fun getInput(message: String): String { + println(message) + val input = Console.readLine() + return input + } + + fun close() = Console.close() + + fun getPurchaseAmount(): String = getInput(PURCHASE_AMOUNT_INPUT) + fun getWinningNumber(): String = getInput(WINNING_NUMBER_INPUT) + fun getBonusNumber(): String = getInput(BONUS_NUMBER_INPUT) + + companion object { + const val PURCHASE_AMOUNT_INPUT = "구입금액을 입력해 주세요." + const val WINNING_NUMBER_INPUT = "당첨 번호를 입력해 주세요." + const val BONUS_NUMBER_INPUT = "보너스 번호를 입력해 주세요." + } +} \ No newline at end of file From 05b99184cbdfe840a02b20a3483684e90dc56f44 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Fri, 1 Nov 2024 16:31:04 +0900 Subject: [PATCH 03/41] =?UTF-8?q?docs:=20=EA=B5=AC=EC=9E=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1,=20=EB=A1=9C=EB=98=90=20=EB=B0=9C=ED=96=89=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=EB=AA=A9=EB=A1=9D=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기능 목록 1. 입력 : 숫자로 입력 2. 로또 발행 전체 완료 --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 537b1969f..3b282657e 100644 --- a/README.md +++ b/README.md @@ -92,31 +92,31 @@ ## 기능 목록 ### 입력 - 구입 금액 - - 숫자로 입력 + - [X] 숫자로 입력 - 로또 번호 - - 쉼표(,)로 연결된 1~45 사이의 6개의 서로 다른 자연수 입력 + - [ ] 쉼표(,)로 연결된 1~45 사이의 6개의 서로 다른 자연수 입력 - 보너스 번호 - - 1~45 사이의 당첨 번호와 중복이 없는 자연수 하나 + - [ ] 1~45 사이의 당첨 번호와 중복이 없는 자연수 하나 ### 로또 발행 - 로또의 수량 - - (입력된 금액 // 1000)개 + - [X] (입력된 금액 // 1000)개 - 로또 발행 - - 1~45 사이의 6개의 서로 다른 자연수를 난수로 생성 + - [X] 1~45 사이의 6개의 서로 다른 자연수를 난수로 생성 - `Randoms.pickUniqueNumbersInRange(1, 45, 6)` - - 로또의 수량 만큼 반복 + - [X] 로또의 수량 만큼 반복 ### 당첨 통계 - 당첨 번호 확인 - - 발행된 로또의 번호와 입력한 로또 번호를 비교 + - [ ] 발행된 로또의 번호와 입력한 로또 번호를 비교 - 일치 번호의 개수에 따라 당첨 등수의 개수 확인 - 5개가 일치할 경우 - 남은 한개의 숫자와 입력한 보너스 번호 비교 - - 두 수가 다를 경우: 3등 - - 두 수가 같을 경우: 2등 + - [ ] 두 수가 다를 경우: 3등 + - [ ] 두 수가 같을 경우: 2등 - 수익률 - - (총 당첨액 / 총 구매액) * 100을 소수점 둘째 자리에서 반올림 한 % - - 총 당첨액 + - [ ] (총 당첨액 / 총 구매액) * 100을 소수점 둘째 자리에서 반올림 한 % + - [ ] 총 당첨액 - (당첨 금액 * 당첨 갯수)를 모두 더한 값 - 3개 일치: 5,000 - 4개 일치: 50,000 From 56a393d822d2af0c20701066b362887cc62efd40 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Fri, 1 Nov 2024 21:05:17 +0900 Subject: [PATCH 04/41] =?UTF-8?q?feat:=20=EB=8B=B9=EC=B2=A8=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=ED=99=95=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Lotto class를 이용해 Lotto 번호, 로또 당첨 등수, 로또 숫자에 대한 유효성 검증를 제공 2. 로또 번호가 5개 일치할 경우 보너스 숫자 포함 여부에 따라 2등과 3등을 구분 --- src/main/kotlin/lotto/Lotto.kt | 9 ------ src/main/kotlin/lotto/model/Lotto.kt | 45 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 9 deletions(-) delete mode 100644 src/main/kotlin/lotto/Lotto.kt create mode 100644 src/main/kotlin/lotto/model/Lotto.kt diff --git a/src/main/kotlin/lotto/Lotto.kt b/src/main/kotlin/lotto/Lotto.kt deleted file mode 100644 index b97abc385..000000000 --- a/src/main/kotlin/lotto/Lotto.kt +++ /dev/null @@ -1,9 +0,0 @@ -package lotto - -class Lotto(private val numbers: List) { - init { - require(numbers.size == 6) { "[ERROR] 로또 번호는 6개여야 합니다." } - } - - // TODO: 추가 기능 구현 -} diff --git a/src/main/kotlin/lotto/model/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt new file mode 100644 index 000000000..7d66345bc --- /dev/null +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -0,0 +1,45 @@ +package lotto.model + +import lotto.util.LottoNumberValidator + +// 로또 번호의 에러 체크 +// 로또 번호 제공 +// 로또 당첨 여부확인 +// 로또 보너스 번호 체크 +class Lotto(private val numbers: List) { + init { + validateLottoNumber(numbers) + } + + fun getLottoNumber(): List = numbers + + fun getLottoRank(winningNumber: List, bonusNumber: Int): Int { + val matchedCount = numbers.count { number -> number in winningNumber } + val lottoRank = determineRank(matchedCount, bonusNumber) + return lottoRank + } + + private fun determineRank(matchedCount: Int, bonusNumber: Int): Int { + val lottoRank = when (matchedCount) { + 6 -> 1 + 5 -> determineSecondRank(bonusNumber) + 4 -> 4 + 3 -> 5 + else -> 0 + } + return lottoRank + } + + private fun determineSecondRank(bonusNumber: Int): Int { + if (bonusNumber in numbers) { + return 2 + } + return 3 + } + + private fun validateLottoNumber(numbers: List) { + LottoNumberValidator.validateLottoNumberCount(numbers) + LottoNumberValidator.validateLottoNumberRange(numbers) + LottoNumberValidator.validateLottoNumberUniqueness(numbers) + } +} From 039949740b947ad4c118da1fa7bcd3ad19389941 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Fri, 1 Nov 2024 21:07:56 +0900 Subject: [PATCH 05/41] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=8B=B9?= =?UTF-8?q?=EC=B2=A8=EB=B2=88=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F=20?= =?UTF-8?q?=EB=B3=B4=EB=84=88=EC=8A=A4=20=EB=B2=88=ED=98=B8=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 로또 당첨번호와 보너스 번호 입력 UI 추가 --- src/main/kotlin/lotto/view/InputView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/lotto/view/InputView.kt b/src/main/kotlin/lotto/view/InputView.kt index 90187e60b..fe7da0045 100644 --- a/src/main/kotlin/lotto/view/InputView.kt +++ b/src/main/kotlin/lotto/view/InputView.kt @@ -17,7 +17,7 @@ class InputView { companion object { const val PURCHASE_AMOUNT_INPUT = "구입금액을 입력해 주세요." - const val WINNING_NUMBER_INPUT = "당첨 번호를 입력해 주세요." - const val BONUS_NUMBER_INPUT = "보너스 번호를 입력해 주세요." + const val WINNING_NUMBER_INPUT = "\n당첨 번호를 입력해 주세요." + const val BONUS_NUMBER_INPUT = "\n보너스 번호를 입력해 주세요." } } \ No newline at end of file From 5097ba81ce47629a08b741c433b78c0b1329a19d Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Fri, 1 Nov 2024 21:08:55 +0900 Subject: [PATCH 06/41] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=B0=9C?= =?UTF-8?q?=ED=96=89=EC=8B=9C=20=EB=A1=9C=EB=98=90=20=EC=88=AB=EC=9E=90?= =?UTF-8?q?=EB=A5=BC=20=EC=98=A4=EB=A6=84=EC=B0=A8=EC=88=9C=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=95=EB=A0=AC=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 기존 로또 발행시 정렬이 안되있었는데 오름차순으로 정렬 --- src/main/kotlin/lotto/model/LottoFactory.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/lotto/model/LottoFactory.kt b/src/main/kotlin/lotto/model/LottoFactory.kt index 30523b747..aecc15861 100644 --- a/src/main/kotlin/lotto/model/LottoFactory.kt +++ b/src/main/kotlin/lotto/model/LottoFactory.kt @@ -15,7 +15,7 @@ class LottoFactory(private val purchaseAmountInput: String) { } private fun createNumber(): List { - val randomNumbers = Randoms.pickUniqueNumbersInRange(1, 45, 6) + val randomNumbers = Randoms.pickUniqueNumbersInRange(1, 45, 6).sorted() return randomNumbers } From 2575435fb0ebf00f7b0e62decf4ab0bf2d93a104 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Fri, 1 Nov 2024 21:11:54 +0900 Subject: [PATCH 07/41] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=8B=B9?= =?UTF-8?q?=EC=B2=A8=20=EA=B2=B0=EA=B3=BC=EC=99=80=20=EC=88=98=EC=9D=B5?= =?UTF-8?q?=EB=A5=A0=20=EA=B3=84=EC=82=B0=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 발행된 로또를 통해 당첨된 로또가 몇개인지, 총 당첨액이 얼마인지, 로또의 총 수익률이 몇 퍼센트인지 계산해주는 LottoResultCalculator 추가 2. 로또 한장의 결과를 저장하는 LottoResult 추가 --- .../lotto/model/LottoResultCalculator.kt | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/main/kotlin/lotto/model/LottoResultCalculator.kt diff --git a/src/main/kotlin/lotto/model/LottoResultCalculator.kt b/src/main/kotlin/lotto/model/LottoResultCalculator.kt new file mode 100644 index 000000000..f8935e684 --- /dev/null +++ b/src/main/kotlin/lotto/model/LottoResultCalculator.kt @@ -0,0 +1,63 @@ +package lotto.model + +class LottoResultCalculator(private val lotteries: List) { + fun getLottoResults(winningNumbers: List, bonusNumber: Int): List { + val lotteriesRank = calculateRanks(winningNumbers, bonusNumber) + val rankWithCounts = countRank(lotteriesRank) + val lottoResults = mapToResult(rankWithCounts) + + return lottoResults + } + + private fun calculateRanks(winningNumbers: List, bonusNumber: Int): List { + val lotteriesRank = lotteries.map { lotto -> lotto.getLottoRank(winningNumbers, bonusNumber) } + return lotteriesRank + } + + private fun countRank(lotteriesRank: List): Map { + val rankWithCounts = lotteriesRank.groupingBy { it }.eachCount() + return rankWithCounts + } + + private fun mapToResult(rankWithCounts: Map): List { + val lottoResult = (1..5).map { rank -> + val count = rankWithCounts.getOrDefault(rank, 0) + LottoResult(rank, count) + } + return lottoResult + } + + fun getLottoYield(lottoResults: List, purchaseAmount: Int): String { + val totalPrice = calculateTotalPrice(lottoResults) + val yield = (totalPrice / purchaseAmount) * 100F + val formattedYield = String.format("%,.2f", yield) + + return formattedYield + } + + private fun calculateTotalPrice(lottoResults: List): Int { + var totalPrice = 0 + lottoResults.forEach { lottoResult -> + val price = getPrice(lottoResult.rank) + val count = lottoResult.count + totalPrice += price * count + } + return totalPrice + } + + private fun getPrice(rank: Int): Int { + return when (rank) { + 1 -> 2000000000 + 2 -> 30000000 + 3 -> 1500000 + 4 -> 50000 + 5 -> 5000 + else -> 0 + } + } +} + +data class LottoResult( + val rank: Int, + val count: Int, +) \ No newline at end of file From 819399e0c60d3602fb6b9a8d28fc9d3782d74ba5 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Fri, 1 Nov 2024 21:16:29 +0900 Subject: [PATCH 08/41] =?UTF-8?q?feat:=20=EA=B2=B0=EA=B3=BC=EA=B0=92=20Out?= =?UTF-8?q?putView=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. LottoResultCalculator를 통해 계산된 로또 당첨 통계 표기 2. 구매금액 대비 수익에 대한 수익률을 소수점 둘째자리에서 반올림하여 표기 --- src/main/kotlin/lotto/view/OutputView.kt | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/kotlin/lotto/view/OutputView.kt diff --git a/src/main/kotlin/lotto/view/OutputView.kt b/src/main/kotlin/lotto/view/OutputView.kt new file mode 100644 index 000000000..8819a42e9 --- /dev/null +++ b/src/main/kotlin/lotto/view/OutputView.kt @@ -0,0 +1,35 @@ +package lotto.view + +import lotto.model.Lotto +import lotto.model.LottoResult + +class OutputView { + fun showLottoQuantity(lottoQuantity: Int) { + println("\n${lottoQuantity}개를 구매했습니다.") + } + + fun showLottoNumbers(lotteries: List) { + for (lotto in lotteries) { + val lottoNumber = lotto.getLottoNumber() + println(lottoNumber) + } + } + + fun showMatchingLottoAmount(lottoResults: List) { + println("당첨 통계") + println("---") + lottoResults.reversed().forEach { lottoResult -> + when (lottoResult.rank) { + 5 -> println("3개 일치 (5,000원) - ${lottoResult.count}개") + 4 -> println("4개 일치 (50,000원) - ${lottoResult.count}개") + 3 -> println("5개 일치 (1,500,000원) - ${lottoResult.count}개") + 2 -> println("5개 일치, 보너스 볼 일치 (30,000,000원) - ${lottoResult.count}개") + 1 -> println("6개 일치 (2,000,000,000원) - ${lottoResult.count}개") + } + } + } + + fun showYield(yield: String) { + println("총 수익률은 ${yield}%입니다.") + } +} \ No newline at end of file From 0aa480e1ef9e6c05e98029482bb2c533f445c94b Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Fri, 1 Nov 2024 21:18:05 +0900 Subject: [PATCH 09/41] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 완료한 기능 목록 체크 - 입력: 로또번호, 보너스 번호 - 당첨 통계: 전체 - 수익률: 전체 2. 새 기능목록 추가 - 로또 발행: 로또의 정렬 - 출력 --- README.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3b282657e..18f74bf00 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ - 구입 금액 - [X] 숫자로 입력 - 로또 번호 - - [ ] 쉼표(,)로 연결된 1~45 사이의 6개의 서로 다른 자연수 입력 + - [X] 쉼표(,)로 연결된 1~45 사이의 6개의 서로 다른 자연수 입력 - 보너스 번호 - - [ ] 1~45 사이의 당첨 번호와 중복이 없는 자연수 하나 + - [X] 1~45 사이의 당첨 번호와 중복이 없는 자연수 하나 ### 로또 발행 - 로또의 수량 @@ -105,18 +105,19 @@ - [X] 1~45 사이의 6개의 서로 다른 자연수를 난수로 생성 - `Randoms.pickUniqueNumbersInRange(1, 45, 6)` - [X] 로또의 수량 만큼 반복 + - [X] 로또 숫자는 오름차순으로 정렬 ### 당첨 통계 - 당첨 번호 확인 - - [ ] 발행된 로또의 번호와 입력한 로또 번호를 비교 + - [X] 발행된 로또의 번호와 입력한 로또 번호를 비교 - 일치 번호의 개수에 따라 당첨 등수의 개수 확인 - 5개가 일치할 경우 - 남은 한개의 숫자와 입력한 보너스 번호 비교 - - [ ] 두 수가 다를 경우: 3등 - - [ ] 두 수가 같을 경우: 2등 + - [X] 두 수가 다를 경우: 3등 + - [X] 두 수가 같을 경우: 2등 - 수익률 - - [ ] (총 당첨액 / 총 구매액) * 100을 소수점 둘째 자리에서 반올림 한 % - - [ ] 총 당첨액 + - [X] (총 당첨액 / 총 구매액) * 100을 소수점 둘째 자리에서 반올림 한 % + - [X] 총 당첨액 - (당첨 금액 * 당첨 갯수)를 모두 더한 값 - 3개 일치: 5,000 - 4개 일치: 50,000 @@ -126,6 +127,12 @@ - 6개 일치: 2,000,000,000 - 총 구매액: 입력 구입 금액 +### 출력 +- 당첨 통계 + - [X] 3개부터 6개 일치하는 로또가 몇 개인지 표기 +- 총 수익률 + - [X] 총 수익률 표기 + ## 오류 처리 - 구입 금액 - 숫자로 입력 From 604ae9848078cbac77cf809e956f443495528c74 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 11:51:26 +0900 Subject: [PATCH 10/41] =?UTF-8?q?fix:=20=EB=A1=9C=EB=98=90=EC=9D=98=20?= =?UTF-8?q?=EC=88=98=EC=9D=B5=EB=A5=A0=20=EA=B3=84=EC=82=B0=EA=B3=B5?= =?UTF-8?q?=EC=8B=9D=20=EB=B0=8F=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 메서드명 변경 - 로또의 순이익을 표기하는 net profit으로 변경 2. yield를 계산할때 netProfit이 정수여서 purchaseAmount가 더 큰 값이면 0으로 계산되는 오류 수정 - netProfit 타입을 float로 변경 --- .../kotlin/lotto/model/LottoResultCalculator.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/lotto/model/LottoResultCalculator.kt b/src/main/kotlin/lotto/model/LottoResultCalculator.kt index f8935e684..66b6d311d 100644 --- a/src/main/kotlin/lotto/model/LottoResultCalculator.kt +++ b/src/main/kotlin/lotto/model/LottoResultCalculator.kt @@ -28,21 +28,21 @@ class LottoResultCalculator(private val lotteries: List) { } fun getLottoYield(lottoResults: List, purchaseAmount: Int): String { - val totalPrice = calculateTotalPrice(lottoResults) - val yield = (totalPrice / purchaseAmount) * 100F - val formattedYield = String.format("%,.2f", yield) + val netProfit = calculateNetProfit(lottoResults) + val yield = (netProfit / purchaseAmount) * 100F + val formattedYield = String.format("%,.1f", yield) return formattedYield } - private fun calculateTotalPrice(lottoResults: List): Int { - var totalPrice = 0 + private fun calculateNetProfit(lottoResults: List): Float { + var netProfit = 0F lottoResults.forEach { lottoResult -> val price = getPrice(lottoResult.rank) val count = lottoResult.count - totalPrice += price * count + netProfit += price * count } - return totalPrice + return netProfit } private fun getPrice(rank: Int): Int { From e74d8d6bfb1efcb7b1b2b70844c3f858b72cdb9e Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 13:29:00 +0900 Subject: [PATCH 11/41] =?UTF-8?q?fix:=20=EB=A1=9C=EB=98=90=EC=9D=98=20?= =?UTF-8?q?=EC=88=98=EC=9D=B5=EB=A5=A0=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 메서드명 변경 - 로또의 순이익을 표기하는 net profit에서 총 수익인 total earnings로 변경 --- src/main/kotlin/lotto/model/LottoResultCalculator.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/lotto/model/LottoResultCalculator.kt b/src/main/kotlin/lotto/model/LottoResultCalculator.kt index 66b6d311d..11a6bad99 100644 --- a/src/main/kotlin/lotto/model/LottoResultCalculator.kt +++ b/src/main/kotlin/lotto/model/LottoResultCalculator.kt @@ -28,21 +28,21 @@ class LottoResultCalculator(private val lotteries: List) { } fun getLottoYield(lottoResults: List, purchaseAmount: Int): String { - val netProfit = calculateNetProfit(lottoResults) - val yield = (netProfit / purchaseAmount) * 100F + val totalEarnings = calculateTotalEarnings(lottoResults) + val yield = (totalEarnings / purchaseAmount) * 100F val formattedYield = String.format("%,.1f", yield) return formattedYield } - private fun calculateNetProfit(lottoResults: List): Float { - var netProfit = 0F + private fun calculateTotalEarnings(lottoResults: List): Float { + var totalEarnings = 0F lottoResults.forEach { lottoResult -> val price = getPrice(lottoResult.rank) val count = lottoResult.count - netProfit += price * count + totalEarnings += price * count } - return netProfit + return totalEarnings } private fun getPrice(rank: Int): Int { From 4f8f106f0d43af3994009d23c15a2c02905563b8 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 13:32:43 +0900 Subject: [PATCH 12/41] =?UTF-8?q?fix:=20=EA=B2=80=EC=A6=9D=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 검증 함수를 object로 Validator로 옮겨서 사용 --- src/main/kotlin/lotto/model/Lotto.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/kotlin/lotto/model/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt index 7d66345bc..f0aa2b9a5 100644 --- a/src/main/kotlin/lotto/model/Lotto.kt +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -8,7 +8,7 @@ import lotto.util.LottoNumberValidator // 로또 보너스 번호 체크 class Lotto(private val numbers: List) { init { - validateLottoNumber(numbers) + LottoNumberValidator.validateLottoNumbers(numbers) } fun getLottoNumber(): List = numbers @@ -36,10 +36,4 @@ class Lotto(private val numbers: List) { } return 3 } - - private fun validateLottoNumber(numbers: List) { - LottoNumberValidator.validateLottoNumberCount(numbers) - LottoNumberValidator.validateLottoNumberRange(numbers) - LottoNumberValidator.validateLottoNumberUniqueness(numbers) - } } From dbc4e21f9e79cfe2db80511e08e4e67e528b82b9 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 13:37:42 +0900 Subject: [PATCH 13/41] =?UTF-8?q?fix:=20=EA=B2=80=EC=A6=9D=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 검증 함수를 object로 Validator로 옮겨서 사용 2. 검증된 입력을 사용하므로 init 제거 3. purchaseAmount 제공하는 메서드 추가 --- src/main/kotlin/lotto/model/LottoFactory.kt | 26 ++++----------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/lotto/model/LottoFactory.kt b/src/main/kotlin/lotto/model/LottoFactory.kt index aecc15861..c6148d767 100644 --- a/src/main/kotlin/lotto/model/LottoFactory.kt +++ b/src/main/kotlin/lotto/model/LottoFactory.kt @@ -1,18 +1,15 @@ package lotto.model import camp.nextstep.edu.missionutils.Randoms +import lotto.util.PurchaseAmountValidator // 로또를 발행하는 역할(로또 생성) // 구입금액을 통해 로또를 발행 -> 발행된 로또 // 구입금액 제공 -class LottoFactory(private val purchaseAmountInput: String) { - val purchaseAmount: Int - val lottoQuantity: Int +class LottoFactory(private val purchaseAmount: Int) { + val lottoQuantity: Int = purchaseAmount / 1000 - init { - purchaseAmount = getValidatePurchaseAmount() - lottoQuantity = purchaseAmount / 1000 - } + fun getPurchaseAmount(): Int = purchaseAmount private fun createNumber(): List { val randomNumbers = Randoms.pickUniqueNumbersInRange(1, 45, 6).sorted() @@ -28,19 +25,4 @@ class LottoFactory(private val purchaseAmountInput: String) { } return lottoList } - - private fun getValidatePurchaseAmount(): Int { - validatePurchaseAmount() - val validatedPurchaseAmount = purchaseAmountInput.trim().toInt() - return validatedPurchaseAmount - } - - private fun validatePurchaseAmount() { - require(purchaseAmountInput.isNotEmpty()) { "[ERROR] 구입 금액은 빈 값이 될 수 없습니다." } - - val amount = purchaseAmountInput.trim().toIntOrNull() - require(amount != null) { "[ERROR] 구입 금액은 숫자여야 합니다." } - require(amount % 1000 == 0) { "[ERROR] 구입 금액은 1,000원 단위여야 합니다." } - require(amount <= 1000000000) { "[ERROR] 구입 금액은 1억원 이하여야 합니다." } - } } \ No newline at end of file From a47d1eaf6ee79f6b653e987c31d9ae9765560eb3 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 13:38:15 +0900 Subject: [PATCH 14/41] =?UTF-8?q?fix:=20import=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 사용하지 않는 import 제거 --- src/main/kotlin/lotto/model/LottoFactory.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/lotto/model/LottoFactory.kt b/src/main/kotlin/lotto/model/LottoFactory.kt index c6148d767..09208b353 100644 --- a/src/main/kotlin/lotto/model/LottoFactory.kt +++ b/src/main/kotlin/lotto/model/LottoFactory.kt @@ -1,7 +1,6 @@ package lotto.model import camp.nextstep.edu.missionutils.Randoms -import lotto.util.PurchaseAmountValidator // 로또를 발행하는 역할(로또 생성) // 구입금액을 통해 로또를 발행 -> 발행된 로또 From a686edca9967da14d198f849e5f16def324aa7d2 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 15:12:04 +0900 Subject: [PATCH 15/41] =?UTF-8?q?feat:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EB=A9=94=EC=9D=B8?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 프로그램을 실행하는 함수들이 있는 컨트롤러 추가 - payment: 구매금액을 받고 로또를 생성 - giveLotteries: 생성된 로또의 갯수, 로또 정보를 보여줌 - inputWinningNumber: 해당 주차 당첨 로또의 당첨 번호를 입력, console 종료 - showResult: 당첨 로또의 갯수 및 총 수익률을 보여줌 2. controller의 run함수로 main에서 주 프로그램 실행 --- src/main/kotlin/lotto/Application.kt | 4 +- .../lotto/controller/LottoController.kt | 86 +++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/lotto/controller/LottoController.kt diff --git a/src/main/kotlin/lotto/Application.kt b/src/main/kotlin/lotto/Application.kt index 151821c9c..4c3ba7459 100644 --- a/src/main/kotlin/lotto/Application.kt +++ b/src/main/kotlin/lotto/Application.kt @@ -1,5 +1,7 @@ package lotto +import lotto.controller.LottoController + fun main() { - // TODO: 프로그램 구현 + LottoController().run() } diff --git a/src/main/kotlin/lotto/controller/LottoController.kt b/src/main/kotlin/lotto/controller/LottoController.kt new file mode 100644 index 000000000..702502673 --- /dev/null +++ b/src/main/kotlin/lotto/controller/LottoController.kt @@ -0,0 +1,86 @@ +package lotto.controller + +import lotto.model.LottoFactory +import lotto.model.LottoResultCalculator +import lotto.util.validator.BonusNumberValidator +import lotto.util.validator.LottoNumberValidator +import lotto.util.validator.PurchaseAmountValidator +import lotto.view.InputView +import lotto.view.OutputView + +class LottoController( + private val inputView: InputView = InputView(), + private val outputView: OutputView = OutputView(), +) { + private lateinit var lottoFactory: LottoFactory + private lateinit var lottoResultCalculator: LottoResultCalculator + private lateinit var winningNumbers: List + private var bonusNumber: Int? = null + + fun run() { + payment() + giveLotteries() + inputWinningNumber() + showResult() + } + + private fun payment() { + val purchaseAmount = getValidatedInput( + inputFunction = { inputView.getPurchaseAmount() }, + validationFunction = { PurchaseAmountValidator.getValidatePurchaseAmount(it) } + ) + lottoFactory = LottoFactory(purchaseAmount) + } + + private fun giveLotteries() { + val lottoQuantity = lottoFactory.lottoQuantity + val purchasedLotteries = lottoFactory.createLotto() + lottoResultCalculator = LottoResultCalculator(purchasedLotteries) + + outputView.showLottoQuantity(lottoQuantity) + outputView.showLottoNumbers(purchasedLotteries) + } + + private fun inputWinningNumber() { + winningNumbers = getValidatedInput( + inputFunction = { inputView.getWinningNumber() }, + validationFunction = { LottoNumberValidator.getValidatedWinningNumbers(it) } + ) + bonusNumber = getValidatedInput( + inputFunction = { inputView.getBonusNumber() }, + validationFunction = { BonusNumberValidator.getValidatedBonusNumber(it, winningNumbers) } + ) + inputView.close() + } + + private fun showResult() { + val lottoResults = lottoResultCalculator.getLottoResults(winningNumbers, bonusNumber!!) + val purchaseAmount = lottoFactory.getPurchaseAmount() + val yield = lottoResultCalculator.getLottoYield(lottoResults, purchaseAmount) + + outputView.showMatchingLottoAmount(lottoResults) + outputView.showYield(yield) + } + + private fun getValidatedInput( + inputFunction: () -> String, + validationFunction: (String) -> T + ): T { + while (true) { + try { + val input = inputFunction() + val validatedInput = validationFunction(input) + return validatedInput + } catch (e: IllegalArgumentException) { + showErrorMessage(e) + } + } + } + + private fun showErrorMessage(e: IllegalArgumentException) { + val errorMessage = e.message + if (errorMessage != null) { + outputView.showErrorMessage(errorMessage) + } + } +} \ No newline at end of file From 20c365740891f6d0c82b4c1dd6fc385a67b9bb92 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 15:14:41 +0900 Subject: [PATCH 16/41] =?UTF-8?q?move:=20inputView=EC=97=90=20const=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. constant 패키지 생성으로 const를 InputView에서 분리해 관리 --- src/main/kotlin/lotto/util/constant/InputConst.kt | 7 +++++++ src/main/kotlin/lotto/view/InputView.kt | 13 ++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/lotto/util/constant/InputConst.kt diff --git a/src/main/kotlin/lotto/util/constant/InputConst.kt b/src/main/kotlin/lotto/util/constant/InputConst.kt new file mode 100644 index 000000000..fc972e551 --- /dev/null +++ b/src/main/kotlin/lotto/util/constant/InputConst.kt @@ -0,0 +1,7 @@ +package lotto.util.constant + +object InputConst { + const val PURCHASE_AMOUNT_INPUT = "구입금액을 입력해 주세요." + const val WINNING_NUMBER_INPUT = "\n당첨 번호를 입력해 주세요." + const val BONUS_NUMBER_INPUT = "\n보너스 번호를 입력해 주세요." +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/view/InputView.kt b/src/main/kotlin/lotto/view/InputView.kt index fe7da0045..fced0f45d 100644 --- a/src/main/kotlin/lotto/view/InputView.kt +++ b/src/main/kotlin/lotto/view/InputView.kt @@ -1,6 +1,7 @@ package lotto.view import camp.nextstep.edu.missionutils.Console +import lotto.util.constant.InputConst class InputView { private fun getInput(message: String): String { @@ -11,13 +12,7 @@ class InputView { fun close() = Console.close() - fun getPurchaseAmount(): String = getInput(PURCHASE_AMOUNT_INPUT) - fun getWinningNumber(): String = getInput(WINNING_NUMBER_INPUT) - fun getBonusNumber(): String = getInput(BONUS_NUMBER_INPUT) - - companion object { - const val PURCHASE_AMOUNT_INPUT = "구입금액을 입력해 주세요." - const val WINNING_NUMBER_INPUT = "\n당첨 번호를 입력해 주세요." - const val BONUS_NUMBER_INPUT = "\n보너스 번호를 입력해 주세요." - } + fun getPurchaseAmount(): String = getInput(InputConst.PURCHASE_AMOUNT_INPUT) + fun getWinningNumber(): String = getInput(InputConst.WINNING_NUMBER_INPUT) + fun getBonusNumber(): String = getInput(InputConst.BONUS_NUMBER_INPUT) } \ No newline at end of file From c767fd441bbc4354d9aeacfbb128d8302b4ccecc Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 15:17:14 +0900 Subject: [PATCH 17/41] =?UTF-8?q?move:=20Validator=EB=A5=BC=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EC=97=AC=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. LottoNumberValidator: 로또 숫자 입력에 대한 Validator 2. PurchaseAmountValidator: 구매금액에 대한 Validator 3. BonusNumberValidator: 보너스 숫자 입력에 대한 Validator --- .../util/validator/BonusNumberValidator.kt | 28 ++++++++++++ .../util/validator/LottoNumberValidator.kt | 45 +++++++++++++++++++ .../util/validator/PurchaseAmountValidator.kt | 38 ++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 src/main/kotlin/lotto/util/validator/BonusNumberValidator.kt create mode 100644 src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt create mode 100644 src/main/kotlin/lotto/util/validator/PurchaseAmountValidator.kt diff --git a/src/main/kotlin/lotto/util/validator/BonusNumberValidator.kt b/src/main/kotlin/lotto/util/validator/BonusNumberValidator.kt new file mode 100644 index 000000000..bc3daeb1f --- /dev/null +++ b/src/main/kotlin/lotto/util/validator/BonusNumberValidator.kt @@ -0,0 +1,28 @@ +package lotto.util.validator + +import lotto.util.constant.ErrorMessages +import lotto.util.constant.LottoRules + +object BonusNumberValidator { + fun getValidatedBonusNumber(bonusNumberInput: String, winningNumbers: List): Int { + validateIsNumeric(bonusNumberInput) + + val bonusNumber = bonusNumberInput.toInt() + validateIsInRange(bonusNumber) + validateUniqueness(bonusNumber, winningNumbers) + + return bonusNumber + } + + private fun validateIsNumeric(input: String) { + require(input.toIntOrNull() != null) { ErrorMessages.BONUS_NUMBER_NUMERIC } + } + + private fun validateIsInRange(input: Int) { + require(input in LottoRules.LOTTO_NUMBER_RANGE) { ErrorMessages.BONUS_NUMBER_RANGE } + } + + private fun validateUniqueness(bonusNumber: Int, numbers: List) { + require(bonusNumber !in numbers) { ErrorMessages.BONUS_NUMBER_UNIQUE } + } +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt b/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt new file mode 100644 index 000000000..b0266a8f1 --- /dev/null +++ b/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt @@ -0,0 +1,45 @@ +package lotto.util.validator + +import lotto.util.constant.ErrorMessages +import lotto.util.constant.LottoRules + +object LottoNumberValidator { + + fun validateLottoNumbers(numbers: List) { + validateLottoNumberCount(numbers) + validateLottoNumberRange(numbers) + validateLottoNumberUniqueness(numbers) + } + + private fun validateLottoNumberDelimiter(input: String) { + require(input.contains(LottoRules.DELIMITER)) { ErrorMessages.LOTTO_NUMBER_DELIMITER } + } + + private fun validateIsNumeric(input: List) { + require(input.all { it.toIntOrNull() != null }) { ErrorMessages.LOTTO_NUMBER_NUMERIC } + } + + private fun validateLottoNumberCount(numbers: List) { + require(numbers.size == LottoRules.LOTTO_NUMBER_COUNT) { ErrorMessages.LOTTO_NUMBER_COUNT } + } + + private fun validateLottoNumberRange(numbers: List) { + require(numbers.all { it in LottoRules.LOTTO_NUMBER_RANGE }) { ErrorMessages.LOTTO_NUMBER_RANGE } + } + + private fun validateLottoNumberUniqueness(numbers: List) { + require(numbers.distinct().size == numbers.size) { ErrorMessages.LOTTO_NUMBER_UNIQUE } + } + + fun getValidatedWinningNumbers(winningNumbersInput: String): List { + validateLottoNumberDelimiter(winningNumbersInput) + + val splittingNumbersInput = winningNumbersInput.split(LottoRules.DELIMITER) + validateIsNumeric(splittingNumbersInput) + + val validatedNumbers = splittingNumbersInput.map { it.toInt() } + validateLottoNumbers(validatedNumbers) + + return validatedNumbers + } +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/util/validator/PurchaseAmountValidator.kt b/src/main/kotlin/lotto/util/validator/PurchaseAmountValidator.kt new file mode 100644 index 000000000..61f429234 --- /dev/null +++ b/src/main/kotlin/lotto/util/validator/PurchaseAmountValidator.kt @@ -0,0 +1,38 @@ +package lotto.util.validator + +import lotto.util.constant.ErrorMessages +import lotto.util.constant.LottoRules + +object PurchaseAmountValidator { + + fun getValidatePurchaseAmount(purchaseAmountInput: String): Int { + validatePurchaseAmount(purchaseAmountInput) + val validatedPurchaseAmount = purchaseAmountInput.trim().toInt() + return validatedPurchaseAmount + } + + private fun validateNotEmpty(purchaseAmountInput: String) { + require(purchaseAmountInput.isNotEmpty()) { ErrorMessages.AMOUNT_IS_NOT_EMPTY } + } + + private fun validateIsNumeric(amount: Int?) { + require(amount != null) { ErrorMessages.AMOUNT_IS_NUMERIC } + } + + private fun validateIsMultipleOfThousand(amount: Int) { + require(amount % LottoRules.AMOUNT_UNIT == LottoRules.ZERO) { ErrorMessages.AMOUNT_IS_MULTIPLE_OF_THOUSAND } + } + + private fun validateMaxAmount(amount: Int) { + require(amount <= LottoRules.MAX_AMOUNT) { ErrorMessages.MAX_AMOUNT } + } + + private fun validatePurchaseAmount(purchaseAmountInput: String) { + validateNotEmpty(purchaseAmountInput) + + val amount = purchaseAmountInput.trim().toIntOrNull() + validateIsNumeric(amount) + validateIsMultipleOfThousand(amount!!) + validateMaxAmount(amount) + } +} \ No newline at end of file From 3e46f0d3beb0533cc7457236c14ce528ce16f2f8 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 15:22:24 +0900 Subject: [PATCH 18/41] =?UTF-8?q?feat:=20=EA=B8=B0=EB=8A=A5=EB=B3=84=20?= =?UTF-8?q?=EA=B3=A0=EC=A0=95=EA=B0=92=20=EC=83=81=EC=88=98=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. ErrorMessages: 에러메세지에 대한 표기 2. LottoRules: 로또에 대한 규칙 상수 - 검증에 대한 다양한 제한값 - 승리 조건에 대한 고정값 - 승리 결과에 대한 고정값 3. OutputConst: 로또 결과를 표기 --- .../lotto/util/constant/ErrorMessages.kt | 22 ++++++++++++ .../kotlin/lotto/util/constant/LottoRules.kt | 36 +++++++++++++++++++ .../kotlin/lotto/util/constant/OutputConst.kt | 19 ++++++++++ 3 files changed, 77 insertions(+) create mode 100644 src/main/kotlin/lotto/util/constant/ErrorMessages.kt create mode 100644 src/main/kotlin/lotto/util/constant/LottoRules.kt create mode 100644 src/main/kotlin/lotto/util/constant/OutputConst.kt diff --git a/src/main/kotlin/lotto/util/constant/ErrorMessages.kt b/src/main/kotlin/lotto/util/constant/ErrorMessages.kt new file mode 100644 index 000000000..10524e454 --- /dev/null +++ b/src/main/kotlin/lotto/util/constant/ErrorMessages.kt @@ -0,0 +1,22 @@ +package lotto.util.constant + +object ErrorMessages { + private const val ERROR_HEADER = "[ERROR]" + + const val AMOUNT_IS_NOT_EMPTY = "$ERROR_HEADER 구입 금액은 빈 값이 될 수 없습니다." + + const val AMOUNT_IS_NUMERIC = "$ERROR_HEADER 구입 금액은 숫자여야 합니다." + const val AMOUNT_IS_MULTIPLE_OF_THOUSAND = "$ERROR_HEADER 구입 금액은 1,000원 단위여야 합니다." + const val MAX_AMOUNT = "$ERROR_HEADER 구입 금액은 10억원 이하여야 합니다." + + const val LOTTO_NUMBER_DELIMITER = "$ERROR_HEADER 로또 번호는 쉼표로 구분해야 합니다." + const val LOTTO_NUMBER_NUMERIC = "$ERROR_HEADER 구입 금액은 숫자여야 합니다." + + const val LOTTO_NUMBER_COUNT = "$ERROR_HEADER 로또 번호는 6개여야 합니다." + const val LOTTO_NUMBER_RANGE = "$ERROR_HEADER 로또 번호는 1부터 45 사이의 숫자여야 합니다." + const val LOTTO_NUMBER_UNIQUE = "$ERROR_HEADER 로또 번호는 중복될 수 없습니다." + + const val BONUS_NUMBER_NUMERIC = "$ERROR_HEADER 보너스 번호는 자연수여야 합니다." + const val BONUS_NUMBER_RANGE = "$ERROR_HEADER 보너스 번호는 1부터 45 사이의 숫자여야 합니다." + const val BONUS_NUMBER_UNIQUE = "$ERROR_HEADER 보너스 번호는 로또 번호와 중복될 수 없습니다." +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/util/constant/LottoRules.kt b/src/main/kotlin/lotto/util/constant/LottoRules.kt new file mode 100644 index 000000000..a8dd7a156 --- /dev/null +++ b/src/main/kotlin/lotto/util/constant/LottoRules.kt @@ -0,0 +1,36 @@ +package lotto.util.constant + +object LottoRules { + const val AMOUNT_UNIT = 1000 + const val ZERO = 0 + const val ZERO_FLOAT = 0F + const val MAX_AMOUNT = 1000000000 + + const val DELIMITER = "," + + const val LOTTO_NUMBER_COUNT = 6 + const val LOTTO_NUMBER_MIN = 1 + const val LOTTO_NUMBER_MAX = 45 + val LOTTO_NUMBER_RANGE = LOTTO_NUMBER_MIN..LOTTO_NUMBER_MAX + + const val MATCHED_SIX = 6 + const val MATCHED_FIVE = 5 + const val MATCHED_FOUR = 4 + const val MATCHED_THREE = 3 + + const val RANK_FIRST = 1 + const val RANK_SECOND = 2 + const val RANK_THIRD = 3 + const val RANK_FOURTH = 4 + const val RANK_FIFTH = 5 + const val OUT_OF_RANK = 0 + + const val PERCENTAGE = 100F + const val YIELD_FORMAT = "%,.1f" + + const val FIRST_PRIZE_MONEY = 2000000000 + const val SECOND_PRIZE_MONEY = 30000000 + const val THIRD_PRIZE_MONEY = 1500000 + const val FOURTH_PRIZE_MONEY = 50000 + const val FIFTH_PRIZE_MONEY = 5000 +} \ No newline at end of file diff --git a/src/main/kotlin/lotto/util/constant/OutputConst.kt b/src/main/kotlin/lotto/util/constant/OutputConst.kt new file mode 100644 index 000000000..690b9ea40 --- /dev/null +++ b/src/main/kotlin/lotto/util/constant/OutputConst.kt @@ -0,0 +1,19 @@ +package lotto.util.constant + +object OutputConst { + private const val LOTTO_QUANTITY = "\n%s개를 구매했습니다." + fun getLottoQuantityMessage(lottoQuantity: Int): String = LOTTO_QUANTITY.format(lottoQuantity) + + const val RESULT = "\n당첨 통계\n---" + const val THREE_MATCHED = "3개 일치 (5,000원)" + const val FOUR_MATCHED = "4개 일치 (50,000원)" + const val FIVE_MATCHED = "5개 일치 (1,500,000원)" + const val FIVE_MATCHED_WITH_BONUS = "5개 일치, 보너스 볼 일치 (30,000,000원)" + const val SIX_MATCHED = "6개 일치 (2,000,000,000원)" + + private const val LOTTO_COUNT = "- %s개" + fun matchedLotteries(count: Int): String = LOTTO_COUNT.format(count) + + private const val TOTAL_YIELD = "총 수익률은 %s%%입니다." + fun getTotalYieldMessage(yield: String): String = TOTAL_YIELD.format(yield) +} \ No newline at end of file From f6fa329e7e0ede89c48eca815c7b2565dd082262 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 15:26:01 +0900 Subject: [PATCH 19/41] =?UTF-8?q?fix:=20=EC=83=81=EC=88=98=EA=B0=92?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EC=99=80=20=EB=B3=80=EC=88=98=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 상수값을 분리 2. LottoResultCalculator - 상금에 대한 이름을 변경: price -> prize --- src/main/kotlin/lotto/model/Lotto.kt | 17 ++++---- src/main/kotlin/lotto/model/LottoFactory.kt | 9 +++- .../lotto/model/LottoResultCalculator.kt | 42 ++++++++++--------- src/main/kotlin/lotto/view/OutputView.kt | 24 +++++++---- 4 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/main/kotlin/lotto/model/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt index f0aa2b9a5..555ff38a5 100644 --- a/src/main/kotlin/lotto/model/Lotto.kt +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -1,6 +1,7 @@ package lotto.model -import lotto.util.LottoNumberValidator +import lotto.util.constant.LottoRules +import lotto.util.validator.LottoNumberValidator // 로또 번호의 에러 체크 // 로또 번호 제공 @@ -21,19 +22,19 @@ class Lotto(private val numbers: List) { private fun determineRank(matchedCount: Int, bonusNumber: Int): Int { val lottoRank = when (matchedCount) { - 6 -> 1 - 5 -> determineSecondRank(bonusNumber) - 4 -> 4 - 3 -> 5 - else -> 0 + LottoRules.MATCHED_SIX -> LottoRules.RANK_FIRST + LottoRules.MATCHED_FIVE -> determineSecondRank(bonusNumber) + LottoRules.MATCHED_FOUR -> LottoRules.RANK_FOURTH + LottoRules.MATCHED_THREE -> LottoRules.RANK_FIFTH + else -> LottoRules.OUT_OF_RANK } return lottoRank } private fun determineSecondRank(bonusNumber: Int): Int { if (bonusNumber in numbers) { - return 2 + return LottoRules.RANK_SECOND } - return 3 + return LottoRules.RANK_THIRD } } diff --git a/src/main/kotlin/lotto/model/LottoFactory.kt b/src/main/kotlin/lotto/model/LottoFactory.kt index 09208b353..52e1a8681 100644 --- a/src/main/kotlin/lotto/model/LottoFactory.kt +++ b/src/main/kotlin/lotto/model/LottoFactory.kt @@ -1,17 +1,22 @@ package lotto.model import camp.nextstep.edu.missionutils.Randoms +import lotto.util.constant.LottoRules // 로또를 발행하는 역할(로또 생성) // 구입금액을 통해 로또를 발행 -> 발행된 로또 // 구입금액 제공 class LottoFactory(private val purchaseAmount: Int) { - val lottoQuantity: Int = purchaseAmount / 1000 + val lottoQuantity: Int = purchaseAmount / LottoRules.AMOUNT_UNIT fun getPurchaseAmount(): Int = purchaseAmount private fun createNumber(): List { - val randomNumbers = Randoms.pickUniqueNumbersInRange(1, 45, 6).sorted() + val randomNumbers = Randoms.pickUniqueNumbersInRange( + LottoRules.LOTTO_NUMBER_MIN, + LottoRules.LOTTO_NUMBER_MAX, + LottoRules.LOTTO_NUMBER_COUNT + ).sorted() return randomNumbers } diff --git a/src/main/kotlin/lotto/model/LottoResultCalculator.kt b/src/main/kotlin/lotto/model/LottoResultCalculator.kt index 11a6bad99..c9356ca17 100644 --- a/src/main/kotlin/lotto/model/LottoResultCalculator.kt +++ b/src/main/kotlin/lotto/model/LottoResultCalculator.kt @@ -1,5 +1,7 @@ package lotto.model +import lotto.util.constant.LottoRules + class LottoResultCalculator(private val lotteries: List) { fun getLottoResults(winningNumbers: List, bonusNumber: Int): List { val lotteriesRank = calculateRanks(winningNumbers, bonusNumber) @@ -9,6 +11,14 @@ class LottoResultCalculator(private val lotteries: List) { return lottoResults } + fun getLottoYield(lottoResults: List, purchaseAmount: Int): String { + val totalEarnings = calculateTotalEarnings(lottoResults) + val yield = (totalEarnings / purchaseAmount) * LottoRules.PERCENTAGE + val formattedYield = String.format(LottoRules.YIELD_FORMAT, yield) + + return formattedYield + } + private fun calculateRanks(winningNumbers: List, bonusNumber: Int): List { val lotteriesRank = lotteries.map { lotto -> lotto.getLottoRank(winningNumbers, bonusNumber) } return lotteriesRank @@ -20,39 +30,31 @@ class LottoResultCalculator(private val lotteries: List) { } private fun mapToResult(rankWithCounts: Map): List { - val lottoResult = (1..5).map { rank -> - val count = rankWithCounts.getOrDefault(rank, 0) + val lottoResult = (LottoRules.RANK_FIRST..LottoRules.RANK_FIFTH).map { rank -> + val count = rankWithCounts.getOrDefault(rank, LottoRules.ZERO) LottoResult(rank, count) } return lottoResult } - fun getLottoYield(lottoResults: List, purchaseAmount: Int): String { - val totalEarnings = calculateTotalEarnings(lottoResults) - val yield = (totalEarnings / purchaseAmount) * 100F - val formattedYield = String.format("%,.1f", yield) - - return formattedYield - } - private fun calculateTotalEarnings(lottoResults: List): Float { - var totalEarnings = 0F + var totalEarnings = LottoRules.ZERO_FLOAT lottoResults.forEach { lottoResult -> - val price = getPrice(lottoResult.rank) + val prizeMoney = getPrizeMoney(lottoResult.rank) val count = lottoResult.count - totalEarnings += price * count + totalEarnings += prizeMoney * count } return totalEarnings } - private fun getPrice(rank: Int): Int { + private fun getPrizeMoney(rank: Int): Int { return when (rank) { - 1 -> 2000000000 - 2 -> 30000000 - 3 -> 1500000 - 4 -> 50000 - 5 -> 5000 - else -> 0 + LottoRules.RANK_FIRST -> LottoRules.FIRST_PRIZE_MONEY + LottoRules.RANK_SECOND -> LottoRules.SECOND_PRIZE_MONEY + LottoRules.RANK_THIRD -> LottoRules.THIRD_PRIZE_MONEY + LottoRules.RANK_FOURTH -> LottoRules.FOURTH_PRIZE_MONEY + LottoRules.RANK_FIFTH -> LottoRules.FIFTH_PRIZE_MONEY + else -> LottoRules.OUT_OF_RANK } } } diff --git a/src/main/kotlin/lotto/view/OutputView.kt b/src/main/kotlin/lotto/view/OutputView.kt index 8819a42e9..1e6c8fd37 100644 --- a/src/main/kotlin/lotto/view/OutputView.kt +++ b/src/main/kotlin/lotto/view/OutputView.kt @@ -2,10 +2,16 @@ package lotto.view import lotto.model.Lotto import lotto.model.LottoResult +import lotto.util.constant.OutputConst class OutputView { + fun showErrorMessage(errorMessages: String) { + println(errorMessages) + } + fun showLottoQuantity(lottoQuantity: Int) { - println("\n${lottoQuantity}개를 구매했습니다.") + val lottoQuantityMessage = OutputConst.getLottoQuantityMessage(lottoQuantity) + println(lottoQuantityMessage) } fun showLottoNumbers(lotteries: List) { @@ -16,20 +22,20 @@ class OutputView { } fun showMatchingLottoAmount(lottoResults: List) { - println("당첨 통계") - println("---") + println(OutputConst.RESULT) lottoResults.reversed().forEach { lottoResult -> when (lottoResult.rank) { - 5 -> println("3개 일치 (5,000원) - ${lottoResult.count}개") - 4 -> println("4개 일치 (50,000원) - ${lottoResult.count}개") - 3 -> println("5개 일치 (1,500,000원) - ${lottoResult.count}개") - 2 -> println("5개 일치, 보너스 볼 일치 (30,000,000원) - ${lottoResult.count}개") - 1 -> println("6개 일치 (2,000,000,000원) - ${lottoResult.count}개") + 5 -> println("${OutputConst.THREE_MATCHED} ${OutputConst.matchedLotteries(lottoResult.count)}") + 4 -> println("${OutputConst.FOUR_MATCHED} ${OutputConst.matchedLotteries(lottoResult.count)}") + 3 -> println("${OutputConst.FIVE_MATCHED} ${OutputConst.matchedLotteries(lottoResult.count)}") + 2 -> println("${OutputConst.FIVE_MATCHED_WITH_BONUS} ${OutputConst.matchedLotteries(lottoResult.count)}") + 1 -> println("${OutputConst.SIX_MATCHED} ${OutputConst.matchedLotteries(lottoResult.count)}") } } } fun showYield(yield: String) { - println("총 수익률은 ${yield}%입니다.") + val totalYieldMessage = OutputConst.getTotalYieldMessage(yield) + println(totalYieldMessage) } } \ No newline at end of file From 90ddcfd4e804e735c45d087b14dc083357ee3aef Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 15:30:17 +0900 Subject: [PATCH 20/41] =?UTF-8?q?fix:=20=EC=97=90=EB=9F=AC=EB=A9=94?= =?UTF-8?q?=EC=84=B8=EC=A7=80=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EA=B3=B5?= =?UTF-8?q?=EB=B0=B1=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. LOTTO_NUMBER_NUMERIC - 구입 금액은 숫자여야 합니다. -> 로또 번호는 자연수여야 합니다. 2. 각 에러에 맞게 공백을 나눔 --- src/main/kotlin/lotto/util/constant/ErrorMessages.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/kotlin/lotto/util/constant/ErrorMessages.kt b/src/main/kotlin/lotto/util/constant/ErrorMessages.kt index 10524e454..f7675d0b7 100644 --- a/src/main/kotlin/lotto/util/constant/ErrorMessages.kt +++ b/src/main/kotlin/lotto/util/constant/ErrorMessages.kt @@ -4,14 +4,12 @@ object ErrorMessages { private const val ERROR_HEADER = "[ERROR]" const val AMOUNT_IS_NOT_EMPTY = "$ERROR_HEADER 구입 금액은 빈 값이 될 수 없습니다." - const val AMOUNT_IS_NUMERIC = "$ERROR_HEADER 구입 금액은 숫자여야 합니다." const val AMOUNT_IS_MULTIPLE_OF_THOUSAND = "$ERROR_HEADER 구입 금액은 1,000원 단위여야 합니다." const val MAX_AMOUNT = "$ERROR_HEADER 구입 금액은 10억원 이하여야 합니다." + const val LOTTO_NUMBER_NUMERIC = "$ERROR_HEADER 로또 번호는 자연수여야 합니다." const val LOTTO_NUMBER_DELIMITER = "$ERROR_HEADER 로또 번호는 쉼표로 구분해야 합니다." - const val LOTTO_NUMBER_NUMERIC = "$ERROR_HEADER 구입 금액은 숫자여야 합니다." - const val LOTTO_NUMBER_COUNT = "$ERROR_HEADER 로또 번호는 6개여야 합니다." const val LOTTO_NUMBER_RANGE = "$ERROR_HEADER 로또 번호는 1부터 45 사이의 숫자여야 합니다." const val LOTTO_NUMBER_UNIQUE = "$ERROR_HEADER 로또 번호는 중복될 수 없습니다." From 642c4838a84837615e82213adb9bae0362c80f24 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 15:31:40 +0900 Subject: [PATCH 21/41] =?UTF-8?q?docs:=20=EC=98=A4=ED=83=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EC=88=98=EC=9D=B5=EB=A5=A0=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=EA=B3=B5=EC=8B=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 오류 처리: 10억원을 넘길 경우 - 구입 금액은 1억원 이하여야 합니다. -> 구입 금액은 10억원 이하여야 합니다. 2. 총 수익률 계산 공식 - (수익/투자금) * 100 --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 18f74bf00..ec5de668d 100644 --- a/README.md +++ b/README.md @@ -132,13 +132,15 @@ - [X] 3개부터 6개 일치하는 로또가 몇 개인지 표기 - 총 수익률 - [X] 총 수익률 표기 + - [X] (수익 / 투자금) * 100 + - ex) (5,000 / 8,000) * 100 = 62.5 ## 오류 처리 - 구입 금액 - 숫자로 입력 - 숫자가 아닐 경우: "[ERROR] 구입 금액은 숫자여야 합니다." - 1,000으로 나눠 떨어지지 않을 경우: "[ERROR] 구입 금액은 1,000원 단위여야 합니다." - - 10억원을 넘길 경우: "[ERROR] 구입 금액은 1억원 이하여야 합니다." + - 10억원을 넘길 경우: "[ERROR] 구입 금액은 10억원 이하여야 합니다." - 로또 번호 - 쉼표(,)로 연결된 1~45 사이의 6개의 서로 다른 자연수 입력 - 쉼표로 연결 되지 않을 경우: "[ERROR] 로또 번호는 쉼표로 구분해야 합니다." @@ -151,7 +153,6 @@ - 1~45 사이의 수가 아닐 경우: "[ERROR] 보너스 번호는 1부터 45 사이의 숫자여야 합니다." - 당첨 번호와 중복이 있을 경우: "[ERROR] 보너스 번호는 로또 번호와 중복될 수 없습니다." - 자연수가 아닐 경우: "[ERROR] 보너스 번호는 자연수여야 합니다." - - 하나의 숫자가 아닐 경우: "[ERROR] 보너스 번호는 하나여야 합니다." ## 테스트 - 당첨 통계 From 17aa9132b2124bf8530c615de2ce2eb2867df3a9 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 17:19:21 +0900 Subject: [PATCH 22/41] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=93=B1?= =?UTF-8?q?=EC=88=98=EB=A5=BC=20=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20Lot?= =?UTF-8?q?toRank=20enum=20class=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. LottoRank - 등수가 갖는 정보를 포함, 로또 등수, 상금 금액, output에서 보여줄 해당 등급의 표기 --- src/main/kotlin/lotto/model/LottoRank.kt | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/main/kotlin/lotto/model/LottoRank.kt diff --git a/src/main/kotlin/lotto/model/LottoRank.kt b/src/main/kotlin/lotto/model/LottoRank.kt new file mode 100644 index 000000000..732356635 --- /dev/null +++ b/src/main/kotlin/lotto/model/LottoRank.kt @@ -0,0 +1,52 @@ +package lotto.model + +import lotto.util.constant.LottoRules +import lotto.util.constant.OutputConst + +enum class LottoRank( + val rankNumber: Int, + val prizeMoney: Int, + val displayName: String? = null +) { + FIRST( + rankNumber = LottoRules.RANK_FIRST, + prizeMoney = LottoRules.FIRST_PRIZE_MONEY, + displayName = OutputConst.SIX_MATCHED + ), + SECOND( + rankNumber = LottoRules.RANK_SECOND, + prizeMoney = LottoRules.SECOND_PRIZE_MONEY, + displayName = OutputConst.FIVE_MATCHED_WITH_BONUS + ), + THIRD( + rankNumber = LottoRules.RANK_THIRD, + prizeMoney = LottoRules.THIRD_PRIZE_MONEY, + displayName = OutputConst.FIVE_MATCHED + ), + FOURTH( + rankNumber = LottoRules.RANK_FOURTH, + prizeMoney = LottoRules.FOURTH_PRIZE_MONEY, + displayName = OutputConst.FOUR_MATCHED + ), + FIFTH( + rankNumber = LottoRules.RANK_FIFTH, + prizeMoney = LottoRules.FIFTH_PRIZE_MONEY, + displayName = OutputConst.THREE_MATCHED + ), + OUT_OF_RANK( + rankNumber = LottoRules.OUT_OF_RANK, + prizeMoney = LottoRules.OUT_OF_RANK, + ); + + companion object { + fun fromMatchedCount(matchedCount: Int, bonusMatched: Boolean = false): LottoRank { + return when (matchedCount) { + LottoRules.MATCHED_SIX -> FIRST + LottoRules.MATCHED_FIVE -> if (bonusMatched) SECOND else THIRD + LottoRules.MATCHED_FOUR -> FOURTH + LottoRules.MATCHED_THREE -> FIFTH + else -> OUT_OF_RANK + } + } + } +} \ No newline at end of file From e0ad87552926e95d483f270987d04eb09ce4bc0d Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 17:27:19 +0900 Subject: [PATCH 23/41] =?UTF-8?q?fix:=20LottoRank=EC=9D=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Lotto - 직접 계산하던 로또 등수를 LottoRank에서 수행후 반환 2. LottoResultCalculator - LottoRank의 추가로 당첨 횟수를 계산하는 로직들이 LottoRank를 이용 - 상금계산도 enum class를 이용 - getLottoYield 위치 변경 3. OutputView - LottoRank를 이용해 불필요한 when을 사용하지 않음 --- src/main/kotlin/lotto/model/Lotto.kt | 28 ++------------ .../lotto/model/LottoResultCalculator.kt | 38 +++++++++---------- src/main/kotlin/lotto/view/OutputView.kt | 10 ++--- 3 files changed, 24 insertions(+), 52 deletions(-) diff --git a/src/main/kotlin/lotto/model/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt index 555ff38a5..7c95425a7 100644 --- a/src/main/kotlin/lotto/model/Lotto.kt +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -1,12 +1,7 @@ package lotto.model -import lotto.util.constant.LottoRules import lotto.util.validator.LottoNumberValidator -// 로또 번호의 에러 체크 -// 로또 번호 제공 -// 로또 당첨 여부확인 -// 로또 보너스 번호 체크 class Lotto(private val numbers: List) { init { LottoNumberValidator.validateLottoNumbers(numbers) @@ -14,27 +9,10 @@ class Lotto(private val numbers: List) { fun getLottoNumber(): List = numbers - fun getLottoRank(winningNumber: List, bonusNumber: Int): Int { + fun getLottoRank(winningNumber: List, bonusNumber: Int): LottoRank { val matchedCount = numbers.count { number -> number in winningNumber } - val lottoRank = determineRank(matchedCount, bonusNumber) + val isBonusNumberMatched = bonusNumber in numbers + val lottoRank = LottoRank.fromMatchedCount(matchedCount, isBonusNumberMatched) return lottoRank } - - private fun determineRank(matchedCount: Int, bonusNumber: Int): Int { - val lottoRank = when (matchedCount) { - LottoRules.MATCHED_SIX -> LottoRules.RANK_FIRST - LottoRules.MATCHED_FIVE -> determineSecondRank(bonusNumber) - LottoRules.MATCHED_FOUR -> LottoRules.RANK_FOURTH - LottoRules.MATCHED_THREE -> LottoRules.RANK_FIFTH - else -> LottoRules.OUT_OF_RANK - } - return lottoRank - } - - private fun determineSecondRank(bonusNumber: Int): Int { - if (bonusNumber in numbers) { - return LottoRules.RANK_SECOND - } - return LottoRules.RANK_THIRD - } } diff --git a/src/main/kotlin/lotto/model/LottoResultCalculator.kt b/src/main/kotlin/lotto/model/LottoResultCalculator.kt index c9356ca17..54b44c8ed 100644 --- a/src/main/kotlin/lotto/model/LottoResultCalculator.kt +++ b/src/main/kotlin/lotto/model/LottoResultCalculator.kt @@ -11,32 +11,34 @@ class LottoResultCalculator(private val lotteries: List) { return lottoResults } - fun getLottoYield(lottoResults: List, purchaseAmount: Int): String { - val totalEarnings = calculateTotalEarnings(lottoResults) - val yield = (totalEarnings / purchaseAmount) * LottoRules.PERCENTAGE - val formattedYield = String.format(LottoRules.YIELD_FORMAT, yield) - - return formattedYield - } - - private fun calculateRanks(winningNumbers: List, bonusNumber: Int): List { + private fun calculateRanks(winningNumbers: List, bonusNumber: Int): List { val lotteriesRank = lotteries.map { lotto -> lotto.getLottoRank(winningNumbers, bonusNumber) } return lotteriesRank } - private fun countRank(lotteriesRank: List): Map { + private fun countRank(lotteriesRank: List): Map { val rankWithCounts = lotteriesRank.groupingBy { it }.eachCount() return rankWithCounts } - private fun mapToResult(rankWithCounts: Map): List { - val lottoResult = (LottoRules.RANK_FIRST..LottoRules.RANK_FIFTH).map { rank -> + private fun mapToResult(rankWithCounts: Map): List { + val lottoResult = LottoRank.entries + .filter { it != LottoRank.OUT_OF_RANK } + .map { rank -> val count = rankWithCounts.getOrDefault(rank, LottoRules.ZERO) - LottoResult(rank, count) + LottoResult(rank.rankNumber, count) } return lottoResult } + fun getLottoYield(lottoResults: List, purchaseAmount: Int): String { + val totalEarnings = calculateTotalEarnings(lottoResults) + val yield = (totalEarnings / purchaseAmount) * LottoRules.PERCENTAGE + val formattedYield = String.format(LottoRules.YIELD_FORMAT, yield) + + return formattedYield + } + private fun calculateTotalEarnings(lottoResults: List): Float { var totalEarnings = LottoRules.ZERO_FLOAT lottoResults.forEach { lottoResult -> @@ -48,14 +50,8 @@ class LottoResultCalculator(private val lotteries: List) { } private fun getPrizeMoney(rank: Int): Int { - return when (rank) { - LottoRules.RANK_FIRST -> LottoRules.FIRST_PRIZE_MONEY - LottoRules.RANK_SECOND -> LottoRules.SECOND_PRIZE_MONEY - LottoRules.RANK_THIRD -> LottoRules.THIRD_PRIZE_MONEY - LottoRules.RANK_FOURTH -> LottoRules.FOURTH_PRIZE_MONEY - LottoRules.RANK_FIFTH -> LottoRules.FIFTH_PRIZE_MONEY - else -> LottoRules.OUT_OF_RANK - } + val prizeMoney = LottoRank.entries.find { it.rankNumber == rank }?.prizeMoney ?: LottoRules.OUT_OF_RANK + return prizeMoney } } diff --git a/src/main/kotlin/lotto/view/OutputView.kt b/src/main/kotlin/lotto/view/OutputView.kt index 1e6c8fd37..589feb59b 100644 --- a/src/main/kotlin/lotto/view/OutputView.kt +++ b/src/main/kotlin/lotto/view/OutputView.kt @@ -1,6 +1,7 @@ package lotto.view import lotto.model.Lotto +import lotto.model.LottoRank import lotto.model.LottoResult import lotto.util.constant.OutputConst @@ -24,12 +25,9 @@ class OutputView { fun showMatchingLottoAmount(lottoResults: List) { println(OutputConst.RESULT) lottoResults.reversed().forEach { lottoResult -> - when (lottoResult.rank) { - 5 -> println("${OutputConst.THREE_MATCHED} ${OutputConst.matchedLotteries(lottoResult.count)}") - 4 -> println("${OutputConst.FOUR_MATCHED} ${OutputConst.matchedLotteries(lottoResult.count)}") - 3 -> println("${OutputConst.FIVE_MATCHED} ${OutputConst.matchedLotteries(lottoResult.count)}") - 2 -> println("${OutputConst.FIVE_MATCHED_WITH_BONUS} ${OutputConst.matchedLotteries(lottoResult.count)}") - 1 -> println("${OutputConst.SIX_MATCHED} ${OutputConst.matchedLotteries(lottoResult.count)}") + val rank = LottoRank.entries.find { it.rankNumber == lottoResult.rank } + rank?.let { + println("${it.displayName} ${OutputConst.matchedLotteries(lottoResult.count)}") } } } From 1bcf0d9edc0ece0bf330afab186ad11761380220 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 17:35:27 +0900 Subject: [PATCH 24/41] =?UTF-8?q?feat:=20=EB=8B=B9=EC=B2=A8=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=20=EA=B0=9C=EC=88=98=20=ED=91=9C=EA=B8=B0=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. LottoRules - Count format을 추가: 1,000단위로 쉼표제공 2. OutputConst - 입력 파라미터값 String으로 변경 3. OutputView - count 포멧 변경값을 표기 --- src/main/kotlin/lotto/util/constant/LottoRules.kt | 1 + src/main/kotlin/lotto/util/constant/OutputConst.kt | 2 +- src/main/kotlin/lotto/view/OutputView.kt | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/lotto/util/constant/LottoRules.kt b/src/main/kotlin/lotto/util/constant/LottoRules.kt index a8dd7a156..8dc4c9fd3 100644 --- a/src/main/kotlin/lotto/util/constant/LottoRules.kt +++ b/src/main/kotlin/lotto/util/constant/LottoRules.kt @@ -27,6 +27,7 @@ object LottoRules { const val PERCENTAGE = 100F const val YIELD_FORMAT = "%,.1f" + const val COUNT_FORMAT = "%,d" const val FIRST_PRIZE_MONEY = 2000000000 const val SECOND_PRIZE_MONEY = 30000000 diff --git a/src/main/kotlin/lotto/util/constant/OutputConst.kt b/src/main/kotlin/lotto/util/constant/OutputConst.kt index 690b9ea40..d8e4d0016 100644 --- a/src/main/kotlin/lotto/util/constant/OutputConst.kt +++ b/src/main/kotlin/lotto/util/constant/OutputConst.kt @@ -12,7 +12,7 @@ object OutputConst { const val SIX_MATCHED = "6개 일치 (2,000,000,000원)" private const val LOTTO_COUNT = "- %s개" - fun matchedLotteries(count: Int): String = LOTTO_COUNT.format(count) + fun matchedLotteries(count: String): String = LOTTO_COUNT.format(count) private const val TOTAL_YIELD = "총 수익률은 %s%%입니다." fun getTotalYieldMessage(yield: String): String = TOTAL_YIELD.format(yield) diff --git a/src/main/kotlin/lotto/view/OutputView.kt b/src/main/kotlin/lotto/view/OutputView.kt index 589feb59b..ecf3f973a 100644 --- a/src/main/kotlin/lotto/view/OutputView.kt +++ b/src/main/kotlin/lotto/view/OutputView.kt @@ -3,6 +3,7 @@ package lotto.view import lotto.model.Lotto import lotto.model.LottoRank import lotto.model.LottoResult +import lotto.util.constant.LottoRules import lotto.util.constant.OutputConst class OutputView { @@ -26,8 +27,9 @@ class OutputView { println(OutputConst.RESULT) lottoResults.reversed().forEach { lottoResult -> val rank = LottoRank.entries.find { it.rankNumber == lottoResult.rank } + val count = String.format(LottoRules.COUNT_FORMAT, lottoResult.count) rank?.let { - println("${it.displayName} ${OutputConst.matchedLotteries(lottoResult.count)}") + println("${it.displayName} ${OutputConst.matchedLotteries(count)}") } } } From 896a041762eee9263286c49413fc31bf24bcae96 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 18:38:18 +0900 Subject: [PATCH 25/41] =?UTF-8?q?docs:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9D=BC=EC=A0=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 기존 기능목록에 대해 테스트 일정 작성 -> class 별 메소드에 대한 테스트로 변경 --- README.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ec5de668d..68428503b 100644 --- a/README.md +++ b/README.md @@ -155,13 +155,23 @@ - 자연수가 아닐 경우: "[ERROR] 보너스 번호는 자연수여야 합니다." ## 테스트 -- 당첨 통계 - - 당첨 번호 확인 - - [ ] 당첨된 로또 분류 기능 - - [ ] 보너스 번호에 따른 2등과 3등 구분 - - 수익률 - - [ ] 총 당첨액 계산 - - [ ] 수익률 계산(소수점 둘째자리에서 반올림) +- Lotto 테스트 + - 초기화 검증 테스트 + - [ ] 로또 번호 개수 테스트 + - [ ] 로또 번호 범위 테스트 + - [ ] 로또 번호 중복 테스트 + - [ ] 로또 번호 불변 테스트 + - 로또 등수 테스트 + - [ ] 당첨 + - [ ] 꽝 + +- LottoFactory 테스트 + - [ ] 변수 불변 테스트 + - [ ] 로또 생성 테스트 + +- LottoResultCalculator 테스트 + - [ ] 로또 결과 테스트 + - [ ] 총 수익률 테스트 - 예외 상황 테스트 - 구입 금액 From 3054191fc8d0dbc4c672372cd92bb9e9d087b3d6 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 18:45:45 +0900 Subject: [PATCH 26/41] =?UTF-8?q?test:=20Lotto=20class=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 초기화 검증 테스트 - 로또 개수 테스트, 초과일 경우, 미만일 경우 - 로또 범위 테스트, 1미만일 경우, 45초과일 경우 - 중복 숫자 테스트 2. 불변성 테스트 - 객체 생성후 객체 내부값은 불변 확인 3. 로또 등수 테스트 - 당첨일 경우 - 꽝일 경우 --- src/test/kotlin/lotto/model/LottoTest.kt | 138 +++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 src/test/kotlin/lotto/model/LottoTest.kt diff --git a/src/test/kotlin/lotto/model/LottoTest.kt b/src/test/kotlin/lotto/model/LottoTest.kt new file mode 100644 index 000000000..7b0cccd88 --- /dev/null +++ b/src/test/kotlin/lotto/model/LottoTest.kt @@ -0,0 +1,138 @@ +package lotto.model + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class LottoTest { + + @DisplayName("로또 번호 검증 테스트") + @Nested + inner class LottoNumbersValidator { + + @DisplayName("범위 테스트") + @Nested + inner class RangeTest { + + @Test + fun `로또 번호의 개수가 6개가 넘어가면 예외가 발생한다`() { + assertThrows { + Lotto(listOf(1, 2, 3, 4, 5, 6, 7)) + } + } + + @Test + fun `로또 번호의 개수가 6개보다 적으면 예외가 발생한다`() { + assertThrows { + Lotto(listOf(1,2,3)) + } + } + } + + @ParameterizedTest + @ValueSource(ints = [0, 46]) + fun `로또 번호가 범위를 넘어가면 예외가 발생한다`(number: Int) { + assertThrows { + Lotto(listOf(1,2,3,4,5,number)) + } + } + + @Test + fun `로또 번호에 중복된 숫자가 있으면 예외가 발생한다`() { + assertThrows { + Lotto(listOf(1, 2, 3, 4, 5, 5)) + } + } + } + + @Test + fun `로또 번호 리스트는 불변성을 유지한다`() { + val originalNumbers = listOf(1,2,3,4,5,6) + val lotto = Lotto(originalNumbers) + + val lottoNumbers = lotto.getLottoNumber() + + val modifiedNumbers = lottoNumbers.toMutableList() + modifiedNumbers[0] = 45 + + assertEquals(originalNumbers, lotto.getLottoNumber()) + } + + @DisplayName("로또 등수 테스트") + @Nested + inner class LottoRankTest { + private val winningNumber = listOf(1, 2, 3, 4, 5, 6) + private val bonusNumber = 7 + + @DisplayName("당첨일 경우") + @Nested + inner class InRank { + + @Test + fun `모든 번호가 일치하는 경우 1등`() { + val lotto = Lotto(listOf(1, 2, 3, 4, 5, 6)) + val rank = lotto.getLottoRank(winningNumber, bonusNumber) + + assertEquals(LottoRank.FIRST, rank) + } + + @Test + fun `5개 번호 일치 + 보너스 번호 일치하는 경우 2등`() { + val lotto = Lotto(listOf(1, 2, 3, 4, 5, 7)) + val rank = lotto.getLottoRank(winningNumber, bonusNumber) + assertEquals(LottoRank.SECOND, rank) + } + + @Test + fun `5개 번호 일치하는 경우 3등`() { + val lotto = Lotto(listOf(1, 2, 3, 4, 5, 8)) + val rank = lotto.getLottoRank(winningNumber, bonusNumber) + assertEquals(LottoRank.THIRD, rank) + } + + @Test + fun `4개 번호 일치하는 경우 4등`() { + val lotto = Lotto(listOf(1, 2, 3, 4, 7, 8)) + val rank = lotto.getLottoRank(winningNumber, bonusNumber) + assertEquals(LottoRank.FOURTH, rank) + } + + @Test + fun `3개 번호 일치하는 경우 5등`() { + val lotto = Lotto(listOf(1, 2, 3, 7, 8, 9)) + val rank = lotto.getLottoRank(winningNumber, bonusNumber) + assertEquals(LottoRank.FIFTH, rank) + } + } + + @DisplayName("꽝인 경우") + @Nested + inner class OutOfRankTest { + + @Test + fun `2개 번호가 일치하는 경우 꽝`() { + val lotto = Lotto(listOf(1, 2, 7, 8, 9, 10)) + val rank = lotto.getLottoRank(winningNumber, bonusNumber) + assertEquals(LottoRank.OUT_OF_RANK, rank) + } + + @Test + fun `1개 번호 일치하는 경우 꽝`() { + val lotto = Lotto(listOf(1, 7, 8, 9, 10, 11)) + val rank = lotto.getLottoRank(winningNumber, bonusNumber) + assertEquals(LottoRank.OUT_OF_RANK, rank) + } + + @Test + fun `번호가 하나도 일치하지 않는 경우 꽝`() { + val lotto = Lotto(listOf(7, 8, 9, 10, 11, 12)) + val rank = lotto.getLottoRank(winningNumber, bonusNumber) + assertEquals(LottoRank.OUT_OF_RANK, rank) + } + } + } +} From 43ac56310621102efe982729e5108865bdfc6925 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 18:50:07 +0900 Subject: [PATCH 27/41] =?UTF-8?q?fix:=20=EC=BD=94=EB=93=9C=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. class나 object에 프로퍼티가 없을 경우 class 명 밑에 공백 한줄 추가 --- src/main/kotlin/lotto/model/Lotto.kt | 1 + src/main/kotlin/lotto/model/LottoFactory.kt | 21 ++++++++++--------- .../lotto/model/LottoResultCalculator.kt | 1 + .../util/validator/BonusNumberValidator.kt | 1 + src/main/kotlin/lotto/view/InputView.kt | 1 + src/main/kotlin/lotto/view/OutputView.kt | 1 + 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/lotto/model/Lotto.kt b/src/main/kotlin/lotto/model/Lotto.kt index 7c95425a7..6d4f0188f 100644 --- a/src/main/kotlin/lotto/model/Lotto.kt +++ b/src/main/kotlin/lotto/model/Lotto.kt @@ -3,6 +3,7 @@ package lotto.model import lotto.util.validator.LottoNumberValidator class Lotto(private val numbers: List) { + init { LottoNumberValidator.validateLottoNumbers(numbers) } diff --git a/src/main/kotlin/lotto/model/LottoFactory.kt b/src/main/kotlin/lotto/model/LottoFactory.kt index 52e1a8681..dfd591149 100644 --- a/src/main/kotlin/lotto/model/LottoFactory.kt +++ b/src/main/kotlin/lotto/model/LottoFactory.kt @@ -7,21 +7,13 @@ import lotto.util.constant.LottoRules // 구입금액을 통해 로또를 발행 -> 발행된 로또 // 구입금액 제공 class LottoFactory(private val purchaseAmount: Int) { + val lottoQuantity: Int = purchaseAmount / LottoRules.AMOUNT_UNIT fun getPurchaseAmount(): Int = purchaseAmount - private fun createNumber(): List { - val randomNumbers = Randoms.pickUniqueNumbersInRange( - LottoRules.LOTTO_NUMBER_MIN, - LottoRules.LOTTO_NUMBER_MAX, - LottoRules.LOTTO_NUMBER_COUNT - ).sorted() - return randomNumbers - } - fun createLotto(): List { - val lottoList: MutableList = emptyList().toMutableList() + val lottoList: MutableList = mutableListOf() repeat(lottoQuantity) { val numbers = createNumber() val lotto = Lotto(numbers) @@ -29,4 +21,13 @@ class LottoFactory(private val purchaseAmount: Int) { } return lottoList } + + private fun createNumber(): List { + val randomNumbers = Randoms.pickUniqueNumbersInRange( + LottoRules.LOTTO_NUMBER_MIN, + LottoRules.LOTTO_NUMBER_MAX, + LottoRules.LOTTO_NUMBER_COUNT + ).sorted() + return randomNumbers + } } \ No newline at end of file diff --git a/src/main/kotlin/lotto/model/LottoResultCalculator.kt b/src/main/kotlin/lotto/model/LottoResultCalculator.kt index 54b44c8ed..92d623719 100644 --- a/src/main/kotlin/lotto/model/LottoResultCalculator.kt +++ b/src/main/kotlin/lotto/model/LottoResultCalculator.kt @@ -3,6 +3,7 @@ package lotto.model import lotto.util.constant.LottoRules class LottoResultCalculator(private val lotteries: List) { + fun getLottoResults(winningNumbers: List, bonusNumber: Int): List { val lotteriesRank = calculateRanks(winningNumbers, bonusNumber) val rankWithCounts = countRank(lotteriesRank) diff --git a/src/main/kotlin/lotto/util/validator/BonusNumberValidator.kt b/src/main/kotlin/lotto/util/validator/BonusNumberValidator.kt index bc3daeb1f..b92f15376 100644 --- a/src/main/kotlin/lotto/util/validator/BonusNumberValidator.kt +++ b/src/main/kotlin/lotto/util/validator/BonusNumberValidator.kt @@ -4,6 +4,7 @@ import lotto.util.constant.ErrorMessages import lotto.util.constant.LottoRules object BonusNumberValidator { + fun getValidatedBonusNumber(bonusNumberInput: String, winningNumbers: List): Int { validateIsNumeric(bonusNumberInput) diff --git a/src/main/kotlin/lotto/view/InputView.kt b/src/main/kotlin/lotto/view/InputView.kt index fced0f45d..5ba460f70 100644 --- a/src/main/kotlin/lotto/view/InputView.kt +++ b/src/main/kotlin/lotto/view/InputView.kt @@ -4,6 +4,7 @@ import camp.nextstep.edu.missionutils.Console import lotto.util.constant.InputConst class InputView { + private fun getInput(message: String): String { println(message) val input = Console.readLine() diff --git a/src/main/kotlin/lotto/view/OutputView.kt b/src/main/kotlin/lotto/view/OutputView.kt index ecf3f973a..674d14d57 100644 --- a/src/main/kotlin/lotto/view/OutputView.kt +++ b/src/main/kotlin/lotto/view/OutputView.kt @@ -7,6 +7,7 @@ import lotto.util.constant.LottoRules import lotto.util.constant.OutputConst class OutputView { + fun showErrorMessage(errorMessages: String) { println(errorMessages) } From ec54bce6d7d570058393630acf868642f245c4de Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 19:20:55 +0900 Subject: [PATCH 28/41] =?UTF-8?q?fix:=20=EC=BD=94=EB=93=9C=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. class나 object에 프로퍼티가 없을 경우 class 명 밑에 공백 한줄 추가 2. 주석 제거 --- src/main/kotlin/lotto/model/LottoFactory.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/kotlin/lotto/model/LottoFactory.kt b/src/main/kotlin/lotto/model/LottoFactory.kt index dfd591149..8bf223fd8 100644 --- a/src/main/kotlin/lotto/model/LottoFactory.kt +++ b/src/main/kotlin/lotto/model/LottoFactory.kt @@ -3,11 +3,7 @@ package lotto.model import camp.nextstep.edu.missionutils.Randoms import lotto.util.constant.LottoRules -// 로또를 발행하는 역할(로또 생성) -// 구입금액을 통해 로또를 발행 -> 발행된 로또 -// 구입금액 제공 class LottoFactory(private val purchaseAmount: Int) { - val lottoQuantity: Int = purchaseAmount / LottoRules.AMOUNT_UNIT fun getPurchaseAmount(): Int = purchaseAmount From dc3ffc7290cfb0849aefefc8f3cf82c206c1891b Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 19:22:23 +0900 Subject: [PATCH 29/41] =?UTF-8?q?test:=20LottoFactory=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 구매 금액 불변성 테스트 2. 로또 발행 테스트 - 발행 로또 갯수는 금액에 따라 결정 - 최대 금액에 대해 빌드 가능한지 테스트 --- .../kotlin/lotto/model/LottoFactoryTest.kt | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/test/kotlin/lotto/model/LottoFactoryTest.kt diff --git a/src/test/kotlin/lotto/model/LottoFactoryTest.kt b/src/test/kotlin/lotto/model/LottoFactoryTest.kt new file mode 100644 index 000000000..40f362ec4 --- /dev/null +++ b/src/test/kotlin/lotto/model/LottoFactoryTest.kt @@ -0,0 +1,42 @@ +package lotto.model + +import lotto.util.constant.LottoRules +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class LottoFactoryTest { + + @Test + fun `구매금액은 불변성을 유지한다`() { + val originalPurchaseAmount = 10000 + val lottoFactory = LottoFactory(originalPurchaseAmount) + val purchaseAmount = lottoFactory.getPurchaseAmount() + val modifiedPurchaseAmount = purchaseAmount + 5000 + + assertEquals(originalPurchaseAmount, lottoFactory.getPurchaseAmount()) + } + + @Test + fun `구매금액에 따라 로또가 발행된다`() { + val purchaseAmount = 10000 + val lottoFactory = LottoFactory(purchaseAmount) + val lotteries = lottoFactory.createLotto() + + val expectedQuantity = purchaseAmount / LottoRules.AMOUNT_UNIT + val result = lotteries.size + + assertEquals(expectedQuantity, result) + } + + @Test + fun `최대금액 10억에 대한 로또 발행`() { + val purchaseAmount = LottoRules.MAX_AMOUNT + val lottoFactory = LottoFactory(purchaseAmount) + val lotteries = lottoFactory.createLotto() + + val expectedQuantity = purchaseAmount / LottoRules.AMOUNT_UNIT + val result = lotteries.size + + assertEquals(expectedQuantity, result) + } +} \ No newline at end of file From fd643843d723cdf85a6ead8a2ffed8d83cf3d480 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 21:12:59 +0900 Subject: [PATCH 30/41] =?UTF-8?q?test:=20LottoResultCalculator=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 로또 결과 테스트 - 1등부터 5등까지 당첨 갯수 확인 - 당첨이 안되면 0으로 표기됨을 확인 2. 로또 수익률 테스트 - 결과 예시에서 나온 계산방식이 맞는지 확인 - 1000단위 구분과 소수점 계산 확인 3. 테스트 결과 Float 타입은 소수점 계산에 오류가 생김 -> Double타입으로 변경 --- .../lotto/model/LottoResultCalculator.kt | 4 +- .../kotlin/lotto/util/constant/LottoRules.kt | 4 +- .../lotto/model/LottoResultCalculatorTest.kt | 102 ++++++++++++++++++ 3 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 src/test/kotlin/lotto/model/LottoResultCalculatorTest.kt diff --git a/src/main/kotlin/lotto/model/LottoResultCalculator.kt b/src/main/kotlin/lotto/model/LottoResultCalculator.kt index 92d623719..b89d0ba9d 100644 --- a/src/main/kotlin/lotto/model/LottoResultCalculator.kt +++ b/src/main/kotlin/lotto/model/LottoResultCalculator.kt @@ -40,8 +40,8 @@ class LottoResultCalculator(private val lotteries: List) { return formattedYield } - private fun calculateTotalEarnings(lottoResults: List): Float { - var totalEarnings = LottoRules.ZERO_FLOAT + private fun calculateTotalEarnings(lottoResults: List): Double { + var totalEarnings = LottoRules.ZERO_DOUBLE lottoResults.forEach { lottoResult -> val prizeMoney = getPrizeMoney(lottoResult.rank) val count = lottoResult.count diff --git a/src/main/kotlin/lotto/util/constant/LottoRules.kt b/src/main/kotlin/lotto/util/constant/LottoRules.kt index 8dc4c9fd3..5f67bcc58 100644 --- a/src/main/kotlin/lotto/util/constant/LottoRules.kt +++ b/src/main/kotlin/lotto/util/constant/LottoRules.kt @@ -3,7 +3,7 @@ package lotto.util.constant object LottoRules { const val AMOUNT_UNIT = 1000 const val ZERO = 0 - const val ZERO_FLOAT = 0F + const val ZERO_DOUBLE = 0.0 // Float로 계산했을때 정밀 소수점 계산이 안됐음 const val MAX_AMOUNT = 1000000000 const val DELIMITER = "," @@ -25,7 +25,7 @@ object LottoRules { const val RANK_FIFTH = 5 const val OUT_OF_RANK = 0 - const val PERCENTAGE = 100F + const val PERCENTAGE = 100.0 const val YIELD_FORMAT = "%,.1f" const val COUNT_FORMAT = "%,d" diff --git a/src/test/kotlin/lotto/model/LottoResultCalculatorTest.kt b/src/test/kotlin/lotto/model/LottoResultCalculatorTest.kt new file mode 100644 index 000000000..143501e2c --- /dev/null +++ b/src/test/kotlin/lotto/model/LottoResultCalculatorTest.kt @@ -0,0 +1,102 @@ +package lotto.model + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test + +class LottoResultCalculatorTest { + + @DisplayName("로또 결과 테스트") + @Nested + inner class LottoResultsTest { + private val winningNumbers = listOf(1, 2, 3, 4, 5, 6) + private val bonusNumber = 7 + + @Test + fun `로또 결과 1~5등 당첨`() { + val lotto1 = Lotto(listOf(1, 2, 3, 4, 5, 6)) // 1 + val lotto2 = Lotto(listOf(1, 2, 3, 4, 5, 7)) // 2 + val lotto3 = Lotto(listOf(1, 2, 3, 4, 5, 8)) // 3 + val lotto4 = Lotto(listOf(1, 2, 3, 4, 7, 8)) // 4 + val lotto5 = Lotto(listOf(1, 2, 3, 7, 8, 9)) // 5 + val lotto6 = Lotto(listOf(2, 3, 4, 5, 6, 8)) // 3 + val lotto7 = Lotto(listOf(3, 4, 5, 8, 9, 10)) // 5 + val lotto8 = Lotto(listOf(2, 4, 5, 9, 7, 8)) // 5 + + val lotteries = listOf(lotto1, lotto2, lotto3, lotto4, lotto5, lotto6, lotto7, lotto8) + val lottoResultCalculator = LottoResultCalculator(lotteries) + + val expected = listOf( + LottoResult(rank = 1, count = 1), + LottoResult(rank = 2, count = 1), + LottoResult(rank = 3, count = 2), + LottoResult(rank = 4, count = 1), + LottoResult(rank = 5, count = 3), + ) + val result = lottoResultCalculator.getLottoResults(winningNumbers, bonusNumber) + + assertEquals(expected, result) + } + + @Test + fun `로또 결과 미당첨`() { + val lotto1 = Lotto(listOf(1, 2, 7, 8, 9, 10)) + val lotto2 = Lotto(listOf(1, 7, 8, 9, 10, 11)) + val lotto3 = Lotto(listOf(7, 8, 9, 10, 11, 12)) + + val lotteries = listOf(lotto1, lotto2, lotto3) + val lottoResultCalculator = LottoResultCalculator(lotteries) + + val expected = listOf( + LottoResult(rank = 1, count = 0), + LottoResult(rank = 2, count = 0), + LottoResult(rank = 3, count = 0), + LottoResult(rank = 4, count = 0), + LottoResult(rank = 5, count = 0), + ) + val result = lottoResultCalculator.getLottoResults(winningNumbers, bonusNumber) + + assertEquals(expected, result) + } + } + + @DisplayName("로또 수익률 테스트") + @Nested + inner class YieldTest { + + @Test + fun `로또 수익률을 올바르게 계산한다`() { + val lottoResults = listOf( + LottoResult(rank = 5, count = 1) + ) + val purchaseAmount = 8000 + + val lottoResultCalculator = LottoResultCalculator(emptyList()) + + val expected = "62.5" + val result = lottoResultCalculator.getLottoYield(lottoResults, purchaseAmount) + + assertEquals(expected, result) + } + + @Test + fun `1,000단위가 넘어갈 때 단위구분을 하는가`() { + val lottoResults = listOf( + LottoResult(rank = 1, count = 1), + LottoResult(rank = 2, count = 1), + LottoResult(rank = 3, count = 2), + LottoResult(rank = 4, count = 1), + LottoResult(rank = 5, count = 3), + ) + val purchaseAmount = 8000 + + val lottoResultCalculator = LottoResultCalculator(emptyList()) + + val expected = "25,413,312.5" + val result = lottoResultCalculator.getLottoYield(lottoResults, purchaseAmount) + + assertEquals(expected, result) + } + } +} \ No newline at end of file From a9dc229c59e9fb0541d34f2293998d82c8f00d71 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 21:47:45 +0900 Subject: [PATCH 31/41] =?UTF-8?q?test:=20PurchaseAmountValidator=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 빈 값 입력 테스트 - 에러 메세지 확인 2. 숫자가 아닌 입력 테스트 3. 구입 금액의 천 단위 테스트 4. 금액 범위를 넘어간 경우 - 기존 10억만 검사하던 기존과 달리 1000~10억으로 변경 --- .../lotto/util/constant/ErrorMessages.kt | 2 +- .../kotlin/lotto/util/constant/LottoRules.kt | 1 + .../util/validator/PurchaseAmountValidator.kt | 4 +- .../lotto/util/PurchaseAmountValidatorTest.kt | 45 +++++++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 src/test/kotlin/lotto/util/PurchaseAmountValidatorTest.kt diff --git a/src/main/kotlin/lotto/util/constant/ErrorMessages.kt b/src/main/kotlin/lotto/util/constant/ErrorMessages.kt index f7675d0b7..cc8122aab 100644 --- a/src/main/kotlin/lotto/util/constant/ErrorMessages.kt +++ b/src/main/kotlin/lotto/util/constant/ErrorMessages.kt @@ -6,7 +6,7 @@ object ErrorMessages { const val AMOUNT_IS_NOT_EMPTY = "$ERROR_HEADER 구입 금액은 빈 값이 될 수 없습니다." const val AMOUNT_IS_NUMERIC = "$ERROR_HEADER 구입 금액은 숫자여야 합니다." const val AMOUNT_IS_MULTIPLE_OF_THOUSAND = "$ERROR_HEADER 구입 금액은 1,000원 단위여야 합니다." - const val MAX_AMOUNT = "$ERROR_HEADER 구입 금액은 10억원 이하여야 합니다." + const val OUT_OF_AMOUNT_RANGE = "$ERROR_HEADER 구입 금액은 1,000원 이상 10억원 이하여야 합니다." const val LOTTO_NUMBER_NUMERIC = "$ERROR_HEADER 로또 번호는 자연수여야 합니다." const val LOTTO_NUMBER_DELIMITER = "$ERROR_HEADER 로또 번호는 쉼표로 구분해야 합니다." diff --git a/src/main/kotlin/lotto/util/constant/LottoRules.kt b/src/main/kotlin/lotto/util/constant/LottoRules.kt index 5f67bcc58..1cfd487ae 100644 --- a/src/main/kotlin/lotto/util/constant/LottoRules.kt +++ b/src/main/kotlin/lotto/util/constant/LottoRules.kt @@ -5,6 +5,7 @@ object LottoRules { const val ZERO = 0 const val ZERO_DOUBLE = 0.0 // Float로 계산했을때 정밀 소수점 계산이 안됐음 const val MAX_AMOUNT = 1000000000 + val AMOUNT_RANGE = AMOUNT_UNIT..MAX_AMOUNT const val DELIMITER = "," diff --git a/src/main/kotlin/lotto/util/validator/PurchaseAmountValidator.kt b/src/main/kotlin/lotto/util/validator/PurchaseAmountValidator.kt index 61f429234..b7cd2d4a0 100644 --- a/src/main/kotlin/lotto/util/validator/PurchaseAmountValidator.kt +++ b/src/main/kotlin/lotto/util/validator/PurchaseAmountValidator.kt @@ -24,10 +24,10 @@ object PurchaseAmountValidator { } private fun validateMaxAmount(amount: Int) { - require(amount <= LottoRules.MAX_AMOUNT) { ErrorMessages.MAX_AMOUNT } + require(amount in LottoRules.AMOUNT_RANGE) { ErrorMessages.OUT_OF_AMOUNT_RANGE } } - private fun validatePurchaseAmount(purchaseAmountInput: String) { + fun validatePurchaseAmount(purchaseAmountInput: String) { validateNotEmpty(purchaseAmountInput) val amount = purchaseAmountInput.trim().toIntOrNull() diff --git a/src/test/kotlin/lotto/util/PurchaseAmountValidatorTest.kt b/src/test/kotlin/lotto/util/PurchaseAmountValidatorTest.kt new file mode 100644 index 000000000..fb0d5caa4 --- /dev/null +++ b/src/test/kotlin/lotto/util/PurchaseAmountValidatorTest.kt @@ -0,0 +1,45 @@ +package lotto.util + +import lotto.util.constant.ErrorMessages +import lotto.util.validator.PurchaseAmountValidator +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class PurchaseAmountValidatorTest { + + @Test + fun `빈 값이 입력된 경우`() { + val input = "" + val exception = assertThrows { PurchaseAmountValidator.validatePurchaseAmount(input) } + + assertThat(exception).hasMessage(ErrorMessages.AMOUNT_IS_NOT_EMPTY) + } + + @ParameterizedTest + @ValueSource(strings = ["1million", "삼천원", "5.5", "8,000"]) + fun `숫자(정수)가 아닌 경우`(input: String) { + val exception = assertThrows { PurchaseAmountValidator.validatePurchaseAmount(input) } + + assertThat(exception).hasMessage(ErrorMessages.AMOUNT_IS_NUMERIC) + } + + @ParameterizedTest + @ValueSource(strings = ["10", "1", "-5", "1001"]) + fun `구입 금액이 천 단위가 아닐 경우`(input: String) { + val exception = assertThrows { PurchaseAmountValidator.validatePurchaseAmount(input) } + + assertThat(exception).hasMessage(ErrorMessages.AMOUNT_IS_MULTIPLE_OF_THOUSAND) + } + + + @ParameterizedTest + @ValueSource(strings = ["-1000", "2000000000"]) + fun `금액 범위를 넘어간 경우`(input: String) { + val exception = assertThrows { PurchaseAmountValidator.validatePurchaseAmount(input) } + + assertThat(exception).hasMessage(ErrorMessages.OUT_OF_AMOUNT_RANGE) + } +} \ No newline at end of file From 2db253fffc72c63156bd2062e7d8c966dff0aa5e Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 22:10:44 +0900 Subject: [PATCH 32/41] =?UTF-8?q?fix:=20PurchaseAmountValidatorTest=20?= =?UTF-8?q?=EB=AA=85=EC=82=AC=ED=98=95=20=EC=9D=B4=EB=A6=84=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=AA=85=EB=A0=B9=ED=98=95=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. ~ 예외가 발생한다 --- src/test/kotlin/lotto/util/PurchaseAmountValidatorTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/kotlin/lotto/util/PurchaseAmountValidatorTest.kt b/src/test/kotlin/lotto/util/PurchaseAmountValidatorTest.kt index fb0d5caa4..31e8e4b01 100644 --- a/src/test/kotlin/lotto/util/PurchaseAmountValidatorTest.kt +++ b/src/test/kotlin/lotto/util/PurchaseAmountValidatorTest.kt @@ -11,7 +11,7 @@ import org.junit.jupiter.params.provider.ValueSource class PurchaseAmountValidatorTest { @Test - fun `빈 값이 입력된 경우`() { + fun `빈 값이 입력된 경우 예외가 발생한다`() { val input = "" val exception = assertThrows { PurchaseAmountValidator.validatePurchaseAmount(input) } @@ -20,7 +20,7 @@ class PurchaseAmountValidatorTest { @ParameterizedTest @ValueSource(strings = ["1million", "삼천원", "5.5", "8,000"]) - fun `숫자(정수)가 아닌 경우`(input: String) { + fun `숫자(정수)가 아닌 경우 예외가 발생한다`(input: String) { val exception = assertThrows { PurchaseAmountValidator.validatePurchaseAmount(input) } assertThat(exception).hasMessage(ErrorMessages.AMOUNT_IS_NUMERIC) @@ -28,7 +28,7 @@ class PurchaseAmountValidatorTest { @ParameterizedTest @ValueSource(strings = ["10", "1", "-5", "1001"]) - fun `구입 금액이 천 단위가 아닐 경우`(input: String) { + fun `구입 금액이 천 단위가 아닐 경우 예외가 발생한다`(input: String) { val exception = assertThrows { PurchaseAmountValidator.validatePurchaseAmount(input) } assertThat(exception).hasMessage(ErrorMessages.AMOUNT_IS_MULTIPLE_OF_THOUSAND) @@ -37,7 +37,7 @@ class PurchaseAmountValidatorTest { @ParameterizedTest @ValueSource(strings = ["-1000", "2000000000"]) - fun `금액 범위를 넘어간 경우`(input: String) { + fun `금액 범위를 넘어간 경우 예외가 발생한다`(input: String) { val exception = assertThrows { PurchaseAmountValidator.validatePurchaseAmount(input) } assertThat(exception).hasMessage(ErrorMessages.OUT_OF_AMOUNT_RANGE) From 87c93f39dbda3f1eefb56e172721a3bb695fc8c7 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 22:16:04 +0900 Subject: [PATCH 33/41] =?UTF-8?q?test:=20LottoNumberValidator=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 입력 문자열 테스트 - 구분자 테스트 - 자연수가 아닌경우 테스트 2. 로또 번호 테스트 - 로또 번호의 개수 테스트 - 로또 번호 범위 테스트 - 로또 번호 중복 숫자 테스트 3. 구분자 추가 - 쉼표와 쉼표뒤 공백 추가 --- .../kotlin/lotto/util/constant/LottoRules.kt | 1 + .../util/validator/LottoNumberValidator.kt | 2 +- .../lotto/util/LottoNumberValidatorTest.kt | 78 +++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/test/kotlin/lotto/util/LottoNumberValidatorTest.kt diff --git a/src/main/kotlin/lotto/util/constant/LottoRules.kt b/src/main/kotlin/lotto/util/constant/LottoRules.kt index 1cfd487ae..469aa146d 100644 --- a/src/main/kotlin/lotto/util/constant/LottoRules.kt +++ b/src/main/kotlin/lotto/util/constant/LottoRules.kt @@ -8,6 +8,7 @@ object LottoRules { val AMOUNT_RANGE = AMOUNT_UNIT..MAX_AMOUNT const val DELIMITER = "," + const val DELIMITER_WITH_SPACE = "$DELIMITER " const val LOTTO_NUMBER_COUNT = 6 const val LOTTO_NUMBER_MIN = 1 diff --git a/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt b/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt index b0266a8f1..20ff45365 100644 --- a/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt +++ b/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt @@ -34,7 +34,7 @@ object LottoNumberValidator { fun getValidatedWinningNumbers(winningNumbersInput: String): List { validateLottoNumberDelimiter(winningNumbersInput) - val splittingNumbersInput = winningNumbersInput.split(LottoRules.DELIMITER) + val splittingNumbersInput = winningNumbersInput.split(LottoRules.DELIMITER, LottoRules.DELIMITER_WITH_SPACE) validateIsNumeric(splittingNumbersInput) val validatedNumbers = splittingNumbersInput.map { it.toInt() } diff --git a/src/test/kotlin/lotto/util/LottoNumberValidatorTest.kt b/src/test/kotlin/lotto/util/LottoNumberValidatorTest.kt new file mode 100644 index 000000000..7ea7c531e --- /dev/null +++ b/src/test/kotlin/lotto/util/LottoNumberValidatorTest.kt @@ -0,0 +1,78 @@ +package lotto.util + +import lotto.util.constant.ErrorMessages +import lotto.util.validator.LottoNumberValidator +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class LottoNumberValidatorTest { + + @DisplayName("입력 문자열 테스트") + @Nested + inner class WinningNumberTest { + + @ParameterizedTest + @ValueSource(strings = ["1/2/3/4/5/6", "1 2 3 4 5 6", "123456"]) + fun `구분자가 쉼표가 아닐 경우 예외가 발생한다`(input: String) { + val exception = assertThrows { LottoNumberValidator.getValidatedWinningNumbers(input) } + + assertThat(exception).hasMessage(ErrorMessages.LOTTO_NUMBER_DELIMITER) + } + + @ParameterizedTest + @ValueSource(strings = ["a,b,c,d,e,f", "1 2,3 4,5 6,7 8,9 10,11 12", " , , , , , "]) + fun `로또 번호가 자연수가 아닌 경우 예외가 발생한다`(input: String) { + val exception = assertThrows { LottoNumberValidator.getValidatedWinningNumbers(input) } + + assertThat(exception).hasMessage(ErrorMessages.LOTTO_NUMBER_NUMERIC) + } + } + + @DisplayName("로또 번호 테스트") + @Nested + inner class LottoNumbersValidator { + + @DisplayName("로또 개수 테스트") + @Nested + inner class RangeTest { + + @Test + fun `로또 번호의 개수가 6개가 넘어가면 예외가 발생한다`() { + val input = listOf(1, 2, 3, 4, 5, 6, 7) + val exception = assertThrows { LottoNumberValidator.validateLottoNumbers(input) } + + assertThat(exception).hasMessage(ErrorMessages.LOTTO_NUMBER_COUNT) + } + + @Test + fun `로또 번호의 개수가 6개보다 적으면 예외가 발생한다`() { + val input = listOf(1,2,3) + val exception = assertThrows { LottoNumberValidator.validateLottoNumbers(input) } + + assertThat(exception).hasMessage(ErrorMessages.LOTTO_NUMBER_COUNT) + } + } + + @ParameterizedTest + @ValueSource(ints = [0, 46]) + fun `로또 번호가 범위를 넘어가면 예외가 발생한다`(number: Int) { + val input = listOf(1,2,3,4,5,number) + val exception = assertThrows { LottoNumberValidator.validateLottoNumbers(input) } + + assertThat(exception).hasMessage(ErrorMessages.LOTTO_NUMBER_RANGE) + } + + @Test + fun `로또 번호에 중복된 숫자가 있으면 예외가 발생한다`() { + val input = listOf(1, 2, 3, 4, 5, 5) + val exception = assertThrows { LottoNumberValidator.validateLottoNumbers(input) } + + assertThat(exception).hasMessage(ErrorMessages.LOTTO_NUMBER_UNIQUE) + } + } +} \ No newline at end of file From cd3c57551b65aaa5baaae56e92d44b5442a6ebb4 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 22:20:53 +0900 Subject: [PATCH 34/41] =?UTF-8?q?test:=20LottoNumberValidator=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 구분자 삭제 - 쉼표와 쉼표뒤 다시 삭제 --- src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt | 2 +- src/test/kotlin/lotto/util/LottoNumberValidatorTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt b/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt index 20ff45365..b0266a8f1 100644 --- a/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt +++ b/src/main/kotlin/lotto/util/validator/LottoNumberValidator.kt @@ -34,7 +34,7 @@ object LottoNumberValidator { fun getValidatedWinningNumbers(winningNumbersInput: String): List { validateLottoNumberDelimiter(winningNumbersInput) - val splittingNumbersInput = winningNumbersInput.split(LottoRules.DELIMITER, LottoRules.DELIMITER_WITH_SPACE) + val splittingNumbersInput = winningNumbersInput.split(LottoRules.DELIMITER) validateIsNumeric(splittingNumbersInput) val validatedNumbers = splittingNumbersInput.map { it.toInt() } diff --git a/src/test/kotlin/lotto/util/LottoNumberValidatorTest.kt b/src/test/kotlin/lotto/util/LottoNumberValidatorTest.kt index 7ea7c531e..69612e6e3 100644 --- a/src/test/kotlin/lotto/util/LottoNumberValidatorTest.kt +++ b/src/test/kotlin/lotto/util/LottoNumberValidatorTest.kt @@ -25,7 +25,7 @@ class LottoNumberValidatorTest { } @ParameterizedTest - @ValueSource(strings = ["a,b,c,d,e,f", "1 2,3 4,5 6,7 8,9 10,11 12", " , , , , , "]) + @ValueSource(strings = ["a,b,c,d,e,f", "1 2,3 4,5 6,7 8,9 10,11 12", " , , , , , ", "1, 2, 3, 4, 5, 6"]) fun `로또 번호가 자연수가 아닌 경우 예외가 발생한다`(input: String) { val exception = assertThrows { LottoNumberValidator.getValidatedWinningNumbers(input) } From 278f53b58048c5aff5f1d5074a6a7d9f2be5ce55 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 22:28:44 +0900 Subject: [PATCH 35/41] =?UTF-8?q?test:=20LottoNumberValidator=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 구분자 삭제 - 쉼표와 쉼표뒤 다시 삭제 --- src/main/kotlin/lotto/util/constant/LottoRules.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/lotto/util/constant/LottoRules.kt b/src/main/kotlin/lotto/util/constant/LottoRules.kt index 469aa146d..1cfd487ae 100644 --- a/src/main/kotlin/lotto/util/constant/LottoRules.kt +++ b/src/main/kotlin/lotto/util/constant/LottoRules.kt @@ -8,7 +8,6 @@ object LottoRules { val AMOUNT_RANGE = AMOUNT_UNIT..MAX_AMOUNT const val DELIMITER = "," - const val DELIMITER_WITH_SPACE = "$DELIMITER " const val LOTTO_NUMBER_COUNT = 6 const val LOTTO_NUMBER_MIN = 1 From 09aa94293fb282158862a994f68fee4103df7ea8 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 22:29:39 +0900 Subject: [PATCH 36/41] =?UTF-8?q?test:=20BonusNumberValidator=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 보너스 번호 입력에 대한 테스트 추가 - 입력값이 정수가 아닌 경우 - 번호 범위 예외 - 중복일 경우 --- .../lotto/util/BonusNumberValidatorTest.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/test/kotlin/lotto/util/BonusNumberValidatorTest.kt diff --git a/src/test/kotlin/lotto/util/BonusNumberValidatorTest.kt b/src/test/kotlin/lotto/util/BonusNumberValidatorTest.kt new file mode 100644 index 000000000..fa9f42742 --- /dev/null +++ b/src/test/kotlin/lotto/util/BonusNumberValidatorTest.kt @@ -0,0 +1,36 @@ +package lotto.util + +import lotto.util.constant.ErrorMessages +import lotto.util.validator.BonusNumberValidator +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class BonusNumberValidatorTest { + private val winningNumberTest = listOf(1, 2, 3, 4, 5, 6) + + @ParameterizedTest + @ValueSource(strings = ["a", "#", "", "0.1"]) + fun `입력 값이 정수가 아닌 경우 예외가 발생한다`(input: String) { + val exception = assertThrows { BonusNumberValidator.getValidatedBonusNumber(input, winningNumberTest) } + + assertThat(exception).hasMessage(ErrorMessages.BONUS_NUMBER_NUMERIC) + } + + @ParameterizedTest + @ValueSource(strings = ["0", "46"]) + fun `보너스 번호가 범위를 넘어가면 예외가 발생한다`(input: String) { + val exception = assertThrows { BonusNumberValidator.getValidatedBonusNumber(input, winningNumberTest) } + + assertThat(exception).hasMessage(ErrorMessages.BONUS_NUMBER_RANGE) + } + + @ParameterizedTest + @ValueSource(strings = ["1", "2", "3", "4", "5", "6"]) + fun `보너스 번호와 당첨 번호에 중복된 숫자가 있으면 예외가 발생한다`(input: String) { + val exception = assertThrows { BonusNumberValidator.getValidatedBonusNumber(input, winningNumberTest) } + + assertThat(exception).hasMessage(ErrorMessages.BONUS_NUMBER_UNIQUE) + } +} \ No newline at end of file From 6defc699e4d2763ed04bbc0d77f44b2d0fadcdfc Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 22:31:10 +0900 Subject: [PATCH 37/41] =?UTF-8?q?docs:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 테스트 코드 작성 완료로 인한 체크 --- README.md | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 68428503b..5939c444e 100644 --- a/README.md +++ b/README.md @@ -157,35 +157,34 @@ ## 테스트 - Lotto 테스트 - 초기화 검증 테스트 - - [ ] 로또 번호 개수 테스트 - - [ ] 로또 번호 범위 테스트 - - [ ] 로또 번호 중복 테스트 - - [ ] 로또 번호 불변 테스트 + - [X] 로또 번호 개수 테스트 + - [X] 로또 번호 범위 테스트 + - [X] 로또 번호 중복 테스트 + - [X] 로또 번호 불변 테스트 - 로또 등수 테스트 - - [ ] 당첨 - - [ ] 꽝 + - [X] 당첨 + - [X] 꽝 - LottoFactory 테스트 - - [ ] 변수 불변 테스트 - - [ ] 로또 생성 테스트 + - [X] 변수 불변 테스트 + - [X] 로또 생성 테스트 - LottoResultCalculator 테스트 - - [ ] 로또 결과 테스트 - - [ ] 총 수익률 테스트 + - [X] 로또 결과 테스트 + - [X] 총 수익률 테스트 - 예외 상황 테스트 - 구입 금액 - - [ ] 숫자가 아닐 경우 - - [ ] 1,000으로 나눠 떨어지지 않을 경우 - - [ ] 10억을 넘길 경우 + - [X] 숫자가 아닐 경우 + - [X] 1,000으로 나눠 떨어지지 않을 경우 + - [X] 1,000에서 10억을 넘길 경우 - 로또 번호 - - [ ] 쉼표로 연결 되지 않을 경우 - - [ ] 1~45 사이의 수가 아닐 경우 - - [ ] 6개가 아닐 경우 - - [ ] 서로 다르지 않을 경우 - - [ ] 자연수가 아닐 경우 + - [X] 쉼표로 연결 되지 않을 경우 + - [X] 1~45 사이의 수가 아닐 경우 + - [X] 6개가 아닐 경우 + - [X] 서로 다르지 않을 경우 + - [X] 자연수가 아닐 경우 - 보너스 번호 - - [ ] 1~45 사이의 수가 아닐 경우 - - [ ] 당첨 번호와 중복이 있을 경우 - - [ ] 자연수가 아닐 경우 - - [ ] 하나의 숫자가 아닐 경우 \ No newline at end of file + - [X] 1~45 사이의 수가 아닐 경우 + - [X] 당첨 번호와 중복이 있을 경우 + - [X] 자연수가 아닐 경우 \ No newline at end of file From acbefabbdcd31cba82431f4297d8a53c6d290072 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 22:41:08 +0900 Subject: [PATCH 38/41] =?UTF-8?q?move:=20=EC=9C=84=EC=B9=98=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. model 패키지로 이동 --- src/test/kotlin/lotto/LottoTest.kt | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 src/test/kotlin/lotto/LottoTest.kt diff --git a/src/test/kotlin/lotto/LottoTest.kt b/src/test/kotlin/lotto/LottoTest.kt deleted file mode 100644 index 122fae572..000000000 --- a/src/test/kotlin/lotto/LottoTest.kt +++ /dev/null @@ -1,23 +0,0 @@ -package lotto - -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows - -class LottoTest { - @Test - fun `로또 번호의 개수가 6개가 넘어가면 예외가 발생한다`() { - assertThrows { - Lotto(listOf(1, 2, 3, 4, 5, 6, 7)) - } - } - - // TODO: 테스트가 통과하도록 프로덕션 코드 구현 - @Test - fun `로또 번호에 중복된 숫자가 있으면 예외가 발생한다`() { - assertThrows { - Lotto(listOf(1, 2, 3, 4, 5, 5)) - } - } - - // TODO: 추가 기능 구현에 따른 테스트 코드 작성 -} From 1af1e9b5b7cefd9066e6a589944dabb8e21bf3b2 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 22:44:55 +0900 Subject: [PATCH 39/41] =?UTF-8?q?test:=20ApplicationTest=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 기능 테스트 2개 추가 2. 예외 테스트는 나눠서 실행 했으므로 추가하지 않음 --- src/test/kotlin/lotto/ApplicationTest.kt | 63 ++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/test/kotlin/lotto/ApplicationTest.kt b/src/test/kotlin/lotto/ApplicationTest.kt index 9c3f0da4b..c6097d5e2 100644 --- a/src/test/kotlin/lotto/ApplicationTest.kt +++ b/src/test/kotlin/lotto/ApplicationTest.kt @@ -41,6 +41,69 @@ class ApplicationTest : NsTest() { ) } + @Test + fun `기능 테스트2`() { + assertRandomUniqueNumbersInRangeTest( + { + run("5000", "1,2,3,4,5,6", "7") + assertThat(output()).contains( + "5개를 구매했습니다.", + "[1, 2, 3, 4, 5, 6]", + "[1, 2, 3, 4, 5, 7]", + "[1, 2, 3, 4, 5, 8]", + "[1, 2, 3, 4, 7, 8]", + "[1, 2, 3, 7, 8, 9]", + "3개 일치 (5,000원) - 1개", + "4개 일치 (50,000원) - 1개", + "5개 일치 (1,500,000원) - 1개", + "5개 일치, 보너스 볼 일치 (30,000,000원) - 1개", + "6개 일치 (2,000,000,000원) - 1개", + "총 수익률은 40,631,100.0%입니다." + ) + }, + listOf(1, 2, 3, 4, 5, 6), + listOf(1, 2, 3, 4, 5, 7), + listOf(1, 2, 3, 4, 5, 8), + listOf(1, 2, 3, 4, 7, 8), + listOf(1, 2, 3, 7, 8, 9), + ) + } + + @Test + fun `기능 테스트3`() { + assertRandomUniqueNumbersInRangeTest( + { + run("8000", "1,2,3,4,5,6", "7") + assertThat(output()).contains( + "8개를 구매했습니다.", + "[1, 2, 3, 10, 11, 12]", + "[1, 2, 3, 11, 12, 13]", + "[1, 2, 3, 13, 14, 15]", + "[1, 2, 3, 4, 10, 11]", + "[1, 2, 3, 4, 5, 12]", + "[1, 2, 3, 4, 5, 13]", + "[1, 2, 3, 4, 5, 7]", + "[1, 2, 3, 4, 5, 6]", + "3개 일치 (5,000원) - 3개", + "4개 일치 (50,000원) - 1개", + "5개 일치 (1,500,000원) - 2개", + "5개 일치, 보너스 볼 일치 (30,000,000원) - 1개", + "6개 일치 (2,000,000,000원) - 1개", + "총 수익률은 25,413,312.5%입니다." + ) + }, + listOf(1, 2, 3, 10, 11, 12), + listOf(1, 2, 3, 11, 12, 13), + listOf(1, 2, 3, 13, 14, 15), + listOf(1, 2, 3, 4, 10, 11), + listOf(1, 2, 3, 4, 5, 12), + listOf(1, 2, 3, 4, 5, 13), + listOf(1, 2, 3, 4, 5, 7), + listOf(1, 2, 3, 4, 5, 6) + ) + } + + @Test fun `예외 테스트`() { assertSimpleTest { From 6242b231370868cc5edd615d9da8e77fc9ee3df9 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 22:55:15 +0900 Subject: [PATCH 40/41] =?UTF-8?q?ref:=20=EC=B4=9D=20=EC=83=81=EA=B8=88=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 기존 forEach를 통해 각각 계산해 넣는 방식과 달리 sumOf를 이용해 더 간단히 각각 계산 --- src/main/kotlin/lotto/model/LottoResultCalculator.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/lotto/model/LottoResultCalculator.kt b/src/main/kotlin/lotto/model/LottoResultCalculator.kt index b89d0ba9d..f42ec7b5d 100644 --- a/src/main/kotlin/lotto/model/LottoResultCalculator.kt +++ b/src/main/kotlin/lotto/model/LottoResultCalculator.kt @@ -41,13 +41,8 @@ class LottoResultCalculator(private val lotteries: List) { } private fun calculateTotalEarnings(lottoResults: List): Double { - var totalEarnings = LottoRules.ZERO_DOUBLE - lottoResults.forEach { lottoResult -> - val prizeMoney = getPrizeMoney(lottoResult.rank) - val count = lottoResult.count - totalEarnings += prizeMoney * count - } - return totalEarnings + val totalEarnings = lottoResults.sumOf { lottoResult -> getPrizeMoney(lottoResult.rank) * lottoResult.count } + return totalEarnings.toDouble() } private fun getPrizeMoney(rank: Int): Int { From 6a2f59ad2dd1f65f0854fb83c4a938b4b8b79446 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1SJ24AG\\hongjin" Date: Mon, 4 Nov 2024 23:29:33 +0900 Subject: [PATCH 41/41] =?UTF-8?q?docs:=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=EC=A1=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 프로젝트 구조 추가 --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index 5939c444e..86f318ecd 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,31 @@ 7. 번호가 몇 개 일치 했는가에 따라 당첨 내역을 출력한다. 8. 당첨 금액과 로또 구매 금액의 비율로 수익률을 구하고 출력한다. +## 프로젝트 구조 +``` +lotto +├── controller +│ └── LottoController.kt +├── model +│ ├── Lotto.kt +│ ├── LottoFactory.kt +│ ├── LottoRank.kt +│ └── LottoResultCalculator.kt +├── view +│ ├── InputView.kt +│ └── OutputView.kt +└── util + ├── constant + │ ├── ErrorMessages.kt + │ ├── InputConstants.kt + │ ├── OutputConstants.kt + │ └── LottoRules.kt + └── validator + ├── BonusNumberValidator.kt + ├── LottoNumberValidator.kt + └── PurchaseAmountValidator.kt +``` + ## 기능 요구 사항 ### 입력 - 로또 구입 금액