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

[자동차 경주] 천지윤 미션 제출합니다. #100

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,27 @@
# kotlin-racingcar-precourse

## 구현할 기능 목록
- [x] 자동차 이름 분류
- [x] (예외) 5자이상인경우
- [x] (예외) 아무입력도 안했을 경우
- [x] (예외) 자동차 이름이 중복인 경우
- [x] 이름 양옆에 공백이 있을 경우 제거
- [x] 이동할 횟수
- [x] (예외) 정수가 아닌 경우

- [x] 랜덤 이동값
- [x] 자동차 개수만큼 이동한 횟수 배열 생성
- [x] 4이상일 경우 이동
- [x] 실행 결과 출력

- [x] 최종 우승자
- [x] 공동 우승자면 함께

- [x] depth 2이하

### 테스트
- [x] 자동차 이름에 아무 입력 안했을 경우
- [x] 자동차 이름이 중복인 경우
- [x] 횟수에 문자를 입력하였을 경우 에러
- [x] 횟수에 소수를 입력하였을 경우 에러
- [x] 공동 우승일 경우
89 changes: 88 additions & 1 deletion src/main/kotlin/racingcar/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,92 @@
package racingcar

import camp.nextstep.edu.missionutils.Randoms
import camp.nextstep.edu.missionutils.Console
import racingcar.Validation.Validation
import racingcar.View.InputView
import racingcar.View.OutputView


fun carsNameTrim(cars : List<String>): List<String> {
return cars.map { it.trim() }
}

fun isCanGo(): Boolean {
return Randoms.pickNumberInRange(0, 9) >= 4

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0과 9, 4 의 의미를 명확히 할 수 있도록 상수화를 하면 어떨까요 ?

Copy link
Author

@cheonjiyun cheonjiyun Oct 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하 좋네요! 앞으로 의미가 있는 숫자는 상수화를 해야겠습니다

}

fun gameOfOneCar(carsMoving: Array<Int>, index: Int) {
if (isCanGo()) {
carsMoving[index] += 1
}
}

fun gameOfTurn(cars: List<String>, carsMovingArray: Array<Int>, outputView: OutputView) {
for (i in 0 until cars.count()) {
gameOfOneCar(carsMovingArray, i)
outputView.gameResult(cars[i], carsMovingArray[i])
}
println()
}

fun game(cars: List<String>, carsMovingArray: Array<Int>, outputView: OutputView, count: Int) {
for (i in 0 until count) {
gameOfTurn(cars, carsMovingArray, outputView)
}
}

fun getWinnerIndex(carsMoving: Array<Int>): MutableList<Int> {
val winners = mutableListOf<Int>()
var maxNumber = 0

carsMoving.forEachIndexed { idx, it ->
if (it == maxNumber) {
winners.addLast(idx)
}
if (it > maxNumber) {
maxNumber = it
winners.clear()
winners.addLast(idx)
}
}
return winners
}

fun inputCars(inputView: InputView, validation: Validation): List<String> {
inputView.inputCars()
val inputCar = Console.readLine()
validation.checkInputCarIsNotEmpty(inputCar)

var cars: List<String> = inputCar.split(',')
validation.checkCarNameDuplication(cars)
cars = carsNameTrim(cars)
validation.checkCarNameLength(cars)

return cars
}

fun inputCount(inputView: InputView, validation: Validation): Int {
inputView.inputCount()
val inputCount = Console.readLine()
validation.checkCountIsNumber(inputCount)
val count = inputCount.toInt()

return count
}

fun main() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

보통 메인 함수가 가장 최상단에 위치하도록 하는 것 같습니다 :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇군요! 몰랐었는데 감사합니다!

// TODO: 프로그램 구현
val outputView = OutputView()
val inputView = InputView()
val validation = Validation()

val cars = inputCars(inputView, validation)
val count = inputCount(inputView, validation)

val carsMovingArray = Array(cars.count()) { 0 }

outputView.outputPrint()
game(cars, carsMovingArray, outputView, count)

val winners = getWinnerIndex(carsMovingArray).map { cars[it] }
outputView.winnerPrint(winners)
}
31 changes: 31 additions & 0 deletions src/main/kotlin/racingcar/Validation/Validation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package racingcar.Validation

