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

4단계 - 자동차 경주(우승자) #6054

Merged
merged 10 commits into from
Mar 23, 2025
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,12 @@
- [x] 자동차 전진하거나 멈추는 메서드 구현
- [x] 전진 조건 : 0에서 9 사이에서 random 값을 구한 후 random 값이 4이상일 경우
- [x] 입력받은 이동 수만큼 경기 진행하는 메서드 구현
- [x] 경기 진행 수와 자동차 상태 표시
- [x] 경기 진행 수와 자동차 상태 표시
- [x] 자동차에 name 받기
- [x] 자동차에 name 변수 추가
- [x] 자동차 name 쉼표(,)를 기준으로 구분
- [x] 자동차 객체에 name 포함한 생성자 만들기
- [x] 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력
- [x] 자동차에 name 받을 때 5자를 초과시 예외 발생
- [x] 우승자 표시 추가

12 changes: 9 additions & 3 deletions src/main/java/racing/RacingCarApplication.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
package racing;

import java.util.List;
import racing.domain.Racing;
import racing.view.InputView;
import racing.view.ResultView;

public class RacingCarApplication {

public static void main(String[] args) {
int carCount = InputView.getNumberOfCars();
String carNamesRaw = InputView.getNumberOfCars();
int roundCount = InputView.getNumberOfRounds();

Racing racing = new Racing(carCount);
Racing racing = new Racing(StringToArray(carNamesRaw));

System.out.println("실행 결과");

for (int i = 0; i < roundCount; i++) {
racing.simulateRace();
ResultView.printRaceResult(racing.getCars());
}
}

List<String> maxPosition = racing.findWinners();
System.out.println(String.join(", ", maxPosition) + "가 최종 우승했습니다.");
}

private static String[] StringToArray(String carNamesRaw) {
return carNamesRaw.split(",");
}
}
31 changes: 29 additions & 2 deletions src/main/java/racing/domain/Car.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,45 @@
public class Car {

private static final int MOVE_THRESHOLD = 4;
private static final int MAX_NAME_LENGTH = 5;
private static final int MIN_RANDOM_VALUE = 0;
private static final int MAX_RANDOM_VALUE = 9;

private int position;

private String name;

Choose a reason for hiding this comment

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

Suggested change
private String name;
private final String name;

name은 변경되지 않으므로 불변하게 수정 가능하겠네요!


public Car(String name) {
this(name, 0);
}

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

private void validateName(String name) {
if (name.length() > MAX_NAME_LENGTH) {
throw new IllegalArgumentException("자동차 이름은 " + MAX_NAME_LENGTH + "자를 초과할 수 없습니다.");
Comment on lines +24 to +26

Choose a reason for hiding this comment

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

자바 표준 예외 사용 👍

}
}

public int getPosition() {
return position;
}

public String getName() {
return name;
}

public void driveOrStop(int randomNumber) {
if (randomNumber < MIN_RANDOM_VALUE || randomNumber > MAX_RANDOM_VALUE) {
throw new IllegalArgumentException("랜덤 값은 0에서 9 사이여야 합니다.");
}

if (randomNumber >= MOVE_THRESHOLD) {
position++;
}
}


}
37 changes: 30 additions & 7 deletions src/main/java/racing/domain/Racing.java

Choose a reason for hiding this comment

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

다음 단계의 목표는 랜덤하게 구성되어있는 경우에 대해서도 테스트가능하도록 하는 것인데요. 만들어주신 RandomGenerator.generate()를 테스트가능한 구조로 만들어 Racing에서 랜덤에 의존하지 않고 simulateRace()를 테스트할 수 있도록 만들어주시면 됩니다. (추상화를 적절히 활용하는 방법을 고려해주시면 되어요)

Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import racing.RandomGenerator;

