diff --git a/README.md b/README.md index 0d49f3cfc8..aed9e98e64 100644 --- a/README.md +++ b/README.md @@ -1 +1,32 @@ -# kotlin-racingcar \ No newline at end of file +# kotlin-racingcar +기능 요구 사항 +- 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. +- 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. +- 자동차 이름은 쉼표를 기준으로 구분하며 이름은 5자 이하만 가능하다. +- 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. +- 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우이다. +- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우슨자는 한 명 이상일 수 있다. +- 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다. +- 사용자가 잘못된 값을 입력할 경우 illegalArgumentException을 발생시키고 Error로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다. + - Exceptiondl 이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리한다. + +프로그래밍 요구 사항 1 +- Kotlin 1.9.0에서 실행 가능 +- Java 코드가 아닌 Kotlin 코드로만 구현 +- 프로그램의 실행의 시작점은 Application의 main() +- build.gradle.kts 파일은 변경할 수 없으며, 제공된 라이브러리 이외의 외부 라이브러리는 사용하지 않는다. +- 프로그램 종료 시 System.exit() 또는 exitProcess()를 호출하지 않는다. +- 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 등의 이름을 바꾸거나 이동하지 않는다. + +프로그래밍 요구 사항 2 +- 코틀린 코드 컨벤션을 지키면서 프로그래밍 한다. + - 기본적으로 Kotlin Coding conventions를 원칙으로 한다. +- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다. + - 예를 들어 while 문 안에 if문이 있으면 들여쓰기는 2 이다. +- JUnit5와 AssertJ를 이용하여 기능 목록 정상 작동 확인 + +프로그래밍 요구 사항 3 +- 함수의 길이가 15라인을 넘어가지 않도록 구현한다. + - 메소드가 가능한 한가지 일만 처리하도록 구현한다. +- 가능한 else를 사용하지 않는다. +- 도메인 로직에 단위 테스트를 구현해야 한다. UI 로직은 제외한다. \ No newline at end of file diff --git a/src/main/kotlin/RacingCar.kt b/src/main/kotlin/RacingCar.kt new file mode 100644 index 0000000000..7bf7076f4c --- /dev/null +++ b/src/main/kotlin/RacingCar.kt @@ -0,0 +1,68 @@ +package com.racingCar.mainKt + +fun inputCarNames(): List{ + val cars = readlnOrNull()?.split(",")?: listOf() + if (cars.find { it.length > 5 } == null && + cars.isNotEmpty()) { + return cars + } + throw IllegalArgumentException("[ERROR] Invalid argument.") +} + +fun initRaces(): MutableMap { + var cars : List + while(true){ + try { + cars = inputCarNames() + break + } catch (e: IllegalArgumentException) { + println(e.message) + } + } + return cars.associateWith { 0 }.toMutableMap() +} + +fun getRandValue(): Int { + val range = kotlin.random.Random.nextInt(0, 10) + return when(range) { + in 4..9 -> 1 + else -> 0 + } +} + +fun runRaces(races: MutableMap, count: Int) { + for (i in 0 until count) { + for (race in races) { + race.setValue(race.value + getRandValue()) + printRace(race) + } + println() + } +} + +fun printRace(race: MutableMap.MutableEntry) { + print(race.key + " : ") + for (j in 0 until race.value) { + print("-") + } + println() +} + +fun getWinners(races: MutableMap): String { + val maxValue = races.values.maxOrNull() + val maxKeys = races.filter { it.value == maxValue }.keys + return maxKeys.joinToString(", ") +} + +fun main() { + println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)") + val races = initRaces() + + println("시도할 회수는 몇회인가요?") + val count = readlnOrNull()?.toInt()?: 0 + + println("실행 결과") + runRaces(races, count) + + println("최종 우승자 : " + getWinners(races)) +} \ No newline at end of file diff --git a/src/test/kotlin/RacingCarTest.kt b/src/test/kotlin/RacingCarTest.kt new file mode 100644 index 0000000000..4bbb4d3d67 --- /dev/null +++ b/src/test/kotlin/RacingCarTest.kt @@ -0,0 +1,69 @@ +import com.racingCar.mainKt.* +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.io.ByteArrayInputStream + +class RacingCarTest { + @Test + fun `Should inputCarNames return list of car names`() { + val input = "car1,car2,car3\n" + System.setIn(ByteArrayInputStream(input.toByteArray())) + + val result = inputCarNames() + assertEquals(listOf("car1", "car2", "car3"), result) + } + + @Test + fun `Should inputCarNames throw IllegalArgumentException`() { + val input = "car1,car2222,car3\n" + System.setIn(ByteArrayInputStream(input.toByteArray())) + + assertThrows { + inputCarNames() + } + } + + @Test + fun `Should inputCarNames throw exception for empty input`() { + val input = "" + System.setIn(ByteArrayInputStream(input.toByteArray())) + + assertThrows { + inputCarNames() + } + } + + @Test + fun `Should initRaces initialize races with car names`() { + // 입력 스트림 설정 + val input = "car1,car2\n" + System.setIn(ByteArrayInputStream(input.toByteArray())) + + val result = initRaces() + assertEquals(mapOf("car1" to 0, "car2" to 0), result) + } + + @Test + fun `Should runRaces update race scores`() { + val races = mutableMapOf("car1" to 0, "car2" to 0) + runRaces(races, 1) + + assertTrue(races["car1"]!! >= 0) + assertTrue(races["car2"]!! >= 0) + } + + @Test + fun `Should getWinners return multiple winners if tied`() { + val races = mutableMapOf("car1" to 5, "car2" to 5) + val winners = getWinners(races) + assertEquals("car1, car2", winners) + } + + @Test + fun `Should get random values between 0~1`() { + val value = getRandValue() + assert(value in 0..1) + } +} \ No newline at end of file