diff --git a/build.gradle b/build.gradle index 239f9e78..8a3d0ff4 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,8 @@ dependencies { testImplementation platform('org.assertj:assertj-bom:3.25.1') testImplementation('org.junit.jupiter:junit-jupiter') testImplementation('org.assertj:assertj-core') + testImplementation 'org.mockito:mockito-core:5.7.0' + testImplementation 'org.mockito:mockito-junit-jupiter:5.7.0' } test { diff --git a/src/main/java/RacingGameApplication.java b/src/main/java/RacingGameApplication.java new file mode 100644 index 00000000..68752301 --- /dev/null +++ b/src/main/java/RacingGameApplication.java @@ -0,0 +1,16 @@ +import domain.RacingGame; +import view.InputView; +import view.ResultView; + +public class RacingGameApplication { + + public static void main(String[] args) throws Exception { + final var carNames = InputView.getCarNames(); + final var tryCount = InputView.getRaceRounds(); + + final var racingGame = new RacingGame(carNames, tryCount); + racingGame.gameStart(); + + ResultView.printWinners(racingGame.getWinner()); + } +} diff --git a/src/main/java/domain/Car.java b/src/main/java/domain/Car.java new file mode 100644 index 00000000..43bb8e06 --- /dev/null +++ b/src/main/java/domain/Car.java @@ -0,0 +1,27 @@ +package domain; + +public class Car { + + private final String name; + private int position; + private static final int MOVE_TRIGGER = 4; + + public Car(String name) { + this.name = name; + this.position = 0; + } + + public void move(int value) { + if (value >= MOVE_TRIGGER) { + position++; + } + } + + public String getName() { + return name; + } + + public int getPosition() { + return position; + } +} diff --git a/src/main/java/domain/RacingGame.java b/src/main/java/domain/RacingGame.java new file mode 100644 index 00000000..372ff8ea --- /dev/null +++ b/src/main/java/domain/RacingGame.java @@ -0,0 +1,76 @@ +package domain; + +import java.util.*; +import java.util.stream.Collectors; + +public class RacingGame { + + private final List cars; + private final int rounds; + private Random random; + + public RacingGame(String[] carsName, int rounds) { + this.cars = createCars(carsName); + this.rounds = rounds; + } + + public RacingGame(List cars, int rounds) { + this.cars = cars; + this.rounds = rounds; + } + + public RacingGame(String[] carsName, int rounds, Random random) { + this.cars = createCars(carsName); + this.rounds = rounds; + this.random = random; + } + + public List getCars() { + return cars; + } + + private List createCars(String[] carNames) { + List cars = new ArrayList<>(); + for (String name : carNames) { + cars.add(new Car(name.trim())); + } + return cars; + } + + public void gameStart() { + for (int i = 0; i < rounds; i++) { + moveCars(); + System.out.println(); + } + } + + private void moveCars() { + for (Car car : cars) { + System.out.print(car.getName() + " : "); + int randomValue = random.nextInt(10); + car.move(randomValue); + System.out.print("-".repeat(car.getPosition())); + System.out.println(); + } + } + + public List getWinner() { + int maxPosition = getMaxPosition(); + return cars.stream() + .filter(car -> car.getPosition() == maxPosition) + .collect(Collectors.toUnmodifiableList()); + } + + private int getMaxPosition() { + return cars.stream() + .mapToInt(Car::getPosition) + .max() + .orElse(0); + } + + public String findWinnerName(List winnerCars) { + return winnerCars.stream() + .map(car -> car.getName()) + .collect(Collectors.joining(", ")); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..3e2d3fac --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,45 @@ +package view; + +import java.util.Scanner; + +public class InputView { + + private static final int MAX_NAME_LENGTH = 5; + private static final Scanner scanner = new Scanner(System.in); + + private static String getUserInput() { + System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); + return scanner.nextLine(); + } + + private static String[] splitCarNames(String inputValue) { + return inputValue.split(","); + } + + public static String[] getCarNames() throws Exception { + String inputValue = getUserInput(); + String[] carsName = splitCarNames(inputValue); + + validateName(carsName); + return carsName; + } + + private static void validateName(String[] carsName) throws Exception { + for (String carName : carsName) { + validateInput(carName); + } + } + + public static void validateInput(String carName) throws Exception { + if (carName.length() > MAX_NAME_LENGTH) { + throw new Exception("자동차 이름은 " + MAX_NAME_LENGTH + "자 이하여야합니다."); + } + } + + public static int getRaceRounds() { + System.out.println("시도할 회수는 몇회인가요?"); + int rounds = scanner.nextInt(); + System.out.println(); + return rounds; + } +} diff --git a/src/main/java/view/ResultView.java b/src/main/java/view/ResultView.java new file mode 100644 index 00000000..58c6e3b3 --- /dev/null +++ b/src/main/java/view/ResultView.java @@ -0,0 +1,16 @@ +package view; + +import domain.Car; + +import java.util.List; + +public class ResultView { + + public static void printWinners(List winnerCars) { + System.out.println("실행 결과"); + String winnerNames = String.join(", ", + winnerCars.stream().map(Car::getName).toArray(String[]::new) + ); + System.out.println(winnerNames + "가 최종 우승했습니다."); + } +} diff --git a/src/test/java/domain/CarTest.java b/src/test/java/domain/CarTest.java new file mode 100644 index 00000000..fef0b42f --- /dev/null +++ b/src/test/java/domain/CarTest.java @@ -0,0 +1,32 @@ +package domain; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +class CarTest { + + @Test + void 자동차_생성_테스트() { + String inputNames = "haeun, minji, god"; + String [] carNames = inputNames.split(", "); + + RacingGame racingGame = new RacingGame(carNames,5); + + List cars = racingGame.getCars(); + + assertThat(cars).hasSize(3); + } + + @Test + void move_값이_4이상이면_전진한다() { + Car car = new Car("람보르기니"); + car.move(5); + assertThat(1).isEqualTo(car.getPosition()); + + car.move(9); + assertThat(2).isEqualTo(car.getPosition()); + } +} diff --git a/src/test/java/domain/RacingGameTest.java b/src/test/java/domain/RacingGameTest.java new file mode 100644 index 00000000..4129f6a9 --- /dev/null +++ b/src/test/java/domain/RacingGameTest.java @@ -0,0 +1,53 @@ +package domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class RacingGameTest { + + private RacingGame racingGame; + private Random mockRandom; + + @BeforeEach + void setUp() { + mockRandom = mock(Random.class); + racingGame = new RacingGame(new String[]{"haeun", "ram", "com"}, 1, mockRandom); + } + + @Test + void moveCars_랜덤값을_5로_고정하여_이동_테스트() { + when(mockRandom.nextInt(10)).thenReturn(5); + + List cars = racingGame.getWinner(); + int beforePosition = cars.get(0).getPosition(); + + cars.get(0).move(mockRandom.nextInt(10)); + assertEquals(beforePosition + 1, cars.get(0).getPosition()); + } + + @Test + void get_winner_테스트() { + + Car car1 = new Car("haeun"); + Car car2 = new Car("ram"); + Car car3 = new Car("com"); + + car1.move(3); + car2.move(9); + car2.move(5); + car3.move(5); + car3.move(9); + + RacingGame game = new RacingGame(List.of(car1, car2, car3), 1); + List winners = game.getWinner(); + + assertTrue(winners.contains(car2)); + assertTrue(winners.contains(car3)); + } +} diff --git a/src/test/java/view/InputViewTest.java b/src/test/java/view/InputViewTest.java new file mode 100644 index 00000000..dd7145da --- /dev/null +++ b/src/test/java/view/InputViewTest.java @@ -0,0 +1,21 @@ +package view; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class InputViewTest { + + @Test + void 자동차_이름_5자_넘으면_예외_발생_테스트() { + Exception exception = assertThrows(Exception.class, () -> { + InputView.validateInput("moremore"); + }); + assertEquals("자동차 이름은 5자 이하여야합니다.", exception.getMessage()); + } + + @Test + void 자동차_이름이_5자_이하면_예외가_발생하지_않는다() { + assertDoesNotThrow(() -> InputView.validateInput("haeun")); + assertDoesNotThrow(() -> InputView.validateInput("ram")); + } +} \ No newline at end of file diff --git a/src/test/java/view/ResultViewTest.java b/src/test/java/view/ResultViewTest.java new file mode 100644 index 00000000..c0639380 --- /dev/null +++ b/src/test/java/view/ResultViewTest.java @@ -0,0 +1,27 @@ +package view; + +import domain.Car; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class ResultViewTest { + + @Test + void 우승자_이름을_올바르게_출력하는지_테스트() { + List winnerCars = List.of( + new Car("haeun"), + new Car("ram"), + new Car("com") + ); + + String expected = "haeun, ram, com"; + + assertEquals(expected, String.join(", ", + winnerCars.stream() + .map(Car::getName) + .toArray(String[]::new))); + } +}