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

[kotlin-racingcar-6] 지혜원 미션 제출합니다. #202

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c9f436d
docs : Write a list of implemented features
altpfwlzh Oct 27, 2023
21ef133
docs : modify a list of implemented features
altpfwlzh Oct 27, 2023
ff88a60
feat(controller/RacingGame) : 경주차 이름 받기 멘트 출력
altpfwlzh Nov 1, 2023
437fd9f
feat(controller/RacingGame) : 레이싱카들의 이름 받기
altpfwlzh Nov 1, 2023
ad86c55
feat(util/Validator) : 차이름 형식 확인
altpfwlzh Nov 1, 2023
8e3b98d
feat(util/Validator) : 시도 횟수 확인
altpfwlzh Nov 1, 2023
6d61bd5
feat(controller/RacingGame) : 실행 결과 멘트 출력
altpfwlzh Nov 1, 2023
19594cf
feat(model/Car, CarList) : 차 이동 함수 구현
altpfwlzh Nov 1, 2023
f73806e
feat(util/RandNumGenerator) : 랜덤으로 숫자를 반환하는 함수 구현
altpfwlzh Nov 1, 2023
0300eb8
feat(controller/RacingGame) : 레이싱카들의 각 턴 속도에 따라 전진하는 함수 구현
altpfwlzh Nov 1, 2023
90d16af
feat(view/OutputView) : 현재 턴의 실행 결과 출력 함수 구현
altpfwlzh Nov 1, 2023
af22ea9
feat(view/OutputView) : 빈 줄을 출력하는 함수를 구현한다.
altpfwlzh Nov 1, 2023
aa3390c
feat(model/CarList) : 차들 중에서 우승자를 찾는 함수 구현
altpfwlzh Nov 1, 2023
14f0707
feat(util/Validator) : 제한에 관한 상수를 companion object로 선언한다.
altpfwlzh Nov 1, 2023
ee4115d
style(util/Validator) : 코드 사이 공백 제거 및 필요 없는 import 삭제
altpfwlzh Nov 1, 2023
3695513
test(racingcar/CarTest) : Car 클래스에 대한 테스트 코드
altpfwlzh Nov 1, 2023
7e42b14
style(util/Validator) : checkInputNull -> checkInputEmpty로 함수 이름 변경
altpfwlzh Nov 1, 2023
c54a1d8
style(util/Validator) : checkInputNull -> checkInputEmpty로 함수 이름 변경
altpfwlzh Nov 1, 2023
80f3981
test(racingcar/ValidatorTest) : Validator를 테스트한다.
altpfwlzh Nov 1, 2023
0abf779
docs : 구현 기능 정리
altpfwlzh Nov 1, 2023
07d7c59
style(test) : 예외 테스트 prefix 제거
altpfwlzh Nov 1, 2023
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
51 changes: 51 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
## 구현 기능 목록

#### 핵심 : 자동차를 일정 확률로 전진 시키고 우승(가장 많이 이동)한 자동차를 출력하라.

1. 경주할 자동차 이름들을 입력 받기
- 자동차 구분
- 자동차는 쉼표(,)로 구분한다.
- 자동차 개수 제한
- 특별한 개수 제한은 없다.
- 자동차 이름 제한
- 5자 이하
- 특별한 문자, 숫자, 특수 기호, 공백 등의 제한은 없다.
- 단, 맨 앞의 공백은 자동으로 제거한다. 이는, 이름 자릿 수에 들어가지 않는다.

2. 경주 시도 횟수 입력 받기
- 시도 횟수는 1번 이상, 100번 미만으로 한다.

3. 경주 실행
- 2번에서 입력 받은 횟수만큼 반복 한다.
- 전진 조건
- 0~9 사이의 무작위 값을 발생 시키고, 그 값이 4이상일 경우 전진하고 그 미만이면 그 자리에 멈춰 있는다.
- 한 번에 한 칸만 전진이 가능하다.

4. 경주 실행 결과 출력
- 3번의 실행 결과를 출력한다.
- 자동차의 이름과 현재 전진 상황을 함께 출력한다.

