From 52d47032d1161919a6a01eb088c2ac99beefbd52 Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Thu, 8 Jun 2023 16:38:23 +0900 Subject: [PATCH 01/15] step3:racingCar done --- src/main/kotlin/Car.kt | 21 +++++++++++++++++++++ src/main/kotlin/InputView.kt | 26 ++++++++++++++++++++++++++ src/main/kotlin/RagingCarMain.kt | 15 +++++++++++++++ src/main/kotlin/ResultView.kt | 12 ++++++++++++ src/test/kotlin/study/CardKoTest.kt | 27 +++++++++++++++++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 src/main/kotlin/Car.kt create mode 100644 src/main/kotlin/InputView.kt create mode 100644 src/main/kotlin/RagingCarMain.kt create mode 100644 src/main/kotlin/ResultView.kt create mode 100644 src/test/kotlin/study/CardKoTest.kt diff --git a/src/main/kotlin/Car.kt b/src/main/kotlin/Car.kt new file mode 100644 index 0000000000..eef6bb5210 --- /dev/null +++ b/src/main/kotlin/Car.kt @@ -0,0 +1,21 @@ +import kotlin.random.Random + +class Car { + + var progreessString = StringBuffer("-") + + fun getCarProgress() : String { + if(checkCanGo()) { + progreessString.append("-") + } + return progreessString.toString() + } + + fun checkCanGo() : Boolean { + return getRandomInt() >= 4 + } + + fun getRandomInt() : Int{ + return Random.nextInt(0, 10) + } +} \ No newline at end of file diff --git a/src/main/kotlin/InputView.kt b/src/main/kotlin/InputView.kt new file mode 100644 index 0000000000..a3a0ee75d4 --- /dev/null +++ b/src/main/kotlin/InputView.kt @@ -0,0 +1,26 @@ +class InputView { + + var carNumber = 0 + var actionCount = 0 + + fun doInput() { + println("자동차 대수는 몇 대인가요?") + runCatching { + carNumber = readlnOrNull()?.toInt()?:0 + }.getOrElse { + throw NumberFormatException("숫자 입력해야함") + } + if(carNumber < 1) { + throw IllegalArgumentException("자동차 대수는 1대 이상이어야 함") + } + println("시도할 횟수는 몇 회인가요?") + runCatching { + actionCount = readlnOrNull()?.toInt()?:0 + }.getOrElse { + throw NumberFormatException("숫자 입력해야함") + } + if(carNumber < 1) { + throw IllegalArgumentException("시도할 횟수는 1회 이상이어야 함") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/RagingCarMain.kt b/src/main/kotlin/RagingCarMain.kt new file mode 100644 index 0000000000..9195d0c7c4 --- /dev/null +++ b/src/main/kotlin/RagingCarMain.kt @@ -0,0 +1,15 @@ + +fun main(args: Array) { + + val inputView = InputView() + inputView.doInput() + + val carList = ArrayList() + for(i in 0 until inputView.carNumber) { + carList.add(Car()) + } + + ResultView().showResult(carList, inputView.actionCount) + + +} \ No newline at end of file diff --git a/src/main/kotlin/ResultView.kt b/src/main/kotlin/ResultView.kt new file mode 100644 index 0000000000..2dedf7674d --- /dev/null +++ b/src/main/kotlin/ResultView.kt @@ -0,0 +1,12 @@ +class ResultView { + + fun showResult(carList : ArrayList, actionCount : Int) { + println("실행 결과") + for(i in 0 until actionCount) { + carList.forEach { + println(it.getCarProgress()) + } + print("\n") + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/study/CardKoTest.kt b/src/test/kotlin/study/CardKoTest.kt new file mode 100644 index 0000000000..b74eb72238 --- /dev/null +++ b/src/test/kotlin/study/CardKoTest.kt @@ -0,0 +1,27 @@ +package study + +import Car +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.ints.shouldBeInRange +import io.kotest.matchers.shouldBe + +class CardKoTest : StringSpec({ + "랜덤값" { + val car = Car() + for(i in 0..10) { + car.getRandomInt() shouldBeInRange 0..9 + } + } + "움직임 여부" { + var car = Car() + car.checkCanGo() shouldBe true + } + + "차 이동" { + var car = Car() + for(i in 0 until 5) { + println(car.getCarProgress()) + } + } + +}) \ No newline at end of file From 0e148b113cf660f7fb2dd353925641c523d6843f Mon Sep 17 00:00:00 2001 From: 1002533 Date: Fri, 9 Jun 2023 10:25:56 +0900 Subject: [PATCH 02/15] =?UTF-8?q?step3:=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/Car.kt | 27 ++++++++++++------- src/main/kotlin/InputView.kt | 25 +++++++++-------- src/main/kotlin/RagingCarMain.kt | 15 +++++------ src/main/kotlin/ResultView.kt | 11 ++++---- .../study/{CardKoTest.kt => CarKoTest.kt} | 9 +++---- 5 files changed, 48 insertions(+), 39 deletions(-) rename src/test/kotlin/study/{CardKoTest.kt => CarKoTest.kt} (83%) diff --git a/src/main/kotlin/Car.kt b/src/main/kotlin/Car.kt index eef6bb5210..4fc9738571 100644 --- a/src/main/kotlin/Car.kt +++ b/src/main/kotlin/Car.kt @@ -2,20 +2,27 @@ import kotlin.random.Random class Car { - var progreessString = StringBuffer("-") + companion object { + const val PROGRESS_STRING = "-" + const val MIN_RANGE = 0 + const val MAX_RANGE = 10 + const val CAN_GO_CONDITION_INT = 4 + } + + private var progressString = StringBuffer(PROGRESS_STRING) - fun getCarProgress() : String { - if(checkCanGo()) { - progreessString.append("-") + fun getCarProgress(): String { + if (checkCanGo()) { + progressString.append(PROGRESS_STRING) } - return progreessString.toString() + return progressString.toString() } - fun checkCanGo() : Boolean { - return getRandomInt() >= 4 + fun checkCanGo(): Boolean { + return getRandomInt() >= CAN_GO_CONDITION_INT } - fun getRandomInt() : Int{ - return Random.nextInt(0, 10) + fun getRandomInt(): Int { + return Random.nextInt(MIN_RANGE, MAX_RANGE) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/InputView.kt b/src/main/kotlin/InputView.kt index a3a0ee75d4..880b68120d 100644 --- a/src/main/kotlin/InputView.kt +++ b/src/main/kotlin/InputView.kt @@ -1,26 +1,29 @@ -class InputView { +object InputView { - var carNumber = 0 - var actionCount = 0 + const val DEFAULT_INPUT = 0 + const val MINIMUM_INPUT = 1 - fun doInput() { + fun doInput(): Pair { + var carNumber = 0 + var actionCount = 0 println("자동차 대수는 몇 대인가요?") runCatching { - carNumber = readlnOrNull()?.toInt()?:0 + carNumber = readlnOrNull()?.toInt() ?: DEFAULT_INPUT }.getOrElse { throw NumberFormatException("숫자 입력해야함") } - if(carNumber < 1) { - throw IllegalArgumentException("자동차 대수는 1대 이상이어야 함") + if (carNumber < MINIMUM_INPUT) { + throw IllegalArgumentException("자동차 대수는 ${MINIMUM_INPUT}대 이상이어야 함") } println("시도할 횟수는 몇 회인가요?") runCatching { - actionCount = readlnOrNull()?.toInt()?:0 + actionCount = readlnOrNull()?.toInt() ?: DEFAULT_INPUT }.getOrElse { throw NumberFormatException("숫자 입력해야함") } - if(carNumber < 1) { - throw IllegalArgumentException("시도할 횟수는 1회 이상이어야 함") + if (actionCount < MINIMUM_INPUT) { + throw IllegalArgumentException("시도할 횟수는 ${MINIMUM_INPUT}회 이상이어야 함") } + return Pair(carNumber, actionCount) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/RagingCarMain.kt b/src/main/kotlin/RagingCarMain.kt index 9195d0c7c4..6b7ee84f4f 100644 --- a/src/main/kotlin/RagingCarMain.kt +++ b/src/main/kotlin/RagingCarMain.kt @@ -1,15 +1,14 @@ fun main(args: Array) { - val inputView = InputView() - inputView.doInput() + val inputData = InputView.doInput() + val carNumber = inputData.first + val actionCount = inputData.second - val carList = ArrayList() - for(i in 0 until inputView.carNumber) { + val carList = mutableListOf() + for (i in 0 until carNumber) { carList.add(Car()) } - ResultView().showResult(carList, inputView.actionCount) - - -} \ No newline at end of file + ResultView.showResult(carList, actionCount) +} diff --git a/src/main/kotlin/ResultView.kt b/src/main/kotlin/ResultView.kt index 2dedf7674d..30e78bf8a3 100644 --- a/src/main/kotlin/ResultView.kt +++ b/src/main/kotlin/ResultView.kt @@ -1,12 +1,13 @@ -class ResultView { +object ResultView { - fun showResult(carList : ArrayList, actionCount : Int) { + private const val NEXT_LINE = "\n" + fun showResult(carList: MutableList, actionCount: Int) { println("실행 결과") - for(i in 0 until actionCount) { + for (i in 0 until actionCount) { carList.forEach { println(it.getCarProgress()) } - print("\n") + print(NEXT_LINE) } } -} \ No newline at end of file +} diff --git a/src/test/kotlin/study/CardKoTest.kt b/src/test/kotlin/study/CarKoTest.kt similarity index 83% rename from src/test/kotlin/study/CardKoTest.kt rename to src/test/kotlin/study/CarKoTest.kt index b74eb72238..1513fbf11e 100644 --- a/src/test/kotlin/study/CardKoTest.kt +++ b/src/test/kotlin/study/CarKoTest.kt @@ -5,10 +5,10 @@ import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.ints.shouldBeInRange import io.kotest.matchers.shouldBe -class CardKoTest : StringSpec({ +class CarKoTest : StringSpec({ "랜덤값" { val car = Car() - for(i in 0..10) { + for (i in 0..10) { car.getRandomInt() shouldBeInRange 0..9 } } @@ -19,9 +19,8 @@ class CardKoTest : StringSpec({ "차 이동" { var car = Car() - for(i in 0 until 5) { + for (i in 0 until 5) { println(car.getCarProgress()) } } - -}) \ No newline at end of file +}) From 92bda41b21bf3196d2a545e7711fe024b9706415 Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Fri, 9 Jun 2023 15:39:33 +0900 Subject: [PATCH 03/15] =?UTF-8?q?step3:=20behaviorTest=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 --- src/test/kotlin/study/CarBehaviorTest.kt | 18 +++++++++++++ src/test/kotlin/study/Person.kt | 3 --- src/test/kotlin/study/PersonTest.kt | 33 ------------------------ 3 files changed, 18 insertions(+), 36 deletions(-) create mode 100644 src/test/kotlin/study/CarBehaviorTest.kt delete mode 100644 src/test/kotlin/study/Person.kt delete mode 100644 src/test/kotlin/study/PersonTest.kt diff --git a/src/test/kotlin/study/CarBehaviorTest.kt b/src/test/kotlin/study/CarBehaviorTest.kt new file mode 100644 index 0000000000..a1faa997f2 --- /dev/null +++ b/src/test/kotlin/study/CarBehaviorTest.kt @@ -0,0 +1,18 @@ +package study + +import Car +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.ints.shouldBeInRange + +class CarBehaviorTest : BehaviorSpec({ + Given("자동차가") { + val car = Car() + When("랜덤 데이터를 받았을 때") { + val randomInt = car.getRandomInt() + Then("데이터는 0~9여야 한다") { + randomInt shouldBeInRange 0..9 + + } + } + } +}) diff --git a/src/test/kotlin/study/Person.kt b/src/test/kotlin/study/Person.kt deleted file mode 100644 index 46b16e49dd..0000000000 --- a/src/test/kotlin/study/Person.kt +++ /dev/null @@ -1,3 +0,0 @@ -package study - -data class Person(val name: String, val age: Int, var nickname: String? = "Guest") diff --git a/src/test/kotlin/study/PersonTest.kt b/src/test/kotlin/study/PersonTest.kt deleted file mode 100644 index d06d209c5b..0000000000 --- a/src/test/kotlin/study/PersonTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -package study - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class PersonTest { - @Test - fun `이름 붙인 인자`() { - val actual = Person(name = "윤성현", age = 20, nickname = "minhyukseul") - assertThat(actual.name).isEqualTo("윤성현") - assertThat(actual.nickname).isEqualTo("minhyukseul") - assertThat(actual.age).isEqualTo(20) - } - - @Test - fun `널 타입`() { - val actual = Person("윤성현", 20, null) - assertThat(actual.nickname).isNull() - } - - @Test - fun `기본 인자`() { - val actual = Person(name = "윤성현", age = 20) - assertThat(actual.nickname).isEqualTo("Guest") - } - - @Test - fun `데이터 클래스`() { - val person1 = Person("홍길동", 20, "Hong") - val person2 = Person("홍길동", 20, "Hong") - assertThat(person1).isEqualTo(person2) - } -} \ No newline at end of file From 5f76e5ec7ad5d0978e62467ba947dbceb40d88cc Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Sun, 11 Jun 2023 11:29:08 +0900 Subject: [PATCH 04/15] =?UTF-8?q?refactor=20:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/Car.kt | 23 +++++++------ src/main/kotlin/InputView.kt | 41 ++++++++++++------------ src/main/kotlin/RagingCarMain.kt | 8 ++--- src/main/kotlin/ResultView.kt | 7 +++- src/test/kotlin/study/CarBehaviorTest.kt | 1 - 5 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/main/kotlin/Car.kt b/src/main/kotlin/Car.kt index 4fc9738571..ed3666391b 100644 --- a/src/main/kotlin/Car.kt +++ b/src/main/kotlin/Car.kt @@ -2,27 +2,26 @@ import kotlin.random.Random class Car { - companion object { - const val PROGRESS_STRING = "-" - const val MIN_RANGE = 0 - const val MAX_RANGE = 10 - const val CAN_GO_CONDITION_INT = 4 - } - - private var progressString = StringBuffer(PROGRESS_STRING) + private var progress = 0 - fun getCarProgress(): String { + fun getCarProgress(): Int { if (checkCanGo()) { - progressString.append(PROGRESS_STRING) + progress++ } - return progressString.toString() + return progress } fun checkCanGo(): Boolean { - return getRandomInt() >= CAN_GO_CONDITION_INT + return getRandomInt() >= GO_RESTRICT_NUMBER } fun getRandomInt(): Int { return Random.nextInt(MIN_RANGE, MAX_RANGE) } + + companion object { + const val MIN_RANGE = 0 + const val MAX_RANGE = 10 + const val GO_RESTRICT_NUMBER = 4 + } } diff --git a/src/main/kotlin/InputView.kt b/src/main/kotlin/InputView.kt index 880b68120d..ba315acbb3 100644 --- a/src/main/kotlin/InputView.kt +++ b/src/main/kotlin/InputView.kt @@ -1,29 +1,30 @@ object InputView { - const val DEFAULT_INPUT = 0 - const val MINIMUM_INPUT = 1 + private const val DEFAULT_INPUT = 0 + private const val MINIMUM_INPUT = 1 + + private const val INPUT_CAR_PREFIX = "자동차 대수는 " + private const val INPUT_ACTION_PREFIX = "시도할 횟수는 " fun doInput(): Pair { - var carNumber = 0 - var actionCount = 0 - println("자동차 대수는 몇 대인가요?") - runCatching { - carNumber = readlnOrNull()?.toInt() ?: DEFAULT_INPUT - }.getOrElse { - throw NumberFormatException("숫자 입력해야함") - } - if (carNumber < MINIMUM_INPUT) { - throw IllegalArgumentException("자동차 대수는 ${MINIMUM_INPUT}대 이상이어야 함") - } - println("시도할 횟수는 몇 회인가요?") - runCatching { - actionCount = readlnOrNull()?.toInt() ?: DEFAULT_INPUT + + println("$INPUT_CAR_PREFIX 몇 대인가요?") + val carNumber = getInputNumber(INPUT_CAR_PREFIX) + println("$INPUT_ACTION_PREFIX 몇 회인가요?") + val actionCount = getInputNumber(INPUT_ACTION_PREFIX) + + return Pair(carNumber, actionCount) + } + + private fun getInputNumber(prefix: String): Int { + return runCatching { + (readlnOrNull()?.toInt() ?: DEFAULT_INPUT).apply { + if (this < MINIMUM_INPUT) { + throw IllegalArgumentException("$prefix ${MINIMUM_INPUT}대 이상이어야 함") + } + } }.getOrElse { throw NumberFormatException("숫자 입력해야함") } - if (actionCount < MINIMUM_INPUT) { - throw IllegalArgumentException("시도할 횟수는 ${MINIMUM_INPUT}회 이상이어야 함") - } - return Pair(carNumber, actionCount) } } diff --git a/src/main/kotlin/RagingCarMain.kt b/src/main/kotlin/RagingCarMain.kt index 6b7ee84f4f..a2206d4545 100644 --- a/src/main/kotlin/RagingCarMain.kt +++ b/src/main/kotlin/RagingCarMain.kt @@ -5,10 +5,10 @@ fun main(args: Array) { val carNumber = inputData.first val actionCount = inputData.second - val carList = mutableListOf() - for (i in 0 until carNumber) { - carList.add(Car()) + val cars = mutableListOf() + repeat(carNumber) { + cars.add(Car()) } - ResultView.showResult(carList, actionCount) + ResultView.showResult(cars, actionCount) } diff --git a/src/main/kotlin/ResultView.kt b/src/main/kotlin/ResultView.kt index 30e78bf8a3..2774042fe1 100644 --- a/src/main/kotlin/ResultView.kt +++ b/src/main/kotlin/ResultView.kt @@ -1,11 +1,16 @@ object ResultView { private const val NEXT_LINE = "\n" + private const val PROGRESS_STRING = "-" fun showResult(carList: MutableList, actionCount: Int) { println("실행 결과") for (i in 0 until actionCount) { carList.forEach { - println(it.getCarProgress()) + val progressString = StringBuffer(PROGRESS_STRING) + repeat(it.getCarProgress()) { + progressString.append(PROGRESS_STRING) + } + println(progressString.toString()) } print(NEXT_LINE) } diff --git a/src/test/kotlin/study/CarBehaviorTest.kt b/src/test/kotlin/study/CarBehaviorTest.kt index a1faa997f2..7b82a1a931 100644 --- a/src/test/kotlin/study/CarBehaviorTest.kt +++ b/src/test/kotlin/study/CarBehaviorTest.kt @@ -11,7 +11,6 @@ class CarBehaviorTest : BehaviorSpec({ val randomInt = car.getRandomInt() Then("데이터는 0~9여야 한다") { randomInt shouldBeInRange 0..9 - } } } From 8861db1fd161e9821a74c4493226c238cefffd8f Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Sun, 11 Jun 2023 11:30:16 +0900 Subject: [PATCH 05/15] =?UTF-8?q?refactor=20:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/RagingCarMain.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/RagingCarMain.kt b/src/main/kotlin/RagingCarMain.kt index a2206d4545..861f9cb78b 100644 --- a/src/main/kotlin/RagingCarMain.kt +++ b/src/main/kotlin/RagingCarMain.kt @@ -1,5 +1,5 @@ -fun main(args: Array) { +fun main() { val inputData = InputView.doInput() val carNumber = inputData.first From b8ceef226defd9d3d961ab4ff0bdf32c78650c8f Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Sun, 11 Jun 2023 23:29:35 +0900 Subject: [PATCH 06/15] =?UTF-8?q?feat=20:=201.=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=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 --- README.md | 15 ++++++++++++++- src/main/kotlin/Car.kt | 2 +- src/main/kotlin/InputView.kt | 17 +++++++++++++---- src/main/kotlin/RagingCarMain.kt | 4 ++-- src/main/kotlin/ResultView.kt | 2 +- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0d49f3cfc8..1466d5c490 100644 --- a/README.md +++ b/README.md @@ -1 +1,14 @@ -# kotlin-racingcar \ No newline at end of file +# kotlin-racingcar + +# 구현 기능 명세 + 1. 입력 클래스 설정 및 구현 + 1) 자동차 이름을 받아오는 기능 구현. 적절한 이름이 아닌 경우에 대한 예외처리 필요 + 2) 시도할 횟수 구현. 0번 이상으로 구현. MAX를 설정할지에 대한 논의 필요 + 2. 출력 클래스 설정 및 구현 + 1) 각 자동차의 진행상황을 출력해 줘야함. 해당 부분에서 표현방식이 변경이 될 수 있는 부분에 대한 고려 필요 + 2) 우승자에 대해 계산해주는 로직 필요함. 1개 이상의 경우를 고려해 구현해야함 + 3. Main 함수 구현 + 1) 입력을 받아오고 출력을 진행. 받아온 자동차 갯수만큼의 이름을 구현해야함 + 4. 요구사항 명세에 맞는 리팩토링 진행 + 1) 들여쓰기 2 넘지 않도록 구현 + 2) 함수 이름 15라인 넘지 않도록 구현 \ No newline at end of file diff --git a/src/main/kotlin/Car.kt b/src/main/kotlin/Car.kt index ed3666391b..d5e1f63833 100644 --- a/src/main/kotlin/Car.kt +++ b/src/main/kotlin/Car.kt @@ -1,6 +1,6 @@ import kotlin.random.Random -class Car { +class Car(val name : String) { private var progress = 0 diff --git a/src/main/kotlin/InputView.kt b/src/main/kotlin/InputView.kt index ba315acbb3..ebea262906 100644 --- a/src/main/kotlin/InputView.kt +++ b/src/main/kotlin/InputView.kt @@ -3,19 +3,28 @@ object InputView { private const val DEFAULT_INPUT = 0 private const val MINIMUM_INPUT = 1 - private const val INPUT_CAR_PREFIX = "자동차 대수는 " + private const val INPUT_SEPERATOR = "," + private const val INPUT_ACTION_PREFIX = "시도할 횟수는 " - fun doInput(): Pair { + fun doInput(): Pair, Int> { - println("$INPUT_CAR_PREFIX 몇 대인가요?") - val carNumber = getInputNumber(INPUT_CAR_PREFIX) + println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).") + val carNumber = getInputCars() println("$INPUT_ACTION_PREFIX 몇 회인가요?") val actionCount = getInputNumber(INPUT_ACTION_PREFIX) return Pair(carNumber, actionCount) } + private fun getInputCars(): List { + return runCatching { + (readlnOrNull()?:"").split(INPUT_SEPERATOR) + }.getOrElse { + throw IllegalArgumentException("형식에 맞는 타입을 입력해야함") + } + } + private fun getInputNumber(prefix: String): Int { return runCatching { (readlnOrNull()?.toInt() ?: DEFAULT_INPUT).apply { diff --git a/src/main/kotlin/RagingCarMain.kt b/src/main/kotlin/RagingCarMain.kt index 861f9cb78b..6ac4617392 100644 --- a/src/main/kotlin/RagingCarMain.kt +++ b/src/main/kotlin/RagingCarMain.kt @@ -6,8 +6,8 @@ fun main() { val actionCount = inputData.second val cars = mutableListOf() - repeat(carNumber) { - cars.add(Car()) + carNumber.forEach { + cars.add(Car(it)) } ResultView.showResult(cars, actionCount) diff --git a/src/main/kotlin/ResultView.kt b/src/main/kotlin/ResultView.kt index 2774042fe1..722199bf54 100644 --- a/src/main/kotlin/ResultView.kt +++ b/src/main/kotlin/ResultView.kt @@ -10,7 +10,7 @@ object ResultView { repeat(it.getCarProgress()) { progressString.append(PROGRESS_STRING) } - println(progressString.toString()) + println("${it.name} : ${progressString.toString()}") } print(NEXT_LINE) } From 5550155e97fa58c9f57987d184c8daa2abbd8082 Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Mon, 12 Jun 2023 14:48:04 +0900 Subject: [PATCH 07/15] =?UTF-8?q?feat=20:=20=EC=9E=85=EB=A0=A5=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=84=A4=EC=A0=95,=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=84=A4=EC=A0=95,=20Main=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 19 +++++---- src/main/kotlin/ResultView.kt | 18 -------- .../kotlin/{ => calculator}/Calculator.kt | 7 ++-- src/main/kotlin/{ => calculator}/Operator.kt | 4 +- src/main/kotlin/{ => racing}/Car.kt | 17 ++++++-- src/main/kotlin/{ => racing}/InputView.kt | 24 ++++++----- src/main/kotlin/{ => racing}/RagingCarMain.kt | 9 ++-- src/main/kotlin/racing/ResultView.kt | 41 +++++++++++++++++++ .../{study => calculator}/CalculatorKoTest.kt | 5 ++- src/test/kotlin/racing/CarTest.kt | 26 ++++++++++++ src/test/kotlin/study/CarBehaviorTest.kt | 17 -------- src/test/kotlin/study/CarKoTest.kt | 26 ------------ 12 files changed, 116 insertions(+), 97 deletions(-) delete mode 100644 src/main/kotlin/ResultView.kt rename src/main/kotlin/{ => calculator}/Calculator.kt (88%) rename src/main/kotlin/{ => calculator}/Operator.kt (98%) rename src/main/kotlin/{ => racing}/Car.kt (53%) rename src/main/kotlin/{ => racing}/InputView.kt (65%) rename src/main/kotlin/{ => racing}/RagingCarMain.kt (73%) create mode 100644 src/main/kotlin/racing/ResultView.kt rename src/test/kotlin/{study => calculator}/CalculatorKoTest.kt (89%) create mode 100644 src/test/kotlin/racing/CarTest.kt delete mode 100644 src/test/kotlin/study/CarBehaviorTest.kt delete mode 100644 src/test/kotlin/study/CarKoTest.kt diff --git a/README.md b/README.md index 1466d5c490..a7fa424e11 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ -# kotlin-racingcar +# kotlin-racingcar 구현 기능 명세 -# 구현 기능 명세 1. 입력 클래스 설정 및 구현 - 1) 자동차 이름을 받아오는 기능 구현. 적절한 이름이 아닌 경우에 대한 예외처리 필요 - 2) 시도할 횟수 구현. 0번 이상으로 구현. MAX를 설정할지에 대한 논의 필요 + - [x] 자동차 이름을 받아오는 기능 구현. 적절한 이름, 그리고 이름이 5개 이상인 경우에 대한 예외처리 필요 + - [x] 시도할 횟수 구현. 0번 이상으로 구현. MAX를 설정할지에 대한 논의 필요 2. 출력 클래스 설정 및 구현 - 1) 각 자동차의 진행상황을 출력해 줘야함. 해당 부분에서 표현방식이 변경이 될 수 있는 부분에 대한 고려 필요 - 2) 우승자에 대해 계산해주는 로직 필요함. 1개 이상의 경우를 고려해 구현해야함 + - [x] 각 자동차의 진행상황을 출력해 줘야함. 해당 부분에서 표현방식이 변경이 될 수 있는 부분에 대한 고려 필요 + - [x] 우승자에 대해 계산해주는 로직 필요함. 3. Main 함수 구현 - 1) 입력을 받아오고 출력을 진행. 받아온 자동차 갯수만큼의 이름을 구현해야함 + - [x] 입력을 받아오고 출력을 진행. 받아온 자동차 갯수만큼의 이름을 구현해야함 4. 요구사항 명세에 맞는 리팩토링 진행 - 1) 들여쓰기 2 넘지 않도록 구현 - 2) 함수 이름 15라인 넘지 않도록 구현 \ No newline at end of file + - [x] 들여쓰기 2 넘지 않도록 구현 + - [x] 함수 이름 15라인 넘지 않도록 구현 + 5. 단위 테스트 구현 + - [ ] 자동차 random이 구현 범위내에 들어오는지 체크 \ No newline at end of file diff --git a/src/main/kotlin/ResultView.kt b/src/main/kotlin/ResultView.kt deleted file mode 100644 index 722199bf54..0000000000 --- a/src/main/kotlin/ResultView.kt +++ /dev/null @@ -1,18 +0,0 @@ -object ResultView { - - private const val NEXT_LINE = "\n" - private const val PROGRESS_STRING = "-" - fun showResult(carList: MutableList, actionCount: Int) { - println("실행 결과") - for (i in 0 until actionCount) { - carList.forEach { - val progressString = StringBuffer(PROGRESS_STRING) - repeat(it.getCarProgress()) { - progressString.append(PROGRESS_STRING) - } - println("${it.name} : ${progressString.toString()}") - } - print(NEXT_LINE) - } - } -} diff --git a/src/main/kotlin/Calculator.kt b/src/main/kotlin/calculator/Calculator.kt similarity index 88% rename from src/main/kotlin/Calculator.kt rename to src/main/kotlin/calculator/Calculator.kt index feca56d7bf..b6362151d0 100644 --- a/src/main/kotlin/Calculator.kt +++ b/src/main/kotlin/calculator/Calculator.kt @@ -1,7 +1,8 @@ +package calculator object Calculator { - private const val SPERATOR = " " + private const val SEPERATOR = " " private const val LAST_INDEX = 1 private const val NEXT_PART_INDEX = 2 private const val NUMBER_POSITION = 0 @@ -11,7 +12,7 @@ object Calculator { if (formulaString.isEmpty()) { throw IllegalArgumentException("Input value is empty") } - val formulaList = formulaString.split(SPERATOR) + val formulaList = formulaString.split(SEPERATOR) val resultValue = recursiveCalculator(formulaList.reversed()) println(resultValue) return resultValue @@ -24,4 +25,4 @@ object Calculator { Operator.getOperator(formulaList[OPERATOR_POSITION]).calculate(recursiveCalculator(formulaList.drop(NEXT_PART_INDEX)), formulaList[NUMBER_POSITION]) } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/Operator.kt b/src/main/kotlin/calculator/Operator.kt similarity index 98% rename from src/main/kotlin/Operator.kt rename to src/main/kotlin/calculator/Operator.kt index 123d3efa4b..c99d625a9c 100644 --- a/src/main/kotlin/Operator.kt +++ b/src/main/kotlin/calculator/Operator.kt @@ -1,3 +1,5 @@ +package calculator + enum class Operator(val operator: String) { PLUS("+") { override fun calculate(preNumber: String, postNumber: String): String { @@ -50,7 +52,7 @@ enum class Operator(val operator: String) { private fun String.isNum(): Boolean { this.forEach { - char -> + char -> val charConvertedToCode = char.code diff --git a/src/main/kotlin/Car.kt b/src/main/kotlin/racing/Car.kt similarity index 53% rename from src/main/kotlin/Car.kt rename to src/main/kotlin/racing/Car.kt index d5e1f63833..3c9be78c50 100644 --- a/src/main/kotlin/Car.kt +++ b/src/main/kotlin/racing/Car.kt @@ -1,21 +1,29 @@ +package racing + import kotlin.random.Random class Car(val name : String) { - private var progress = 0 + init { + require(name.length <= MAXIMUM_NAME_LENGTH) { + "자동차 이름은 ${MAXIMUM_NAME_LENGTH}자를 초과할 수 없다." + } + } + + var progress = 0 - fun getCarProgress(): Int { + fun moveCar(): Int { if (checkCanGo()) { progress++ } return progress } - fun checkCanGo(): Boolean { + private fun checkCanGo(): Boolean { return getRandomInt() >= GO_RESTRICT_NUMBER } - fun getRandomInt(): Int { + private fun getRandomInt(): Int { return Random.nextInt(MIN_RANGE, MAX_RANGE) } @@ -23,5 +31,6 @@ class Car(val name : String) { const val MIN_RANGE = 0 const val MAX_RANGE = 10 const val GO_RESTRICT_NUMBER = 4 + const val MAXIMUM_NAME_LENGTH = 5 } } diff --git a/src/main/kotlin/InputView.kt b/src/main/kotlin/racing/InputView.kt similarity index 65% rename from src/main/kotlin/InputView.kt rename to src/main/kotlin/racing/InputView.kt index ebea262906..7ab65fe66c 100644 --- a/src/main/kotlin/InputView.kt +++ b/src/main/kotlin/racing/InputView.kt @@ -1,20 +1,26 @@ +package racing + object InputView { private const val DEFAULT_INPUT = 0 private const val MINIMUM_INPUT = 1 + + private const val INPUT_SEPERATOR = "," private const val INPUT_ACTION_PREFIX = "시도할 횟수는 " fun doInput(): Pair, Int> { - println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).") - val carNumber = getInputCars() - println("$INPUT_ACTION_PREFIX 몇 회인가요?") - val actionCount = getInputNumber(INPUT_ACTION_PREFIX) + val carNames = getInputCars() - return Pair(carNumber, actionCount) + println("$INPUT_ACTION_PREFIX 몇 회인가요?") + val actionCount = getInputNumber() + if (actionCount < MINIMUM_INPUT) { + throw IllegalArgumentException("$INPUT_ACTION_PREFIX ${MINIMUM_INPUT}대 이상이어야 함") + } + return Pair(carNames, actionCount) } private fun getInputCars(): List { @@ -25,13 +31,9 @@ object InputView { } } - private fun getInputNumber(prefix: String): Int { + private fun getInputNumber(): Int { return runCatching { - (readlnOrNull()?.toInt() ?: DEFAULT_INPUT).apply { - if (this < MINIMUM_INPUT) { - throw IllegalArgumentException("$prefix ${MINIMUM_INPUT}대 이상이어야 함") - } - } + (readlnOrNull()?.toInt() ?: DEFAULT_INPUT) }.getOrElse { throw NumberFormatException("숫자 입력해야함") } diff --git a/src/main/kotlin/RagingCarMain.kt b/src/main/kotlin/racing/RagingCarMain.kt similarity index 73% rename from src/main/kotlin/RagingCarMain.kt rename to src/main/kotlin/racing/RagingCarMain.kt index 6ac4617392..3669d9a93a 100644 --- a/src/main/kotlin/RagingCarMain.kt +++ b/src/main/kotlin/racing/RagingCarMain.kt @@ -1,14 +1,11 @@ - +package racing fun main() { - val inputData = InputView.doInput() - val carNumber = inputData.first + val carNames = inputData.first val actionCount = inputData.second - val cars = mutableListOf() - carNumber.forEach { + carNames.forEach { cars.add(Car(it)) } - ResultView.showResult(cars, actionCount) } diff --git a/src/main/kotlin/racing/ResultView.kt b/src/main/kotlin/racing/ResultView.kt new file mode 100644 index 0000000000..1c14dbad20 --- /dev/null +++ b/src/main/kotlin/racing/ResultView.kt @@ -0,0 +1,41 @@ +package racing + +object ResultView { + private const val NEXT_LINE = "\n" + private const val PROGRESS_STRING = "-" + private const val SEPERATOR = ", " + + fun showResult(cars: MutableList, actionCount: Int) { + println("실행 결과") + repeat(actionCount) { + gameStart(cars) + print(NEXT_LINE) + } + print("${showWinner(cars)}가 최종 우승했습니다.") + } + + private fun showWinner(cars: List) : String{ + val firstGradePosition = cars.maxOf(Car::progress) + return cars.filter { + it.progress == firstGradePosition + }.joinToString(SEPERATOR, transform = Car::name) + + } + + private fun gameStart(cars : List) { + cars.forEach { + car -> + car.moveCar() + showSkidMarks(car) + } + + } + + private fun showSkidMarks(car: Car) { + val progressString = StringBuffer() + repeat(car.progress) { + progressString.append(PROGRESS_STRING) + } + println("${car.name} : $progressString") + } +} diff --git a/src/test/kotlin/study/CalculatorKoTest.kt b/src/test/kotlin/calculator/CalculatorKoTest.kt similarity index 89% rename from src/test/kotlin/study/CalculatorKoTest.kt rename to src/test/kotlin/calculator/CalculatorKoTest.kt index eabbec44d1..ed13a5c1d5 100644 --- a/src/test/kotlin/study/CalculatorKoTest.kt +++ b/src/test/kotlin/calculator/CalculatorKoTest.kt @@ -1,6 +1,7 @@ -package study +package calculator -import Calculator +import calculator.Calculator +import calculator.Operator import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt new file mode 100644 index 0000000000..222df50423 --- /dev/null +++ b/src/test/kotlin/racing/CarTest.kt @@ -0,0 +1,26 @@ +package racing + +import io.kotest.assertions.throwables.shouldThrowExactly +import io.kotest.core.spec.style.AnnotationSpec +import io.kotest.matchers.ints.shouldBeInRange +import java.lang.IllegalArgumentException + +class CarTest : AnnotationSpec() { + + @Test + fun `자동차_이름이_5자가_넘는경우`() { + Car("minhyukseul") + } + + @Test + fun `자동차가 움직일 경우 위치가 0이거나 1인지 확인`() { + val car = Car("pobi") + car.moveCar() shouldBeInRange 0..1 + } + + @Test + fun `자동차 여러대를 생성해서 실제 우승자를 체크해봄`() { + val cars = mutableListOf(Car("pobi"), Car("crong"), Car("honux")) + ResultView.showResult(cars, 5) + } +} diff --git a/src/test/kotlin/study/CarBehaviorTest.kt b/src/test/kotlin/study/CarBehaviorTest.kt deleted file mode 100644 index 7b82a1a931..0000000000 --- a/src/test/kotlin/study/CarBehaviorTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package study - -import Car -import io.kotest.core.spec.style.BehaviorSpec -import io.kotest.matchers.ints.shouldBeInRange - -class CarBehaviorTest : BehaviorSpec({ - Given("자동차가") { - val car = Car() - When("랜덤 데이터를 받았을 때") { - val randomInt = car.getRandomInt() - Then("데이터는 0~9여야 한다") { - randomInt shouldBeInRange 0..9 - } - } - } -}) diff --git a/src/test/kotlin/study/CarKoTest.kt b/src/test/kotlin/study/CarKoTest.kt deleted file mode 100644 index 1513fbf11e..0000000000 --- a/src/test/kotlin/study/CarKoTest.kt +++ /dev/null @@ -1,26 +0,0 @@ -package study - -import Car -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.ints.shouldBeInRange -import io.kotest.matchers.shouldBe - -class CarKoTest : StringSpec({ - "랜덤값" { - val car = Car() - for (i in 0..10) { - car.getRandomInt() shouldBeInRange 0..9 - } - } - "움직임 여부" { - var car = Car() - car.checkCanGo() shouldBe true - } - - "차 이동" { - var car = Car() - for (i in 0 until 5) { - println(car.getCarProgress()) - } - } -}) From 78aa10605e27a7e0ffcba7015fb092d9e87bac20 Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Mon, 12 Jun 2023 14:52:29 +0900 Subject: [PATCH 08/15] =?UTF-8?q?refactoring=20:=20klint=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/calculator/Calculator.kt | 2 +- src/main/kotlin/calculator/Operator.kt | 2 +- src/main/kotlin/racing/Car.kt | 2 +- src/main/kotlin/racing/InputView.kt | 4 +--- src/main/kotlin/racing/ResultView.kt | 6 ++---- src/test/kotlin/calculator/CalculatorKoTest.kt | 2 -- src/test/kotlin/racing/CarTest.kt | 2 -- 7 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/calculator/Calculator.kt b/src/main/kotlin/calculator/Calculator.kt index b6362151d0..0cf1dc6601 100644 --- a/src/main/kotlin/calculator/Calculator.kt +++ b/src/main/kotlin/calculator/Calculator.kt @@ -25,4 +25,4 @@ object Calculator { Operator.getOperator(formulaList[OPERATOR_POSITION]).calculate(recursiveCalculator(formulaList.drop(NEXT_PART_INDEX)), formulaList[NUMBER_POSITION]) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/calculator/Operator.kt b/src/main/kotlin/calculator/Operator.kt index c99d625a9c..4f92adaf67 100644 --- a/src/main/kotlin/calculator/Operator.kt +++ b/src/main/kotlin/calculator/Operator.kt @@ -52,7 +52,7 @@ enum class Operator(val operator: String) { private fun String.isNum(): Boolean { this.forEach { - char -> + char -> val charConvertedToCode = char.code diff --git a/src/main/kotlin/racing/Car.kt b/src/main/kotlin/racing/Car.kt index 3c9be78c50..e7f61f583e 100644 --- a/src/main/kotlin/racing/Car.kt +++ b/src/main/kotlin/racing/Car.kt @@ -2,7 +2,7 @@ package racing import kotlin.random.Random -class Car(val name : String) { +class Car(val name: String) { init { require(name.length <= MAXIMUM_NAME_LENGTH) { diff --git a/src/main/kotlin/racing/InputView.kt b/src/main/kotlin/racing/InputView.kt index 7ab65fe66c..69dcae2d38 100644 --- a/src/main/kotlin/racing/InputView.kt +++ b/src/main/kotlin/racing/InputView.kt @@ -5,8 +5,6 @@ object InputView { private const val DEFAULT_INPUT = 0 private const val MINIMUM_INPUT = 1 - - private const val INPUT_SEPERATOR = "," private const val INPUT_ACTION_PREFIX = "시도할 횟수는 " @@ -25,7 +23,7 @@ object InputView { private fun getInputCars(): List { return runCatching { - (readlnOrNull()?:"").split(INPUT_SEPERATOR) + (readlnOrNull() ?: "").split(INPUT_SEPERATOR) }.getOrElse { throw IllegalArgumentException("형식에 맞는 타입을 입력해야함") } diff --git a/src/main/kotlin/racing/ResultView.kt b/src/main/kotlin/racing/ResultView.kt index 1c14dbad20..db06add860 100644 --- a/src/main/kotlin/racing/ResultView.kt +++ b/src/main/kotlin/racing/ResultView.kt @@ -14,21 +14,19 @@ object ResultView { print("${showWinner(cars)}가 최종 우승했습니다.") } - private fun showWinner(cars: List) : String{ + private fun showWinner(cars: List): String { val firstGradePosition = cars.maxOf(Car::progress) return cars.filter { it.progress == firstGradePosition }.joinToString(SEPERATOR, transform = Car::name) - } - private fun gameStart(cars : List) { + private fun gameStart(cars: List) { cars.forEach { car -> car.moveCar() showSkidMarks(car) } - } private fun showSkidMarks(car: Car) { diff --git a/src/test/kotlin/calculator/CalculatorKoTest.kt b/src/test/kotlin/calculator/CalculatorKoTest.kt index ed13a5c1d5..fe778f5f36 100644 --- a/src/test/kotlin/calculator/CalculatorKoTest.kt +++ b/src/test/kotlin/calculator/CalculatorKoTest.kt @@ -1,7 +1,5 @@ package calculator -import calculator.Calculator -import calculator.Operator import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index 222df50423..c5c9d10fd6 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -1,9 +1,7 @@ package racing -import io.kotest.assertions.throwables.shouldThrowExactly import io.kotest.core.spec.style.AnnotationSpec import io.kotest.matchers.ints.shouldBeInRange -import java.lang.IllegalArgumentException class CarTest : AnnotationSpec() { From 6a6f5176564a03134b8aa5ae880fc87fa044efc9 Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Tue, 13 Jun 2023 09:22:37 +0900 Subject: [PATCH 09/15] =?UTF-8?q?refactoring=20:=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=20random=20=EC=88=AB=EC=9E=90=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9D=84=20=EC=99=B8=EB=B6=80=EC=97=90=EC=84=9C=20=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95.=20=EA=B7=B8=20?= =?UTF-8?q?=EC=99=B8=20=EC=BD=94=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/kotlin/racing/Car.kt | 21 +++++--------------- src/main/kotlin/racing/CarRandomGenerator.kt | 12 +++++++++++ src/main/kotlin/racing/InputView.kt | 4 +++- src/main/kotlin/racing/RagingCarMain.kt | 5 ++--- src/main/kotlin/racing/ResultView.kt | 5 +++-- src/test/kotlin/racing/CarTest.kt | 15 +++++++++++++- 7 files changed, 40 insertions(+), 24 deletions(-) create mode 100644 src/main/kotlin/racing/CarRandomGenerator.kt diff --git a/README.md b/README.md index a7fa424e11..edb7791f32 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,4 @@ - [x] 들여쓰기 2 넘지 않도록 구현 - [x] 함수 이름 15라인 넘지 않도록 구현 5. 단위 테스트 구현 - - [ ] 자동차 random이 구현 범위내에 들어오는지 체크 \ No newline at end of file + - [x] 자동차 random이 구현 범위내에 들어오는지 체크 \ No newline at end of file diff --git a/src/main/kotlin/racing/Car.kt b/src/main/kotlin/racing/Car.kt index e7f61f583e..6f5694a34b 100644 --- a/src/main/kotlin/racing/Car.kt +++ b/src/main/kotlin/racing/Car.kt @@ -1,35 +1,24 @@ package racing -import kotlin.random.Random - class Car(val name: String) { + var progress = 0 + private set + init { require(name.length <= MAXIMUM_NAME_LENGTH) { "자동차 이름은 ${MAXIMUM_NAME_LENGTH}자를 초과할 수 없다." } } - var progress = 0 - - fun moveCar(): Int { - if (checkCanGo()) { + fun moveCar(randomNumber: Int): Int { + if (randomNumber >= GO_RESTRICT_NUMBER) { progress++ } return progress } - private fun checkCanGo(): Boolean { - return getRandomInt() >= GO_RESTRICT_NUMBER - } - - private fun getRandomInt(): Int { - return Random.nextInt(MIN_RANGE, MAX_RANGE) - } - companion object { - const val MIN_RANGE = 0 - const val MAX_RANGE = 10 const val GO_RESTRICT_NUMBER = 4 const val MAXIMUM_NAME_LENGTH = 5 } diff --git a/src/main/kotlin/racing/CarRandomGenerator.kt b/src/main/kotlin/racing/CarRandomGenerator.kt new file mode 100644 index 0000000000..6a25e322a8 --- /dev/null +++ b/src/main/kotlin/racing/CarRandomGenerator.kt @@ -0,0 +1,12 @@ +package racing + +import kotlin.random.Random + +object CarRandomGenerator { + + private const val MIN_RANGE = 0 + + fun createRandom(range: Int): Int { + return Random.nextInt(MIN_RANGE, range) + } +} diff --git a/src/main/kotlin/racing/InputView.kt b/src/main/kotlin/racing/InputView.kt index 69dcae2d38..3a5adccb3e 100644 --- a/src/main/kotlin/racing/InputView.kt +++ b/src/main/kotlin/racing/InputView.kt @@ -23,7 +23,9 @@ object InputView { private fun getInputCars(): List { return runCatching { - (readlnOrNull() ?: "").split(INPUT_SEPERATOR) + val inputCars = (readlnOrNull() ?: "") + if (inputCars.isEmpty()) throw IllegalArgumentException("이름은 한글자 이상이어야 함") + inputCars.split(INPUT_SEPERATOR) }.getOrElse { throw IllegalArgumentException("형식에 맞는 타입을 입력해야함") } diff --git a/src/main/kotlin/racing/RagingCarMain.kt b/src/main/kotlin/racing/RagingCarMain.kt index 3669d9a93a..2db9ab3074 100644 --- a/src/main/kotlin/racing/RagingCarMain.kt +++ b/src/main/kotlin/racing/RagingCarMain.kt @@ -3,9 +3,8 @@ fun main() { val inputData = InputView.doInput() val carNames = inputData.first val actionCount = inputData.second - val cars = mutableListOf() - carNames.forEach { - cars.add(Car(it)) + val cars = carNames.map { + Car(it) } ResultView.showResult(cars, actionCount) } diff --git a/src/main/kotlin/racing/ResultView.kt b/src/main/kotlin/racing/ResultView.kt index db06add860..70cb2b2ddf 100644 --- a/src/main/kotlin/racing/ResultView.kt +++ b/src/main/kotlin/racing/ResultView.kt @@ -4,8 +4,9 @@ object ResultView { private const val NEXT_LINE = "\n" private const val PROGRESS_STRING = "-" private const val SEPERATOR = ", " + private const val MAX_RANGE = 10 - fun showResult(cars: MutableList, actionCount: Int) { + fun showResult(cars: List, actionCount: Int) { println("실행 결과") repeat(actionCount) { gameStart(cars) @@ -24,7 +25,7 @@ object ResultView { private fun gameStart(cars: List) { cars.forEach { car -> - car.moveCar() + car.moveCar(CarRandomGenerator.createRandom(MAX_RANGE)) showSkidMarks(car) } } diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index c5c9d10fd6..9f451e691b 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -1,5 +1,6 @@ package racing +import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.AnnotationSpec import io.kotest.matchers.ints.shouldBeInRange @@ -8,12 +9,24 @@ class CarTest : AnnotationSpec() { @Test fun `자동차_이름이_5자가_넘는경우`() { Car("minhyukseul") + shouldThrow { + "이름이 5자 넘어야함" + } } @Test fun `자동차가 움직일 경우 위치가 0이거나 1인지 확인`() { val car = Car("pobi") - car.moveCar() shouldBeInRange 0..1 + car.moveCar(CarRandomGenerator.createRandom(10)) shouldBeInRange 0..1 + } + + @Test + fun `자동차가 랜덤 값 5회 반복으로 범위 안에 들어오는지 확인`() { + repeat(5) { + val data = CarRandomGenerator.createRandom(10) + println(data) + data shouldBeInRange 0..9 + } } @Test From b8417a80ccfceae13c77b1f6e3e05743afeb5815 Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Tue, 13 Jun 2023 18:56:58 +0900 Subject: [PATCH 10/15] =?UTF-8?q?refactoring:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=EC=A7=84=ED=96=89?= =?UTF-8?q?=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/racing/Car.kt | 6 +++--- src/test/kotlin/racing/CarTest.kt | 14 ++++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/racing/Car.kt b/src/main/kotlin/racing/Car.kt index 6f5694a34b..1435d8e9c0 100644 --- a/src/main/kotlin/racing/Car.kt +++ b/src/main/kotlin/racing/Car.kt @@ -11,15 +11,15 @@ class Car(val name: String) { } } - fun moveCar(randomNumber: Int): Int { - if (randomNumber >= GO_RESTRICT_NUMBER) { + fun moveCar(pedalStrength: Int): Int { + if (pedalStrength >= GO_RESTRICT_STRENGTH) { progress++ } return progress } companion object { - const val GO_RESTRICT_NUMBER = 4 + const val GO_RESTRICT_STRENGTH = 4 const val MAXIMUM_NAME_LENGTH = 5 } } diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index 9f451e691b..7aaa66017d 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -3,21 +3,27 @@ package racing import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.AnnotationSpec import io.kotest.matchers.ints.shouldBeInRange +import io.kotest.matchers.shouldBe class CarTest : AnnotationSpec() { @Test fun `자동차_이름이_5자가_넘는경우`() { - Car("minhyukseul") shouldThrow { - "이름이 5자 넘어야함" - } + Car("minhyukseul") + }.message shouldBe "자동차 이름은 ${Car.MAXIMUM_NAME_LENGTH}자를 초과할 수 없다." + } + + @Test + fun `랜덤한 숫자를 생성하여 범위내에 들어오는지 확인`() { + CarRandomGenerator.createRandom(10) shouldBeInRange 0..9 } @Test fun `자동차가 움직일 경우 위치가 0이거나 1인지 확인`() { val car = Car("pobi") - car.moveCar(CarRandomGenerator.createRandom(10)) shouldBeInRange 0..1 + car.moveCar(4) shouldBe 1 + car.moveCar(3) shouldBe 1 } @Test From e6586428675293ae15aec8695c6d915ab7fed500 Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Wed, 14 Jun 2023 11:29:32 +0900 Subject: [PATCH 11/15] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EA=B3=BC=20=EC=9C=84=EC=B9=98=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EA=B8=B0=EB=B3=B8=20=EB=8B=A8=EC=9C=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B0=8F=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +++++- build.gradle.kts | 2 +- src/main/kotlin/racing/RagingCarMain.kt | 5 +++ src/main/kotlin/racing/{ => domain}/Car.kt | 12 +++--- src/main/kotlin/racing/domain/RacingGame.kt | 8 ++++ .../kotlin/racing/{ => view}/InputView.kt | 2 +- .../kotlin/racing/{ => view}/ResultView.kt | 11 +++-- src/test/kotlin/racing/CarTest.kt | 6 ++- src/test/kotlin/racing/RacingCarTest.kt | 43 +++++++++++++++++++ 9 files changed, 89 insertions(+), 14 deletions(-) rename src/main/kotlin/racing/{ => domain}/Car.kt (65%) create mode 100644 src/main/kotlin/racing/domain/RacingGame.kt rename src/main/kotlin/racing/{ => view}/InputView.kt (98%) rename src/main/kotlin/racing/{ => view}/ResultView.kt (82%) create mode 100644 src/test/kotlin/racing/RacingCarTest.kt diff --git a/README.md b/README.md index edb7791f32..1df00f8dff 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,16 @@ - [x] 들여쓰기 2 넘지 않도록 구현 - [x] 함수 이름 15라인 넘지 않도록 구현 5. 단위 테스트 구현 - - [x] 자동차 random이 구현 범위내에 들어오는지 체크 \ No newline at end of file + - [x] 자동차 random이 구현 범위내에 들어오는지 체크 + +### STEP5 리팩토링 + + +- [x] 자동차는 이름을 가지고 최초 위치는 0을 가리킨다. +- [x] 자동차 이름은 5자를 초과할 수 없다. +- [ ] 자동차 이름은 쉼표(,)를 기준으로 구분한다. +- [ ] 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. +- [ ] 자동차 이름은 쉼표(,)를 기준으로 구분한다. +- [ ] 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. +- [x] 핵심 비지니스 로직을 가지는 객체를 domain패키지, UI관련한 객체를 view패키지에 구현 +- [ ] MVC패턴 기반으로 리팩토링, view 패키지의 객체가 domain 패키지에 의존할 수 있음, domain패키지의 객체는 view 패키지에 의존하지 않도록 구현 \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 43c17967be..9d2186baac 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,7 @@ repositories { dependencies { testImplementation("org.junit.jupiter", "junit-jupiter", "5.8.2") testImplementation("org.assertj", "assertj-core", "3.22.0") - testImplementation("io.kotest", "kotest-runner-junit5", "5.5.0") + testImplementation("io.kotest", "kotest-runner-junit5", "5.6.2") } tasks { diff --git a/src/main/kotlin/racing/RagingCarMain.kt b/src/main/kotlin/racing/RagingCarMain.kt index 2db9ab3074..3918759831 100644 --- a/src/main/kotlin/racing/RagingCarMain.kt +++ b/src/main/kotlin/racing/RagingCarMain.kt @@ -1,4 +1,9 @@ package racing + +import racing.domain.Car +import racing.view.InputView +import racing.view.ResultView + fun main() { val inputData = InputView.doInput() val carNames = inputData.first diff --git a/src/main/kotlin/racing/Car.kt b/src/main/kotlin/racing/domain/Car.kt similarity index 65% rename from src/main/kotlin/racing/Car.kt rename to src/main/kotlin/racing/domain/Car.kt index 1435d8e9c0..29eb103abf 100644 --- a/src/main/kotlin/racing/Car.kt +++ b/src/main/kotlin/racing/domain/Car.kt @@ -1,8 +1,8 @@ -package racing +package racing.domain class Car(val name: String) { - var progress = 0 + var position = DEFAULT_POSITION private set init { @@ -11,14 +11,16 @@ class Car(val name: String) { } } - fun moveCar(pedalStrength: Int): Int { + fun moveCar(pedalStrength: Int): Boolean { if (pedalStrength >= GO_RESTRICT_STRENGTH) { - progress++ + position++ + return true } - return progress + return false } companion object { + const val DEFAULT_POSITION = 0 const val GO_RESTRICT_STRENGTH = 4 const val MAXIMUM_NAME_LENGTH = 5 } diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt new file mode 100644 index 0000000000..5a64de59e7 --- /dev/null +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -0,0 +1,8 @@ +package racing.domain + +class RacingGame { + + fun generatePedalStrength() { + + } +} \ No newline at end of file diff --git a/src/main/kotlin/racing/InputView.kt b/src/main/kotlin/racing/view/InputView.kt similarity index 98% rename from src/main/kotlin/racing/InputView.kt rename to src/main/kotlin/racing/view/InputView.kt index 3a5adccb3e..73ce531b13 100644 --- a/src/main/kotlin/racing/InputView.kt +++ b/src/main/kotlin/racing/view/InputView.kt @@ -1,4 +1,4 @@ -package racing +package racing.view object InputView { diff --git a/src/main/kotlin/racing/ResultView.kt b/src/main/kotlin/racing/view/ResultView.kt similarity index 82% rename from src/main/kotlin/racing/ResultView.kt rename to src/main/kotlin/racing/view/ResultView.kt index 70cb2b2ddf..87b8720dab 100644 --- a/src/main/kotlin/racing/ResultView.kt +++ b/src/main/kotlin/racing/view/ResultView.kt @@ -1,4 +1,7 @@ -package racing +package racing.view + +import racing.domain.Car +import racing.CarRandomGenerator object ResultView { private const val NEXT_LINE = "\n" @@ -16,9 +19,9 @@ object ResultView { } private fun showWinner(cars: List): String { - val firstGradePosition = cars.maxOf(Car::progress) + val firstGradePosition = cars.maxOf(Car::position) return cars.filter { - it.progress == firstGradePosition + it.position == firstGradePosition }.joinToString(SEPERATOR, transform = Car::name) } @@ -32,7 +35,7 @@ object ResultView { private fun showSkidMarks(car: Car) { val progressString = StringBuffer() - repeat(car.progress) { + repeat(car.position) { progressString.append(PROGRESS_STRING) } println("${car.name} : $progressString") diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt index 7aaa66017d..4369b3071f 100644 --- a/src/test/kotlin/racing/CarTest.kt +++ b/src/test/kotlin/racing/CarTest.kt @@ -4,14 +4,16 @@ import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.AnnotationSpec import io.kotest.matchers.ints.shouldBeInRange import io.kotest.matchers.shouldBe +import racing.domain.Car +import racing.view.ResultView class CarTest : AnnotationSpec() { @Test - fun `자동차_이름이_5자가_넘는경우`() { + fun `자동차 이름은 5자를 넘을 수 없음`() { shouldThrow { Car("minhyukseul") - }.message shouldBe "자동차 이름은 ${Car.MAXIMUM_NAME_LENGTH}자를 초과할 수 없다." + } } @Test diff --git a/src/test/kotlin/racing/RacingCarTest.kt b/src/test/kotlin/racing/RacingCarTest.kt new file mode 100644 index 0000000000..c8def2dbeb --- /dev/null +++ b/src/test/kotlin/racing/RacingCarTest.kt @@ -0,0 +1,43 @@ +package racing + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.AnnotationSpec +import io.kotest.matchers.shouldBe +import racing.domain.Car + +class RacingCarTest : AnnotationSpec() { + + @Test + fun `자동차는 이름을 가지고 최초 위치는 0을 가리킨다`() { + val name = "poby" + val car = Car(name) + car.name shouldBe name + car.position shouldBe 0 + } + + @Test + fun `자동차 이름은 5글자가 넘을 수가 없음`() { + shouldThrow { + Car("123456") + } + } + + @Test + fun `자동차는 강도 4이상의 엑셀을 밟으면 움직 일 수 있음`() { + val numbers = listOf(4, 5, 6, 7, 8, 9) + val car = Car("Poby") + numbers.forEach { + car.moveCar(it) shouldBe true + } + + } + + @Test + fun `자동차는 강도 4미만의 엑셀을 밟으면 움직 일 수 없음`() { + val numbers = listOf(0, 1, 2, 3) + val car = Car("Poby") + numbers.forEach { + car.moveCar(it) shouldBe false + } + } +} \ No newline at end of file From e037f1f6fe6765b68641ecc79202f7d187db6c8a Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Wed, 14 Jun 2023 11:38:11 +0900 Subject: [PATCH 12/15] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EC=9D=80=20=EC=89=BC=ED=91=9C(,)=EB=A5=BC=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EA=B5=AC=EB=B6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/kotlin/racing/InputParser.kt | 10 ++++++++++ src/main/kotlin/racing/view/InputView.kt | 12 ++++++++---- src/test/kotlin/racing/RacingCarTest.kt | 10 ++++++++++ 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 src/main/kotlin/racing/InputParser.kt diff --git a/README.md b/README.md index 1df00f8dff..25d999a5e5 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ - [x] 자동차는 이름을 가지고 최초 위치는 0을 가리킨다. - [x] 자동차 이름은 5자를 초과할 수 없다. -- [ ] 자동차 이름은 쉼표(,)를 기준으로 구분한다. +- [x] 자동차 이름은 쉼표(,)를 기준으로 구분한다. - [ ] 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. - [ ] 자동차 이름은 쉼표(,)를 기준으로 구분한다. - [ ] 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. diff --git a/src/main/kotlin/racing/InputParser.kt b/src/main/kotlin/racing/InputParser.kt new file mode 100644 index 0000000000..089c57a220 --- /dev/null +++ b/src/main/kotlin/racing/InputParser.kt @@ -0,0 +1,10 @@ +package racing + +object InputParser { + + private const val INPUT_SEPERATOR = "," + fun parse(carNames: String) : List { + return carNames.split(INPUT_SEPERATOR) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/racing/view/InputView.kt b/src/main/kotlin/racing/view/InputView.kt index 73ce531b13..10b85bf9fb 100644 --- a/src/main/kotlin/racing/view/InputView.kt +++ b/src/main/kotlin/racing/view/InputView.kt @@ -1,11 +1,13 @@ package racing.view +import racing.InputParser + object InputView { private const val DEFAULT_INPUT = 0 private const val MINIMUM_INPUT = 1 - private const val INPUT_SEPERATOR = "," + private const val INPUT_ACTION_PREFIX = "시도할 횟수는 " @@ -23,14 +25,16 @@ object InputView { private fun getInputCars(): List { return runCatching { - val inputCars = (readlnOrNull() ?: "") - if (inputCars.isEmpty()) throw IllegalArgumentException("이름은 한글자 이상이어야 함") - inputCars.split(INPUT_SEPERATOR) + val inputCars = readlnOrNull() + if (inputCars.isNullOrEmpty()) throw IllegalArgumentException("이름은 한글자 이상이어야 함") + InputParser.parse(inputCars) }.getOrElse { throw IllegalArgumentException("형식에 맞는 타입을 입력해야함") } } + + private fun getInputNumber(): Int { return runCatching { (readlnOrNull()?.toInt() ?: DEFAULT_INPUT) diff --git a/src/test/kotlin/racing/RacingCarTest.kt b/src/test/kotlin/racing/RacingCarTest.kt index c8def2dbeb..6439ca2532 100644 --- a/src/test/kotlin/racing/RacingCarTest.kt +++ b/src/test/kotlin/racing/RacingCarTest.kt @@ -2,8 +2,12 @@ package racing import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.AnnotationSpec +import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe import racing.domain.Car +import racing.view.InputView + + class RacingCarTest : AnnotationSpec() { @@ -40,4 +44,10 @@ class RacingCarTest : AnnotationSpec() { car.moveCar(it) shouldBe false } } + + @Test + fun `자동차 이름은 쉼표로 구분함`() { + val carNames = "pobi,crong,honux" + InputParser.parse(carNames) shouldHaveSize(3) + } } \ No newline at end of file From 894f8652f4811d7752c86b161b1c3f21f6743a53 Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Wed, 14 Jun 2023 11:45:51 +0900 Subject: [PATCH 13/15] =?UTF-8?q?feat:=200=EC=97=90=EC=84=9C=209=20?= =?UTF-8?q?=EC=82=AC=EC=9D=B4=EC=97=90=EC=84=9C=20=EB=AC=B4=EC=9E=91?= =?UTF-8?q?=EC=9C=84=20=EA=B0=92=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + src/main/kotlin/racing/domain/RacingGame.kt | 8 +++++--- src/test/kotlin/racing/RacingCarTest.kt | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 25d999a5e5..f666a47d05 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ - [x] 자동차는 이름을 가지고 최초 위치는 0을 가리킨다. - [x] 자동차 이름은 5자를 초과할 수 없다. - [x] 자동차 이름은 쉼표(,)를 기준으로 구분한다. +- [x] 0에서 9 사이에서 무작위 값을 구한다. - [ ] 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. - [ ] 자동차 이름은 쉼표(,)를 기준으로 구분한다. - [ ] 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 5a64de59e7..95735ed8c5 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -1,8 +1,10 @@ package racing.domain -class RacingGame { +object RacingGame { - fun generatePedalStrength() { + const val MAX_BOUND = 10 + + fun gameStart(cars: List) { } -} \ No newline at end of file +} diff --git a/src/test/kotlin/racing/RacingCarTest.kt b/src/test/kotlin/racing/RacingCarTest.kt index 6439ca2532..7a9841c983 100644 --- a/src/test/kotlin/racing/RacingCarTest.kt +++ b/src/test/kotlin/racing/RacingCarTest.kt @@ -3,8 +3,10 @@ package racing import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.AnnotationSpec import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.ints.shouldBeInRange import io.kotest.matchers.shouldBe import racing.domain.Car +import racing.domain.RacingGame import racing.view.InputView @@ -50,4 +52,20 @@ class RacingCarTest : AnnotationSpec() { val carNames = "pobi,crong,honux" InputParser.parse(carNames) shouldHaveSize(3) } + + @Test + fun `0에서 9 사이에서 무작위 값을 구한다`() { + repeat(5) { + CarRandomGenerator.createRandom(RacingGame.MAX_BOUND) shouldBeInRange 0..9 + } + } + + @Test + fun `전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다`() { + val carNames = "pobi,crong,honux" + val cars = InputParser.parse(carNames).map { Car(it) } + + RacingGame.gameStart(cars) + + } } \ No newline at end of file From 8dc62b708da3683a31256e9e801417eb85f9b13a Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Wed, 14 Jun 2023 12:34:57 +0900 Subject: [PATCH 14/15] =?UTF-8?q?feat:=20=EC=A0=84=EC=A7=84=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=9E=90=EB=8F=99=EC=B0=A8=EB=A5=BC=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=ED=95=A0=20=EB=95=8C=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EC=9D=84=20=EA=B0=99=EC=9D=B4=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EB=8B=A8=EC=9C=84=ED=85=8C=EC=8A=A4=ED=8A=B8=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 --- README.md | 3 +- src/main/kotlin/racing/RagingCarMain.kt | 7 +++- src/main/kotlin/racing/domain/RacingGame.kt | 8 +++- src/main/kotlin/racing/view/InputView.kt | 4 +- src/main/kotlin/racing/view/ResultView.kt | 32 ++++----------- src/test/kotlin/racing/CarTest.kt | 45 --------------------- src/test/kotlin/racing/RacingCarTest.kt | 10 ++--- 7 files changed, 26 insertions(+), 83 deletions(-) delete mode 100644 src/test/kotlin/racing/CarTest.kt diff --git a/README.md b/README.md index f666a47d05..c0dd326905 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,7 @@ - [x] 자동차 이름은 5자를 초과할 수 없다. - [x] 자동차 이름은 쉼표(,)를 기준으로 구분한다. - [x] 0에서 9 사이에서 무작위 값을 구한다. -- [ ] 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. -- [ ] 자동차 이름은 쉼표(,)를 기준으로 구분한다. +- [x] 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. - [ ] 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. - [x] 핵심 비지니스 로직을 가지는 객체를 domain패키지, UI관련한 객체를 view패키지에 구현 - [ ] MVC패턴 기반으로 리팩토링, view 패키지의 객체가 domain 패키지에 의존할 수 있음, domain패키지의 객체는 view 패키지에 의존하지 않도록 구현 \ No newline at end of file diff --git a/src/main/kotlin/racing/RagingCarMain.kt b/src/main/kotlin/racing/RagingCarMain.kt index 3918759831..753326f749 100644 --- a/src/main/kotlin/racing/RagingCarMain.kt +++ b/src/main/kotlin/racing/RagingCarMain.kt @@ -1,6 +1,7 @@ package racing import racing.domain.Car +import racing.domain.RacingGame import racing.view.InputView import racing.view.ResultView @@ -11,5 +12,9 @@ fun main() { val cars = carNames.map { Car(it) } - ResultView.showResult(cars, actionCount) + repeat(actionCount) { + RacingGame.raceStart(cars) + ResultView.showSkidMarks(cars) + } + ResultView.showWinner(cars) } diff --git a/src/main/kotlin/racing/domain/RacingGame.kt b/src/main/kotlin/racing/domain/RacingGame.kt index 95735ed8c5..9bdb44944f 100644 --- a/src/main/kotlin/racing/domain/RacingGame.kt +++ b/src/main/kotlin/racing/domain/RacingGame.kt @@ -1,10 +1,14 @@ package racing.domain +import racing.CarRandomGenerator + object RacingGame { const val MAX_BOUND = 10 - fun gameStart(cars: List) { - + fun raceStart(cars: List) { + cars.forEach { + it.moveCar(CarRandomGenerator.createRandom(MAX_BOUND)) + } } } diff --git a/src/main/kotlin/racing/view/InputView.kt b/src/main/kotlin/racing/view/InputView.kt index 10b85bf9fb..3781676745 100644 --- a/src/main/kotlin/racing/view/InputView.kt +++ b/src/main/kotlin/racing/view/InputView.kt @@ -8,7 +8,6 @@ object InputView { private const val MINIMUM_INPUT = 1 - private const val INPUT_ACTION_PREFIX = "시도할 횟수는 " fun doInput(): Pair, Int> { @@ -20,7 +19,7 @@ object InputView { if (actionCount < MINIMUM_INPUT) { throw IllegalArgumentException("$INPUT_ACTION_PREFIX ${MINIMUM_INPUT}대 이상이어야 함") } - return Pair(carNames, actionCount) + return carNames to actionCount } private fun getInputCars(): List { @@ -34,7 +33,6 @@ object InputView { } - private fun getInputNumber(): Int { return runCatching { (readlnOrNull()?.toInt() ?: DEFAULT_INPUT) diff --git a/src/main/kotlin/racing/view/ResultView.kt b/src/main/kotlin/racing/view/ResultView.kt index 87b8720dab..e090cefb51 100644 --- a/src/main/kotlin/racing/view/ResultView.kt +++ b/src/main/kotlin/racing/view/ResultView.kt @@ -1,7 +1,6 @@ package racing.view import racing.domain.Car -import racing.CarRandomGenerator object ResultView { private const val NEXT_LINE = "\n" @@ -9,35 +8,20 @@ object ResultView { private const val SEPERATOR = ", " private const val MAX_RANGE = 10 - fun showResult(cars: List, actionCount: Int) { - println("실행 결과") - repeat(actionCount) { - gameStart(cars) - print(NEXT_LINE) - } - print("${showWinner(cars)}가 최종 우승했습니다.") - } - - private fun showWinner(cars: List): String { + fun showWinner(cars: List): String { val firstGradePosition = cars.maxOf(Car::position) return cars.filter { it.position == firstGradePosition }.joinToString(SEPERATOR, transform = Car::name) } - private fun gameStart(cars: List) { - cars.forEach { - car -> - car.moveCar(CarRandomGenerator.createRandom(MAX_RANGE)) - showSkidMarks(car) - } - } - - private fun showSkidMarks(car: Car) { - val progressString = StringBuffer() - repeat(car.position) { - progressString.append(PROGRESS_STRING) + fun showSkidMarks(cars: List) { + cars.forEach { car -> + val progressString = StringBuffer() + repeat(car.position) { + progressString.append(PROGRESS_STRING) + } + println("${car.name} : $progressString") } - println("${car.name} : $progressString") } } diff --git a/src/test/kotlin/racing/CarTest.kt b/src/test/kotlin/racing/CarTest.kt deleted file mode 100644 index 4369b3071f..0000000000 --- a/src/test/kotlin/racing/CarTest.kt +++ /dev/null @@ -1,45 +0,0 @@ -package racing - -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.AnnotationSpec -import io.kotest.matchers.ints.shouldBeInRange -import io.kotest.matchers.shouldBe -import racing.domain.Car -import racing.view.ResultView - -class CarTest : AnnotationSpec() { - - @Test - fun `자동차 이름은 5자를 넘을 수 없음`() { - shouldThrow { - Car("minhyukseul") - } - } - - @Test - fun `랜덤한 숫자를 생성하여 범위내에 들어오는지 확인`() { - CarRandomGenerator.createRandom(10) shouldBeInRange 0..9 - } - - @Test - fun `자동차가 움직일 경우 위치가 0이거나 1인지 확인`() { - val car = Car("pobi") - car.moveCar(4) shouldBe 1 - car.moveCar(3) shouldBe 1 - } - - @Test - fun `자동차가 랜덤 값 5회 반복으로 범위 안에 들어오는지 확인`() { - repeat(5) { - val data = CarRandomGenerator.createRandom(10) - println(data) - data shouldBeInRange 0..9 - } - } - - @Test - fun `자동차 여러대를 생성해서 실제 우승자를 체크해봄`() { - val cars = mutableListOf(Car("pobi"), Car("crong"), Car("honux")) - ResultView.showResult(cars, 5) - } -} diff --git a/src/test/kotlin/racing/RacingCarTest.kt b/src/test/kotlin/racing/RacingCarTest.kt index 7a9841c983..d1f97eda76 100644 --- a/src/test/kotlin/racing/RacingCarTest.kt +++ b/src/test/kotlin/racing/RacingCarTest.kt @@ -7,8 +7,7 @@ import io.kotest.matchers.ints.shouldBeInRange import io.kotest.matchers.shouldBe import racing.domain.Car import racing.domain.RacingGame -import racing.view.InputView - +import racing.view.ResultView class RacingCarTest : AnnotationSpec() { @@ -64,8 +63,7 @@ class RacingCarTest : AnnotationSpec() { fun `전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다`() { val carNames = "pobi,crong,honux" val cars = InputParser.parse(carNames).map { Car(it) } - - RacingGame.gameStart(cars) - + RacingGame.raceStart(cars) + ResultView.showSkidMarks(cars) } -} \ No newline at end of file +} From 01572ba1f59ed90c4cab16914185e3763e84c715 Mon Sep 17 00:00:00 2001 From: minhyukseul Date: Wed, 14 Jun 2023 12:40:37 +0900 Subject: [PATCH 15/15] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EA=B2=BD=EC=A3=BC=20=EA=B2=8C=EC=9E=84=EC=9D=84=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C=ED=95=9C=20=ED=9B=84=20=EB=88=84=EA=B0=80=20=EC=9A=B0?= =?UTF-8?q?=EC=8A=B9=ED=96=88=EB=8A=94=EC=A7=80=20=EB=8B=A8=EC=9C=84?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20?= =?UTF-8?q?main=20controller=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- src/main/kotlin/racing/RagingCarMain.kt | 1 + src/main/kotlin/racing/view/ResultView.kt | 12 ++++++++---- src/test/kotlin/racing/RacingCarTest.kt | 10 ++++++++++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c0dd326905..cc09b8600f 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,6 @@ - [x] 자동차 이름은 쉼표(,)를 기준으로 구분한다. - [x] 0에서 9 사이에서 무작위 값을 구한다. - [x] 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. -- [ ] 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. +- [x] 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. - [x] 핵심 비지니스 로직을 가지는 객체를 domain패키지, UI관련한 객체를 view패키지에 구현 -- [ ] MVC패턴 기반으로 리팩토링, view 패키지의 객체가 domain 패키지에 의존할 수 있음, domain패키지의 객체는 view 패키지에 의존하지 않도록 구현 \ No newline at end of file +- [x] MVC패턴 기반으로 리팩토링, view 패키지의 객체가 domain 패키지에 의존할 수 있음, domain패키지의 객체는 view 패키지에 의존하지 않도록 구현 \ No newline at end of file diff --git a/src/main/kotlin/racing/RagingCarMain.kt b/src/main/kotlin/racing/RagingCarMain.kt index 753326f749..18c02f3987 100644 --- a/src/main/kotlin/racing/RagingCarMain.kt +++ b/src/main/kotlin/racing/RagingCarMain.kt @@ -15,6 +15,7 @@ fun main() { repeat(actionCount) { RacingGame.raceStart(cars) ResultView.showSkidMarks(cars) + ResultView.printEnter() } ResultView.showWinner(cars) } diff --git a/src/main/kotlin/racing/view/ResultView.kt b/src/main/kotlin/racing/view/ResultView.kt index e090cefb51..779aeb9124 100644 --- a/src/main/kotlin/racing/view/ResultView.kt +++ b/src/main/kotlin/racing/view/ResultView.kt @@ -3,16 +3,16 @@ package racing.view import racing.domain.Car object ResultView { - private const val NEXT_LINE = "\n" private const val PROGRESS_STRING = "-" private const val SEPERATOR = ", " - private const val MAX_RANGE = 10 - fun showWinner(cars: List): String { + + fun showWinner(cars: List) { val firstGradePosition = cars.maxOf(Car::position) - return cars.filter { + val winners = cars.filter { it.position == firstGradePosition }.joinToString(SEPERATOR, transform = Car::name) + print("${winners}가 최종 우승했습니다.") } fun showSkidMarks(cars: List) { @@ -24,4 +24,8 @@ object ResultView { println("${car.name} : $progressString") } } + + fun printEnter() { + println() + } } diff --git a/src/test/kotlin/racing/RacingCarTest.kt b/src/test/kotlin/racing/RacingCarTest.kt index d1f97eda76..bc5c68cafd 100644 --- a/src/test/kotlin/racing/RacingCarTest.kt +++ b/src/test/kotlin/racing/RacingCarTest.kt @@ -66,4 +66,14 @@ class RacingCarTest : AnnotationSpec() { RacingGame.raceStart(cars) ResultView.showSkidMarks(cars) } + + @Test + fun ` 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다`() { + val carNames = "pobi,crong,honux" + val cars = InputParser.parse(carNames).map { Car(it) } + RacingGame.raceStart(cars) + ResultView.showWinner(cars) + } + + }