diff --git a/src/main/java/step3/Main.java b/src/main/java/step3/Main.java index 0d67957593b..8b58872c21f 100644 --- a/src/main/java/step3/Main.java +++ b/src/main/java/step3/Main.java @@ -1,10 +1,7 @@ package step3; -import step3.game.Car; -import step3.game.CarFactory; -import step3.game.GameHistory; -import step3.game.RacingGame; +import step3.game.*; import step3.random.DefaultRandomStrategy; import step3.util.InputView; import step3.util.OutputView; @@ -12,14 +9,15 @@ import java.util.List; public class Main { - private static final String CAR_NAME_MESSAGE = "경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."; - private static final String MOVE_COUNT_MESSAGE = "시도할 회수는 몇 회 인가요?"; public static void main(String[] args) { - String carNames = InputView.inputString(CAR_NAME_MESSAGE); - int moveCount = InputView.inputInt(MOVE_COUNT_MESSAGE); + String carNames = InputView.inputCarNames(); + int moveCount = InputView.inputMove(); + List cars = CarFactory.createCars(carNames); - RacingGame game = new RacingGame(moveCount, new DefaultRandomStrategy(), cars); - List> result = game.start(); - OutputView.printResult(result, game.getCurrentWinners()); + + RacingGame game = new RacingGame(moveCount, cars); + List result = game.start(new DefaultRandomStrategy()); + + OutputView.printResult(result, Winners.findWinners(result)); } } \ No newline at end of file diff --git a/src/main/java/step3/game/Car.java b/src/main/java/step3/game/Car.java index 1d6d07c6dbc..54a30c2e521 100644 --- a/src/main/java/step3/game/Car.java +++ b/src/main/java/step3/game/Car.java @@ -1,13 +1,19 @@ package step3.game; +import java.util.Objects; + public class Car { private String name; + private int position = 0; + private static final int POSSIBLE_MOVE_CONDITION = 4; private static final int MAX_MOVE_CONDITION = 9; private static final int MIN_MOVE_CONDITION = 0; - private int position = 0; public Car(String name) { + this(name, 0); + } + public Car(String name, int position) { if (name == null || name.isEmpty()) { throw new IllegalArgumentException("자동차 이름은 비어있거나 null이 될 수 없습니다."); } @@ -15,8 +21,8 @@ public Car(String name) { throw new IllegalArgumentException("자동차 이름은 5자 이하여야 합니다."); } this.name = name; + this.position = position; } - public void move(int number) { if (number > MAX_MOVE_CONDITION || number < MIN_MOVE_CONDITION) { throw new IllegalArgumentException("움직일 수 있는 조건을 벗어났습니다. 값 : " + number); @@ -25,11 +31,32 @@ public void move(int number) { position++; } } + public boolean isSamePosition(int other) { + return position == other; + } - public int getPosition() { - return position; + public int max(int other) { + return Math.max(position, other); + } + public Car copy() { + return new Car(name, position); } public String getName() { return name; } + public int getPosition() { + return position; + } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Car car = (Car) o; + return position == car.position && Objects.equals(name, car.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, position); + } } diff --git a/src/main/java/step3/game/CarFactory.java b/src/main/java/step3/game/CarFactory.java index 267c596bf0d..e8be34881b4 100644 --- a/src/main/java/step3/game/CarFactory.java +++ b/src/main/java/step3/game/CarFactory.java @@ -5,12 +5,13 @@ public class CarFactory { private final static String CAR_NAME_DELIMITER = ","; + private final static int MINIMUM_CAR_COUNT = 2; public static List createCars(String names) { if (!names.contains(CAR_NAME_DELIMITER)) { throw new IllegalArgumentException("자동차 이름은 쉼표(,)를 기준으로 구분해야 합니다."); } String[] carNames = names.split(CAR_NAME_DELIMITER); - if (carNames.length < 2) { + if (carNames.length < MINIMUM_CAR_COUNT) { throw new IllegalArgumentException("자동차는 최소 2대 이상이어야 합니다."); } List cars = new ArrayList<>(); @@ -19,4 +20,12 @@ public static List createCars(String names) { } return cars; } + + public static List copyCars(List cars) { + List copyCar = new ArrayList<>(); + for (int i = 0; i < cars.size(); i++) { + copyCar.add(cars.get(i).copy()); + } + return copyCar; + } } diff --git a/src/main/java/step3/game/GameHistory.java b/src/main/java/step3/game/GameHistory.java deleted file mode 100644 index 8e840c1b11c..00000000000 --- a/src/main/java/step3/game/GameHistory.java +++ /dev/null @@ -1,20 +0,0 @@ -package step3.game; - -public class GameHistory { - private String name; - private int position; - public GameHistory(String name, int position) { - this.name = name; - this.position = position; - } - public String getName() { - return name; - } - public int getPosition() { - return position; - } - @Override - public String toString() { - return name + " : " + "-".repeat(position); - } -} diff --git a/src/main/java/step3/game/GameRound.java b/src/main/java/step3/game/GameRound.java new file mode 100644 index 00000000000..5caeb948df7 --- /dev/null +++ b/src/main/java/step3/game/GameRound.java @@ -0,0 +1,31 @@ +package step3.game; + +import java.util.List; +import java.util.Objects; + +public class GameRound { + private final List result; + + public GameRound(List cars) { + this.result = CarFactory.copyCars(cars); + } + + public List getRound() { + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + GameRound that = (GameRound) o; + + return Objects.equals(result, that.result); + } + + @Override + public int hashCode() { + return result.hashCode(); + } +} diff --git a/src/main/java/step3/game/RacingGame.java b/src/main/java/step3/game/RacingGame.java index fb6f19d2e5a..5491f95c2cd 100644 --- a/src/main/java/step3/game/RacingGame.java +++ b/src/main/java/step3/game/RacingGame.java @@ -3,62 +3,28 @@ import step3.random.RandomStrategy; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class RacingGame { - private List cars; - private final List> result = new ArrayList<>(); + private final List cars; + private final List result = new ArrayList<>(); private final int moveCount; - private final RandomStrategy random; - - public RacingGame(int moveCount, RandomStrategy random, List cars) { - this.random = random; + public RacingGame(int moveCount, List cars) { this.moveCount = moveCount; this.cars = cars; } - public List> start() { + public List start(RandomStrategy random) { for (int i = 0; i < moveCount; i++) { - moveCars(); - saveCurrentCarPositions(i); + moveCars(random); } return result; } - private void moveCars() { - for (Car car : cars) { - car.move(random()); - } - } - - private int random() { - return random.generateRandomValue(); - } - - private void saveCurrentCarPositions(int index) { - result.add(new ArrayList<>()); + private void moveCars(RandomStrategy random) { for (Car car : cars) { - result.get(index).add(new GameHistory(car.getName(), car.getPosition())); - } - } - - public List getCurrentWinners() { - if (result.isEmpty()) { - return Collections.emptyList(); - } - - List winners = new ArrayList<>(); - int max = 0; - for (GameHistory history : result.get(result.size() - 1)) { - if (history.getPosition() > max) { - max = history.getPosition(); - winners.clear(); - winners.add(history.getName()); - } else if (history.getPosition() == max) { - winners.add(history.getName()); - } + car.move(random.generateRandomValue()); } - return winners; + result.add(new GameRound(cars)); } } diff --git a/src/main/java/step3/game/Winners.java b/src/main/java/step3/game/Winners.java new file mode 100644 index 00000000000..e42fc8fbf37 --- /dev/null +++ b/src/main/java/step3/game/Winners.java @@ -0,0 +1,26 @@ +package step3.game; + +import java.util.List; +import java.util.stream.Collectors; + +public class Winners { + public static List findWinners(List cars) { + List finalRound = cars.get(cars.size() - 1).getRound(); + return filterWinners(finalRound, findMaxPosition(finalRound)); + } + + private static List filterWinners(List cars, int maxPosition) { + return cars.stream() + .filter(car -> car.isSamePosition(maxPosition)) + .map(Car::getName) + .collect(Collectors.toList()); + } + + private static int findMaxPosition(List cars) { + int maxPosition = 0; + for (Car car : cars) { + maxPosition = car.max(maxPosition); + } + return maxPosition; + } +} diff --git a/src/main/java/step3/util/InputView.java b/src/main/java/step3/util/InputView.java index 471598e3329..7ba17016c79 100644 --- a/src/main/java/step3/util/InputView.java +++ b/src/main/java/step3/util/InputView.java @@ -4,16 +4,18 @@ public class InputView { private static final Scanner scanner = new Scanner(System.in); + private static final String CAR_NAME_MESSAGE = "경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."; + private static final String MOVE_COUNT_MESSAGE = "시도할 회수는 몇 회 인가요?"; public InputView() {} - public static int inputInt(String message) { - System.out.println(message); + public static int inputMove() { + System.out.println(MOVE_COUNT_MESSAGE); return scanner.nextInt(); } - public static String inputString(String message) { - System.out.println(message); + public static String inputCarNames() { + System.out.println(CAR_NAME_MESSAGE); return scanner.nextLine(); } } diff --git a/src/main/java/step3/util/OutputView.java b/src/main/java/step3/util/OutputView.java index eb73066cd0f..ea9d08f95c0 100644 --- a/src/main/java/step3/util/OutputView.java +++ b/src/main/java/step3/util/OutputView.java @@ -1,21 +1,22 @@ package step3.util; -import step3.game.GameHistory; +import step3.game.Car; +import step3.game.GameRound; import java.util.List; public class OutputView { - public static void printResult(List> result, List winners) { + public static void printResult(List result, List winners) { System.out.println("실행결과"); printHistories(result); printWinners(winners); } - private static void printHistories(List> result) { - for (List history : result) { - for (int i = 0; i < history.size(); i++) { - System.out.println(history.get(i).toString()); + private static void printHistories(List result) { + for (GameRound round : result) { + for (Car car : round.getRound()) { + System.out.println(car.getName() + " : " + "-".repeat(car.getPosition())); } System.out.println(); } diff --git a/src/test/java/step3/CarFactoryTest.java b/src/test/java/step3/CarFactoryTest.java index fd57ef38b4f..1ad8e1432c3 100644 --- a/src/test/java/step3/CarFactoryTest.java +++ b/src/test/java/step3/CarFactoryTest.java @@ -44,4 +44,16 @@ public void createCarsExceptionTest2() { }).isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("자동차는 최소 2대 이상이어야 합니다."); } + + @Test + @DisplayName("자동차 copy가 정상적으로 이루어지는지 확인한다.") + public void copyCarsTest() { + // given + List cars = List.of(new Car("a", 1), new Car("b", 2), new Car("c", 3)); + // when + List copyCars = CarFactory.copyCars(cars); + + // then + assertThat(copyCars).isNotSameAs(cars); + } } diff --git a/src/test/java/step3/CarTest.java b/src/test/java/step3/CarTest.java index 487f16a2c9d..3929b777f5a 100644 --- a/src/test/java/step3/CarTest.java +++ b/src/test/java/step3/CarTest.java @@ -3,7 +3,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvFileSource; import org.junit.jupiter.params.provider.CsvSource; import step3.game.Car; @@ -12,12 +11,12 @@ public class CarTest { @ParameterizedTest - @CsvSource(value = {"3:0", "4:1", "5:1"}, delimiter = ':') + @CsvSource(value = {"3:0", "4:1"}, delimiter = ':') @DisplayName("움직임이 4 미만일 경우, 자동차는 움직이지 않아야 한다.") void carMoveTest(int number, int expected) { Car car = new Car("car1"); car.move(number); - assertThat(car.getPosition()).isEqualTo(expected); + assertThat(car.isSamePosition(expected)).isTrue(); } @Test @@ -74,4 +73,25 @@ void carNameLengthTest() { assertThat(car.getName()).isEqualTo("hihi"); } + @Test + @DisplayName("자동차 isSamePosition 메서드가 정상적으로 작동하는지 확인한다.") + void carIsSamePositionTest() { + Car car = new Car("car1", 1); + assertThat(car.isSamePosition(1)).isTrue(); + } + + @Test + @DisplayName("자동차 max 메서드가 정상적으로 작동하는지 확인한다.") + void carMaxTest() { + Car car = new Car("car1", 1); + assertThat(car.max(2)).isEqualTo(2); + } + + @Test + @DisplayName("자동차 copy 메서드가 정상적으로 작동하는지 확인한다.") + void carCopyTest() { + Car car = new Car("car1", 1); + Car copyCar = car.copy(); + assertThat(copyCar).isNotSameAs(car); + } } diff --git a/src/test/java/step3/RacingGameTest.java b/src/test/java/step3/RacingGameTest.java index 31dcf479d7c..97b2b717486 100644 --- a/src/test/java/step3/RacingGameTest.java +++ b/src/test/java/step3/RacingGameTest.java @@ -3,12 +3,13 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import step3.game.CarFactory; +import step3.game.GameRound; import step3.game.RacingGame; +import step3.game.Car; import step3.random.RandomStrategy; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; @@ -18,11 +19,15 @@ public class RacingGameTest { @DisplayName("움직일 수 있는 기회가 1번인 경우 RacingGame 경기가 정상적으로 작동하는지 체크한다") void startWithOneMoveTest() { // given - List> expected = new ArrayList<>(); - expected.add(new ArrayList<>(List.of(1, 0, 1))); + List expected = new ArrayList<>(); + expected.add(new GameRound(List.of( + new Car("a", 1), + new Car("b", 0), + new Car("c", 1)))); // when - RacingGame game = new RacingGame(1, new RandomStrategy() { + RacingGame game = new RacingGame(1, CarFactory.createCars("a,b,c")); + RandomStrategy random = new RandomStrategy() { private int index = 0; private final int[] values = {6, 2, 4}; @@ -30,87 +35,40 @@ void startWithOneMoveTest() { public int generateRandomValue() { return values[index++]; } - }, CarFactory.createCars("a,b,c")); - + }; // then - List> actual = game.start().stream().map(list -> { - List positions = new ArrayList<>(); - list.forEach(gameHistory -> positions.add(gameHistory.getPosition())); - return positions; - }).collect(Collectors.toList()); - assertThat(actual).isEqualTo(expected); + assertThat(game.start(random)).isEqualTo(expected); } @Test @DisplayName("움직일 수 있는 기회가 여러 번인 경우 RacingGame 경기가 정상적으로 작동하는지 체크한다") void startTest1() { // given - List> expected = new ArrayList<>(); - expected.add(new ArrayList<>(List.of(1, 0))); - expected.add(new ArrayList<>(List.of(1, 1))); - expected.add(new ArrayList<>(List.of(2, 1))); + List expected = new ArrayList<>(); + expected.add(new GameRound(List.of( + new Car("a", 1), + new Car("b", 0)))); + expected.add(new GameRound(List.of( + new Car("a", 1), + new Car("b", 1)))); + expected.add(new GameRound(List.of( + new Car("a", 2), + new Car("b", 1)))); // when - RacingGame game = new RacingGame(3, new RandomStrategy() { + RacingGame game = new RacingGame(3, CarFactory.createCars("a,b")); + RandomStrategy random = new RandomStrategy() { private int index = 0; private final int[] values = {6, 2, 3, 4, 5, 1}; - @Override - public int generateRandomValue() { - - return values[index++]; - } - }, CarFactory.createCars("a,b")); - - // then - List> actual = game.start().stream().map(list -> { - List positions = new ArrayList<>(); - list.forEach(gameHistory -> positions.add(gameHistory.getPosition())); - return positions; - }).collect(Collectors.toList()); - assertThat(actual).isEqualTo(expected); - } - - @Test - @DisplayName("winners가 한명인 경우, 정상적으로 반환하는지 체크한다") - void getCurrentOneWinnersTest() { - // given - List expected = List.of("a"); - // when - RacingGame game = new RacingGame(2, new RandomStrategy() { - private int index = 0; - private final int[] values = {6, 2, 3, 4, 5, 1}; - - @Override - public int generateRandomValue() { - return values[index++]; - } - }, CarFactory.createCars("a,b,c")); - - // then - game.start(); - assertThat(game.getCurrentWinners()).isEqualTo(expected); - } - - @Test - @DisplayName("winners가 여러명인 경우, 정상적으로 반환하는지 체크한다") - void getCurrentMultiWinnersTest() { - // given - List expected = List.of("a", "b"); - // when - RacingGame game = new RacingGame(2, new RandomStrategy() { - private int index = 0; - private final int[] values = {6, 4, 3, 4, 5, 1}; - @Override public int generateRandomValue() { return values[index++]; } - }, CarFactory.createCars("a,b,c")); + }; // then - game.start(); - assertThat(game.getCurrentWinners()).isEqualTo(expected); + assertThat(game.start(random)).isEqualTo(expected); } } diff --git a/src/test/java/step3/WinnersTest.java b/src/test/java/step3/WinnersTest.java new file mode 100644 index 00000000000..bdac7ee7544 --- /dev/null +++ b/src/test/java/step3/WinnersTest.java @@ -0,0 +1,32 @@ +package step3; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import step3.game.Car; +import step3.game.GameRound; +import step3.game.Winners; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class WinnersTest { + @Test + @DisplayName("우승자를 출력하는지 확인한다.") + void printWinnersTest() { + List result = new ArrayList<>(); + result.add(new GameRound(List.of( + new Car("a", 1), + new Car("b", 2), + new Car("c", 3) + ))); + + // when + List actual = Winners.findWinners(result); + + // then + assertThat(actual.size()).isEqualTo(1); + assertThat(actual).isEqualTo(List.of("c")); + } +}