diff --git a/docs/README.md b/docs/README.md index e69de29bb..c7dca30a3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,14 @@ + # 기능 목록 + ## 경기 시작 전 + - 쉼표(,)가 포함된 문자열에서 자동차 이름을 추출 + - 이동 횟수를 입력 + ## 경기 중 + - 무작위 값(0~9)을 추출하여 4와 비교 + - 자동차의 현 위치 출력 + ## 경기 후 + - 우승자 출력 + - 우승자가 2명 이상일 경우 (,) 구분 출력 + ## Test코드 + - 자동차 이름 이상값 test (ApplicationTest) + - 시도 횟수 이상값 test + - 공동 우승 test \ No newline at end of file diff --git a/src/main/kotlin/racingcar/Application.kt b/src/main/kotlin/racingcar/Application.kt index 0d8f3a79d..23d76ed22 100644 --- a/src/main/kotlin/racingcar/Application.kt +++ b/src/main/kotlin/racingcar/Application.kt @@ -1,5 +1,8 @@ package racingcar +import racingcar.controller.RacingCarController + fun main() { - // TODO: 프로그램 구현 + val racingCarController = RacingCarController() + racingCarController.play() } diff --git a/src/main/kotlin/racingcar/controller/RacingCarController.kt b/src/main/kotlin/racingcar/controller/RacingCarController.kt new file mode 100644 index 000000000..8aec1c490 --- /dev/null +++ b/src/main/kotlin/racingcar/controller/RacingCarController.kt @@ -0,0 +1,66 @@ +package racingcar.controller + +import camp.nextstep.edu.missionutils.Console +import camp.nextstep.edu.missionutils.Randoms +import racingcar.model.RacingCar +import racingcar.view.InputView +import racingcar.view.OutputView + + +class RacingCarController { + private val inputView = InputView() + private val outputView = OutputView() + + fun play() { + inputView.submitCarNames() + val input = Console.readLine() + val carList = makeCarList(input) + outputView.startGameMessage() + playWithCarList(carList, inputView.askTimes(), outputView) + val winnerList = findWinner(carList) + outputView.noticeWinner(winnerList) + } + + private fun makeCarList(input: String?): MutableList { + val cars = input?.split(',') + if (cars != null) { + regexCheck(cars) + } else { + throw IllegalArgumentException() + } + val carList = mutableListOf() + for (car in cars) { + carList.add(RacingCar(car, 0)) + } + return carList + } + + private fun regexCheck(cars: List) { + for (car in cars) { + if (!car.matches(Regex("\\w{1,5}"))) { + throw IllegalArgumentException() + } + } + } + + private fun moveForwardOrNot(carList: MutableList) { + for (car in carList) { + val randomNumber = Randoms.pickNumberInRange(0, 9) + if (randomNumber >= 4) { + car.moveForward() + } + } + } + + private fun playWithCarList(carList: MutableList, times: Int, outputView: OutputView) { + for (i in 0 until times) { + moveForwardOrNot(carList) + outputView.printCurrentPlace(carList) + } + } + + private fun findWinner(carList: MutableList): List { + val maxForward = carList.maxByOrNull { it.getForward() }?.getForward() + return carList.filter { it.getForward() == maxForward } + } +} \ No newline at end of file diff --git a/src/main/kotlin/racingcar/model/RacingCar.kt b/src/main/kotlin/racingcar/model/RacingCar.kt new file mode 100644 index 000000000..977131ec0 --- /dev/null +++ b/src/main/kotlin/racingcar/model/RacingCar.kt @@ -0,0 +1,16 @@ +package racingcar.model + +class RacingCar(private val carName: String, private var forward: Int = 0) { + fun moveForward() { + forward++ + } + + fun getCarName(): String { + return carName + } + + fun getForward(): Int { + return forward + } + +} \ No newline at end of file diff --git a/src/main/kotlin/racingcar/view/InputView.kt b/src/main/kotlin/racingcar/view/InputView.kt new file mode 100644 index 000000000..394487d01 --- /dev/null +++ b/src/main/kotlin/racingcar/view/InputView.kt @@ -0,0 +1,20 @@ +package racingcar.view + +import camp.nextstep.edu.missionutils.Console + +class InputView { + fun submitCarNames() = println(SUBMIT_CAR_NAMES_MESSAGE) + fun askTimes(): Int { + println(ASK_TIMES_MESSAGE) + val timesInput = Console.readLine().toInt() + if (timesInput < 1) { + throw IllegalArgumentException() + } + return timesInput + } + + companion object { + const val SUBMIT_CAR_NAMES_MESSAGE = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" + const val ASK_TIMES_MESSAGE = "시도할 횟수는 몇 회인가요?" + } +} \ No newline at end of file diff --git a/src/main/kotlin/racingcar/view/OutputView.kt b/src/main/kotlin/racingcar/view/OutputView.kt new file mode 100644 index 000000000..68586fe75 --- /dev/null +++ b/src/main/kotlin/racingcar/view/OutputView.kt @@ -0,0 +1,24 @@ +package racingcar.view + +import racingcar.model.RacingCar + +class OutputView { + fun noticeWinner(winnerList: List) { + println(WINNER_MESSAGE + winnerList.joinToString(", ") { it.getCarName() }) + } + + fun printCurrentPlace(carList: MutableList) { + for (car in carList) { + val currentPlace = "-".repeat(car.getForward()) + println(car.getCarName() + " : " + currentPlace) + } + println("\n") + } + + fun startGameMessage() = println(START_GAME_MESSAGE) + + companion object { + const val WINNER_MESSAGE = "최종 우승자 : " + const val START_GAME_MESSAGE = "실행 결과" + } +} \ No newline at end of file diff --git a/src/test/kotlin/racingcar/RacingCarTest.kt b/src/test/kotlin/racingcar/RacingCarTest.kt new file mode 100644 index 000000000..939161ec1 --- /dev/null +++ b/src/test/kotlin/racingcar/RacingCarTest.kt @@ -0,0 +1,46 @@ +package racingcar + +import camp.nextstep.edu.missionutils.test.Assertions +import camp.nextstep.edu.missionutils.test.Assertions.assertRandomNumberInRangeTest +import camp.nextstep.edu.missionutils.test.NsTest +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + +class RacingCarTest : NsTest() { + @Test + fun `시도 횟수 이상값 test`() { + Assertions.assertSimpleTest { + assertThrows { runException("bon,jovi", "가") } + } + Assertions.assertSimpleTest { + assertThrows { runException("bon,jovi", "hello") } + } + Assertions.assertSimpleTest { + assertThrows { runException("bon,jovi", "-1") } + } + Assertions.assertSimpleTest { + assertThrows { runException("bon,jovi", "0") } + } + } + + @Test + fun `공동 우승`() { + assertRandomNumberInRangeTest( + { + run("bon,jovi", "3") + assertThat(output()).contains("최종 우승자 : bon, jovi") + }, + 5 + ) + } + + public override fun runMain() { + main() + } + + companion object { + private const val MOVING_FORWARD = 4 + private const val STOP = 3 + } +} \ No newline at end of file