diff --git a/src/main/kotlin/src/racingcar/Car.kt b/src/main/kotlin/src/racingcar/Car.kt deleted file mode 100644 index 056936ac86..0000000000 --- a/src/main/kotlin/src/racingcar/Car.kt +++ /dev/null @@ -1,14 +0,0 @@ -package src.racingcar - -class Car(private var moveCount: Int = 0) { - - fun move(): Int { - if (CAR_MOVE_CONDITION_NUMBER <= getCarMoveRandomValue()) moveCount++ - - return moveCount - } - - companion object { - private const val CAR_MOVE_CONDITION_NUMBER = 4 - } -} diff --git a/src/main/kotlin/src/racingcar/CarService.kt b/src/main/kotlin/src/racingcar/CarService.kt deleted file mode 100644 index bcf0bb0ffa..0000000000 --- a/src/main/kotlin/src/racingcar/CarService.kt +++ /dev/null @@ -1,17 +0,0 @@ -package src.racingcar - -class CarService { - - fun execute(tryCount: Int, carCount: Int) { - (1..tryCount).forEach { _ -> - moveCars(carCount) - } - } - - private fun moveCars(carCount: Int) { - (1..carCount).forEach { _ -> - ResultView.printRacingCarGameResult(Car().move()) - } - println() - } -} \ No newline at end of file diff --git a/src/main/kotlin/src/racingcar/InputView.kt b/src/main/kotlin/src/racingcar/InputView.kt deleted file mode 100644 index 928dc64893..0000000000 --- a/src/main/kotlin/src/racingcar/InputView.kt +++ /dev/null @@ -1,17 +0,0 @@ -package src.racingcar - -object InputView { - fun executeInputScreen(): RacingCarGameInput { - println("자동차 대수는 몇 대인가요?") - val carNumber: String = readln() - println("시도할 횟수는 몇 회인가요?") - val tryCount = readln().toInt() - - return RacingCarGameInput(carNumber.toInt(), tryCount) - } -} - -data class RacingCarGameInput( - val carNumber: Int, - val tryCount: Int -) diff --git a/src/main/kotlin/src/racingcar/RacingCarGame.kt b/src/main/kotlin/src/racingcar/RacingCarGame.kt index 06441fd0a9..46cf45fe10 100644 --- a/src/main/kotlin/src/racingcar/RacingCarGame.kt +++ b/src/main/kotlin/src/racingcar/RacingCarGame.kt @@ -1,9 +1,12 @@ package src.racingcar +import src.racingcar.view.InputView +import src.racingcar.view.ResultView + object RacingCarGame { fun startGame() { val inputValue = InputView.executeInputScreen() - CarService().execute(inputValue.tryCount, inputValue.carNumber) + ResultView.printRacingCarGameResult(inputValue.tryCount, inputValue.carNames) } } diff --git a/src/main/kotlin/src/racingcar/RamdomUtil.kt b/src/main/kotlin/src/racingcar/RamdomUtil.kt deleted file mode 100644 index 015f93f905..0000000000 --- a/src/main/kotlin/src/racingcar/RamdomUtil.kt +++ /dev/null @@ -1,10 +0,0 @@ -package src.racingcar - -import kotlin.random.Random -import kotlin.random.nextInt - -private val RANDOM_NUMBER_RANGE = 0..9 - -fun getCarMoveRandomValue(): Int { - return Random.nextInt(RANDOM_NUMBER_RANGE) -} diff --git a/src/main/kotlin/src/racingcar/ResultView.kt b/src/main/kotlin/src/racingcar/ResultView.kt deleted file mode 100644 index c151fca945..0000000000 --- a/src/main/kotlin/src/racingcar/ResultView.kt +++ /dev/null @@ -1,7 +0,0 @@ -package src.racingcar - -object ResultView { - fun printRacingCarGameResult(moveCount: Int) { - println("-".repeat(moveCount)) - } -} diff --git a/src/main/kotlin/src/racingcar/description.md b/src/main/kotlin/src/racingcar/description.md new file mode 100644 index 0000000000..cf0f2d709b --- /dev/null +++ b/src/main/kotlin/src/racingcar/description.md @@ -0,0 +1,40 @@ +경주할 자동차 이름을 추출 하는 기능. + +경주할 자동차 대수를 추출 하는 기능. + +경주 자동차 이름 별로 "-" 가 나오도록 구현. + +어떤 자동차가 최종 우승 하였는지 알아내는 기능 + +모든 로직에 단위 테스트를 구현한다. + +단, UI(System.out, System.in) 로직은 제외 +핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다. + +UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다. + +indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다. + +예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. + +힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다. + +함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다. + +함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다. + +기능을 구현하기 전에 README.md 파일에 구현할 기능 목록을 정리해 추가한다. + +git의 commit 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가한다. + +사용자가 입력한 이름의 숫자 만큼 자동차 대수를 생성한다. + +자동차는 자동차 이름과 위치 정보를 가지는 Car 객체를 추가해 구현한다. + +각 자동차에 이름을 부여할 수 있다. 자동차 이름은 5자를 초과할 수 없다. + +전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. + +자동차 이름은 쉼표(,)를 기준으로 구분한다. + +자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. \ No newline at end of file diff --git a/src/main/kotlin/src/racingcar/domain/Car.kt b/src/main/kotlin/src/racingcar/domain/Car.kt new file mode 100644 index 0000000000..e6e8f3ff33 --- /dev/null +++ b/src/main/kotlin/src/racingcar/domain/Car.kt @@ -0,0 +1,22 @@ +package src.racingcar.domain + +open class Car( + val name: String, + moveCount: Int = 0 +) { + + var moveCount: Int = moveCount + protected set + + open fun move(carMoveNumber: Int = (MOVE_START_POINT..MOVE_END_POINT).random()): Int { + if (CAR_MOVE_CONDITION_NUMBER <= carMoveNumber) moveCount++ + + return moveCount + } + + companion object { + private const val CAR_MOVE_CONDITION_NUMBER = 4 + private const val MOVE_START_POINT = 0 + private const val MOVE_END_POINT = 9 + } +} diff --git a/src/main/kotlin/src/racingcar/domain/Race.kt b/src/main/kotlin/src/racingcar/domain/Race.kt new file mode 100644 index 0000000000..54560c32df --- /dev/null +++ b/src/main/kotlin/src/racingcar/domain/Race.kt @@ -0,0 +1,21 @@ +package src.racingcar.domain + +class Race(cars: List) { + var cars: List = cars + private set + + fun start(): List { + cars.forEach { it.move() } + + return cars + } + + companion object { + fun create(carNames: List): Race { + val cars = buildList { + carNames.forEach { this.add(Car(it)) } + } + return Race(cars) + } + } +} diff --git a/src/main/kotlin/src/racingcar/domain/Winner.kt b/src/main/kotlin/src/racingcar/domain/Winner.kt new file mode 100644 index 0000000000..2f6ee64c5c --- /dev/null +++ b/src/main/kotlin/src/racingcar/domain/Winner.kt @@ -0,0 +1,10 @@ +package src.racingcar.domain + +class Winner( + private val racingCars: List +) { + fun findWinners(): List { + val max = racingCars.maxOf { it.moveCount } + return racingCars.filter { car -> car.moveCount >= max } + } +} diff --git a/src/main/kotlin/src/racingcar/utils/Parser.kt b/src/main/kotlin/src/racingcar/utils/Parser.kt new file mode 100644 index 0000000000..4d38d884b9 --- /dev/null +++ b/src/main/kotlin/src/racingcar/utils/Parser.kt @@ -0,0 +1,5 @@ +package src.racingcar.utils + +fun parseComma(input: String): List { + return input.split(",") +} diff --git a/src/main/kotlin/src/racingcar/view/InputView.kt b/src/main/kotlin/src/racingcar/view/InputView.kt new file mode 100644 index 0000000000..4ece455455 --- /dev/null +++ b/src/main/kotlin/src/racingcar/view/InputView.kt @@ -0,0 +1,17 @@ +package src.racingcar.view + +object InputView { + fun executeInputScreen(): RacingCarGameInput { + println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).") + val carNames: String = readln() + println("시도할 횟수는 몇 회인가요?") + val tryCount = readln().toInt() + + return RacingCarGameInput(carNames, tryCount) + } +} + +data class RacingCarGameInput( + val carNames: String, + val tryCount: Int +) diff --git a/src/main/kotlin/src/racingcar/view/ResultView.kt b/src/main/kotlin/src/racingcar/view/ResultView.kt new file mode 100644 index 0000000000..2f49f87ad1 --- /dev/null +++ b/src/main/kotlin/src/racingcar/view/ResultView.kt @@ -0,0 +1,32 @@ +package src.racingcar.view + +import src.racingcar.domain.Car +import src.racingcar.domain.Race +import src.racingcar.domain.Winner +import src.racingcar.utils.parseComma + +object ResultView { + fun printRacingCarGameResult(tryCount: Int, carNames: String) { + val race = Race.create(parseComma(carNames)) + repeat(tryCount) { + val raceCars = race.start() + printRacing(raceCars) + } + + printWinner(Winner(race.cars).findWinners()) + } + + private fun printRacing(raceCars: List) { + for (raceCar in raceCars) { + print(raceCar.name) + print(" : ") + println("-".repeat(raceCar.moveCount)) + } + println() + } + + private fun printWinner(findWinners: List) { + print(findWinners.joinToString { car -> car.name }) + print("가 최종 우승 했습니다.") + } +} diff --git a/src/test/kotlin/src/racingcar/CarTest.kt b/src/test/kotlin/src/racingcar/CarTest.kt index 0c09bd51e5..534662ec36 100644 --- a/src/test/kotlin/src/racingcar/CarTest.kt +++ b/src/test/kotlin/src/racingcar/CarTest.kt @@ -1,14 +1,26 @@ package src.racingcar -import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test +import src.racingcar.domain.Car class CarTest { @Test - fun `자동차는 한번에 두번 이상 움직일 수 없다`() { - val moveCount = Car().move() + fun `랜덤 값이 4 이상이면 차가 움직인다`() { + val moveCount = Car("testName").move(4) + assertThat(moveCount).isEqualTo(1) + } - Assertions.assertThat(moveCount).isLessThan(2) + @Test + fun `랜덤 값이 4 미만이면 차가 움직이지 않는다`() { + val moveCount = Car("testName").move(3) + assertThat(moveCount).isEqualTo(0) + } + + @Test + fun `차의 이름을 지정할 수 있다`() { + val car = Car("testName") + assertThat(car.name).isEqualTo("testName") } } diff --git a/src/test/kotlin/src/racingcar/RaceTest.kt b/src/test/kotlin/src/racingcar/RaceTest.kt new file mode 100644 index 0000000000..361c20d667 --- /dev/null +++ b/src/test/kotlin/src/racingcar/RaceTest.kt @@ -0,0 +1,25 @@ +package src.racingcar + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import src.racingcar.domain.Car +import src.racingcar.domain.Race + +class RaceTest { + + @Test + fun `여러대의 차들은 움직일 수 있다`() { + val car1 = StubCar() + val cars = listOf(car1) + + val race = Race(cars).start() + + assertThat(race[0].moveCount).isEqualTo(1) + } + + class StubCar : Car("test") { + override fun move(carMoveNumber: Int): Int { + return super.moveCount++ + } + } +} diff --git a/src/test/kotlin/src/racingcar/WinnerTest.kt b/src/test/kotlin/src/racingcar/WinnerTest.kt new file mode 100644 index 0000000000..1a283236fe --- /dev/null +++ b/src/test/kotlin/src/racingcar/WinnerTest.kt @@ -0,0 +1,25 @@ +package src.racingcar + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import src.racingcar.domain.Car +import src.racingcar.domain.Winner + +class WinnerTest { + + @Test + fun `레이싱 우승자를 찾을 수 있다`() { + val car1 = Car("test1") + val car2 = Car("test2") + val car3 = Car("test3") + val cars = listOf(car1, car2, car3) + car1.move(0) + car2.move(4) + car3.move(4) + + val winners = Winner(cars).findWinners() + + assertThat(winners[0].name).isEqualTo("test2") + assertThat(winners[1].name).isEqualTo("test3") + } +}