public class Racing {

List<Car> cars = new ArrayList<>();
private final List<Car> cars = new ArrayList<>();

Choose a reason for hiding this comment

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

List<Car>를 핵심적으로 다루는 객체가 되면서(움직임, 우승자) Racing보다는 "자동차들"을 관리한다는 이름을 잘 전달해주는 네이밍으로 변경해보면 어떨까요?

Copy link
Author

@yeonjiyeon yeonjiyeon Mar 23, 2025

Choose a reason for hiding this comment

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

@jinyoungchoi95 안녕하세요 진영님.
리뷰 감사합니다. 리뷰 주신 것들 반영 중 궁금한 것이 있어 메시지 드립니다.
해당 클래스에 simulateRace 메서드가 있어서
Racing 클래스를 두었는데, 혹시 그렇다면 car를 관리하는 다른 클래스로 분리하는 방법은 혹시 좋은 방법이 아닐까요?
아니면 simulateRace 메서드가 있어도 클래스명을 변경하는 것이 크게 상관이 없을까요?

Choose a reason for hiding this comment

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

simulateRace도 결국엔 cars를 실행시키는 기능을 진행하기 때문에 "레이싱"이라는 개념보다는 "자동차들"을 관리하는 느낌이 좀 더 강한 것 같아요.

Racing이라는 객체가 들어서려면 Cars를 가지고 round를 가지며 관리하는 등의 조금 더 상위의 개념이어야하지 않을까 싶습니다 😄


public Racing(int carCount) {
generateCars(carCount);
public Racing(String[] carNames) {
generateCars(carNames);
}

private List<Car> generateCars(int carCount) {
for (int i = 0; i < carCount; i++) {
cars.add(new Car());
}
public Racing(List<Car> cars) {
this.cars.addAll(cars);
}

private List<Car> generateCars(String[] carNames) {
for (String carName : carNames) {
cars.add(new Car(carName));
}
return cars;
}

Expand All @@ -30,5 +34,24 @@ public void simulateRace() {
}
}

public List<String> findWinners() {
int maxPosition = calculateMaxPosition();


return findMaxPosition(maxPosition);
}

private int calculateMaxPosition() {
return cars.stream()
.mapToInt(Car::getPosition)
.max()
.getAsInt();
}

private List<String> findMaxPosition(int maxPosition) {
return cars.stream()
.filter(car -> car.getPosition() == maxPosition)
.map(Car::getName)
.collect(Collectors.toList());
}
}
6 changes: 3 additions & 3 deletions src/main/java/racing/view/InputView.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ public class InputView {

private static final Scanner scanner = new Scanner(System.in);

public static int getNumberOfCars() {
System.out.print("자동차 대수는 몇 대 인가요?");
return scanner.nextInt();
public static String getNumberOfCars() {
System.out.print("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).");
return scanner.nextLine();
}

public static int getNumberOfRounds() {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/racing/view/ResultView.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class ResultView {

public static void printRaceResult(List<Car> cars) {
for (Car car : cars) {
System.out.println("-".repeat(car.getPosition()));
System.out.println(car.getName() + ":" + "-".repeat(car.getPosition()));
}
System.out.println();
}
Expand Down
24 changes: 0 additions & 24 deletions src/test/java/racing/CarTest.java

This file was deleted.

16 changes: 0 additions & 16 deletions src/test/java/racing/RacingTest.java

This file was deleted.

46 changes: 46 additions & 0 deletions src/test/java/racing/domain/CarTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package racing.domain;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import org.junit.jupiter.api.Test;
import racing.domain.Car;

public class CarTest {

Car car = new Car("pobi");

@Test
void 자동차_멈춤() {
car.driveOrStop(3);
assertThat(car.getPosition()).isEqualTo(0);
}

@Test
void 자동차_전진() {
car.driveOrStop(4);
assertThat(car.getPosition()).isEqualTo(1);
}

@Test
void 랜덤값_0미만_예외_발생() {
assertThatThrownBy(() -> car.driveOrStop(-1))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("랜덤 값은 0에서 9 사이여야 합니다.");
}

@Test
void 랜덤값_최대초과_예외_발생() {
assertThatThrownBy(() -> car.driveOrStop(10))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("랜덤 값은 0에서 9 사이여야 합니다.");
}

@Test
void 자동차_이름_5글자_초과() {
assertThatThrownBy(() -> new Car("longname"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("자동차 이름은 5자를 초과할 수 없습니다.");
}
}

35 changes: 35 additions & 0 deletions src/test/java/racing/domain/RacingTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package racing.domain;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import racing.domain.Car;
import racing.domain.Racing;

class RacingTest {

@Test
void 자동차_객체_생성() {
String[] carNames = {"pobi", "crong", "honux"};
assertThat(new Racing(carNames).getCars().size()).isEqualTo(3);

}

@Test
void 제일_높은_position_가진_자동차_구하기() {
Car pobi = new Car("pobi", 3);
Car jason = new Car("jason", 1);
Car brown = new Car("brown", 2);

List<Car> cars = List.of(pobi, jason, brown);

Racing racing = new Racing(cars);

List<String> winners = racing.findWinners();

assertThat(winners).containsExactlyInAnyOrder("pobi");
}

}