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

[연습] 자동차 경주 #514

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3732b70
docs: 구현 기능 목록 정의
This2sho Dec 1, 2022
64f0da6
docs: 구현 기능 목록 정의
This2sho Dec 1, 2022
c74ffb9
test(Car): 자동차 이름 유효성 검사 테스트
This2sho Dec 1, 2022
d3b17d4
feat(Car): 자동차 이름 유효성 검사 로직 구현
This2sho Dec 1, 2022
5402740
test(Car): 자동차 전진 기능 테스트
This2sho Dec 1, 2022
5c37b2f
feat(Car): 자동차 연료에 따른 전진 기능 구현
This2sho Dec 1, 2022
a50d563
docs: 구현 기능 목록 수정
This2sho Dec 1, 2022
a38d016
docs: 구현 기능 목록 기능 분리
This2sho Dec 1, 2022
06d72a5
docs: 구현 기능 목록 기능 분리
This2sho Dec 1, 2022
61b8daf
test(CarGame): 자동차 등록 성공, 실패 테스트
This2sho Dec 1, 2022
16af14f
feat(Car): 자동차 이름 사용할 수 있게 getter 적용
This2sho Dec 1, 2022
970064c
feat(CarGame): 자동차 등록하는 기능 구현
This2sho Dec 1, 2022
b9be6d0
refactor(CarGameTest): 초기화 init 메소드로 추출
This2sho Dec 1, 2022
d35210d
docs: 이동횟수 예외처리 부분 수정
This2sho Dec 1, 2022
a0fd5c5
test(CarGame): 이동횟수 등록시 예외 로직 검증
This2sho Dec 1, 2022
389d30f
feat(CarGame): 이동횟수 등록 기능 구현
This2sho Dec 1, 2022
15427cd
refactor(Car): 상수명 변경
This2sho Dec 1, 2022
475188d
refactor(CarGameTest): 테스트명 변경
This2sho Dec 1, 2022
7f14435
docs: 자동차 경주 게임 기능 분리
This2sho Dec 1, 2022
780dc00
test(CarGame): 자동차 경주 우승자 확인 테스트
This2sho Dec 1, 2022
2eb4395
feat(CarGame): 자동차 경주 시작 기능 구현
This2sho Dec 1, 2022
6854d10
feat(CarGame): 자동차 경주 우승자 알려주는 기능 구현
This2sho Dec 1, 2022
391b802
feat(InputView): 자동차 입력 기능 구현
This2sho Dec 1, 2022
a36a3f5
feat(InputView): 이동 횟수 입력 기능 구현
This2sho Dec 1, 2022
7548e0f
feat(OutputView): 자동차 출력 기능 구현
This2sho Dec 1, 2022
40e9197
feat(OutputView): 우승자 출력 기능 구현
This2sho Dec 1, 2022
0d8b21e
feat(InputView): 입력 메시지 추가
This2sho Dec 1, 2022
8eb4a81
refactor(CarGame): 자동차 경주 시작 로직 변경
This2sho Dec 1, 2022
9cb01d1
feat(OutputView): 경기 시작 메시지 출력 기능 추가
This2sho Dec 1, 2022
b7c46fa
feat(InputView): 자동차 이름 입력 유효성 검증 추가
This2sho Dec 1, 2022
9ae3034
feat(MainController): 자동차 경주 순서에 맞게 서비스 기능과 입/출력 구현
This2sho Dec 1, 2022
694ec26
feat(OutputView): 에러 출력 기능 구현
This2sho Dec 1, 2022
82bdc23
feat(MainController): 사용자가 잘못된 값을 입력할 경우 그 부분부터 다시 입력받는 기능 추가
This2sho Dec 1, 2022
03a3227
feat(Application): 프로그램 시작 기능 구현
This2sho Dec 1, 2022
4696e37
refactor(All): 출력관련 메시지 분리
This2sho Dec 1, 2022
a61b1a5
perf(OutputView): 개행 출력 개행 문자로 변경
This2sho Dec 1, 2022
dfd9714
refactor(InputView, OutputView): view 패키지로 이동
This2sho Dec 1, 2022
b8fb51b
docs: 구현 기능 목록에 동작 순서 추가
This2sho Dec 1, 2022
a0eda97
feat(MainController): 에러 발생시 다시 입력받는 기능 수정
This2sho Dec 1, 2022
5e3d7d3
refactor(CarTest): 계층형 구조로 테스트 변경
This2sho Dec 1, 2022
bc56861
refactor(CarGameTest): 계층형 구조로 테스트 변경
This2sho Dec 1, 2022
2cff2fa
refactor(MainController): 반복 입력받는 try-catch 부분 중복 제거
This2sho Dec 6, 2022
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
39 changes: 39 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 🚗 구현 기능 목록
Copy link

