From 692eedcfd6b7b217b8259f3253e627f6e96891e3 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 18:51:18 +0900 Subject: [PATCH 01/37] =?UTF-8?q?docs($README.md):=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=ED=95=A0=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 62fa463c..7758a388 100644 --- a/README.md +++ b/README.md @@ -1 +1,28 @@ -# kotlin-racingcar-precourse +# 프리코스 2주차 _ 자동차 경주 + +## 자동차 경주 + +📍구현할 기능 목록 +1. 경주할 자동차 이름 입력받기 +2. 입력받은 자동차 이름 유효성 검증 + + - 잘못된 값을 입력할 경우 `IllegalArgumentException` 을 발생시킨 후 애플리케이션 종료 + 1. 이름을 5자 초과하여 입력한 경우 + 2. 빈 값을 입력한 경우 + 3. 쉼표가 아닌 구분자를 사용한 경우 (구분자를 쉼표(,)만 인식하도록 하여 하나의 문자열로 처리) + 4. 자동차 이름이 중복된 경우 + +3. 시도할 횟수 입력받기 +4. 입력받은 시도 횟수 유효성 검증 + + - 잘못된 값을 입력할 경우 `IllegalArgumentException` 을 발생시킨 후 애플리케이션 종료 + 1. 음수를 입력한 경우 + 2. 0을 입력한 경우 + 3. 문자열을 입력한 경우 + 4. 입력한 수가 Int 범위를 벗어나는 경우 + +5. 0부터 9 사이의 랜덤값을 통해 전진 유무를 결정 +6. 입력받은 시도 횟수만큼 반복 +7. 실행 결과 출력 +8. 전진 횟수가 가장 많은 자동차 판별 +9. 최종 우승자 출력 \ No newline at end of file From 6d589c96d0e83f8f589ef1dbcc13ab079822e8df Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 18:53:41 +0900 Subject: [PATCH 02/37] =?UTF-8?q?feat(InputView.kt):=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=9E=85=EB=A0=A5=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?InputView=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/InputView.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/kotlin/racingcar/view/InputView.kt diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt new file mode 100644 index 00000000..34339872 --- /dev/null +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -0,0 +1,5 @@ +package racingcar.view + +class InputView { + +} \ No newline at end of file From b63d33ea75b7ced23db9dde2070f73e2e633d072 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 18:57:39 +0900 Subject: [PATCH 03/37] =?UTF-8?q?feat(InputView.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20=EC=9E=85=EB=A0=A5=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/InputView.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 34339872..ccc3f8c9 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -1,5 +1,15 @@ package racingcar.view +import camp.nextstep.edu.missionutils.Console + class InputView { + fun inputCarNames() { + println(MESSAGE_ENTER_CAR_NAMES) + val input = Console.readLine().orEmpty() + } + + companion object { + const val MESSAGE_ENTER_CAR_NAMES = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" + } } \ No newline at end of file From 67c6b08ffcf8b3d553a2d2dca6fa5d21d0c679b9 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 18:59:54 +0900 Subject: [PATCH 04/37] =?UTF-8?q?feat(InputView.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20=EB=B9=88=EA=B0=92=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/InputView.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index ccc3f8c9..7c9d065c 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -7,9 +7,15 @@ class InputView { fun inputCarNames() { println(MESSAGE_ENTER_CAR_NAMES) val input = Console.readLine().orEmpty() + validateEmptyInput(input) + } + + private fun validateEmptyInput(input: String) { + if (input.isBlank()) throw IllegalArgumentException(ERROR_EMPTY_INPUT) } companion object { const val MESSAGE_ENTER_CAR_NAMES = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" + const val ERROR_EMPTY_INPUT = "자동차 이름을 입력해야 합니다." } } \ No newline at end of file From ba421793d7a718c6967fd26b3680916c11d9d62d Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:02:35 +0900 Subject: [PATCH 05/37] =?UTF-8?q?feat(InputView.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20=EC=9E=85=EB=A0=A5=20=EC=8B=9C?= =?UTF-8?q?=20=EA=B5=AC=EB=B6=84=EC=9E=90=20=EA=B2=80=EC=82=AC=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/InputView.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 7c9d065c..892c8c49 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -8,14 +8,24 @@ class InputView { println(MESSAGE_ENTER_CAR_NAMES) val input = Console.readLine().orEmpty() validateEmptyInput(input) + validateSeparator(input) } private fun validateEmptyInput(input: String) { if (input.isBlank()) throw IllegalArgumentException(ERROR_EMPTY_INPUT) } + private fun validateSeparator(input: String) { + val names = input.split(COMMA).map { it.trim() } + require(names.isNotEmpty() && names.all { it.isNotBlank() }) { + ERROR_INVALID_SEPARATOR + } + } + companion object { const val MESSAGE_ENTER_CAR_NAMES = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" const val ERROR_EMPTY_INPUT = "자동차 이름을 입력해야 합니다." + const val ERROR_INVALID_SEPARATOR = "자동차 이름은 쉼표(,)로 구분해야 합니다." + const val COMMA = "," } } \ No newline at end of file From db4006bacdebba9d9c5023a15f0feb6c930053e7 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:07:02 +0900 Subject: [PATCH 06/37] =?UTF-8?q?feat(InputView.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EC=9D=B4=EB=A6=84=EC=9D=84=20=EA=B5=AC=EB=B6=84?= =?UTF-8?q?=EC=9E=90=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/InputView.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 892c8c49..1bb9f7ab 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -9,6 +9,8 @@ class InputView { val input = Console.readLine().orEmpty() validateEmptyInput(input) validateSeparator(input) + + val names = splitAndTrimNames(input) } private fun validateEmptyInput(input: String) { @@ -22,6 +24,10 @@ class InputView { } } + private fun splitAndTrimNames(input: String): List { + return input.split(COMMA).map { it.trim() } + } + companion object { const val MESSAGE_ENTER_CAR_NAMES = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" const val ERROR_EMPTY_INPUT = "자동차 이름을 입력해야 합니다." From 9d419aaf6a597a5be3ce5941253b4e6e46d7d5ad Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:08:49 +0900 Subject: [PATCH 07/37] =?UTF-8?q?feat(InputView.kt):=20=EA=B0=81=20?= =?UTF-8?q?=EC=9E=90=EB=8F=99=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20=EA=B8=B8?= =?UTF-8?q?=EC=9D=B4=20=EA=B2=80=EC=82=AC=20=ED=95=A8=EC=88=98=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 --- src/main/kotlin/racingcar/view/InputView.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 1bb9f7ab..6b6e76fa 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -1,6 +1,7 @@ package racingcar.view import camp.nextstep.edu.missionutils.Console +import java.util.prefs.Preferences.MAX_NAME_LENGTH class InputView { @@ -28,10 +29,17 @@ class InputView { return input.split(COMMA).map { it.trim() } } + private fun validateNameLength(names: List) { + require(names.all { it.isNotBlank() && it.length <= MAX_NAME_LENGTH }) { + ERROR_NAME_LENGTH + } + } + companion object { const val MESSAGE_ENTER_CAR_NAMES = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" const val ERROR_EMPTY_INPUT = "자동차 이름을 입력해야 합니다." const val ERROR_INVALID_SEPARATOR = "자동차 이름은 쉼표(,)로 구분해야 합니다." + const val ERROR_NAME_LENGTH = "자동차 이름은 1자 이상 5자 이하여야 합니다." const val COMMA = "," } } \ No newline at end of file From 7a0e5e8bc4fd067726df7e7bf0cca934e223911f Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:09:07 +0900 Subject: [PATCH 08/37] =?UTF-8?q?feat(InputView.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20=EC=A4=91=EB=B3=B5=20=EA=B2=80?= =?UTF-8?q?=EC=82=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/InputView.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 6b6e76fa..0187eafc 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -35,11 +35,18 @@ class InputView { } } + private fun validateDuplicateNames(names: List) { + require(names.distinct().size == names.size) { + ERROR_DUPLICATE_NAMES + } + } + companion object { const val MESSAGE_ENTER_CAR_NAMES = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" const val ERROR_EMPTY_INPUT = "자동차 이름을 입력해야 합니다." const val ERROR_INVALID_SEPARATOR = "자동차 이름은 쉼표(,)로 구분해야 합니다." const val ERROR_NAME_LENGTH = "자동차 이름은 1자 이상 5자 이하여야 합니다." + const val ERROR_DUPLICATE_NAMES = "자동차 이름은 중복될 수 없습니다." const val COMMA = "," } } \ No newline at end of file From b63257d7cce5e24d99efa19516c7f75342b83f47 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:21:29 +0900 Subject: [PATCH 09/37] =?UTF-8?q?feat(InputView.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 자동차 이름 길이 유효성 검사와 중복 검사를 하나의 함수로 묶어서 호출하도록 구현 --- src/main/kotlin/racingcar/view/InputView.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 0187eafc..9d0a55cb 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -12,6 +12,7 @@ class InputView { validateSeparator(input) val names = splitAndTrimNames(input) + validateCarNames(names) } private fun validateEmptyInput(input: String) { @@ -29,6 +30,11 @@ class InputView { return input.split(COMMA).map { it.trim() } } + private fun validateCarNames(names: List) { + validateNameLength(names) + validateDuplicateNames(names) + } + private fun validateNameLength(names: List) { require(names.all { it.isNotBlank() && it.length <= MAX_NAME_LENGTH }) { ERROR_NAME_LENGTH From dfe1885be8519fc5fd1dcdea0be1ff12af380030 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:31:20 +0900 Subject: [PATCH 10/37] =?UTF-8?q?feat(InputView.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20=EC=9E=85=EB=A0=A5=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EC=97=90=EC=84=9C=20=EC=9D=B4=EB=A6=84=20=EB=B0=98?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 타 클래스에서 입력받은 자동차 이름들을 사용하기 위해 inputCarNames 함수에서 names를 리턴 --- src/main/kotlin/racingcar/view/InputView.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 9d0a55cb..bb60a54e 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -5,7 +5,7 @@ import java.util.prefs.Preferences.MAX_NAME_LENGTH class InputView { - fun inputCarNames() { + fun inputCarNames(): List { println(MESSAGE_ENTER_CAR_NAMES) val input = Console.readLine().orEmpty() validateEmptyInput(input) @@ -13,6 +13,8 @@ class InputView { val names = splitAndTrimNames(input) validateCarNames(names) + + return names } private fun validateEmptyInput(input: String) { From 4591953bb022549eddb738fd5b1b8c82263cdba1 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:45:33 +0900 Subject: [PATCH 11/37] =?UTF-8?q?feat(InputView.kt):=20=EC=8B=9C=EB=8F=84?= =?UTF-8?q?=ED=95=A0=20=ED=9A=9F=EC=88=98=EB=A5=BC=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EB=B0=9B=EB=8A=94=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/InputView.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index bb60a54e..2074ab6a 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -17,6 +17,11 @@ class InputView { return names } + fun inputRounds() { + println(MESSAGE_ENTER_ROUNDS) + val input = Console.readLine().orEmpty() + } + private fun validateEmptyInput(input: String) { if (input.isBlank()) throw IllegalArgumentException(ERROR_EMPTY_INPUT) } @@ -51,6 +56,7 @@ class InputView { companion object { const val MESSAGE_ENTER_CAR_NAMES = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" + const val MESSAGE_ENTER_ROUNDS = "시도할 횟수는 몇 회인가요?" const val ERROR_EMPTY_INPUT = "자동차 이름을 입력해야 합니다." const val ERROR_INVALID_SEPARATOR = "자동차 이름은 쉼표(,)로 구분해야 합니다." const val ERROR_NAME_LENGTH = "자동차 이름은 1자 이상 5자 이하여야 합니다." From 6c2836f6d88c6031d4f4d87fa87a2f821babe3e1 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:46:38 +0900 Subject: [PATCH 12/37] =?UTF-8?q?feat(InputView.kt):=20=EC=8B=9C=EB=8F=84?= =?UTF-8?q?=ED=95=A0=20=ED=9A=9F=EC=88=98=EB=A5=BC=20=EC=A0=95=EC=88=98?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=ED=99=98=ED=95=B4=EC=84=9C=20=EB=B0=98?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 정수로 변환하는 parseRounds 함수를 통해 변환하도록 구현 --- src/main/kotlin/racingcar/view/InputView.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 2074ab6a..2c779a9a 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -17,9 +17,12 @@ class InputView { return names } - fun inputRounds() { + fun inputRounds(): Int { println(MESSAGE_ENTER_ROUNDS) val input = Console.readLine().orEmpty() + println() + + return parseRounds(input) } private fun validateEmptyInput(input: String) { @@ -54,6 +57,12 @@ class InputView { } } + private fun parseRounds(input: String): Int { + val rounds = input.toIntOrNull() ?: throw IllegalArgumentException(ERROR_INVALID_NUMBER) + + return rounds + } + companion object { const val MESSAGE_ENTER_CAR_NAMES = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" const val MESSAGE_ENTER_ROUNDS = "시도할 횟수는 몇 회인가요?" @@ -61,6 +70,7 @@ class InputView { const val ERROR_INVALID_SEPARATOR = "자동차 이름은 쉼표(,)로 구분해야 합니다." const val ERROR_NAME_LENGTH = "자동차 이름은 1자 이상 5자 이하여야 합니다." const val ERROR_DUPLICATE_NAMES = "자동차 이름은 중복될 수 없습니다." + const val ERROR_INVALID_NUMBER = "이동 횟수는 숫자로 입력해야 합니다." const val COMMA = "," } } \ No newline at end of file From 041df0dde5f5cd88c7a5530a81dd818420ee5d2b Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:50:46 +0900 Subject: [PATCH 13/37] =?UTF-8?q?feat(InputView.kt):=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EB=B0=9B=EC=9D=80=20=ED=9A=9F=EC=88=98=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=EC=84=B1=20=EA=B2=80=EC=82=AC=20=ED=95=A8=EC=88=98=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 이상, Int 최댓값 이하인지 유효성 검사 진행 --- src/main/kotlin/racingcar/view/InputView.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 2c779a9a..31d5e35b 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -59,10 +59,15 @@ class InputView { private fun parseRounds(input: String): Int { val rounds = input.toIntOrNull() ?: throw IllegalArgumentException(ERROR_INVALID_NUMBER) + validatePositiveRounds(rounds) return rounds } + private fun validatePositiveRounds(rounds: Int) { + require(rounds in 1..Int.MAX_VALUE) { ERROR_NON_POSITIVE_ROUNDS } + } + companion object { const val MESSAGE_ENTER_CAR_NAMES = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" const val MESSAGE_ENTER_ROUNDS = "시도할 횟수는 몇 회인가요?" @@ -71,6 +76,7 @@ class InputView { const val ERROR_NAME_LENGTH = "자동차 이름은 1자 이상 5자 이하여야 합니다." const val ERROR_DUPLICATE_NAMES = "자동차 이름은 중복될 수 없습니다." const val ERROR_INVALID_NUMBER = "이동 횟수는 숫자로 입력해야 합니다." + const val ERROR_NON_POSITIVE_ROUNDS = "입력한 이동 횟수가 범위를 벗어났습니다." const val COMMA = "," } } \ No newline at end of file From 2b65ab75c17be5a04001eceacde8fd977d9bd704 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:53:18 +0900 Subject: [PATCH 14/37] =?UTF-8?q?feat(Car.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=EC=9D=98=20=EC=83=81=ED=83=9C=EC=99=80=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=EC=9D=84=20=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20Car?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/model/Car.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/kotlin/racingcar/model/Car.kt diff --git a/src/main/kotlin/racingcar/model/Car.kt b/src/main/kotlin/racingcar/model/Car.kt new file mode 100644 index 00000000..3cf5b773 --- /dev/null +++ b/src/main/kotlin/racingcar/model/Car.kt @@ -0,0 +1,5 @@ +package racingcar.model + +class Car() { + +} \ No newline at end of file From 1913e6e34b31acd923480c67574dc6d288853408 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:56:24 +0900 Subject: [PATCH 15/37] =?UTF-8?q?feat(Car.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=EC=9D=98=20=EC=9D=B4=EB=8F=99=20=EA=B1=B0=EB=A6=AC?= =?UTF-8?q?=EB=A5=BC=20=EC=A6=9D=EA=B0=80=EC=8B=9C=ED=82=A4=EB=8A=94=20mov?= =?UTF-8?q?e=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/model/Car.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/racingcar/model/Car.kt b/src/main/kotlin/racingcar/model/Car.kt index 3cf5b773..7455b978 100644 --- a/src/main/kotlin/racingcar/model/Car.kt +++ b/src/main/kotlin/racingcar/model/Car.kt @@ -1,5 +1,10 @@ package racingcar.model -class Car() { +class Car(val name: String) { + var distance: Int = 0 + private set + fun move() { + distance++ + } } \ No newline at end of file From 127ef0e2d5e69948aac8a87edfd6d7d5c2b698ba Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 19:57:45 +0900 Subject: [PATCH 16/37] =?UTF-8?q?feat(Game.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EA=B2=BD=EC=A3=BC=20=EA=B2=8C=EC=9E=84=EC=9D=98=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=EB=A5=BC=20=EA=B4=80=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20Game=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/model/Game.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/kotlin/racingcar/model/Game.kt diff --git a/src/main/kotlin/racingcar/model/Game.kt b/src/main/kotlin/racingcar/model/Game.kt new file mode 100644 index 00000000..0c5c531f --- /dev/null +++ b/src/main/kotlin/racingcar/model/Game.kt @@ -0,0 +1,5 @@ +package racingcar.model + +class Game() { + +} \ No newline at end of file From 421355ebae4944eef9c9518f90a3583b8ddbbac7 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:08:50 +0900 Subject: [PATCH 17/37] =?UTF-8?q?feat(Game.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EB=B0=9B?= =?UTF-8?q?=EC=95=84=20=EA=B2=8C=EC=9E=84=EC=9D=84=20=ED=94=8C=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=ED=95=98=EB=8A=94=20=ED=95=A8=EC=88=98=20=EC=84=B8?= =?UTF-8?q?=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/model/Game.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/racingcar/model/Game.kt b/src/main/kotlin/racingcar/model/Game.kt index 0c5c531f..2cfeb7ea 100644 --- a/src/main/kotlin/racingcar/model/Game.kt +++ b/src/main/kotlin/racingcar/model/Game.kt @@ -1,5 +1,11 @@ package racingcar.model -class Game() { +class Game(carNames: List) { + private val cars = carNames.map { Car(it) } + fun playRound() { + cars.forEach { car -> + + } + } } \ No newline at end of file From 53fb0971a389464df17b0b8f97ab82836582a4bc Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:10:21 +0900 Subject: [PATCH 18/37] =?UTF-8?q?feat(Game.kt):=20=EB=9E=9C=EB=8D=A4?= =?UTF-8?q?=EA=B0=92=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=A0=84=EC=A7=84?= =?UTF-8?q?=EC=9D=84=20=EA=B2=B0=EC=A0=95=ED=95=98=EB=8A=94=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 랜덤값이 4 이상일 경우 car의 move 함수를 호출하여 거리 증가 --- src/main/kotlin/racingcar/model/Game.kt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/racingcar/model/Game.kt b/src/main/kotlin/racingcar/model/Game.kt index 2cfeb7ea..41e64bb0 100644 --- a/src/main/kotlin/racingcar/model/Game.kt +++ b/src/main/kotlin/racingcar/model/Game.kt @@ -1,11 +1,25 @@ package racingcar.model +import camp.nextstep.edu.missionutils.Randoms + class Game(carNames: List) { private val cars = carNames.map { Car(it) } fun playRound() { cars.forEach { car -> - + if (isMoveForward()) { + car.move() + } } } + + private fun isMoveForward(): Boolean { + return Randoms.pickNumberInRange(MIN_MOVE_THRESHOLD, MAX_MOVE_THRESHOLD) >= MOVE_THRESHOLD + } + + companion object { + const val MOVE_THRESHOLD = 4 + const val MIN_MOVE_THRESHOLD = 0 + const val MAX_MOVE_THRESHOLD = 9 + } } \ No newline at end of file From 8278c49d191891899f7558cfaa5a7311be715e01 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:16:27 +0900 Subject: [PATCH 19/37] =?UTF-8?q?feat(Game.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=ED=95=98=EB=8A=94=20=ED=95=A8=EC=88=98=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 --- src/main/kotlin/racingcar/model/Game.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/kotlin/racingcar/model/Game.kt b/src/main/kotlin/racingcar/model/Game.kt index 41e64bb0..426d54f8 100644 --- a/src/main/kotlin/racingcar/model/Game.kt +++ b/src/main/kotlin/racingcar/model/Game.kt @@ -17,6 +17,10 @@ class Game(carNames: List) { return Randoms.pickNumberInRange(MIN_MOVE_THRESHOLD, MAX_MOVE_THRESHOLD) >= MOVE_THRESHOLD } + fun getCars(): List { + return cars + } + companion object { const val MOVE_THRESHOLD = 4 const val MIN_MOVE_THRESHOLD = 0 From e138b07d8f794bd55c3d76bee03921fc95b96ee1 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:19:03 +0900 Subject: [PATCH 20/37] =?UTF-8?q?feat(Game.kt):=20=EC=9A=B0=EC=8A=B9?= =?UTF-8?q?=EC=9E=90=EB=A5=BC=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 거리를 가장 많이 이동한 자동차 이름 리스트를 리턴 --- src/main/kotlin/racingcar/model/Game.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/kotlin/racingcar/model/Game.kt b/src/main/kotlin/racingcar/model/Game.kt index 426d54f8..f588de33 100644 --- a/src/main/kotlin/racingcar/model/Game.kt +++ b/src/main/kotlin/racingcar/model/Game.kt @@ -21,6 +21,12 @@ class Game(carNames: List) { return cars } + fun getWinners(): List { + val maxDistance = cars.maxOf { it.distance } + + return cars.filter { it.distance == maxDistance }.map { it.name } + } + companion object { const val MOVE_THRESHOLD = 4 const val MIN_MOVE_THRESHOLD = 0 From 78ae6c7f4032a5e1f1f08f2b2d1d2b947a171aa2 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:21:37 +0900 Subject: [PATCH 21/37] =?UTF-8?q?feat(ResultView.kt):=20=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=EB=A5=BC=20=EB=B3=B4=EC=97=AC=EC=A4=84=20ResultView=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/ResultView.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/kotlin/racingcar/view/ResultView.kt diff --git a/src/main/kotlin/racingcar/view/ResultView.kt b/src/main/kotlin/racingcar/view/ResultView.kt new file mode 100644 index 00000000..aa1ee26f --- /dev/null +++ b/src/main/kotlin/racingcar/view/ResultView.kt @@ -0,0 +1,5 @@ +package racingcar.view + +class ResultView { + +} \ No newline at end of file From f1f00a767e5d258a356ac7be43fc9196ff01b56a Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:23:31 +0900 Subject: [PATCH 22/37] =?UTF-8?q?feat(ResultView.kt):=20=EB=9D=BC=EC=9A=B4?= =?UTF-8?q?=EB=93=9C=20=EB=B3=84=20=EC=A7=84=ED=96=89=EC=83=81=ED=99=A9=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 라운드 별 '자동차 이름 : -- (이동 거리)' 출력 --- src/main/kotlin/racingcar/view/ResultView.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/kotlin/racingcar/view/ResultView.kt b/src/main/kotlin/racingcar/view/ResultView.kt index aa1ee26f..aed0745a 100644 --- a/src/main/kotlin/racingcar/view/ResultView.kt +++ b/src/main/kotlin/racingcar/view/ResultView.kt @@ -1,5 +1,13 @@ package racingcar.view +import racingcar.model.Car + class ResultView { + fun printRoundResult(cars: List) { + cars.forEach { car -> + println("${car.name} : ${"-".repeat(car.distance)}") + } + println() + } } \ No newline at end of file From 7c7ea8282527795ec5227b0b1ee0f8a4aaf800e3 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:25:33 +0900 Subject: [PATCH 23/37] =?UTF-8?q?feat(ResultView.kt):=20=EC=B5=9C=EC=A2=85?= =?UTF-8?q?=20=EC=9A=B0=EC=8A=B9=EC=9E=90=20=EC=B6=9C=EB=A0=A5=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/ResultView.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/kotlin/racingcar/view/ResultView.kt b/src/main/kotlin/racingcar/view/ResultView.kt index aed0745a..b4210f42 100644 --- a/src/main/kotlin/racingcar/view/ResultView.kt +++ b/src/main/kotlin/racingcar/view/ResultView.kt @@ -10,4 +10,12 @@ class ResultView { } println() } + + fun printWinners(winners: List) { + println("$MESSAGE_WINNERS: ${winners.joinToString(", ")}") + } + + companion object { + const val MESSAGE_WINNERS = "최종 우승자" + } } \ No newline at end of file From 2a3934beb8bad73e252395e912163b0876cc008e Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:27:18 +0900 Subject: [PATCH 24/37] =?UTF-8?q?feat(RacingGameController.kt):=20View?= =?UTF-8?q?=EC=99=80=20Model=EC=9D=84=20=EA=B4=80=EB=A6=AC=ED=95=A0=20Cont?= =?UTF-8?q?roller=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/controller/RacingGameController.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/kotlin/racingcar/controller/RacingGameController.kt diff --git a/src/main/kotlin/racingcar/controller/RacingGameController.kt b/src/main/kotlin/racingcar/controller/RacingGameController.kt new file mode 100644 index 00000000..243454e9 --- /dev/null +++ b/src/main/kotlin/racingcar/controller/RacingGameController.kt @@ -0,0 +1,5 @@ +package racingcar.controller + +class RacingGameController{ + +} \ No newline at end of file From 099f569f6347de2deaf57a524c5f5f4ea500829a Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:28:40 +0900 Subject: [PATCH 25/37] =?UTF-8?q?feat(RacingGameController.kt):=20inputVie?= =?UTF-8?q?w=EC=9D=98=20=ED=95=A8=EC=88=98=EB=A5=BC=20=ED=86=B5=ED=95=B4?= =?UTF-8?q?=20=EB=9D=BC=EC=9A=B4=EB=93=9C=20=EC=9E=85=EB=A0=A5=EB=B0=9B?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/racingcar/controller/RacingGameController.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/racingcar/controller/RacingGameController.kt b/src/main/kotlin/racingcar/controller/RacingGameController.kt index 243454e9..560cf5d7 100644 --- a/src/main/kotlin/racingcar/controller/RacingGameController.kt +++ b/src/main/kotlin/racingcar/controller/RacingGameController.kt @@ -1,5 +1,11 @@ package racingcar.controller -class RacingGameController{ +import racingcar.view.InputView +class RacingGameController( + private val inputView: InputView = InputView() +) { + fun startGame() { + val rounds = inputView.inputRounds() + } } \ No newline at end of file From d68dd49ef4c71d73f355897dfa1991accdcd7a0d Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:29:20 +0900 Subject: [PATCH 26/37] =?UTF-8?q?feat(RacingGameController.kt):=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EB=B0=9B=EC=9D=80=20round=20=ED=9A=9F?= =?UTF-8?q?=EC=88=98=EB=A7=8C=ED=81=BC=20=EA=B2=8C=EC=9E=84=20=EC=A7=84?= =?UTF-8?q?=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../racingcar/controller/RacingGameController.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/racingcar/controller/RacingGameController.kt b/src/main/kotlin/racingcar/controller/RacingGameController.kt index 560cf5d7..4016f554 100644 --- a/src/main/kotlin/racingcar/controller/RacingGameController.kt +++ b/src/main/kotlin/racingcar/controller/RacingGameController.kt @@ -1,11 +1,20 @@ package racingcar.controller +import racingcar.model.Game import racingcar.view.InputView +import racingcar.view.ResultView class RacingGameController( - private val inputView: InputView = InputView() + private val inputView: InputView = InputView(), + private val resultView: ResultView = ResultView(), + private val racingGame: Game = Game(inputView.inputCarNames()) ) { fun startGame() { val rounds = inputView.inputRounds() + + repeat(rounds) { + racingGame.playRound() + resultView.printRoundResult(racingGame.getCars()) + } } } \ No newline at end of file From 6d3f45a8fc215a2a0546e791f04ac931b173831b Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:29:39 +0900 Subject: [PATCH 27/37] =?UTF-8?q?feat(RacingGameController.kt):=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=EC=9D=B4=20=EB=81=9D=EB=82=98=EB=A9=B4=20?= =?UTF-8?q?=EC=B5=9C=EC=A2=85=20=EC=9A=B0=EC=8A=B9=EC=9E=90=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/controller/RacingGameController.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/kotlin/racingcar/controller/RacingGameController.kt b/src/main/kotlin/racingcar/controller/RacingGameController.kt index 4016f554..91ab31a2 100644 --- a/src/main/kotlin/racingcar/controller/RacingGameController.kt +++ b/src/main/kotlin/racingcar/controller/RacingGameController.kt @@ -16,5 +16,8 @@ class RacingGameController( racingGame.playRound() resultView.printRoundResult(racingGame.getCars()) } + + val winners = racingGame.getWinners() + resultView.printWinners(winners) } } \ No newline at end of file From 305bf6fc064a98ddf0c2ad8851b9ef0ccafc780b Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:30:51 +0900 Subject: [PATCH 28/37] =?UTF-8?q?feat(Application.kt):=20controller?= =?UTF-8?q?=EB=A5=BC=20=ED=86=B5=ED=95=B4=20=EA=B2=8C=EC=9E=84=20=EC=8B=9C?= =?UTF-8?q?=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RacingGameController의 startGame() 함수를 호출해 자동차 경주 게임 시작 --- src/main/kotlin/racingcar/Application.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/racingcar/Application.kt b/src/main/kotlin/racingcar/Application.kt index 0d8f3a79..279c1cab 100644 --- a/src/main/kotlin/racingcar/Application.kt +++ b/src/main/kotlin/racingcar/Application.kt @@ -1,5 +1,8 @@ package racingcar +import racingcar.controller.RacingGameController + fun main() { - // TODO: 프로그램 구현 -} + val controller = RacingGameController() + controller.startGame() +} \ No newline at end of file From e57a82409a3ab7b3901905c308a5e025a1293882 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:40:42 +0900 Subject: [PATCH 29/37] =?UTF-8?q?docs($README.md):=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EC=84=A4=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7758a388..232f7bd8 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,47 @@ 6. 입력받은 시도 횟수만큼 반복 7. 실행 결과 출력 8. 전진 횟수가 가장 많은 자동차 판별 -9. 최종 우승자 출력 \ No newline at end of file +9. 최종 우승자 출력 + + +## 코드 구조 +MVC (모델 - 뷰 - 컨트롤러) 패턴을 사용하여 코드 구조 설계 + +### Model +1. Car + - 역할 : 자동차의 상태와 동작을 정의 + - 주요 메서드 + - `move()` : 자동차가 전진할 때 호출되는 메서드로 거리를 증가시킴 +2. Game + - 역할 : 자동차 경주 게임의 상태를 관리 + - 주요 메서드 + - `playRound()` : 각 자동차가 이동하는 게임 라운드를 실행 + - `getCars()` : 현재 게임에 참여하고 있는 자동차 리스트를 반환 + - `getWinners()` : 현재까지의 라운드에서 가장 멀리 이동한 자동차를 찾아 그 이름을 리스트로 반환 + - `isMoveForward()` : Ramdon값을 사용하여 자동차의 이동 여부를 결정 + +### View +1. InputView + - 역할 : 사용자로부터 입력을 받고, 해당 입력의 유효성을 검증 + - 주요 메서드 + - `inputCarNames()` : 사용자에게 자동차 이름을 입력받음 + - `inputRounds()` : 사용자에게 시도할 라운드 수를 입력받음 + - `validateEmptyInput()` : 입력이 비어있거나 공백만 포함된 경우 유효성 검사 + - `validateSeparator()` : 입력 문자열이 유효한 쉼표 구분 형식인지 확인 + - `validateCarNames()` : 자동차 이름의 유효성을 검사하는 메서드로, 이름의 길이와 중복 여부를 확인 + - `validateNameLength()` : 자동차 이름의 길이가 1자 이상 5자 이하인지 확인 + - `validateDuplicateNames()` : 자동차 이름 리스트에서 중복된 이름이 없는지 확인 + - `splitAndTrimNames()` : 입력 문자열을 쉼표로 분리하고, 각 이름의 앞뒤 공백을 제거하여 리스트로 반환 + - `parseRounds()` : 입력 문자열을 정수로 변환하고, 변환된 값이 유효한 라운드 수인지 확인 + - `validatePositiveRounds()` : 라운드 수가 1 이상, 정수 범위 내에 있는지 확인 +2. ResultView + - 역할 : 자동차 경주 게임의 결과를 출력 + - 주요 메서드 + - `printRoundResult()` : 각 자동차의 이름과 이동 거리를 출력 + - `printWinners()` : 최종 우승자 목록을 출력 + +### Controller +1. RacingGameController + - 역할 : 자동차 경주 게임의 주요 로직을 관리하며 View와 Model 간의 상호작용을 조정 + - 주요 메서드 + - `startGame()` : 게임을 시작하는 메서드 From a0aa107eb9f3437793b26758e75c715fc7963505 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:58:29 +0900 Subject: [PATCH 30/37] =?UTF-8?q?test(CarNameInputTest.kt):=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/racingcar/CarNameInputTest.kt | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/test/kotlin/racingcar/CarNameInputTest.kt diff --git a/src/test/kotlin/racingcar/CarNameInputTest.kt b/src/test/kotlin/racingcar/CarNameInputTest.kt new file mode 100644 index 00000000..fb72b2ad --- /dev/null +++ b/src/test/kotlin/racingcar/CarNameInputTest.kt @@ -0,0 +1,55 @@ +package racingcar + +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import racingcar.view.InputView + +class CarNameInputTest { + private val inputView = InputView() + + @Test + @DisplayName("빈 값 입력 시 예외 발생") + fun validateEmptyInput_ThrowsException_WhenInputIsEmpty() { + val input = " " + assertThrows(IllegalArgumentException::class.java) { + inputView.validateEmptyInput(input) + } + } + + @Test + @DisplayName("구분자가 쉼표가 아닌 경우 예외 발생") + fun validateSeparator_ThrowsException_WhenSeparatorIsNotComma() { + val input = "car1;car2" + assertThrows(IllegalArgumentException::class.java) { + inputView.validateSeparator(input) + } + } + + @Test + @DisplayName("자동차 이름이 5자를 초과할 경우 예외 발생") + fun validateNameLength_ThrowsException_WhenNameLengthIsExceeding() { + val names = listOf("car123", "car2") + assertThrows(IllegalArgumentException::class.java) { + inputView.validateNameLength(names) + } + } + + @Test + @DisplayName("자동차 이름이 중복될 경우 예외 발생") + fun validateDuplicateNames_ThrowsException_WhenNamesAreDuplicate() { + val names = listOf("car1", "car1", "car2") + assertThrows(IllegalArgumentException::class.java) { + inputView.validateDuplicateNames(names) + } + } + + @Test + @DisplayName("유효한 자동차 이름 리스트 정상 처리") + fun splitAndTrimNames_ReturnsCorrectList_WhenInputIsValid() { + val input = "car1, car2, car3" + val names = inputView.splitAndTrimNames(input) + assert(names.size == 3) + assert(names == listOf("car1", "car2", "car3")) + } +} \ No newline at end of file From 87814f261d1c788be4c253195087cc61912cb97a Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:59:13 +0900 Subject: [PATCH 31/37] =?UTF-8?q?test(RoundInputTest.kt):=20=EC=8B=9C?= =?UTF-8?q?=EB=8F=84=20=ED=9A=9F=EC=88=98=20=EC=9E=85=EB=A0=A5=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/racingcar/RoundInputTest.kt | 54 +++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/test/kotlin/racingcar/RoundInputTest.kt diff --git a/src/test/kotlin/racingcar/RoundInputTest.kt b/src/test/kotlin/racingcar/RoundInputTest.kt new file mode 100644 index 00000000..254fd8da --- /dev/null +++ b/src/test/kotlin/racingcar/RoundInputTest.kt @@ -0,0 +1,54 @@ +package racingcar + +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import racingcar.view.InputView + +class RoundInputTest { + private val inputView = InputView() + + @Test + @DisplayName("음수 입력 시 예외 발생") + fun parseRounds_ThrowsException_WhenInputIsNegative() { + val input = "-1" + assertThrows(IllegalArgumentException::class.java) { + inputView.parseRounds(input) + } + } + + @Test + @DisplayName("0 입력 시 예외 발생") + fun parseRounds_ThrowsException_WhenInputIsZero() { + val input = "0" + assertThrows(IllegalArgumentException::class.java) { + inputView.parseRounds(input) + } + } + + @Test + @DisplayName("문자열 입력 시 예외 발생") + fun parseRounds_ThrowsException_WhenInputIsString() { + val input = "invalid" + assertThrows(IllegalArgumentException::class.java) { + inputView.parseRounds(input) + } + } + + @Test + @DisplayName("정수 범위를 초과한 값 입력 시 예외 발생") + fun parseRounds_ThrowsException_WhenInputExceedsIntRange() { + val input = "${Int.MAX_VALUE + 1L}" + assertThrows(IllegalArgumentException::class.java) { + inputView.parseRounds(input) + } + } + + @Test + @DisplayName("유효한 시도 횟수 입력 시 정상 처리") + fun parseRounds_ReturnsCorrectValue_WhenInputIsValid() { + val input = "3" + val rounds = inputView.parseRounds(input) + assert(rounds == 3) + } +} \ No newline at end of file From 9cd3d3eb80eec3b52353e8de96b03fcc811309b2 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 20:59:41 +0900 Subject: [PATCH 32/37] =?UTF-8?q?test(GameTest.kt):=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=20=EC=A7=84=ED=96=89=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/racingcar/GameTest.kt | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/test/kotlin/racingcar/GameTest.kt diff --git a/src/test/kotlin/racingcar/GameTest.kt b/src/test/kotlin/racingcar/GameTest.kt new file mode 100644 index 00000000..a2ea2862 --- /dev/null +++ b/src/test/kotlin/racingcar/GameTest.kt @@ -0,0 +1,47 @@ +package racingcar + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import racingcar.model.Game + +class GameTest { + private lateinit var game: Game + + @BeforeEach + fun setup() { + game = Game(listOf("pobi", "crong", "honux")) + } + + @Test + @DisplayName("자동차 리스트가 정상적으로 반환되는지 확인") + fun getCars_ReturnsCorrectCars() { + val cars = game.getCars() + assertEquals(3, cars.size) + assertEquals("pobi", cars[0].name) + } + + @Test + @DisplayName("자동차가 움직였을 때 거리가 증가하는지 확인") + fun playRound_CarsMoveForward() { + val car = game.getCars().first() + val initialDistance = car.distance + + game.playRound() + + assertTrue(car.distance >= initialDistance) + } + + @Test + @DisplayName("가장 멀리 이동한 자동차가 우승자로 선택되는지 확인") + fun getWinners_ReturnsCorrectWinners() { + // 일부러 특정 자동차만 이동 + val cars = game.getCars() + cars[0].move() // pobi만 전진 + + val winners = game.getWinners() + assertEquals(listOf("pobi"), winners) + } +} \ No newline at end of file From 23174828c596ac8020aee085f3e49ca7e35db43e Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 21:05:47 +0900 Subject: [PATCH 33/37] =?UTF-8?q?fix(InputView.kt):=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=20=EC=B5=9C=EB=8C=80=20=EA=B8=80=EC=9E=90=EC=88=98=20=EC=83=81?= =?UTF-8?q?=EC=88=98=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 이름 글자수 유효성 검사 시 라이브러리에 있는 MAX_NAME_LENGTH를 호출해 상수로 MAX_NAME_LENGTH 추가 --- src/main/kotlin/racingcar/view/InputView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index 31d5e35b..ed56d3b3 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -1,7 +1,6 @@ package racingcar.view import camp.nextstep.edu.missionutils.Console -import java.util.prefs.Preferences.MAX_NAME_LENGTH class InputView { @@ -78,5 +77,6 @@ class InputView { const val ERROR_INVALID_NUMBER = "이동 횟수는 숫자로 입력해야 합니다." const val ERROR_NON_POSITIVE_ROUNDS = "입력한 이동 횟수가 범위를 벗어났습니다." const val COMMA = "," + const val MAX_NAME_LENGTH = 5 } } \ No newline at end of file From 1216c00687b94efa8cd9e83445b9013ef81675b4 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 23:13:59 +0900 Subject: [PATCH 34/37] =?UTF-8?q?del(CarNameInputTest.kt):=20CarNameInputT?= =?UTF-8?q?est=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/racingcar/CarNameInputTest.kt | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 src/test/kotlin/racingcar/CarNameInputTest.kt diff --git a/src/test/kotlin/racingcar/CarNameInputTest.kt b/src/test/kotlin/racingcar/CarNameInputTest.kt deleted file mode 100644 index fb72b2ad..00000000 --- a/src/test/kotlin/racingcar/CarNameInputTest.kt +++ /dev/null @@ -1,55 +0,0 @@ -package racingcar - -import org.junit.jupiter.api.Assertions.assertThrows -import org.junit.jupiter.api.DisplayName -import org.junit.jupiter.api.Test -import racingcar.view.InputView - -class CarNameInputTest { - private val inputView = InputView() - - @Test - @DisplayName("빈 값 입력 시 예외 발생") - fun validateEmptyInput_ThrowsException_WhenInputIsEmpty() { - val input = " " - assertThrows(IllegalArgumentException::class.java) { - inputView.validateEmptyInput(input) - } - } - - @Test - @DisplayName("구분자가 쉼표가 아닌 경우 예외 발생") - fun validateSeparator_ThrowsException_WhenSeparatorIsNotComma() { - val input = "car1;car2" - assertThrows(IllegalArgumentException::class.java) { - inputView.validateSeparator(input) - } - } - - @Test - @DisplayName("자동차 이름이 5자를 초과할 경우 예외 발생") - fun validateNameLength_ThrowsException_WhenNameLengthIsExceeding() { - val names = listOf("car123", "car2") - assertThrows(IllegalArgumentException::class.java) { - inputView.validateNameLength(names) - } - } - - @Test - @DisplayName("자동차 이름이 중복될 경우 예외 발생") - fun validateDuplicateNames_ThrowsException_WhenNamesAreDuplicate() { - val names = listOf("car1", "car1", "car2") - assertThrows(IllegalArgumentException::class.java) { - inputView.validateDuplicateNames(names) - } - } - - @Test - @DisplayName("유효한 자동차 이름 리스트 정상 처리") - fun splitAndTrimNames_ReturnsCorrectList_WhenInputIsValid() { - val input = "car1, car2, car3" - val names = inputView.splitAndTrimNames(input) - assert(names.size == 3) - assert(names == listOf("car1", "car2", "car3")) - } -} \ No newline at end of file From 8cec194e8827769cf86651638e7c275e4a78aee8 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 23:14:07 +0900 Subject: [PATCH 35/37] =?UTF-8?q?del(RoundInputTest.kt):=20RoundInputTest?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/racingcar/RoundInputTest.kt | 54 --------------------- 1 file changed, 54 deletions(-) delete mode 100644 src/test/kotlin/racingcar/RoundInputTest.kt diff --git a/src/test/kotlin/racingcar/RoundInputTest.kt b/src/test/kotlin/racingcar/RoundInputTest.kt deleted file mode 100644 index 254fd8da..00000000 --- a/src/test/kotlin/racingcar/RoundInputTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -package racingcar - -import org.junit.jupiter.api.Assertions.assertThrows -import org.junit.jupiter.api.DisplayName -import org.junit.jupiter.api.Test -import racingcar.view.InputView - -class RoundInputTest { - private val inputView = InputView() - - @Test - @DisplayName("음수 입력 시 예외 발생") - fun parseRounds_ThrowsException_WhenInputIsNegative() { - val input = "-1" - assertThrows(IllegalArgumentException::class.java) { - inputView.parseRounds(input) - } - } - - @Test - @DisplayName("0 입력 시 예외 발생") - fun parseRounds_ThrowsException_WhenInputIsZero() { - val input = "0" - assertThrows(IllegalArgumentException::class.java) { - inputView.parseRounds(input) - } - } - - @Test - @DisplayName("문자열 입력 시 예외 발생") - fun parseRounds_ThrowsException_WhenInputIsString() { - val input = "invalid" - assertThrows(IllegalArgumentException::class.java) { - inputView.parseRounds(input) - } - } - - @Test - @DisplayName("정수 범위를 초과한 값 입력 시 예외 발생") - fun parseRounds_ThrowsException_WhenInputExceedsIntRange() { - val input = "${Int.MAX_VALUE + 1L}" - assertThrows(IllegalArgumentException::class.java) { - inputView.parseRounds(input) - } - } - - @Test - @DisplayName("유효한 시도 횟수 입력 시 정상 처리") - fun parseRounds_ReturnsCorrectValue_WhenInputIsValid() { - val input = "3" - val rounds = inputView.parseRounds(input) - assert(rounds == 3) - } -} \ No newline at end of file From 57633b8bbb23e4f71a537c9192f04cf3292509ee Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 23:49:31 +0900 Subject: [PATCH 36/37] =?UTF-8?q?del(GameTest.kt):=20GameTest=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/racingcar/GameTest.kt | 47 --------------------------- 1 file changed, 47 deletions(-) delete mode 100644 src/test/kotlin/racingcar/GameTest.kt diff --git a/src/test/kotlin/racingcar/GameTest.kt b/src/test/kotlin/racingcar/GameTest.kt deleted file mode 100644 index a2ea2862..00000000 --- a/src/test/kotlin/racingcar/GameTest.kt +++ /dev/null @@ -1,47 +0,0 @@ -package racingcar - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.DisplayName -import org.junit.jupiter.api.Test -import racingcar.model.Game - -class GameTest { - private lateinit var game: Game - - @BeforeEach - fun setup() { - game = Game(listOf("pobi", "crong", "honux")) - } - - @Test - @DisplayName("자동차 리스트가 정상적으로 반환되는지 확인") - fun getCars_ReturnsCorrectCars() { - val cars = game.getCars() - assertEquals(3, cars.size) - assertEquals("pobi", cars[0].name) - } - - @Test - @DisplayName("자동차가 움직였을 때 거리가 증가하는지 확인") - fun playRound_CarsMoveForward() { - val car = game.getCars().first() - val initialDistance = car.distance - - game.playRound() - - assertTrue(car.distance >= initialDistance) - } - - @Test - @DisplayName("가장 멀리 이동한 자동차가 우승자로 선택되는지 확인") - fun getWinners_ReturnsCorrectWinners() { - // 일부러 특정 자동차만 이동 - val cars = game.getCars() - cars[0].move() // pobi만 전진 - - val winners = game.getWinners() - assertEquals(listOf("pobi"), winners) - } -} \ No newline at end of file From d02cf8ba9bdacd6404e9427c87a7fe8e4d38d3b7 Mon Sep 17 00:00:00 2001 From: Jieun Date: Mon, 28 Oct 2024 23:58:49 +0900 Subject: [PATCH 37/37] =?UTF-8?q?feat(InputView.kt):=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20=EC=9D=B4=EB=A6=84=20=EC=88=AB=EC=9E=90=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racingcar/view/InputView.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt index ed56d3b3..2e1cf6b3 100644 --- a/src/main/kotlin/racingcar/view/InputView.kt +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -42,6 +42,7 @@ class InputView { private fun validateCarNames(names: List) { validateNameLength(names) validateDuplicateNames(names) + validateNumericNames(names) } private fun validateNameLength(names: List) { @@ -56,6 +57,13 @@ class InputView { } } + private fun validateNumericNames(names: List) { + require(names.none { it.all { char -> char.isDigit() } }) { + ERROR_NUMERIC_NAMES + } + } + + private fun parseRounds(input: String): Int { val rounds = input.toIntOrNull() ?: throw IllegalArgumentException(ERROR_INVALID_NUMBER) validatePositiveRounds(rounds) @@ -76,6 +84,7 @@ class InputView { const val ERROR_DUPLICATE_NAMES = "자동차 이름은 중복될 수 없습니다." const val ERROR_INVALID_NUMBER = "이동 횟수는 숫자로 입력해야 합니다." const val ERROR_NON_POSITIVE_ROUNDS = "입력한 이동 횟수가 범위를 벗어났습니다." + const val ERROR_NUMERIC_NAMES = "자동차 이름은 숫자일 수 없습니다." const val COMMA = "," const val MAX_NAME_LENGTH = 5 }