Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 기능 목록

## 입력
- 경주할 자동차 이름을 ,기준으로 입력받는다.
- 시도할 횟수를 입력받는다.

## 입력 검증
- 자동차 이름이 공백이거나 빈값이면 `IllegalArgumentException`을 발생시킨다.
- 자동차 이름이 5자를 초과하면 `IllegalArgumentException`을 발생시킨다.
- 자동차 이름이 중복되면 `IllegalArgumentException`을 발생시킨다.
- 시도할 횟수가 숫자가 아니면 `IllegalArgumentException`을 발생시킨다.
- 시도할 횟수가 1 미만이면 `IllegalArgumentException`을 발생시킨다.

## 자동차 이동
- 0~9 사이의 무작위 값을 발생시킨다.
- 무작위 값이 4 이상이면 전진한다.

## 출력
- 각 횟수별 실행 결과를 자동차 이름과 함께 출력한다.
- 최종 우승자를 출력한다.
- 우승자가 여러 명일 경우 ,로 구분하여 출력한다.
3 changes: 2 additions & 1 deletion src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

템플릿 TODO 주석이 그대로 남아 있어 제출 코드의 완성도를 떨어뜨립니다. 구현이 완료된 상태라면 해당 TODO 주석을 제거해 주세요.

Suggested change
// TODO: 프로그램 구현

Copilot uses AI. Check for mistakes.
new RunRacingGame().run();
}
}
}
Copy link
Copy Markdown
Collaborator

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.

넵 감사합니다.

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

import camp.nextstep.edu.missionutils.Console;
import racingcar.entity.Car;
import racingcar.entity.Cars;

import java.util.ArrayList;

import static racingcar.util.Utils.isValidNumber;
import static racingcar.util.Utils.splitNames;

public class RunRacingGame {
public void run() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.

현재 run() 메소드는 너무 많은 일을 하고 있는 거 같아요 !
부분부분 메소드로 분리해보면 어떨까요 ?

System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");
String[] carNames = splitNames(Console.readLine());
System.out.println("시도할 회수는 몇회인가요?");
int number = isValidNumber(Console.readLine());

ArrayList<Car> carsList = new ArrayList<>();
for (String carName : carNames) {
Car car = new Car(carName);
carsList.add(car);
}

System.out.println("\n실행 결과");
Cars cars = new Cars(carsList);
for (int i = 0; i < number; i++) {
cars.moveAllCars();
cars.printMoveResult();
}
cars.printWinner();
}
}
29 changes: 29 additions & 0 deletions src/main/java/racingcar/entity/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package racingcar.entity;

import camp.nextstep.edu.missionutils.Randoms;
import racingcar.util.Utils;