Choose a reason for hiding this comment

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

기능 목록을 자세히 작성하신 것이 보기 좋은 것 같습니다 !


## 자동차
- [x] 각 자동차에 이름을 부여할 수 있다.
- [x] **[예외처리]** 자동차의 이름이 5자 초과일 경우 예외처리한다.
- [x] 전진하거나 멈출 수 있다.
- [x] 연료가 4 이상일 경우 전진한다.
- [x] **[예외처리]** 연료가 0 미만 9 초과의 값이 들어오면 예외처리한다.


## 자동차 경주 게임
- [x] 경주에 참여할 자동차들을 등록한다.
- [x] **[예외처리]** 참여할 자동차는 최소 1대여야한다.
- [x] 이동 횟수를 등록한다.
- [x] **[예외처리]** 이동횟수가 0 이하면 예외처리한다.
- [x] 자동차 경주를 시작한다.
- [x] 각 이동횟수마다 각 자동차에게 랜덤한 연료를 주입한다.
- [x] 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다.(여러명의 우승자가 나올 수 있다.)


## 입력
- [x] 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름을 입력받는다.
- [x] **[예외처리]** 쉼표를 기준으로 나눴을 때 자동차 이름이 0보다 작거나 5보다 크면 예외처리한다.
- [x] 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
- [x] **[예외처리]** 이동 횟수는 숫자여야 한다.
- [x] 사용자가 잘못된 값을 입력할 경우 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다.


## 출력
- [x] 자동차 이름과 자동차의 현재 위치를 출력한다.
- [x] 최종 우승자를 출력한다.
- [x] 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다.

---
## 동작 순서
1. 경주에 등록할 자동차를 입력받는다.
2. 경주 시도 횟수를 입력받는다.
3. 시도 횟수 만큼 자동차가 전진하거나 멈춘다.
4. 경주가 종료되고 우승자를 알려준다.
2 changes: 2 additions & 0 deletions src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
public class Application {
public static void main(String[] args) {
// TODO 구현 진행
MainController mainController = new MainController();
mainController.run();
}
}
39 changes: 39 additions & 0 deletions src/main/java/racingcar/Car.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,51 @@
package racingcar;

public class Car {

public static final int MIN_FUEL = 0;
public static final int MAX_FUEL = 9;
public static final int MIN_MOVE_FUEL = 4;

public static final int MAX_NAME_LENGTH = 5;

private final String name;
private int position = 0;

public Car(String name) {
validateName(name);
this.name = name;
}

// 추가 기능 구현
private void validateName(String name) {
if (name.length() > MAX_NAME_LENGTH) {
throw new IllegalArgumentException(Message.CAR_NAME_VALIDATION);

Choose a reason for hiding this comment

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

저는 예외 메세지는 추후에도 수정할 일이 없고,
여러 곳이 아닌 해당하는 하나의 예외에만 사용되기 때문에
가독성을 위해 상수화하지 않고 있습니다!
다른 분들의 의견은 어떨지 모르겠네요!

Copy link
Member

Choose a reason for hiding this comment

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

저도 성훈님이랑 비슷한 의견입니다

}
}


public void moveOrStop(int fuel) {
validateFuel(fuel);

Choose a reason for hiding this comment

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

Fuel 부분은 Randoms 라이브러리를 사용하는데,
검증 책임은 라이브러리를 만든 쪽에 있다고 생각해서
라이브러리를 사용하는 부분은 검증하지 않아도 될 것 같습니다!

Copy link

Choose a reason for hiding this comment

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

저도 같은 의견입니다 !

if (fuel >= MIN_MOVE_FUEL) {
move();
}
}
Comment on lines +29 to +32
Copy link

Choose a reason for hiding this comment

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

도메인 함수 내부에서 다른 도메인 함수를 호출하는 것 보다
boolean type을 반환하도록 moveOrStop 함수를 변경해 접근해보면 어떤지 제안드립니다 !


private void validateFuel(int fuel) {
if (fuel < MIN_FUEL || fuel > MAX_FUEL) {
throw new IllegalArgumentException(Message.CAR_FUEL_VALIDATION);
}
}

private void move() {
position++;
}

public int getCurrentPosition() {
return position;
}

public String getName() {
return name;
}
}
70 changes: 70 additions & 0 deletions src/main/java/racingcar/CarGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package racingcar;

