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

[자동차 경주] 조민지 미션 제출합니다. #212

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
22 changes: 22 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# 기능 목록

## 입력
- 경주할 자동차의 이름 ( 5자 이하, 중복 x)
- 시도 횟수 (숫자)
- #### 단, 잘못된 값을 입력하면 IllegalArgumetException 발생 후 강제 종료

## 문구 출력
- 입력 시 )
- 자동차 이름 입력 문구
- 시도 횟수 입력 문구
- 실행 결과 출력 시 )
- 각 라운드 당 결과 출력
- 최종 우승자 문구 출력 ( 단독 / 공동 )

## 게임 과정
- 자동차 이름과 시도 횟수 입력 받기 (검증)
- 0~9 무작위 값 구하기
- 해당 무작위 값이 4이상인지 판단하기
- 4이상이면 한 칸 전진(+)
- 각 라운드 수행 시 결과 반영
- 모든 라운드 수행 시 최종 결과 판단
5 changes: 4 additions & 1 deletion src/main/kotlin/racingcar/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package racingcar

import racingcar.controller.Controller

fun main() {
// TODO: 프로그램 구현
val controller = Controller()
controller.start()
}
56 changes: 56 additions & 0 deletions src/main/kotlin/racingcar/controller/Controller.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package racingcar.controller

import racingcar.domain.Car
import racingcar.view.InputView
import racingcar.view.OutputView
import racingcar.domain.Validator

class Controller {
private val inputView = InputView()
private val outputView = OutputView()
fun start() {
val inputCarsNames = readInputCars()
val inputRound = readInputRound().toInt()
Validator(inputCarsNames, inputRound)
val carList: List<Car> = inputCarsNames.split(',').map { Car(it) }
outputView.printStartOfResultPhrase()

repeat(inputRound) {
playGame(carList)
showResult(carList)
println()
}

showWinners(carList)

inputView.finish()
}

private fun readInputCars(): String {
outputView.printInputNameOfCars()
return inputView.readUserInput()
}

private fun readInputRound(): String {
outputView.printInputNumberOfAttempts()
return inputView.readUserInput()
}

private fun playGame(carList: List<Car>) {
carList.forEach { it.goForward() }
}

private fun showResult(carList: List<Car>) {
carList.forEach { outputView.printRoundResultFormat(it.carName, it.forward) }
}

private fun showWinners(carList: List<Car>) {
outputView.printWinnerFormat(decideWinners(carList))
}

private fun decideWinners(carList: List<Car>): List<String> {
val maxForward = carList.maxByOrNull { it.forward }?.forward
return carList.filter { it.forward == maxForward }.map { it.carName }
}

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

class Car(name: String) {
var carName: String = name.trim()
var forward = 0


fun goForward() {
if (DecisionMaker().decideToMove()) {
forward++
}
}
}
18 changes: 18 additions & 0 deletions src/main/kotlin/racingcar/domain/Cars.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package racingcar.domain

class Cars(private val cars: List<Car>) {

private val stateOfGame = cars.associate { it.carName to it.forward }.toMutableMap()
fun moveCar(name: String) {
stateOfGame[name] = stateOfGame[name]!! + 1
}

companion object {
fun registerCars(userInput: String) {
val carNames = userInput.split(",")
val cars = carNames.map { Car(it) }
Cars(cars)
}
}

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

import camp.nextstep.edu.missionutils.Randoms

class DecisionMaker() {

companion object {
const val MIN_DIGIT = 0
const val MAX_DIGIT = 9
const val FORWARD_THRESHOLD = 4
}

fun decideToMove(): Boolean {
val random = Randoms.pickNumberInRange(MIN_DIGIT, MAX_DIGIT)
return random >= FORWARD_THRESHOLD
}
}
43 changes: 43 additions & 0 deletions src/main/kotlin/racingcar/domain/Validator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package racingcar.domain

class Validator(inputCarsNames: String, inputRound: Int) {

init {
validateLength(inputCarsNames)
validateDuplicate(inputCarsNames)
validateNumOfCars(inputCarsNames)
validateRound(inputRound)
}

companion object {

private fun validateLength(inputCarsNames: String) {
val carList = inputCarsNames.split(',').toList()
carList.forEach { car ->
if (car.length > 5) {
throw IllegalArgumentException("이름은 5자 이하만 가능합니다.")
}
}
}

private fun validateDuplicate(inputCarsNames: String) :String {
val carList = inputCarsNames.split(',').toList()
require(HashSet(carList).size != carList.size) { "중복된 이름이 존재하면 안 됩니다."}

return this.toString()
}

private fun validateNumOfCars(inputCarsNames: String) {
val carList = inputCarsNames.split(',').toList()
if (carList.size == 1) {
throw IllegalArgumentException("2대 이상의 차가 필요합니다.")
}
}

private fun validateRound(inputRound: Int) {
if (inputRound < 0 || inputRound > 100) {
throw IllegalArgumentException("1 ~ 100 범위의 숫자만 입력 가능합니다.")
}
}
}
}
10 changes: 10 additions & 0 deletions src/main/kotlin/racingcar/view/InputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package racingcar.view

import camp.nextstep.edu.missionutils.Console

class InputView {

fun readUserInput(): String = Console.readLine()

fun finish() = Console.close()
}
13 changes: 13 additions & 0 deletions src/main/kotlin/racingcar/view/Message.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package racingcar.view

class Message(private val message: String) {
override fun toString() = message

companion object {
const val NAME_OF_CARS = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"
const val NUMBER_OF_ATTEMPTS = "시도할 횟수는 몇 회인가요?"
const val RESULT_PHRASE = "\n실행 결과"
const val FINAL_WINNER_FORMAT = "최종 우승자 : "
}

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

import racingcar.domain.Car


class OutputView {

fun printInputNameOfCars() = println(Message.NAME_OF_CARS)

fun printInputNumberOfAttempts() = println(Message.NUMBER_OF_ATTEMPTS)

fun printStartOfResultPhrase() = println(Message.RESULT_PHRASE)

fun printRoundResultFormat(name: String, position: Int) {
println("$name : ${"-".repeat(position)}")
}

fun printWinnerFormat(winnerList: List<String>) {
val winners = winnerList.joinToString(",")
println("${Message.FINAL_WINNER_FORMAT}${winners}")
}
}
23 changes: 23 additions & 0 deletions src/test/kotlin/racingcar/CarTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package racingcar

import camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import racingcar.domain.Car
import racingcar.domain.Validator
class CarTest {

@Test
fun `이름 중복 예외`() {
assertSimpleTest {
assertThrows<IllegalArgumentException> { Validator("mark,mark", 3)}
}
}

@Test
fun `이름 5자 초과 예외`() {
assertSimpleTest{
assertThrows<IllegalArgumentException> { Car("chominji") }
}
}
}