Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5782e25
feat: 입력 기능 추가
Mar 27, 2026
f8158ca
feat: 차수별 실행 결과 출력 추가
Mar 27, 2026
2ef3bd5
feat: 자동차 전진 기능 추가
Mar 27, 2026
7609a87
feat: 우승자 안내 문구 출력 추가
Mar 27, 2026
c8dabab
feat: 예외처리 추가
Mar 27, 2026
8a2c008
docs: 기능리스트 작성, refactor: Random, Scanner 변경
Mar 30, 2026
3c60903
feat: 예외처리 추가
Mar 30, 2026
a434709
docs: 기능리스트 수정
Apr 3, 2026
ed3c3a3
refactor: Car 클래스 작성
Apr 4, 2026
81acf3d
refactor: Racing 클래스 작성
Apr 4, 2026
cc6a200
refactor: View 클래스 작성
Apr 4, 2026
2cbf37c
refactor: Application 클래스 리팩토링, View 클래스 우승자 출력 작성
Apr 4, 2026
f6ca1ad
refactor: Application 클래스 예외처리 함수명 변경
Apr 4, 2026
4ff8bc8
refactor: Winner 클래스 작성
Apr 4, 2026
23cb018
style: 공백 제거
Apr 4, 2026
6e3e1ad
refactor: Car 클래스 생성자 예외처리 추가
Apr 4, 2026
269196a
refactor: 메소드 관례에 맞춰 이름 변경
Apr 6, 2026
0cefb8c
refactor: 개행 방법 변경
Apr 6, 2026
847980f
refactor: 자동차 움직이는 조건 상수로 변경
Apr 6, 2026
5b4f821
refactor: Cars 클래스 작성
Apr 6, 2026
42c7cd2
refactor: View클래스명 변경
Apr 6, 2026
524e707
refactor: InputView클래스 작성
Apr 6, 2026
ad58b59
refactor: Cars 클래스 메소드 연동
Apr 6, 2026
566231d
refactor: OutputView 클래스 실행결과 메소드 추가
Apr 6, 2026
e7bce28
refactor: InputValidator 클래스 작성
Apr 6, 2026
725854b
refactor: RacingController 클래스 작성, 패키지 생성 및 분류
Apr 6, 2026
6400245
refactor: Racing 클래스 삭제
Apr 6, 2026
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
28 changes: 28 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
자동차 경주
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

마크다운 파일로 구현해야될 것들 정리해주신 부분 좋습니다!!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

감사합니다! 다음에는 클래스들의 역할과 구조를 추가해서 적어보겠습니다.

-

`기능`

입력 기능
- 각 자동차에 이름 부여(쉼표를 기준으로 구분하여 입력)
- 몇 번의 이동을 할 것인지 입력

차수별 실행 결과 출력 기능
- 사용자 입력값에 기반해 차수만큼 자동차 진행결과 출력

자동차 전진 기능
- [전진] : 0~9 사이에서 무작위 값을 구한 후 4 이상이면 자동차 '-' 출력
- [멈춤] : 4미만이면 정지. 출력X

우승자 안내 문구 출력 기능
- 우승자 안내, 쉼표로 우승자 나열

`예외처리`
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

예외처리도 프로그램 설계할 때 정말 중요한 요소입니다
우선 작성해주신 코드를 봤을 때는 깔끔하게 예외처리 잘 해주신 것 같습니다!

추가로 다른 예외 상황(시도횟수에 소숫점을 입력했을 때, 시도횟수에 너무 큰 수를 입력했을 때 등)들도 있을지 더 고민해보시면 좋을 것 같습니다

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

예외처리를 test파일에 있는 것만 생각했었는데 더 완벽한 프로그램을 위해서는 추가해야할 것 같습니다. 조언 감사합니다.


- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생
- 자동차 이름 5자 초과
- 이름 공백 포함
- 이름 빈값
- 이름 중복
- 시도 횟수 0이하
- 시도 횟수 숫자 아님
4 changes: 3 additions & 1 deletion src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package racingcar;

import racingcar.controller.RacingController;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
RacingController.startRacing();
}
}
35 changes: 35 additions & 0 deletions src/main/java/racingcar/controller/RacingController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package racingcar.controller;

import racingcar.util.InputValidator;
import racingcar.view.InputView;
import racingcar.view.OutputView;
import racingcar.domain.Car;
import racingcar.domain.Cars;

import java.util.HashSet;

public class RacingController {

public static void startRacing() {
HashSet<String> uniqueElements = new HashSet<>();

String carName = InputView.getCarName();

InputValidator.validCarName(carName); // 예외처리

String[] tokens = carName.split(",");

Cars.validEqualName(tokens, uniqueElements); // 예외처리

Comment on lines +17 to +23
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

InputValidatr.validCarName() , Cars.validEqualName() 둘다 자동차와 관련된 검증인 것 같은데, 두 메소드를 서로 다른 클래스에 배치한 이유가 있을까요?

Car[] cars = Cars.rappingCars(tokens);

String racingCount = InputView.getTryCount();
int counts = InputValidator.validTryCountNum(racingCount); // 예외처리
InputValidator.validTryCount(counts); // 예외처리

OutputView.viewStartResult(tokens, counts, cars);

OutputView view = new OutputView();
view.viewWinner(cars);
}
}
37 changes: 37 additions & 0 deletions src/main/java/racingcar/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package racingcar.domain;