import camp.nextstep.edu.missionutils.Randoms;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class CarGame {
Copy link

@sh111-coder sh111-coder Dec 1, 2022

Choose a reason for hiding this comment

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

'CarGame'이라고 네이밍을 하면 어떤 역할을 가지는 객체인지
처음에 알기 힘들 것 같아요!
어떤 책임을 가지는 객체인지 알기 쉽게 네이밍 해주면 좋을 것 같습니다!

추가적으로 CarGame이 너무 많은 역할을 하고 있는 것 같아요.
MVC 패턴을 참고해서 클래스 분리를 하는 것이 좋을 것 같아요!


private final List<Car> cars;
private int moveCounts;

public CarGame() {
cars = new ArrayList<>();
}

public void registerCar(List<String> cars) {
validateCars(cars);
for (String carName : cars) {
this.cars.add(new Car(carName));
}
Comment on lines +19 to +21
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
for (String carName : cars) {
this.cars.add(new Car(carName));
}
this.cars = cars.stream()
.map(Car::new)
.collect(Collectors.toList());

이런식으로 map을 사용하는 코드는 어떠신가요?

Copy link
Author

Choose a reason for hiding this comment

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

이 부분에 대해서는 stream으로 처리할 생각을 못했는데
사용하는 것도 괜찮은거 같습니다.

Comment on lines +13 to +21
Copy link

Choose a reason for hiding this comment

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

Car 객체들을 registerCar 함수가 아닌, 컨트롤러에서 생성해 생성자 주입 방식을 사용하는 방법을 제안드립니다 !

}

private void validateCars(List<String> cars) {
if (cars.isEmpty()) {
throw new IllegalArgumentException(Message.NUMBER_OF_CARS_VALIDATION);
}
}

public List<Car> getCars() {

Choose a reason for hiding this comment

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

Collection에 getter를 사용할 때 그냥 Collection 자체를 return하게 되면
외부에서 Collection을 받아서 Collection 내부의 값을 변경할 수도 있으므로
Collections.unmodifiableList(cars)로 외부에서 내부의 값을 변경 못하도록 막아서 반환하는 게 좋을 것 같습니다!

Copy link
Member

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.

감사합니다 이 부분은 처음 알았네요!
적용해보겠습니다~!

return cars;
}

public void registerMoveCounts(int moveCounts) {
validateMoveCounts(moveCounts);
this.moveCounts = moveCounts;
}
Comment on lines +34 to +37
Copy link

Choose a reason for hiding this comment

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

도메인에서 한번 더 검증을 해줄 필요가 있을까? 라는 생각이 있었는데
결국 계층간의 의존성 없이 개발을 하기 위해서는 확실히 한번 더 검증을 해주는 것이 좋다는 느낌이 드는 것 같습니다 :D
잘 배우고 갑니다 !


private void validateMoveCounts(int moveCounts) {
if (moveCounts <= 0) {
throw new IllegalArgumentException(Message.MOVE_COUNTS_VALIDATION);
}
}

public void startRacing() {
if (checkIsOver()) {
throw new IllegalStateException(Message.GAME_OVER);
}
Comment on lines +46 to +48
Copy link
Member

Choose a reason for hiding this comment

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

MainController에서 while (!carGame.checkIsOver()) 하면서 반복하고 있는데 if문으로 한번 더 검증하는 로직은 불필요할 것 같아 보입니다!

for (Car car : cars) {
car.moveOrStop(getRandomFuel());
}
moveCounts--;

Choose a reason for hiding this comment

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

시도 횟수를 하나씩 줄여가면서 하는 것보다
for문으로 하나씩 늘려가면서 하는 게 가독성에 더 좋을 것 같습니다!

}

public boolean checkIsOver() {
return moveCounts <= 0;
Copy link
Member

Choose a reason for hiding this comment

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

0보다 작은 경우라고 표현하는 것보다 확실이 0일 경우 끝난다고 표현하는 것이 좋아보입니다

Copy link
Author

Choose a reason for hiding this comment

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

확실히 우석님이 말씀하신대로 작성하는게 side effect 가 없을 거 같네요!
감사합니댜!

}

private int getRandomFuel() {
return Randoms.pickNumberInRange(Car.MIN_FUEL, Car.MAX_FUEL);
}

public List<String> announceWinners() {
return cars.stream()
.filter(car -> car.getCurrentPosition() == cars.stream().map(Car::getCurrentPosition)

Choose a reason for hiding this comment

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

저도 Car에 Position을 얻기 위해 getter를 사용해서 받아왔었는데,
getter를 사용하는 대신 객체에 메시지를 보내자
이후에 생각나서 찾아보니
이 링크를 참고해서 Car 객체 내부에서 비교를 하도록 하는 것이 좋을 것 같습니다!

Copy link
Author

Choose a reason for hiding this comment

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

좋은 자료 감사합니다!!

.max(Integer::compareTo).orElse(0))
.map(Car::getName)
.collect(Collectors.toList());
}
}
57 changes: 57 additions & 0 deletions src/main/java/racingcar/MainController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package racingcar;

