-
Notifications
You must be signed in to change notification settings - Fork 202
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
[코드 리뷰용 PR입니다!] - 재구현 스터디 #236
base: main
Are you sure you want to change the base?
Changes from all commits
b615aea
d0350f4
0f1a768
18ae353
45e1172
0587a28
f7d197c
a07cc7c
87bbdd6
b1fb645
24a689a
8838fe9
1a39005
6885c1a
830e7a0
f9389e3
a373b2c
5ddaae7
fa304a9
2226495
e1e5331
55d31c6
68543a9
26dff7b
e5107a3
0e47d26
c620702
1b72d7f
f15e1d2
8b7ee71
388d7f4
ffbdf01
c97b43e
ae6ac32
397aa67
6bc811a
3babfca
08fb80d
50e8ace
9bbe173
4a61b98
f358cec
4a0784d
9456a40
beea07d
05ee616
2a3ea1e
3c50f41
f492c8f
c8a1010
76e39ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# 기능 목록 | ||
|
||
### 입력 | ||
|
||
- 경주할 자동차 이름을 입력하는 기능 | ||
- 몇 번의 이동을 할 지 입력하는 기능 | ||
|
||
### 출력 | ||
|
||
- `“경주할 자동차 이름을 입력하세요."`를 출력하는 기능 | ||
- `“시도할 횟수는 몇 회인가요?”`를 출력하는 기능 | ||
- `“최종 우승자 : "`를 출력하는 기능 | ||
- 각 차수별 실행 결과를 출력하는 기능 | ||
|
||
### 경주 | ||
|
||
- 무작위 수를 생성하는 기능 | ||
- 자동차가 전진하는지 정지하는지 판단하는 기능 (무작위 수가 4 이상, 미만) | ||
- 우승자를 판별하는 기능 | ||
- 각 자동차마다 움직인 거리 저장 기능 | ||
|
||
### 검사 및 예외처리 | ||
|
||
- 자동차 이름이 올바른 값인 지 검사하는 기능 | ||
- 올바른값: Null X, 5자리 이하, 중복 X | ||
- 사용자가 몇 번 이동할 지 입력 할 때 숫자를 올바른 값을 입력하는 지 검사하는 기능 | ||
- 올바른값: Null X, 0 보다 큰 정수 | ||
- 사용자 입력 값에 대해 올바르지 않을 경우 `IllegalArgumentException` 를 발생시키는 기능 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,10 @@ | ||
package racingcar | ||
|
||
import racingcar.controller.RacingController | ||
|
||
|
||
fun main() { | ||
// TODO: 프로그램 구현 | ||
val racingController = RacingController() | ||
racingController.run() | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package racingcar.controller | ||
|
||
import racingcar.model.AttemptsNumber | ||
import racingcar.model.Car | ||
import racingcar.model.Cars | ||
import racingcar.model.Racing | ||
import racingcar.util.Constants | ||
import racingcar.view.InputView | ||
import racingcar.view.OutputView | ||
|
||
class RacingController() { | ||
private var attemptsNum = 0 | ||
private lateinit var carList: List<Car> | ||
private val inputView = InputView() | ||
private val outputView = OutputView() | ||
|
||
fun run() { | ||
printStartAndGetCarList() | ||
requestAttemptsNumber() | ||
doRacingAndPrintResult() | ||
} | ||
|
||
private fun doRacingAndPrintResult() { | ||
val racing = Racing(carList) | ||
repeat(attemptsNum) { racing.runRaceOnce().apply { outputView.printMatchProgress(carList) } } | ||
racing.getWinner() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
outputView.printWinner(racing.winner) | ||
} | ||
|
||
private fun requestAttemptsNumber() { | ||
outputView.requestAttemptsNumber(Constants.NUMBER_ATTEMPTS_MSG) | ||
val attemptsNumber = AttemptsNumber(inputView.getAttemptsNumber()) | ||
attemptsNum = attemptsNumber.validAttemptsNum | ||
} | ||
|
||
private fun printStartAndGetCarList() { | ||
outputView.printRaceStart(Constants.RACE_START_MSG) | ||
val cars = Cars(inputView.getCarList()) | ||
carList = cars.carList | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package racingcar.model | ||
|
||
import racingcar.util.Validator.isNumberAttemptsValid | ||
|
||
class AttemptsNumber(private val attempts: String) { | ||
|
||
val validAttemptsNum: Int | ||
get() = getValidAttemptsNum().toInt() | ||
Comment on lines
+7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
private fun getValidAttemptsNum(): String { | ||
isNumberAttemptsValid(attempts) | ||
return attempts | ||
Comment on lines
+10
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 함수로 만들어 검증하는 것 보다는 |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package racingcar.model | ||
|
||
data class Car( | ||
var name:String = "", | ||
var distance:Int = 0 | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package racingcar.model | ||
|
||
import racingcar.util.Validator.isCarNameLengthValid | ||
import racingcar.util.Validator.isCarNameNotEmpty | ||
import racingcar.util.Validator.isCarNameUnique | ||
|
||
class Cars(private val carNameList: List<String>) { | ||
|
||
private var _carNames = getValidCarName() | ||
|
||
val carList: List<Car> | ||
get() = _carList | ||
private var _carList = initializeCars() | ||
|
||
private fun getValidCarName(): List<String> { | ||
isCarNameUnique(carNameList) | ||
carNameList.forEach { name -> | ||
isCarNameLengthValid(name) | ||
isCarNameNotEmpty(name) | ||
} | ||
_carNames = carNameList | ||
return _carNames | ||
Comment on lines
+21
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분에서 이미 |
||
} | ||
|
||
private fun initializeCars(): List<Car> { | ||
val initializedCarList: List<Car> = _carNames.indices.map { Car(name = "", distance = 0) } | ||
_carNames.forEachIndexed { idx, name -> initializedCarList[idx].name = name } | ||
return initializedCarList | ||
Comment on lines
+26
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package racingcar.model | ||
|
||
import camp.nextstep.edu.missionutils.Randoms | ||
import racingcar.util.Constants | ||
|
||
class Racing(private val cars: List<Car>) { | ||
val winner: String | ||
get() = _winner | ||
|
||
private var _winner = "" | ||
|
||
|
||
private fun makeRandomNumber() = Randoms.pickNumberInRange(0, 9) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0, 9 값 전부 상수로 만들면 가독성이 좋아질 것 같습니다. |
||
|
||
private fun determineMoveOrStop(randomNumber: Int) = randomNumber >= Constants.BASE_NUMBER | ||
|
||
fun runRaceOnce() { | ||
cars.forEach { car -> | ||
val randomNumber = makeRandomNumber() | ||
if (determineMoveOrStop(randomNumber)) car.distance++ | ||
println(car.distance) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. model에서는 view와 의존하면 안돼요. |
||
} | ||
} | ||
|
||
fun getWinner() { | ||
val maxDistance = cars.maxOfOrNull { it.distance } | ||
val winnerList = cars.filter { it.distance == maxDistance } | ||
_winner = winnerList.joinToString { it.name } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package racingcar.util | ||
|
||
object Constants { | ||
const val CAR_NAME_MAX_LENGTH = 5 | ||
const val RACE_START_MSG = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)" | ||
const val NUMBER_ATTEMPTS_MSG = "시도할 횟수는 몇 회인가요?" | ||
const val BASE_NUMBER = 4 | ||
const val WINNER_MSG = "최종 우승자 : " | ||
const val DISTANCE_MSG = "-" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package racingcar.util | ||
|
||
object Validator { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
private const val DUPLICATE_NAME_ERROR_MSG = "Duplicate car names are not allowed." | ||
private const val NAME_OVER_LENGTH_MSG = | ||
"Car name exceeds the maximum allowed length of ${Constants.CAR_NAME_MAX_LENGTH}." | ||
private const val NAME_EMPTY_MSG = "Car name cannot be empty." | ||
private const val INVALID_NUMBER_FORMAT_MSG = | ||
"Invalid format for number of attempts. Please use the specified format." | ||
|
||
fun isCarNameUnique(carList: List<String>) { | ||
if (carList.size != carList.toSet().size) throw IllegalArgumentException(DUPLICATE_NAME_ERROR_MSG) | ||
} | ||
|
||
fun isCarNameLengthValid(carName: String) { | ||
if (carName.length > Constants.CAR_NAME_MAX_LENGTH) throw IllegalArgumentException(NAME_OVER_LENGTH_MSG) | ||
} | ||
Comment on lines
+16
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이부분에서 혹시 Constants를 import하지 않고 사용하신 이유가 있을까요?만약 특별한 이유가 없다면 Constants를 import하는 쪽이 좀 더 간결하게 보일 것 같아서요 |
||
|
||
fun isCarNameNotEmpty(carName: String) { | ||
if (carName.trim().isEmpty()) throw IllegalArgumentException(NAME_EMPTY_MSG) | ||
} | ||
|
||
fun isNumberAttemptsValid(numberAttempts: String) { | ||
if (!(numberAttempts.all { it.isDigit() }) || numberAttempts.toInt() < 1) throw IllegalArgumentException( | ||
INVALID_NUMBER_FORMAT_MSG | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package racingcar.view | ||
|
||
import camp.nextstep.edu.missionutils.Console | ||
|
||
class InputView { | ||
fun getCarList() = Console.readLine().split(",") | ||
fun getAttemptsNumber(): String = Console.readLine().trim() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package racingcar.view | ||
|
||
import racingcar.model.Car | ||
import racingcar.util.Constants | ||
|
||
class OutputView { | ||
fun printRaceStart(raceStartMsg: String) { | ||
println(raceStartMsg) | ||
} | ||
|
||
fun requestAttemptsNumber(numberAttemptsMsg: String) { | ||
println(numberAttemptsMsg) | ||
} | ||
|
||
fun printMatchProgress(cars: List<Car>) { | ||
cars.forEach { car -> println("${car.name} : ${Constants.DISTANCE_MSG.repeat(car.distance)}") } | ||
println() | ||
} | ||
|
||
fun printWinner(winnerNames: String) { | ||
println("${Constants.WINNER_MSG}$winnerNames") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
예외 처리에 대해 꼼꼼하게 정리해주시고 README를 두분 모두 깔끔하게 정리해주셔서 여러모로 많이 배우네요:)