public class Car {
private final String name;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

final 선언을 한 이유가 있으신가요?

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.

이름의 값은 변하지 않는다와 혹시 모를 이름 변경이 되는 것을 막기 위해 final로 선언했습니다.

private int moveCnt;

public Car(String name) {
Utils.isValidName(this.name = name);
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

생성자에서 Utils.isValidName(this.name = name)처럼 대입을 인자에서 수행하면 가독성이 떨어지고(필드 초기화/검증 순서가 한 줄에 섞임) 디버깅도 어려워집니다. 먼저 파라미터 name을 검증한 뒤, 검증 통과 시에만 필드에 대입하도록 분리해 주세요.

Suggested change
Utils.isValidName(this.name = name);
Utils.isValidName(name);
this.name = name;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

@dh2906 dh2906 Mar 29, 2026

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.

넵 감사합니다!

this.moveCnt = 0;
}

public String getName() {
return this.name;
}

public int getMoveCnt() {
return this.moveCnt;
}

public void setMoveCnt() {
int RandomNum = Randoms.pickNumberInRange(0, 9);
if (RandomNum >= 4) {
Comment on lines +23 to +25
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

setMoveCnt()는 일반적인 setter처럼 보이지만 실제로는 난수에 따라 이동을 수행합니다. API 의미가 불명확해 호출부(Cars.moveAllCars)도 읽기 어려우니 move()/tryMove() 등 동작을 드러내는 이름으로 바꾸고, 로컬 변수명도 Java 컨벤션에 맞게 lowerCamelCase(예: randomNumber)로 정리해 주세요.

Suggested change
public void setMoveCnt() {
int RandomNum = Randoms.pickNumberInRange(0, 9);
if (RandomNum >= 4) {
public void move() {
int randomNumber = Randoms.pickNumberInRange(0, 9);
if (randomNumber >= 4) {

Copilot uses AI. Check for mistakes.
this.moveCnt += 1;
}
Comment on lines +24 to +27
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
int RandomNum = Randoms.pickNumberInRange(0, 9);
if (RandomNum >= 4) {
this.moveCnt += 1;
}
if (Randoms.pickNumberInRange(0, 9) >= 4) {
this.moveCnt += 1;
}

이렇게 할 수도 있어 보여요.

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.

넵 감사합니다!

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

import java.util.ArrayList;

public class Cars {
private ArrayList<Car> cars;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

타입이 List가 아닌 ArrayList로 둔 이유가 있으신가요??

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.

java 입문서에서 ArrayList로 선언하는 예제를 보고 그대로 사용했습니다.


public Cars(ArrayList<Car> cars) {
this.cars = cars;
Comment on lines +4 to +9
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Cars 생성자가 ArrayList<Car>를 그대로 받아 필드에 저장하면 외부에서 전달된 리스트를 수정해 내부 상태가 예기치 않게 변할 수 있습니다. 타입은 List<Car>로 받도록 좁히고, 내부에서는 방어적 복사(예: new ArrayList<>(cars)) 및 final 필드로 불변성을 높여 주세요.

Suggested change
public class Cars {
private ArrayList<Car> cars;
public Cars(ArrayList<Car> cars) {
this.cars = cars;
import java.util.List;
public class Cars {
private final List<Car> cars;
public Cars(List<Car> cars) {
this.cars = new ArrayList<>(cars);

Copilot uses AI. Check for mistakes.
}

public void moveAllCars() {
for (Car car : this.cars) {
car.setMoveCnt();
}
}

public void printMoveResult() {
for (Car car : this.cars) {
System.out.println(car.getName() + " : " + "-".repeat(car.getMoveCnt()));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

String의 repeat 메소드 좋습니다 !
자바에도 형식을 지정해서 출력하는 메소드 System.out.printf()가 존재합니다. 추가적으로 알아보면 좋을 거 같아요 !

}
System.out.println();
}
Comment on lines +18 to +23
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Cars가 도메인 컬렉션 역할을 하면서 System.out.println로 출력까지 수행하면 도메인 로직과 I/O가 결합되어 테스트/확장이 어려워집니다. 이동 결과/우승자 정보를 문자열 또는 DTO로 반환하고, 출력은 별도 View/Printer(또는 RunRacingGame)로 위임하는 구조로 분리해 주세요.

Copilot uses AI. Check for mistakes.

private int findMaxMoveCnt() {
int max = 0;
for (Car car : this.cars) {
if (car.getMoveCnt() > max) {
max = car.getMoveCnt();
}
}
return max;
}
Comment on lines +25 to +33
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

depth를 더 줄인다면 이렇게도 될 거 같아요 !
Java에서 기본적으로 제공해주는 유용한 메소드들도 많아서, 한 번 찾아보면 좋을 거 같아요 👍

Suggested change
private int findMaxMoveCnt() {
int max = 0;
for (Car car : this.cars) {
if (car.getMoveCnt() > max) {
max = car.getMoveCnt();
}
}
return max;
}
private int findMaxMoveCnt() {
int max = -1;
for (Car car : this.cars) {
max = Math.max(max, car.getMoveCnt();
}
return max;
}


private ArrayList<String> findWinners(int max) {
ArrayList<String> winners = new ArrayList<>();
for (Car car : this.cars) {
if (car.getMoveCnt() == max) {
winners.add(car.getName());
}
}
Comment on lines +37 to +41
Copy link
Copy Markdown
Collaborator

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.

넵 한번 적용해보겠습니다!

return winners;
}

public void printWinner() {
ArrayList<String> winners = findWinners(findMaxMoveCnt());
System.out.println("최종 우승자 : " + String.join(", ", winners));
}
}
38 changes: 38 additions & 0 deletions src/main/java/racingcar/util/Utils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package racingcar.util;

import java.util.HashSet;

public class Utils {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

이 클래스의 역할은 주로 입력된 값을 검증하므로 ~~Validator 같은 네이밍도 좋아 보여요!

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.

넵! 감사합니다


Comment on lines +5 to +6
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Utils는 static 메서드만 제공하는 유틸 클래스인데 public 기본 생성자가 열려 있어 인스턴스화가 가능합니다. 의도치 않은 사용을 막기 위해 final 클래스로 만들고 private 생성자를 추가하는 방식으로 유틸리티 클래스를 고정해 주세요.

Suggested change
public class Utils {
public final class Utils {
private Utils() {
// Utility class; prevent instantiation
}

Copilot uses AI. Check for mistakes.
public static void isValidName(String name) {
if (name.isBlank() || name.contains(" ")) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

isBlank()가 공백 글자도 잘 잡는걸로 아는데 조건을 하나 더 쓴 이유가 있으신가요??

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.

이름 중간에 공백이 들어갈 시 isBlank가 검증에 실패할 때도 있어서 contain 조건도 추가했습니다.

throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}
Comment on lines +8 to +10
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

이름 공백 검증이 name.contains(" ")로 되어 있어 탭(\t), 개행(\n) 같은 다른 공백 문자가 포함된 경우는 통과할 수 있습니다. 요구사항이 '공백 포함 불가'라면 Character.isWhitespace/정규식(\s) 등으로 모든 whitespace를 차단하도록 검증을 강화해 주세요.

Suggested change
if (name.isBlank() || name.contains(" ")) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}
if (name.chars().anyMatch(Character::isWhitespace)) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}

Copilot uses AI. Check for mistakes.
if (name.length() > 5) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

5라는 숫자는 매직넘버라 추후에 요구사항으로 최대 이름의 글자수가 변경된다면 글자수와 관련된 모든 로직에 수정이 필요해질 수 있어요.
그러므로 이는 상수로 분리하는 것을 추천드립니다!

자료 참고해주세요!

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.

넵! 감사합니다

throw new IllegalArgumentException("5글자 초과했습니다.");
}
Comment on lines +8 to +13
Copy link
Copy Markdown
Collaborator

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.

넵 감사합니다.

}

public static int isValidNumber(String input) {
try {
int number = Integer.parseInt(input);
if (number < 1) {
throw new IllegalArgumentException("1 미만의 숫자는 입력할 수 없습니다.");
}
return number;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("숫자를 입력해야 합니다.");
}
}

public static String[] splitNames(String input) {
String[] names = input.split(",");
HashSet<String> set = new HashSet<>();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Set 자료구조는 무엇이고, HashSet와는 무슨 차이가 있을까요?

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.

Set은 인터페이스고 HashSet은 인터페이스를 이용한 클래스로 알고있습니다.

for (String name : names) {
if (!set.add(name)) {
throw new IllegalArgumentException("이름 중복은 허용 안됩니다.");
}
}
return names;
Comment on lines +28 to +36
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

String#split(",")은 기본 동작상 뒤쪽의 빈 토큰을 제거합니다. 예를 들어 입력이 "pobi,woni," 또는 "pobi,," 처럼 끝에 쉼표가 오면 마지막 빈 이름이 배열에서 사라져 빈값 검증이 누락될 수 있습니다. trailing empty token을 보존하도록 split에 limit(-1)을 사용하고, 생성된 토큰에 대해 빈 문자열도 예외 처리되도록 해주세요.

Copilot uses AI. Check for mistakes.
}
}
Loading