import java.util.List;
import racingcar.view.InputView;
import racingcar.view.OutputView;

public class MainController {

private final CarGame carGame;
private final InputView inputView;
private final OutputView outputView;

public MainController() {
Copy link

@sh111-coder sh111-coder Dec 1, 2022

Choose a reason for hiding this comment

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

클래스 변수로 받을 때 new로 생성 안하고,
생성자로 MainController가 생성될 때
new로 생성하는 이유가 따로 있나요?!

Copy link
Author

Choose a reason for hiding this comment

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

딱히 이유는 없었던거 같아요.
스프링 프로젝트를 할 때 생성자 주입을 사용하다보니 습관적으로 한거 같아요!

carGame = new CarGame();
inputView = new InputView();
outputView = new OutputView();
}

public void run() {
registerCars();
registerMoveCounts();
startRace();
endRace();
}

private void registerCars() {
try {
List<String> inputCars = inputView.inputCars();
carGame.registerCar(inputCars);
} catch (IllegalArgumentException e) {
outputView.printError(e.getMessage());
registerCars();
}
}

private void registerMoveCounts() {
try {
int moveCounts = inputView.inputMoveCounts();
carGame.registerMoveCounts(moveCounts);
} catch (IllegalArgumentException e) {
outputView.printError(e.getMessage());

Choose a reason for hiding this comment

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

catch에서 Error 메세지를 출력할 때,
저는 그냥 System.out.println으로 출력했는데
OutputView에 에러를 출력하는 기능을 만들어서
OutputView에게 에러 출력 책임을 맡기게 하는 것 잘 배워갑니다!

registerMoveCounts();
}
}

private void startRace() {
outputView.printRaceStart();
while (!carGame.checkIsOver()) {
Copy link

Choose a reason for hiding this comment

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

"게임을 종료할 수 없는 동안" 이라는 조건보다, "게임이 진행되는 동안"으로 표현한다면 좀 더 직관적일 것 같습니다.

carGame.startRacing();
outputView.printCars(carGame.getCars());
}
}

private void endRace() {
outputView.printWinners(carGame.announceWinners());
}
}
17 changes: 17 additions & 0 deletions src/main/java/racingcar/Message.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package racingcar;

public class Message {

public static final String CAR_NAME_VALIDATION = "자동차의 이름은 1~5자여야 합니다.";
public static final String CAR_FUEL_VALIDATION = "연료는 0 이상 9 이하의 값이어야 합니다.";
public static final String NUMBER_OF_CARS_VALIDATION = "등록할 자동차는 최소 1대여야 합니다.";
public static final String MOVE_COUNTS_VALIDATION = "이동횟수는 최소 1회 이상이어야 합니다.";
public static final String GAME_OVER = "경기가 종료되었습니다.";

public static final String INPUT_CAR_MESSAGE = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)";
public static final String INPUT_MOVE_COUNTS_MESSAGE = "시도할 회수는 몇회인가요?";
public static final String INPUT_NUMBER_ERROR = "숫자만 입력이 가능합니다.";

public static final String OUTPUT_RACE_RESULT = "\n실행 결과";

}
49 changes: 49 additions & 0 deletions src/main/java/racingcar/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package racingcar.view;

import camp.nextstep.edu.missionutils.Console;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import racingcar.Car;
import racingcar.Message;

