diff --git a/README.md b/README.md index 62fa463c..ec6eff76 100644 --- a/README.md +++ b/README.md @@ -1 +1,140 @@ # kotlin-racingcar-precourse + + +## ๐Ÿ“‹ ๊ณผ์ œ ์ง„ํ–‰ ์š”๊ตฌ ์‚ฌํ•ญ + +- ๋ฏธ์…˜์€ ์ž๋™์ฐจ ๊ฒฝ์ฃผ ์ €์žฅ์†Œ๋ฅผ ํฌํฌํ•˜๊ณ  ํด๋ก ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•œ๋‹ค. +- ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์ „ README.md์— ๊ตฌํ˜„ํ•  ๊ธฐ๋Šฅ ๋ชฉ๋ก์„ ์ •๋ฆฌํ•ด ์ถ”๊ฐ€ํ•œ๋‹ค. +- Git์˜ ์ปค๋ฐ‹ ๋‹จ์œ„๋Š” ์•ž ๋‹จ๊ณ„์—์„œ README.md์— ์ •๋ฆฌํ•œ ๊ธฐ๋Šฅ ๋ชฉ๋ก ๋‹จ์œ„๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค. +- AngularJS Git Commit Message Conventions์„ ์ฐธ๊ณ ํ•ด ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ ์ž‘์„ฑํ•œ๋‹ค. +- ์ž์„ธํ•œ ๊ณผ์ œ ์ง„ํ–‰ ๋ฐฉ๋ฒ•์€ ํ”„๋ฆฌ์ฝ”์Šค ์ง„ํ–‰ ๊ฐ€์ด๋“œ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•œ๋‹ค. + +## ๊ธฐ๋Šฅ ์š”๊ตฌ ์‚ฌํ•ญ + +์ดˆ๊ฐ„๋‹จ ์ž๋™์ฐจ ๊ฒฝ์ฃผ ๊ฒŒ์ž„์„ ๊ตฌํ˜„ํ•œ๋‹ค. + +- ์ฃผ์–ด์ง„ ํšŸ์ˆ˜ ๋™์•ˆ n๋Œ€์˜ ์ž๋™์ฐจ๋Š” ์ „์ง„ ๋˜๋Š” ๋ฉˆ์ถœ ์ˆ˜ ์žˆ๋‹ค. +- ๊ฐ ์ž๋™์ฐจ์— ์ด๋ฆ„์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ „์ง„ํ•˜๋Š” ์ž๋™์ฐจ๋ฅผ ์ถœ๋ ฅํ•  ๋•Œ ์ž๋™์ฐจ ์ด๋ฆ„์„ ๊ฐ™์ด ์ถœ๋ ฅํ•œ๋‹ค. +- ์ž๋™์ฐจ ์ด๋ฆ„์€ ์‰ผํ‘œ(,)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ตฌ๋ถ„ํ•˜๋ฉฐ ์ด๋ฆ„์€ 5์ž ์ดํ•˜๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค. +- ์‚ฌ์šฉ์ž๋Š” ๋ช‡ ๋ฒˆ์˜ ์ด๋™์„ ํ•  ๊ฒƒ์ธ์ง€๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. +- ์ „์ง„ํ•˜๋Š” ์กฐ๊ฑด์€ 0์—์„œ 9 ์‚ฌ์ด์—์„œ ๋ฌด์ž‘์œ„ ๊ฐ’์„ ๊ตฌํ•œ ํ›„ ๋ฌด์ž‘์œ„ ๊ฐ’์ด 4 ์ด์ƒ์ผ ๊ฒฝ์šฐ์ด๋‹ค. +- ์ž๋™์ฐจ ๊ฒฝ์ฃผ ๊ฒŒ์ž„์„ ์™„๋ฃŒํ•œ ํ›„ ๋ˆ„๊ฐ€ ์šฐ์Šนํ–ˆ๋Š”์ง€๋ฅผ ์•Œ๋ ค์ค€๋‹ค. ์šฐ์Šน์ž๋Š” ํ•œ ๋ช… ์ด์ƒ์ผ ์ˆ˜ ์žˆ๋‹ค. +- ์šฐ์Šน์ž๊ฐ€ ์—ฌ๋Ÿฌ ๋ช…์ผ ๊ฒฝ์šฐ ์‰ผํ‘œ(,)๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌ๋ถ„ํ•œ๋‹ค. +- ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป๋œ ๊ฐ’์„ ์ž…๋ ฅํ•  ๊ฒฝ์šฐ IllegalArgumentException์„ ๋ฐœ์ƒ์‹œํ‚จ ํ›„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ข…๋ฃŒ๋˜์–ด์•ผ ํ•œ๋‹ค. + +### ์ž…์ถœ๋ ฅ ์š”๊ตฌ ์‚ฌํ•ญ + +**์ž…๋ ฅ** + +- ๊ฒฝ์ฃผํ•  ์ž๋™์ฐจ ์ด๋ฆ„(์ด๋ฆ„์€ ์‰ผํ‘œ(,) ๊ธฐ์ค€์œผ๋กœ ๊ตฌ๋ถ„) +``` +pobi,woni,jun +``` + +- ์‹œ๋„ํ•  ํšŸ์ˆ˜ +``` +5 +``` + +**์ถœ๋ ฅ** + +- ์ฐจ์ˆ˜๋ณ„ ์‹คํ–‰ ๊ฒฐ๊ณผ +``` +pobi : -- +woni : ---- +jun : --- +``` + +- ๋‹จ๋… ์šฐ์Šน์ž ์•ˆ๋‚ด ๋ฌธ๊ตฌ +``` +์ตœ์ข… ์šฐ์Šน์ž : pobi +``` + +- ๊ณต๋™ ์šฐ์Šน์ž ์•ˆ๋‚ด ๋ฌธ๊ตฌ +``` +์ตœ์ข… ์šฐ์Šน์ž : pobi, jun +``` + +**์‹คํ–‰ ๊ฒฐ๊ณผ ์˜ˆ์‹œ** + +``` +๊ฒฝ์ฃผํ•  ์ž๋™์ฐจ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”.(์ด๋ฆ„์€ ์‰ผํ‘œ(,) ๊ธฐ์ค€์œผ๋กœ ๊ตฌ๋ถ„) +pobi,woni,jun +์‹œ๋„ํ•  ํšŸ์ˆ˜๋Š” ๋ช‡ ํšŒ์ธ๊ฐ€์š”? +5 + +์‹คํ–‰ ๊ฒฐ๊ณผ +pobi : - +woni : +jun : - + +pobi : -- +woni : - +jun : -- + +pobi : --- +woni : -- +jun : --- + +pobi : ---- +woni : --- +jun : ---- + +pobi : ----- +woni : ---- +jun : ----- + +์ตœ์ข… ์šฐ์Šน์ž : pobi, jun +``` + +## ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ ์‚ฌํ•ญ 1 + +- Kotlin 1.9.24์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. +- Java ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ Kotlin ์ฝ”๋“œ๋กœ๋งŒ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. +- ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์˜ ์‹œ์ž‘์ ์€ Application์˜ main()์ด๋‹ค. +- build.gradle.kts ํŒŒ์ผ์€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์ œ๊ณต๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ด์™ธ์˜ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. +- ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ์‹œ System.exit() ๋˜๋Š” exitProcess()๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค. +- ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ ์‚ฌํ•ญ์—์„œ ๋‹ฌ๋ฆฌ ๋ช…์‹œํ•˜์ง€ ์•Š๋Š” ํ•œ ํŒŒ์ผ, ํŒจํ‚ค์ง€ ๋“ฑ์˜ ์ด๋ฆ„์„ ๋ฐ”๊พธ๊ฑฐ๋‚˜ ์ด๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค. +- ์ฝ”ํ‹€๋ฆฐ ์ฝ”๋“œ ์ปจ๋ฒค์…˜์„ ์ง€ํ‚ค๋ฉด์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•œ๋‹ค. +- ๊ธฐ๋ณธ์ ์œผ๋กœ Kotlin Style Guide๋ฅผ ์›์น™์œผ๋กœ ํ•œ๋‹ค. +- +## ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ ์‚ฌํ•ญ 2 +- indent(์ธ๋ดํŠธ, ๋“ค์—ฌ์“ฐ๊ธฐ) depth๋ฅผ 3์ด ๋„˜์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. 2๊นŒ์ง€๋งŒ ํ—ˆ์šฉํ•œ๋‹ค. + - ์˜ˆ๋ฅผ ๋“ค์–ด while๋ฌธ ์•ˆ์— if๋ฌธ์ด ์žˆ์œผ๋ฉด ๋“ค์—ฌ์“ฐ๊ธฐ๋Š” 2์ด๋‹ค. + - ํžŒํŠธ: indent(์ธ๋ดํŠธ, ๋“ค์—ฌ์“ฐ๊ธฐ) depth๋ฅผ ์ค„์ด๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์„œ๋“œ)๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด ๋œ๋‹ค. +- ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์„œ๋“œ)๊ฐ€ ํ•œ ๊ฐ€์ง€ ์ผ๋งŒ ํ•˜๋„๋ก ์ตœ๋Œ€ํ•œ ์ž‘๊ฒŒ ๋งŒ๋“ค์–ด๋ผ. +- JUnit 5์™€ AssertJ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ •๋ฆฌํ•œ ๊ธฐ๋Šฅ ๋ชฉ๋ก์ด ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋กœ ํ™•์ธํ•œ๋‹ค. + - ํ…Œ์ŠคํŠธ ๋„๊ตฌ ์‚ฌ์šฉ๋ฒ•์ด ์ต์ˆ™ํ•˜์ง€ ์•Š๋‹ค๋ฉด ์•„๋ž˜ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ํ•™์Šตํ•œ ํ›„ ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค. + - JUnit 5 User Guide + - AssertJ User Guide + - AssertJ Exception Assertions + - Guide to JUnit 5 Parameterized Tests + +## ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ + +- camp.nextstep.edu.missionutils์—์„œ ์ œ๊ณตํ•˜๋Š” Randoms ๋ฐ Console API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. + - Random ๊ฐ’ ์ถ”์ถœ์€ camp.nextstep.edu.missionutils.Randoms์˜ pickNumberInRange()๋ฅผ ํ™œ์šฉํ•œ๋‹ค. + - ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•˜๋Š” ๊ฐ’์€ camp.nextstep.edu.missionutils.Console์˜ readLine()์„ ํ™œ์šฉํ•œ๋‹ค. + +### ์‚ฌ์šฉ ์˜ˆ์‹œ +- 0์—์„œ 0๊นŒ์ง€์˜ ์ •์ˆ˜ ์ค‘ ํ•œ ๊ฐœ์˜ ์ •์ˆ˜ ๋ฐ˜ํ™˜ +``` +Randoms.pickNumberInRange(0, 9) +``` + +## ๊ตฌํ˜„ํ•  ๊ธฐ๋Šฅ ๋ชฉ๋ก +1. ์ž๋™์ฐจ ์ด๋ฆ„์„ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค. + - ์‰ผํ‘œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค. + - ์ฐจ์˜ ์ด๋ฆ„๊ณผ ์ „์ง„ํ•˜๊ณ  ๊ทธ์˜ ํšŸ์ˆ˜๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. + - ์ฐจ์˜ ์ด๋ฆ„์ด 5์ž ์ด์ƒ์ด๋ฉด IllegalArgumentException์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. + - ์ฐจ์˜ ์ด๋ฆ„์ด ๋นˆ ๋ฌธ์ž์—ด์ด๋ฉด IllegalArgumentException์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. + - ์ฐจ์˜ ์ด๋ฆ„์ด ์ค‘๋ณต๋˜๋ฉด IllegalArgumentException์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. +2. ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค. + - ์‹œ๋„ ํšŸ์ˆ˜๊ฐ€ 1 ๋ฏธ๋งŒ์ด๋ฉด IllegalArgumentException์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. + - ์‹œ๋„ ํšŸ์ˆ˜๊ฐ€ Int๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†์œผ๋ฉด IllegalArgumentException์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. +3. ๋ฌด์ž‘์œ„ ๊ฐ’์„ ๊ตฌํ•ด์„œ ์‹œ๋„ํšŸ์ˆ˜ ๋งŒํผ ๊ฐ๊ฐ ์ž๋™์ฐจ๋ฅผ ์›€์ง์ด๋Š” ๊ธฐํšŒ๋ฅผ ๊ฐ–๋„๋ก ํ•œ๋‹ค. + - 4 ์ด์ƒ์ผ ๊ฒฝ์šฐ์— ์›€์ง์ผ ์ˆ˜ ์žˆ๋„๋ก ์ง„ํ–‰ํ•œ๋‹ค. + - ์‹œ๋„ํ•˜๋Š” ํšŸ์ˆ˜ ๋™์•ˆ ์ž๋™์ฐจ์˜ ์ด๋™์„ ์ถœ๋ ฅํ•œ๋‹ค. + - ๊ฐ๊ฐ์˜ ์ž๋™์ฐจ๊ฐ€ ์ด ์›€์ง์ธ ํšŸ์ˆ˜๋ฅผ ๊ตฌํ•œ๋‹ค. +4. ์ž๋™์ฐจ๊ฐ€ ์ด ์›€์ง์ธ ํšŸ์ˆ˜๋ฅผ ๋น„๊ตํ•˜์—ฌ ์šฐ์Šน์ž๋ฅผ ๊ตฌํ•œ๋‹ค. + - ์šฐ์Šน์ž๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. \ No newline at end of file diff --git a/src/main/kotlin/racingcar/Application.kt b/src/main/kotlin/racingcar/Application.kt index 0d8f3a79..3edbb366 100644 --- a/src/main/kotlin/racingcar/Application.kt +++ b/src/main/kotlin/racingcar/Application.kt @@ -1,5 +1,18 @@ package racingcar +import racingcar.presenter.RacingCarPresenter +import racingcar.util.ConstantsUtil.DELIMITER_COMMA +import racingcar.util.ConstantsUtil.MESSAGE_INPUT_CAR_NAME +import racingcar.util.ConstantsUtil.MESSAGE_INPUT_ROUND +import racingcar.view.RacingCarView +import racingcar.view.RacingCarViewImpl + fun main() { - // TODO: ํ”„๋กœ๊ทธ๋žจ ๊ตฌํ˜„ + val view: RacingCarView = RacingCarViewImpl() + val presenter = RacingCarPresenter(view) + + val carNames = view.getUserInput(MESSAGE_INPUT_CAR_NAME).split(DELIMITER_COMMA) + val round = view.getUserInput(MESSAGE_INPUT_ROUND) + + presenter.startRacingCar(carNames, round) } diff --git a/src/main/kotlin/racingcar/model/Car.kt b/src/main/kotlin/racingcar/model/Car.kt new file mode 100644 index 00000000..121f873f --- /dev/null +++ b/src/main/kotlin/racingcar/model/Car.kt @@ -0,0 +1,13 @@ +package racingcar.model + +import racingcar.util.ConstantsUtil.CAR_INITIAL_POSITION + +data class Car( + val name: String, + var position: Int = CAR_INITIAL_POSITION +) { + + fun move() { + position++ + } +} diff --git a/src/main/kotlin/racingcar/model/RacingCar.kt b/src/main/kotlin/racingcar/model/RacingCar.kt new file mode 100644 index 00000000..99c9f7d4 --- /dev/null +++ b/src/main/kotlin/racingcar/model/RacingCar.kt @@ -0,0 +1,27 @@ +package racingcar.model + +import camp.nextstep.edu.missionutils.Randoms +import racingcar.util.ConstantsUtil.MAX_RANDOM_NUMBER +import racingcar.util.ConstantsUtil.MIN_RANDOM_NUMBER +import racingcar.util.ConstantsUtil.MOVE_MIN_NUMBER + +class RacingCar( + private val cars: List +) { + fun playRound() { + cars.forEach { car -> + if (isMove()) { + car.move() + } + } + } + + private fun isMove(): Boolean { + return Randoms.pickNumberInRange(MIN_RANDOM_NUMBER, MAX_RANDOM_NUMBER) >= MOVE_MIN_NUMBER + } + + fun findWinners(): List { + val maxPosition = cars.maxOf { it.position } + return cars.filter { it.position == maxPosition } + } +} \ No newline at end of file diff --git a/src/main/kotlin/racingcar/presenter/RacingCarPresenter.kt b/src/main/kotlin/racingcar/presenter/RacingCarPresenter.kt new file mode 100644 index 00000000..5088ee79 --- /dev/null +++ b/src/main/kotlin/racingcar/presenter/RacingCarPresenter.kt @@ -0,0 +1,43 @@ +package racingcar.presenter + +import racingcar.model.Car +import racingcar.model.RacingCar +import racingcar.util.ValidatorUtil +import racingcar.util.ValidatorUtil.validateCarLength +import racingcar.util.ValidatorUtil.validateCarName +import racingcar.util.ValidatorUtil.validateCarsNames +import racingcar.util.ValidatorUtil.validateRoundRange +import racingcar.util.ValidatorUtil.validateRoundType +import racingcar.view.RacingCarView + +class RacingCarPresenter( + private val racingCarView: RacingCarView +) { + fun startRacingCar( + carNames: List, + roundString: String + ) { + + validateCarsNames(carNames) + carNames.forEach { name -> + validateCarLength(name.length) + validateCarName(name) + } + + validateRoundType(roundString) + val roundNumber = roundString.toInt() + validateRoundRange(roundNumber) + + val cars = carNames.map { Car(it) } + val racingCar = RacingCar(cars) + + repeat(roundNumber) { + racingCar.playRound() + racingCarView.displayRaceRound(cars) + } + + val winners = racingCar.findWinners() + racingCarView.displayWinners(winners) + + } +} \ No newline at end of file diff --git a/src/main/kotlin/racingcar/util/ConstantsUtil.kt b/src/main/kotlin/racingcar/util/ConstantsUtil.kt new file mode 100644 index 00000000..c6a7888c --- /dev/null +++ b/src/main/kotlin/racingcar/util/ConstantsUtil.kt @@ -0,0 +1,22 @@ +package racingcar.util + +object ConstantsUtil { + const val CAR_INITIAL_POSITION = 0 + const val MOVE_MIN_NUMBER = 4 + const val CAR_NAME_MAX_LENGTH = 5 + const val MIN_RANDOM_NUMBER = 0 + const val MAX_RANDOM_NUMBER = 9 + + const val DELIMITER_COMMA = "," + + const val MESSAGE_CAR_LENGTH_EXCEEDED = "์ž๋™์ฐจ ์ด๋ฆ„ ๊ธธ์ด๊ฐ€ 5์ž๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค." + const val MESSAGE_CAR_NAME_BLANK = "์ž๋™์ฐจ ์ด๋ฆ„ ๊ธธ์ด๊ฐ€ 5์ž๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค." + const val MESSAGE_CAR_NAME_DUPLICATE = "์ž๋™์ฐจ ์ด๋ฆ„์ด ์ค‘๋ณต๋˜์—ˆ์Šต๋‹ˆ๋‹ค." + const val MESSAGE_ROUND_NOT_EXCEEDED= "์‹œ๋„ ํšŸ์ˆ˜๊ฐ€ 1 ๋ฏธ๋งŒ์ž…๋‹ˆ๋‹ค." + const val MESSAGE_ROUND_NOT_INT= "์‹œ๋„ ํšŸ์ˆ˜๊ฐ€ ์ˆซ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค." + + const val MESSAGE_INPUT_CAR_NAME = "๊ฒฝ์ฃผํ•  ์ž๋™์ฐจ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”.(์ด๋ฆ„์€ ์‰ผํ‘œ(,) ๊ธฐ์ค€์œผ๋กœ ๊ตฌ๋ถ„)" + const val MESSAGE_INPUT_ROUND = "์‹œ๋„ํ•  ํšŸ์ˆ˜๋Š” ๋ช‡ ํšŒ์ธ๊ฐ€์š”?" + + const val MESSAGE_RACING_WINNERS_FORMAT = "์ตœ์ข… ์šฐ์Šน์ž : %s" +} \ No newline at end of file diff --git a/src/main/kotlin/racingcar/util/ValidatorUtil.kt b/src/main/kotlin/racingcar/util/ValidatorUtil.kt new file mode 100644 index 00000000..23075151 --- /dev/null +++ b/src/main/kotlin/racingcar/util/ValidatorUtil.kt @@ -0,0 +1,41 @@ +package racingcar.util + +import racingcar.util.ConstantsUtil.CAR_NAME_MAX_LENGTH +import racingcar.util.ConstantsUtil.MESSAGE_CAR_LENGTH_EXCEEDED +import racingcar.util.ConstantsUtil.MESSAGE_CAR_NAME_BLANK +import racingcar.util.ConstantsUtil.MESSAGE_CAR_NAME_DUPLICATE +import racingcar.util.ConstantsUtil.MESSAGE_ROUND_NOT_EXCEEDED +import racingcar.util.ConstantsUtil.MESSAGE_ROUND_NOT_INT + +object ValidatorUtil { + + fun validateCarLength(carLength: Int) { + require(carLength <= CAR_NAME_MAX_LENGTH){ + MESSAGE_CAR_LENGTH_EXCEEDED + } + } + + fun validateCarName(carName: String) { + require(carName.isNotBlank()) { + MESSAGE_CAR_NAME_BLANK + } + } + + fun validateCarsNames(carNames: List) { + require(carNames.size == carNames.distinct().size){ + MESSAGE_CAR_NAME_DUPLICATE + } + } + + fun validateRoundType(roundString: String) { + require(roundString.toIntOrNull() != null){ + MESSAGE_ROUND_NOT_INT + } + } + + fun validateRoundRange(roundNumber: Int){ + require(roundNumber >= 1){ + MESSAGE_ROUND_NOT_EXCEEDED + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/racingcar/view/RacingCarView.kt b/src/main/kotlin/racingcar/view/RacingCarView.kt new file mode 100644 index 00000000..cc1c7a2c --- /dev/null +++ b/src/main/kotlin/racingcar/view/RacingCarView.kt @@ -0,0 +1,9 @@ +package racingcar.view + +import racingcar.model.Car + +interface RacingCarView { + fun getUserInput(message: String): String + fun displayRaceRound(cars: List) + fun displayWinners(cars: List) +} \ No newline at end of file diff --git a/src/main/kotlin/racingcar/view/RacingCarViewImpl.kt b/src/main/kotlin/racingcar/view/RacingCarViewImpl.kt new file mode 100644 index 00000000..5498c9a7 --- /dev/null +++ b/src/main/kotlin/racingcar/view/RacingCarViewImpl.kt @@ -0,0 +1,29 @@ +package racingcar.view + +import camp.nextstep.edu.missionutils.Console +import racingcar.model.Car +import racingcar.util.ConstantsUtil.MESSAGE_RACING_WINNERS_FORMAT + +class RacingCarViewImpl : RacingCarView { + + override fun getUserInput(message: String): String { + println(message) + return Console.readLine() + } + + override fun displayRaceRound(cars: List) { + cars.forEach { car -> + println("${car.name} : ${"-".repeat(car.position)}") + } + println() + } + + override fun displayWinners(cars: List) { + println(formatWinners(cars)) + } + + private fun formatWinners(cars: List): String { + val winners = cars.joinToString(", ") { it.name } + return MESSAGE_RACING_WINNERS_FORMAT.format(winners) + } +} \ No newline at end of file diff --git a/src/test/kotlin/racingcar/ApplicationTest.kt b/src/test/kotlin/racingcar/ApplicationTest.kt deleted file mode 100644 index 3c601c8e..00000000 --- a/src/test/kotlin/racingcar/ApplicationTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package racingcar - -import camp.nextstep.edu.missionutils.test.Assertions.assertRandomNumberInRangeTest -import camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest -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 ApplicationTest : NsTest() { - @Test - fun `๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ`() { - assertRandomNumberInRangeTest( - { - run("pobi,woni", "1") - assertThat(output()).contains("pobi : -", "woni : ", "์ตœ์ข… ์šฐ์Šน์ž : pobi") - }, - MOVING_FORWARD, STOP - ) - } - - @Test - fun `์˜ˆ์™ธ ํ…Œ์ŠคํŠธ`() { - assertSimpleTest { - assertThrows { runException("pobi,javaji", "1") } - } - } - - override fun runMain() { - main() - } - - companion object { - private const val MOVING_FORWARD: Int = 4 - private const val STOP: Int = 3 - } -} diff --git a/src/test/kotlin/racingcar/CarInputTest.kt b/src/test/kotlin/racingcar/CarInputTest.kt new file mode 100644 index 00000000..b32156dd --- /dev/null +++ b/src/test/kotlin/racingcar/CarInputTest.kt @@ -0,0 +1,37 @@ +package racingcar + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import racingcar.util.ConstantsUtil.DELIMITER_COMMA +import racingcar.util.ValidatorUtil.validateCarLength +import racingcar.util.ValidatorUtil.validateCarName +import racingcar.util.ValidatorUtil.validateCarsNames + +class CarInputTest { + @Test + fun `์ž๋™์ฐจ ์ด๋ฆ„์ด 5 ์ดˆ๊ณผ์ผ ๊ฒฝ์šฐ ์˜ˆ์™ธ ํ…Œ์ŠคํŠธ`() { + assertThrows { + val input = "pobiiii" + validateCarLength(input.length) + } + + } + + @Test + fun `์ž๋™์ฐจ ์ด๋ฆ„์ด ๊ณต๋ฐฑ์ผ ๊ฒฝ์šฐ ์˜ˆ์™ธ ํ…Œ์ŠคํŠธ`() { + assertThrows { + val input = " " + validateCarName(input) + } + + } + + @Test + fun `์ž๋™์ฐจ ์ด๋ฆ„์ด ์ค‘๋ณต์ผ ๊ฒฝ์šฐ ์˜ˆ์™ธ ํ…Œ์ŠคํŠธ`() { + assertThrows { + val input = "pobi,pobi,jun".split(DELIMITER_COMMA) + validateCarsNames(input) + } + } + +} \ 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 00000000..c620fd5a --- /dev/null +++ b/src/test/kotlin/racingcar/RacingCarTest.kt @@ -0,0 +1,39 @@ +package racingcar + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import racingcar.model.Car +import racingcar.model.RacingCar + +class RacingCarTest { + + @Test + fun `์ž๋™์ฐจ๊ฐ€ ์ด๋™ํ•  ๋•Œ ์œ„์น˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ`() { + val car = Car("pobi") + car.move() + + assertEquals(1, car.position) + } + + @Test + fun `์ตœ์ข… ์šฐ์Šน์ž ์ฐพ๊ธฐ ํ…Œ์ŠคํŠธ`() { + val car1 = Car("pobi") + val car2 = Car("jun") + val car3 = Car("woni") + val cars = listOf(car1, car2, car3) + val racingCar = RacingCar(cars) + + val round = 5 + + repeat(round) { + racingCar.playRound() + } + + val winners = racingCar.findWinners() + val maxPosition = cars.maxOf { it.position } + assertTrue(winners.all { it.position == maxPosition }) + assertTrue(winners.isNotEmpty()) + } + +} \ No newline at end of file diff --git a/src/test/kotlin/racingcar/RoundInputTest.kt b/src/test/kotlin/racingcar/RoundInputTest.kt new file mode 100644 index 00000000..0592a482 --- /dev/null +++ b/src/test/kotlin/racingcar/RoundInputTest.kt @@ -0,0 +1,25 @@ +package racingcar + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import racingcar.util.ValidatorUtil.validateRoundRange +import racingcar.util.ValidatorUtil.validateRoundType + +class RoundInputTest { + @Test + fun `์‹œ๋„ ํšŸ์ˆ˜๊ฐ€ ์ˆซ์ž๋กœ ๋ณ€ํ™˜ ํ•  ์ˆ˜ ์—†์„ ๊ฒฝ์šฐ ์˜ˆ์™ธ ํ…Œ์ŠคํŠธ`() { + assertThrows { + val input = "ใ„ฑใ„ดใ„ท" + validateRoundType(input) + } + } + + @Test + fun `์‹œ๋„ ํšŸ์ˆ˜๊ฐ€ ์–‘์ˆ˜๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ ๋ฐ˜ํ™˜`() { + assertThrows { + val input = -1 + validateRoundRange(input) + } + } + +} \ No newline at end of file