Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eideallab #1566

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,32 @@
# kotlin-racingcar
# 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 로직은 제외한다.
68 changes: 68 additions & 0 deletions src/main/kotlin/RacingCar.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.racingCar.mainKt

fun inputCarNames(): List<String>{
val cars = readlnOrNull()?.split(",")?: listOf()
if (cars.find { it.length > 5 } == null &&
cars.isNotEmpty()) {
return cars
}
throw IllegalArgumentException("[ERROR] Invalid argument.")
}

fun initRaces(): MutableMap<String, Int> {
var cars : List<String>
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<String, Int>, 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<String, Int>) {
print(race.key + " : ")
for (j in 0 until race.value) {
print("-")
}
println()
}

fun getWinners(races: MutableMap<String, Int>): 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))
}
69 changes: 69 additions & 0 deletions src/test/kotlin/RacingCarTest.kt
Original file line number Diff line number Diff line change
@@ -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<IllegalArgumentException> {
inputCarNames()
}
}

@Test
fun `Should inputCarNames throw exception for empty input`() {
val input = ""
System.setIn(ByteArrayInputStream(input.toByteArray()))

assertThrows<IllegalArgumentException> {
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)
}
}