diff --git a/docs/step4.md b/docs/step4.md new file mode 100644 index 00000000000..e300daa261c --- /dev/null +++ b/docs/step4.md @@ -0,0 +1,13 @@ +## 기능 요구사항 +- 각 자동차에 이름을 부여할 수 있다. 자동차 이름은 5자를 초과할 수 없다. +- 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. +- 자동차 이름은 쉼표(,)를 기준으로 구분한다. +- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. + +## 기능 목록 +- [x] 자동차에 이름을 부여한다. +- [x] 자동차 이름이 5자를 초과하는지 검사한다. +- [x] 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. +- [x] 자동차 이름을 쉼표로 구분한다. +- [x] 자동차 경주 게임 우승자를 판별한다. +- [x] 자동차 경주 게임 우승자를 출력한다. \ No newline at end of file diff --git a/src/main/java/RacingCar.java b/src/main/java/RacingCar.java index ffde03625cf..d06a4b450a5 100644 --- a/src/main/java/RacingCar.java +++ b/src/main/java/RacingCar.java @@ -1,8 +1,7 @@ -import car.Car; -import car.Cars; +import domain.Cars; +import domain.WinnerDeterminer; import utils.*; -import java.util.List; import java.util.stream.IntStream; public class RacingCar { @@ -11,10 +10,10 @@ public static void main(String[] args) { } private static void play() { - int carCount = InputView.inputCarCount(); + String[] carNames = InputView.inputCarNames(); int tryCount = InputView.inputTryCount(); - Cars cars = new Cars(CarGenerator.generateCars(carCount)); + Cars cars = new Cars(Cars.generateCars(carNames)); OutputView.displayResultMessage(); NumberGenerator numberGenerator = new RandomNumberGenerator(); @@ -23,5 +22,7 @@ private static void play() { cars.moveAll(numberGenerator); OutputView.displayRoundResult(cars.getCars()); }); + + OutputView.displayWinners(WinnerDeterminer.findWinners(cars)); } } diff --git a/src/main/java/domain/Car.java b/src/main/java/domain/Car.java new file mode 100644 index 00000000000..f130783e073 --- /dev/null +++ b/src/main/java/domain/Car.java @@ -0,0 +1,53 @@ +package domain; + +import utils.NumberGenerator; + +public class Car { + private final static int BASE_NUMBER = 4; + private final static int MAX_NAME_LENGTH = 5; + private final String name; + private final Position position; + + public Car(String name) { + this(name, 0); + } + + public Car(String name, int position) { + validateName(name); + this.name = name; + this.position = new Position(position); + } + + public void move(NumberGenerator numberGenerator) { + int movableNumber = numberGenerator.generate(); + if (isAtLeastBaseNumber(movableNumber)) { + goForward(); + } + } + + private void goForward() { + this.position.increase(); + } + + public int getPosition() { + return this.position.getValue(); + } + + public String getName() { + return this.name; + } + + private boolean isAtLeastBaseNumber(int number) { + return BASE_NUMBER <= number; + } + + private void validateName(String name) { + if (exceedsMaxNameLength(name)) { + throw new IllegalArgumentException("자동차 이름은 5자 이하여야 합니다."); + } + } + + private boolean exceedsMaxNameLength(String name) { + return name.length() > MAX_NAME_LENGTH; + } +} diff --git a/src/main/java/domain/Cars.java b/src/main/java/domain/Cars.java new file mode 100644 index 00000000000..d68a59af92e --- /dev/null +++ b/src/main/java/domain/Cars.java @@ -0,0 +1,37 @@ +package domain; + +import utils.NumberGenerator; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class Cars { + List cars = new ArrayList<>(); + + public Cars(List cars) { + this.cars = cars; + } + + public static List generateCars(String[] carNames) { + return Arrays.stream(carNames) + .map(Car::new) + .collect(Collectors.toList()); + } + + public void moveAll(NumberGenerator numberGenerator) { + cars.forEach(car -> car.move(numberGenerator)); + } + + public List getPositions() { + return cars.stream() + .map(Car::getPosition) + .collect(Collectors.toList()); + } + + public List getCars() { + return List.copyOf(cars); + } + +} diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java new file mode 100644 index 00000000000..d28c16fc906 --- /dev/null +++ b/src/main/java/domain/Position.java @@ -0,0 +1,17 @@ +package domain; + +public class Position { + private int value; + + public Position(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } + + public void increase() { + this.value++; + } +} diff --git a/src/main/java/domain/WinnerDeterminer.java b/src/main/java/domain/WinnerDeterminer.java new file mode 100644 index 00000000000..9aad5c4fa78 --- /dev/null +++ b/src/main/java/domain/WinnerDeterminer.java @@ -0,0 +1,21 @@ +package domain; + +import java.util.List; +import java.util.stream.Collectors; + +public class WinnerDeterminer { + + public static List findWinners(Cars cars) { + int maxPosition = findMaxPosition(cars); + return cars.getCars().stream() + .filter(car -> car.getPosition() == maxPosition) + .collect(Collectors.toList()); + } + + private static int findMaxPosition(Cars cars) { + return cars.getCars().stream() + .mapToInt(Car::getPosition) + .max() + .orElse(0); + } +} \ No newline at end of file diff --git a/src/main/java/utils/InputView.java b/src/main/java/utils/InputView.java index 87459647ac9..969d7053723 100644 --- a/src/main/java/utils/InputView.java +++ b/src/main/java/utils/InputView.java @@ -3,13 +3,13 @@ import java.util.Scanner; public class InputView { - private static final String INPUT_CAR_COUNT_MESSAGE = "자동차 대수는 몇 대 인가요?"; + private static final String INPUT_CAR_NAMES_MESSAGE = "경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."; private static final String INPUT_TRY_COUNT_MESSAGE = "시도할 횟수는 몇 회 인가요?"; private static final Scanner scanner = new Scanner(System.in); - public static int inputCarCount() { - println(INPUT_CAR_COUNT_MESSAGE); - return toInt(inputNextLine()); + public static String[] inputCarNames() { + println(INPUT_CAR_NAMES_MESSAGE); + return splitCarNames(inputNextLine()); } public static int inputTryCount() { @@ -25,6 +25,10 @@ private static int toInt(String number) { return Integer.parseInt(number); } + private static String[] splitCarNames(String inputNames) { + return inputNames.split(","); + } + private static void println(String message) { System.out.println(message); } diff --git a/src/main/java/utils/OutputView.java b/src/main/java/utils/OutputView.java index a11e90372af..07471a1454b 100644 --- a/src/main/java/utils/OutputView.java +++ b/src/main/java/utils/OutputView.java @@ -1,15 +1,18 @@ package utils; -import car.Car; +import domain.Car; import java.util.List; +import java.util.stream.Collectors; public class OutputView { private static final String CAR_POSITION_MARK = "-"; private static final String RESULT_MESSAGE = "실행 결과"; + private static final String COLON = " : "; + private static final String WINNER_MESSAGE = "가 최종 우승했습니다."; public static void displayRoundResult(List cars) { - cars.forEach(car -> printCarPosition(car.getPosition())); + cars.forEach(car -> printCarPosition(car.getName(), car.getPosition())); println(); } @@ -17,8 +20,15 @@ public static void displayResultMessage() { println(RESULT_MESSAGE); } - private static void printCarPosition(int count) { - println(CAR_POSITION_MARK.repeat(count)); + public static void displayWinners(List winners) { + String winnerNames = winners.stream() + .map(Car::getName) + .collect(Collectors.joining(", ")); + println(winnerNames + WINNER_MESSAGE); + } + + private static void printCarPosition(String carName, int count) { + println(carName + COLON + CAR_POSITION_MARK.repeat(count)); } private static void println(String string) { diff --git a/src/test/java/domain/CarTest.java b/src/test/java/domain/CarTest.java new file mode 100644 index 00000000000..47137ea727c --- /dev/null +++ b/src/test/java/domain/CarTest.java @@ -0,0 +1,35 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import utils.FixedNumberGenerator; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; + +public class CarTest { + @Test + @DisplayName("숫자가 4 이상일 때 자동차가 전진한다.") + void 자동차_전진() { + Car car = new Car("pobi"); + car.move(new FixedNumberGenerator(4)); + assertThat(car.getPosition()).isEqualTo(1); + } + + @Test + @DisplayName("숫자가 4 미만일 때 자동차가 정지한다.") + void 자동차_정지() { + Car car = new Car("pobi"); + car.move(new FixedNumberGenerator(1)); + assertThat(car.getPosition()).isEqualTo(0); + } + + @Test + @DisplayName("자동차 이름이 5자가 넘으면 예외가 발생한다.") + void 자동차_이름_초과() { + assertThrows(IllegalArgumentException.class, () -> { + new Car("pobijjang"); + }); + } + +} diff --git a/src/test/java/domain/PositionTest.java b/src/test/java/domain/PositionTest.java new file mode 100644 index 00000000000..f6510574153 --- /dev/null +++ b/src/test/java/domain/PositionTest.java @@ -0,0 +1,14 @@ +package domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class PositionTest { + @Test + @DisplayName("value 값과 함께 position을 생성하면 position의 값이 4로 설정된다.") + void create() { + Position position = new Position(4); + Assertions.assertThat(position.getValue()).isEqualTo(4); + } +} diff --git a/src/test/java/domain/WinnerDeterminerTest.java b/src/test/java/domain/WinnerDeterminerTest.java new file mode 100644 index 00000000000..7e39341a5bf --- /dev/null +++ b/src/test/java/domain/WinnerDeterminerTest.java @@ -0,0 +1,41 @@ +package domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import utils.FixedNumberGenerator; +import utils.NumberGenerator; + +import java.util.List; + + +class WinnerDeterminerTest { + + @Test + @DisplayName("단독 우승자가 정상적으로 판별되어야 한다") + void 우승자_판별() { + Car car1 = new Car("pobi", 4); + Car car2 = new Car("crong", 3); + Car car3 = new Car("honux", 2); + + Cars cars = new Cars(List.of(car1, car2, car3)); + + Assertions.assertThat(WinnerDeterminer.findWinners(cars)).isEqualTo(List.of(car1)); + } + + @Test + @DisplayName("공동 우승자가 있을 경우, 모두 우승자로 판별되어야 한다") + void 공동_우승자_판별() { + Car car1 = new Car("pobi"); + Car car2 = new Car("crong"); + Car car3 = new Car("honux"); + + Cars cars = new Cars(List.of(car1, car2, car3)); + + NumberGenerator fixedNumberGenerator = new FixedNumberGenerator(4); + car1.move(fixedNumberGenerator); + car2.move(fixedNumberGenerator); + + Assertions.assertThat(WinnerDeterminer.findWinners(cars)).isEqualTo(List.of(car1, car2)); + } +} \ No newline at end of file