5. 우승 자동차 선정
- 가장 많이 전진한 자동차가 우승자가 된다.
- 우승한 자동차는 한 대, 또는 그 이상이다.

6. 우승 자동차 출력
- 우승한 자동차가 여러 대일 경우 쉼표(,)로 구분한다.
- 쉼표(,) 바로 뒤에 띄어 쓰기를 하고 이름을 출력한다.
- 이후에 곧바로 경주를 종료한다.



----

#### 예외 사항

1. 입력 오류
- `IllegalArgumentException`을 발생시킨 후 애플리케이션을 종료 한다.







8 changes: 8 additions & 0 deletions local.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Fri Oct 27 13:46:24 KST 2023
sdk.dir=C\:\\Users\\lifei\\AppData\\Local\\Android\\Sdk
11 changes: 11 additions & 0 deletions src/main/kotlin/constants/ErrorMessage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package constants

object ErrorMessage {
const val INPUT_NULL = "[ERROR] 아무것도 입력되지 않았습니다."
const val INPUT_TYPE_BE_INT = "[ERROR] 숫자로 입력해야 합니다."

const val INPUT_CAR_NAME_NULL = "[ERROR] 입력되지 않은 자동차 이름이 있습니다."
const val INPUT_CAR_NAME_SIZE_OVER = "[ERROR] 자동차 이름은 5글자 이하여야 합니다."
const val INPUT_TRY_NUM_SIZE_UNDER = "[ERROR] 시도 횟수는 1번을 이상이어야 합니다"
const val INPUT_TRY_NUM_SIZE_OVER = "[ERROR] 시도 횟수는 100번을 미만이어야 합니다"
}
9 changes: 9 additions & 0 deletions src/main/kotlin/constants/Strings.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package constants

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

37 changes: 37 additions & 0 deletions src/main/kotlin/controller/RacingGame.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package controller

import model.CarList
import util.RandNumGenerator
import view.InputView
import view.OutputView