public class Car {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

작성해주셨던 위의 코드의 자동차 검증 관련(이름 길이, 빈칸 체크 등)을 여기 Car 객체 내의 private 메소드로 옮겨서 수행해주는 방법도 있습니다
또한 자동차 생성 시점에 이를 바로 확인시켜줄 수도 있습니다

public Car(String carName) {
  this.carName = carName;
  this.movement = 0;
  validateCar();
}

private void validateCar() {
  validateDuplicate();
  validateBlank();
  validateLength();
}

private void validateBlank() {
  if (carName.isBlank()) {
                throw new IllegalArgumentException("자동차 이름은 공백일 수 없습니다.");
  }
}

...

private String carName;
private int movement;

public Car(String carName) {
if (carName.isEmpty()) {
throw new IllegalArgumentException("자동차를 적어야합니다.");
}
else if (carName.length() > 5) {
throw new IllegalArgumentException("자동차 이름은 5자 이하만 가능합니다.");
}
else if (carName.isBlank()) {
throw new IllegalArgumentException("자동차 이름을 적어야 합니다.");
}
else if (carName.contains(" ")) {
throw new IllegalArgumentException("자동차 이름에 공백은 불가능합니다.");
}
else {
this.carName = carName;
}
this.movement = 0;
}

public void move() {
movement += 1;
}

public String checkCarName() {
return carName;
}
Comment on lines +30 to +32
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

아래 checkMovement() 과 마찬가지로,
보통 객체의 필드 값을 가져오는 메소드는 get___() 으로 이름 짓는 것이 관례입니다

intelliJ 내에서 Shift + Insert 키 누르시면 Getter와 Setter 메소드를 자동으로 넣어주는 기능도 있으니 사용해보시는 것을 추천드립니다!

public String getCarName() {
  return carName();
}


public int checkMovement() {
return movement;
}
}
54 changes: 54 additions & 0 deletions src/main/java/racingcar/domain/Cars.java
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cars 클래스는 도메인 보다는 Car 에 대한 검증들이나 기능들을 모아둔 것 같은데, CarUtils, CarValidator 등으로 이름을 바꾼 다음 util 디렉토리로 옮기는 것이 더 좋아보입니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package racingcar.domain;

import camp.nextstep.edu.missionutils.Randoms;
import java.util.HashSet;

public class Cars {
private static final int CAR_MOVE_STANDARD = 4;

public static Car[] rappingCars(String[] tokens) {
Car[] cars = new Car[tokens.length];
for (int i = 0; i < tokens.length; i++) {
cars[i] = new Car(tokens[i]);
}

return cars;
}

public static void validEqualName(String[] tokens, HashSet<String> uniqueElements) {
for (String token : tokens) {
if (!uniqueElements.add(token)) {
throw new IllegalArgumentException("자동차 이름이 중복됩니다.");
}
}
}

public static void goOrStop(Car car) {
int randomNum = Randoms.pickNumberInRange(0, 9);
if (randomNum >= CAR_MOVE_STANDARD) {
car.move();
}
}

public static StringBuilder calculateWinner(Car[] cars) {
int max = cars[0].checkMovement();
StringBuilder sb = new StringBuilder();

for (Car car : cars) {
if (max < car.checkMovement()) {
max = car.checkMovement();
}
}

for (Car car : cars) {
if (car.checkMovement() == max) {
if (!sb.isEmpty()) {
sb.append(", ");
}
sb.append(car.checkCarName());
}
}

return sb;
}
}
28 changes: 28 additions & 0 deletions src/main/java/racingcar/util/InputValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package racingcar.util;

public class InputValidator {

public static void validCarName(String carName) {
if (carName == null || carName.isBlank()) {
throw new IllegalArgumentException("이름을 입력하지 않았습니다.");
}
Comment on lines +5 to +8
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

이 부분은 상술했듯이 Car 객체 내부 메소드로 옮기거나, 아니면 CarValidator 클래스를 만든 다음 그곳으로 옮기는 것이 좀 더 옳은 방향인 것 같습니다


if (carName.endsWith(",")) {
throw new IllegalArgumentException("마지막은 쉼표로 끝날 수 없습니다.");
}
}

public static void validTryCount(int counts) {
if (counts < 1) {
throw new IllegalArgumentException("시도 횟수는 0보다 커야합니다.");
}
}

public static int validTryCountNum(String racingCount) {
try {
return Integer.parseInt(racingCount);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("시도 횟수는 숫자여야합니다.");
}
}
}
18 changes: 18 additions & 0 deletions src/main/java/racingcar/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package racingcar.view;

import camp.nextstep.edu.missionutils.Console;

public class InputView {

public static String getCarName() {
System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");

return Console.readLine();
}

public static String getTryCount() {
System.out.println("시도할 횟수는 몇 회인가요?");

return Console.readLine();
}
}
23 changes: 23 additions & 0 deletions src/main/java/racingcar/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package racingcar.view;

import racingcar.domain.Car;
import racingcar.domain.Cars;

public class OutputView {

public static void viewStartResult(String[] tokens, int counts, Car[] cars) {
System.out.print('\n');
System.out.println("실행 결과");
for (int i = 0; i < counts; i++) {
Comment on lines +8 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

메소드 이름이 조금 모호한 것 같은데, 경기 상황을 출력하는 메소드이므로 viewRaceStatus 등으로 바꾸는 것이 좀더 적절해보여요! 이에 대한 지호님의 의견도 궁금합니다..!

for (int j = 0; j < tokens.length; j++) {
Cars.goOrStop(cars[j]);
System.out.println(cars[j].checkCarName() + " : " + "-".repeat(cars[j].checkMovement()));
}
System.out.print('\n');
}
}

public void viewWinner(Car[] cars) {
System.out.println("최종 우승자 : " + Cars.calculateWinner(cars));
}
}
1 change: 1 addition & 0 deletions src/test/java/racingcar/ApplicationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class ApplicationTest extends NsTest {
assertThat(output()).contains("pobi : -", "woni : ", "최종 우승자 : pobi");
},
MOVING_FORWARD, STOP

);
}

Expand Down