public class InputView {

public static final String CAR_REGEX = ",";
private static final String ONLY_NUMBER_REGEX = "^[0-9]+$";

public List<String> inputCars() {
System.out.println(Message.INPUT_CAR_MESSAGE);

Choose a reason for hiding this comment

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

입력 문구를 출력하는 것도 출력하는 책임이라고 생각해서
출력 처리를 하는 책임을 가진 OutputView에서 처리하는 것이 좋을 것 같습니다!

Copy link
Author

Choose a reason for hiding this comment

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

흠..저도 프리코스 진행할 때 고민했었는데
저는 View라는 자체가 사용자에게 보여지는 계층이다 보니
입력에 필요한 출력은 어쩔수 없이 InputView에서 담당하는게 맞다고 생각했습니다.

Copy link

Choose a reason for hiding this comment

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

InputView 클래스 자체가 입력에 관한 책임을 가지기 때문에 저도 입력에 필요한 출력은 InputView에서 담당하는것이 좀 더 낫다고 생각합니다 !

String input = Console.readLine();
validateInputCars(input);
String[] inputCars = input.split(CAR_REGEX);
return Arrays.stream(inputCars).collect(Collectors.toList());
Comment on lines +20 to +21
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
String[] inputCars = input.split(CAR_REGEX);
return Arrays.stream(inputCars).collect(Collectors.toList());
return Arrays.stream(input.split(CAR_REGEX)).collect(Collectors.toList());

한번 밖에 쓰이지 않는 변수를 할당하는 것보다 합치는 것이 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

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

놓친거 같아요! 확실히 깔끔해보이네요~

}

private void validateInputCars(String input) {
if (input.endsWith(CAR_REGEX)) {
throw new IllegalArgumentException(Message.CAR_NAME_VALIDATION);
}

String[] inputCars = input.split(CAR_REGEX);
for (String inputCar : inputCars) {
if (inputCar.length() > Car.MAX_NAME_LENGTH) {
throw new IllegalArgumentException(Message.CAR_NAME_VALIDATION);
}
}
Comment on lines +30 to +34
Copy link
Member

Choose a reason for hiding this comment

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

자동차의 이름에 대한 유효성 검증은 Car 객체에서 하는 것이 좋아보이고 실제로 Car 클래스에서 하시고 계셔서 없어져도 좋을 코드 같습니다!

Copy link
Author

Choose a reason for hiding this comment

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

다시보니 검증에 대한 중복이 많네요!
신경써야할 거 같습니다 감사합니다~

}

public int inputMoveCounts() {
System.out.println(Message.INPUT_MOVE_COUNTS_MESSAGE);
String input = Console.readLine();
validateNumber(input);
return Integer.parseInt(input);
}

private void validateNumber(String input) {
if (!Pattern.matches(ONLY_NUMBER_REGEX, input)) {
throw new IllegalArgumentException(Message.INPUT_NUMBER_ERROR);
}
}
}
51 changes: 51 additions & 0 deletions src/main/java/racingcar/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package racingcar.view;

import java.util.List;
import racingcar.Car;
import racingcar.Message;

public class OutputView {

public static final String CAR_FORMAT = "%s : %s\n";
public static final String MOVE_UNIT = "-";
public static final String DELIMITER = ", ";
public static final String ERROR_SUFFIX = "[ERROR]";
public static final String WINNER_FORMAT = "최종 우승자 : %s";
public static final String ERROR_FORMAT = "%s %s\n";

public void printCars(List<Car> cars) {
for (Car car : cars) {
printCar(car);
}
printNewLine();
Copy link
Member

Choose a reason for hiding this comment

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

이런식으로 메서드를 만드는 것이 좋아보이네요 배워갑니다!

}

private void printNewLine() {
System.out.println();
}

public void printRaceStart() {
System.out.println(Message.OUTPUT_RACE_RESULT);
}

private void printCar(Car car) {
Copy link

@sh111-coder sh111-coder Dec 1, 2022

Choose a reason for hiding this comment

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

포맷으로 출력하는 System.put.printf를 몰랐었는데
건호님 코드 보고 알게 되었습니다! 감사합니다

System.out.printf(CAR_FORMAT, car.getName(), getMove(car.getCurrentPosition()));
}

private String getMove(int currentPosition) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < currentPosition; i++) {

Choose a reason for hiding this comment

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

반복문 변수도 i 말고 네이밍 해주는 것이 좋을 것 같습니다!

stringBuilder.append(MOVE_UNIT);
}
return stringBuilder.toString();
}

public void printWinners(List<String> winners) {
String winnersName = String.join(DELIMITER, winners);
System.out.printf(WINNER_FORMAT, winnersName);
}

public void printError(String errorMessage) {
System.out.printf(ERROR_FORMAT, ERROR_SUFFIX, errorMessage);
}
}
Loading