class RacingGame(private val outputView: OutputView, private val inputView: InputView) {
fun runGame() {
outputView.outputCarList()
val carList: CarList = CarList(inputCarList())
outputView.outputTryNum()
val tryNum: Int = inputTryNum()
outputView.outputTryResult()
repeat(tryNum) {
tryTurn(carList)
}
outputView.outputWinners(carList)
}

private fun inputCarList(): String {
return inputView.inputCarNames()
}

private fun inputTryNum(): Int {
return inputView.inputTryNum().toInt()
}

private fun tryTurn(carList: CarList) {
repeat(carList.carList.size) {
val speed: Int = RandNumGenerator().getRandNum0to9()
carList.move(it, speed)
outputView.outputTurnResult(carList.carList[it])
}
outputView.outputBlankLine()
}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/model/Car.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package model

import util.Validator

class Car(val name: String, position: Int = 0) {
private var _position: Int = position
val position: Int get() = _position

init {
Validator().checkCarName(name)
}

fun move(speed: Int) {
if(speed >= 4) _position++
}
}
14 changes: 14 additions & 0 deletions src/main/kotlin/model/CarList.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package model

class CarList(val carList: List<Car>) {
constructor(input: String) : this(input.split(",").mapIndexed { _, name -> Car(name.trim()) })

fun move(index: Int, speed: Int) {
carList[index].move(speed)
}

fun findWinnerList(carList: CarList): String {
val maxPosition: Int = carList.carList.maxOf { it.position }
return carList.carList.filter { it.position == maxPosition }.joinToString(separator = ", ") { it.name }
}
}
8 changes: 7 additions & 1 deletion src/main/kotlin/racingcar/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package racingcar

import controller.RacingGame
import view.InputView
import view.OutputView

fun main() {
// TODO: 프로그램 구현
val racingGame = RacingGame(OutputView(), InputView())
racingGame.runGame()
}

9 changes: 9 additions & 0 deletions src/main/kotlin/util/RandNumGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package util

import camp.nextstep.edu.missionutils.Randoms

class RandNumGenerator {
fun getRandNum0to9(): Int {
return Randoms.pickNumberInRange(0, 9)
}
}
43 changes: 43 additions & 0 deletions src/main/kotlin/util/Validator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package util

import constants.ErrorMessage

class Validator {
fun checkCarName(name: String) {
checkNameNull(name)
checkNameSize(name)
}

fun checkTryNum(num: String) {
checkInputEmpty(num)
checkTypeInt(num)
checkTryNumSize(num)
}

fun checkInputEmpty(input: String){
if(input.isEmpty()) throw IllegalArgumentException(ErrorMessage.INPUT_NULL)
}

private fun checkTypeInt(input: String) {
if(input.chars().allMatch{ !Character.isDigit(it) }) throw IllegalArgumentException(ErrorMessage.INPUT_TYPE_BE_INT)
}

private fun checkNameNull(name: String) {
if(name.isEmpty()) throw IllegalArgumentException(ErrorMessage.INPUT_CAR_NAME_NULL)
}

private fun checkNameSize(name: String) {
if(name.length > NAME_MAX_LENGTH) throw IllegalArgumentException(ErrorMessage.INPUT_CAR_NAME_SIZE_OVER)
}

private fun checkTryNumSize(num: String) {
if(num.toInt() < TRY_NUM_MIN_SIZE) throw IllegalArgumentException(ErrorMessage.INPUT_TRY_NUM_SIZE_UNDER)
if(num.toInt() > TRY_NUM_MAX_SIZE) throw IllegalArgumentException(ErrorMessage.INPUT_TRY_NUM_SIZE_OVER)
}

companion object {
private const val NAME_MAX_LENGTH = 5
private const val TRY_NUM_MIN_SIZE = 1
private const val TRY_NUM_MAX_SIZE = 100
}
}
18 changes: 18 additions & 0 deletions src/main/kotlin/view/InputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package view

import camp.nextstep.edu.missionutils.Console
import util.Validator

class InputView {
fun inputCarNames(): String {
val input: String = Console.readLine()
Validator().checkInputEmpty(input)
return input
}

fun inputTryNum(): String {
val input: String = Console.readLine()
Validator().checkTryNum(input)
return input
}
}
33 changes: 33 additions & 0 deletions src/main/kotlin/view/OutputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package view

import constants.Strings
import model.Car
import model.CarList

class OutputView {
fun outputCarList() {
println(Strings.INPUT_CAR_NAME)
}

fun outputTryNum() {
println(Strings.INPUT_TRY_NUM)
}

fun outputTryResult() {
println("\n" + Strings.TURN_RESULT)
}

fun outputTurnResult(car: Car) {
val positionResult: String = "-".repeat(car.position)
println("${car.name} : $positionResult")
}

fun outputWinners(carList: CarList) {
val winnerList: String = carList.findWinnerList(carList)
println(Strings.WINNER_LIST + winnerList)
}

fun outputBlankLine() {
println()
}
}
22 changes: 22 additions & 0 deletions src/test/kotlin/racingcar/CarTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package racingcar

import model.Car
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows

class CarTest {
@Test
fun `자동차 이름이 공백인 경우 `() {
assertThrows<IllegalArgumentException> {
Car("")
}
}

@Test
fun `자동차 이름의 5글자 이상일 경우`() {
val name: String = "내이름은슈룹이야"
assertThrows<IllegalArgumentException> {
Car(name)
}
}
}
28 changes: 28 additions & 0 deletions src/test/kotlin/racingcar/ValidatorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package racingcar

import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import util.Validator

class ValidatorTest {
@Test
fun `입력 값이 없을 경우`() {
assertThrows<IllegalArgumentException> {
Validator().checkInputEmpty("")
}
}

@Test
fun `시도 횟수가 0번일 경우`() {
assertThrows<IllegalArgumentException> {
Validator().checkTryNum(0.toString())
}
}

@Test
fun `시도 횟수가 숫자가 아니거나 음수일 경우`() {
assertThrows<IllegalArgumentException> {
Validator().checkTryNum("-100")
}
}
}