import java.lang.NumberFormatException

class Validation {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 아래 케이스에 대해서도 고민을 해봤는데요 한번 생각해보셔도 좋을거 같습니다 !

게임 플레이를 한명만 입력되도 허용할 것인지?
이름에 특수문자를 허용하실 것인지?
,가 아닌 구분자가 들어왔을 때 : 3;4;5

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다. 오류는 아니라고 생각해서 하지 않았는데, 사용자가 실수하는 것도 고려해볼 수가 있겠네요!

fun checkCarNameLength(cars: List<String>) {
if (!(cars.all { it -> it.count() <= 5 })) {
throw IllegalArgumentException("자동차 이름은 5자 이하만 가능합니다")
}
Comment on lines +7 to +9

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

람다식에서 사용되는 기본 변수 네임을 it 그대로 사용하실 거라면
it ->은 생략해도 될 것 같네요 !

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 생략해도 되는지 몰랐네요. 알려주셔서 감사합니다!

}

fun checkInputCarIsNotEmpty(inputCar: String) {
if (inputCar == "") {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isBlank()라는 메서드도 있어요!

inputCar.isBlank()

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와 감사합니다. 코틀린 문법 하나 또 배웠습니다!!

throw IllegalArgumentException("자동차 이름을 입력하지 않았습니다")
}
}

fun checkCarNameDuplication(cars: List<String>) {
if (cars.toSet().size != cars.size) {
throw IllegalArgumentException("자동차 이름이 중복입니다")
}

}
fun checkCountIsNumber(inputCount: String) {
try {
inputCount.toInt()
} catch (e: NumberFormatException) {
throw IllegalArgumentException("정수만 입력가능합니다")
}
}
}
11 changes: 11 additions & 0 deletions src/main/kotlin/racingcar/View/InputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package racingcar.View

class InputView {
fun inputCars() {
println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)")
}

fun inputCount() {
println("시도할 횟수는 몇 회인가요?")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"시도할 횟수는 몇 회인가요?" 와 같이 변할 수 있는 값을 변수로 빼서 관리하면 유지보수가 수월해질꺼 같습니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 문자열로 한 번 더 빼는 거군요. 감사합니다

}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/racingcar/View/OutputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package racingcar.View

class OutputView {
fun outputPrint() {
println("실행 결과")
}

fun gameResult(carName: String, movingCount: Int) {
println("$carName : ${"-".repeat(movingCount)}")
}
Comment on lines +8 to +10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

함수의 이름이 "게임의 결과"를 출력한다는 의미일까요 ? 그렇다면 printGameResult 는 어떨까요 !


fun winnerPrint(winners: List<String>) {
println("최종 우승자 : ${winners.joinToString(", ")}")

}
Comment on lines +12 to +15

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코틀린 함수 네이밍 컨벤션에 따르면 동사 + 명사 구조로 네이밍을 하도록 가이드하고 있습니다 !
println처럼 printWinner로 네이밍 하는 것이 맞을 것 같습니다 🤔

}
20 changes: 20 additions & 0 deletions src/test/kotlin/racingcar/ApplicationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,33 @@ class ApplicationTest : NsTest() {
},
MOVING_FORWARD, STOP
)
assertRandomNumberInRangeTest(
{
run("pobi,woni,jiji", "1")
assertThat(output()).contains("pobi : -", "woni : -", "jiji : ", "최종 우승자 : pobi, woni")
},
MOVING_FORWARD, MOVING_FORWARD, STOP
)
}

@Test
fun `예외 테스트`() {
assertSimpleTest {
assertThrows<IllegalArgumentException> { runException("pobi,javaji", "1") }
}
assertSimpleTest {
assertThrows<IllegalArgumentException> { runException("", "1") }
}
assertSimpleTest {
assertThrows<IllegalArgumentException> { runException("pobi,pobi,woni", "3") }
}

assertSimpleTest {
assertThrows<IllegalArgumentException> { runException("pobi,woni", "a") }
}
assertSimpleTest {
assertThrows<IllegalArgumentException> { runException("pobi,woni", "1.1") }
}
}

override fun runMain() {
Expand Down