diff --git a/src/main/java/racing/RacingGameApplication.java b/src/main/java/racing/RacingGameApplication.java index c137223..6fbd928 100644 --- a/src/main/java/racing/RacingGameApplication.java +++ b/src/main/java/racing/RacingGameApplication.java @@ -9,7 +9,7 @@ public class RacingGameApplication { public static void main(String[] args) { - InputValueDto inputValueDto = InputView.getInputValue(); + InputValueDto inputValueDto = InputView.getInputValueWithName(); RacingGame racingGame = new RacingGame(inputValueDto); diff --git a/src/main/java/racing/domain/Car.java b/src/main/java/racing/domain/Car.java index bd42242..de0861f 100644 --- a/src/main/java/racing/domain/Car.java +++ b/src/main/java/racing/domain/Car.java @@ -3,6 +3,16 @@ public class Car { private static final int MOVE_CONIDTION = 4; private int distance; + private String name; + + public Car(String name) { + this.name = name; + this.distance = 0; + } + + public String getName() { + return name; + } public int attemptToMove(int randomNumber) { if (isMove(randomNumber)) { diff --git a/src/main/java/racing/domain/GameResult.java b/src/main/java/racing/domain/GameResult.java index 4407612..58191ec 100644 --- a/src/main/java/racing/domain/GameResult.java +++ b/src/main/java/racing/domain/GameResult.java @@ -5,27 +5,33 @@ public class GameResult { - private final List racingResults; + private final List phaseResults; private int numberOfPhase; - public GameResult() { - this.racingResults = new ArrayList<>(); - } - public GameResult(int numberOfPhase) { - this.racingResults = new ArrayList<>(); + this.phaseResults = new ArrayList<>(); this.numberOfPhase = numberOfPhase; } - public void addEachRacingResult(RacingResult racingResult) { - this.racingResults.add(racingResult); + public void addEachRacingResult(PhaseResult phaseResult) { + this.phaseResults.add(phaseResult); } - public RacingResult findRacingResultByPhase(int phase) { - return racingResults.get(phase - 1); + public PhaseResult findRacingResultByPhase(int phase) { + try { + return phaseResults.get(phase - 1); + } catch (IndexOutOfBoundsException e) { + throw new IllegalArgumentException(String.format("존재하지 않는 시도 횟수입니다. - %d \n", phase)); + } } public int getNumberOfPhase() { return numberOfPhase; } + + public List getWinner() { + PhaseResult lastResult = findRacingResultByPhase(numberOfPhase); + + return lastResult.getCurrentLeads(); + } } diff --git a/src/main/java/racing/domain/ParticipateCars.java b/src/main/java/racing/domain/ParticipateCars.java index e63ee23..3f72ae2 100644 --- a/src/main/java/racing/domain/ParticipateCars.java +++ b/src/main/java/racing/domain/ParticipateCars.java @@ -2,15 +2,17 @@ import racing.domain.common.NumberGenerator; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class ParticipateCars { private final List cars; - public ParticipateCars(int numberOfCars) { - this.cars = createCars(numberOfCars); + public ParticipateCars(String[] namesOfCars) { + cars = createCars(namesOfCars); } public List tryMove(NumberGenerator numberGenerator) { @@ -19,13 +21,33 @@ public List tryMove(NumberGenerator numberGenerator) { .collect(Collectors.toList()); } - private List createCars(int numberOfCars) { - List cars = new ArrayList<>(); + public Map tryMoveWithName(NumberGenerator numberGenerator) { - for (int i = 0; i < numberOfCars; i++) { - cars.add(new Car()); +/* Map moveResults = new LinkedHashMap<>(); + + for (Car car : cars) { + moveResults.put(car.getName(),car.attemptToMove(numberGenerator.generateNumber())); } - return cars; + return moveResults;*/ + + return cars.stream() + .collect(Collectors.toMap(Car::getName, + car -> car.attemptToMove(numberGenerator.generateNumber()), + (x, y) -> x, + LinkedHashMap::new)); + } + + private List createCars(String[] namesOfCars) { +/* List cars = new ArrayList<>(); + + for (int i = 0 ; i < namesOfCars.length ; i++) { + cars.add(new Car(namesOfCars[i])); + }*/ + + return Arrays.stream(namesOfCars) + .map(String::trim) + .map(Car::new) + .collect(Collectors.toList()); } } diff --git a/src/main/java/racing/domain/PhaseResult.java b/src/main/java/racing/domain/PhaseResult.java new file mode 100644 index 0000000..9201980 --- /dev/null +++ b/src/main/java/racing/domain/PhaseResult.java @@ -0,0 +1,30 @@ +package racing.domain; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +public class PhaseResult { + private final Map raceResults; + + public PhaseResult(Map raceResults) { + this.raceResults = raceResults; + } + + public Map getRaceResults() { + return raceResults; + } + + public List getCurrentLeads() { + int max = raceResults.entrySet().stream() + .mapToInt(Map.Entry::getValue) + .max() + .orElseThrow(IllegalStateException::new); + + return raceResults.entrySet().stream() + .filter(x -> x.getValue() == max) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/racing/domain/RacingGame.java b/src/main/java/racing/domain/RacingGame.java index 36405fa..bbd7d53 100644 --- a/src/main/java/racing/domain/RacingGame.java +++ b/src/main/java/racing/domain/RacingGame.java @@ -9,7 +9,7 @@ public class RacingGame { public RacingGame(InputValueDto inputValueDto) { this.inputValueDto = inputValueDto; - this.racingPhase = new RacingPhase(inputValueDto.getNumberOfCars()); + this.racingPhase = new RacingPhase(inputValueDto.getNamesOfCars()); } public GameResult startGame(NumberGenerator numberGenerator) { @@ -17,8 +17,8 @@ public GameResult startGame(NumberGenerator numberGenerator) { GameResult gameResult = new GameResult(numberOfAttempts); for (int i = 0; i < numberOfAttempts; i++) { - RacingResult eachRacingResult = racingPhase.startRace(numberGenerator); - gameResult.addEachRacingResult(eachRacingResult); + PhaseResult eachPhaseResult = racingPhase.startRace(numberGenerator); + gameResult.addEachRacingResult(eachPhaseResult); } return gameResult; diff --git a/src/main/java/racing/domain/RacingPhase.java b/src/main/java/racing/domain/RacingPhase.java index 55129dd..fadcb8b 100644 --- a/src/main/java/racing/domain/RacingPhase.java +++ b/src/main/java/racing/domain/RacingPhase.java @@ -5,13 +5,11 @@ public class RacingPhase { private final ParticipateCars participateCars; - public RacingPhase(int numberOfCars) { - this.participateCars = new ParticipateCars(numberOfCars); + public RacingPhase(String[] namesOfCars) { + this.participateCars = new ParticipateCars(namesOfCars); } - public RacingResult startRace(NumberGenerator numberGenerator) { - return new RacingResult(participateCars.tryMove(numberGenerator)); + public PhaseResult startRace(NumberGenerator numberGenerator) { + return new PhaseResult(participateCars.tryMoveWithName(numberGenerator)); } - - } diff --git a/src/main/java/racing/domain/RacingResult.java b/src/main/java/racing/domain/RacingResult.java deleted file mode 100644 index 9cb2c94..0000000 --- a/src/main/java/racing/domain/RacingResult.java +++ /dev/null @@ -1,15 +0,0 @@ -package racing.domain; - -import java.util.List; - -public class RacingResult { - private final List raceResults; - - public RacingResult(List raceResults) { - this.raceResults = raceResults; - } - - public List getRaceResults() { - return raceResults; - } -} diff --git a/src/main/java/racing/dto/InputValueDto.java b/src/main/java/racing/dto/InputValueDto.java index 310bf22..107d3ed 100644 --- a/src/main/java/racing/dto/InputValueDto.java +++ b/src/main/java/racing/dto/InputValueDto.java @@ -1,7 +1,8 @@ package racing.dto; public class InputValueDto { - final private int numberOfCars; + private int numberOfCars; + private String[] namesOfCars; final private int numberOfAttempts; public InputValueDto(int numberOfCars, int numberOfAttempts) { @@ -10,6 +11,12 @@ public InputValueDto(int numberOfCars, int numberOfAttempts) { this.numberOfAttempts = numberOfAttempts; } + public InputValueDto(String[] namesOfCars, int numberOfAttempts) { + validateInputValue(namesOfCars, numberOfAttempts); + this.namesOfCars = namesOfCars; + this.numberOfAttempts = numberOfAttempts; + } + public int getNumberOfCars() { return numberOfCars; } @@ -18,6 +25,10 @@ public int getNumberOfAttempts() { return numberOfAttempts; } + public String[] getNamesOfCars() { + return namesOfCars; + } + private void validateInputValue(int numberOfCars, int numberOfAttempts) { if (numberOfCars <= 0) { throw new IllegalArgumentException("참여할 자동차의 대수는 0 보다 커야합니다."); @@ -27,4 +38,14 @@ private void validateInputValue(int numberOfCars, int numberOfAttempts) { throw new IllegalArgumentException("시도할 횟수는 0 보다 커야합니다."); } } + + private void validateInputValue(String[] namesOfCars, int numberOfAttempts) { + if (namesOfCars.length <= 0) { + throw new IllegalArgumentException("입력된 자동차 이름의 개수는 0 보다 커야합니다."); + } + + if (numberOfAttempts <= 0) { + throw new IllegalArgumentException("시도할 횟수는 0 보다 커야합니다."); + } + } } diff --git a/src/main/java/racing/view/InputView.java b/src/main/java/racing/view/InputView.java index d3f0547..b947ee9 100644 --- a/src/main/java/racing/view/InputView.java +++ b/src/main/java/racing/view/InputView.java @@ -6,13 +6,14 @@ public class InputView { private static final Scanner scanner = new Scanner(System.in); + private static final String DELIMETER = ","; - public static InputValueDto getInputValue() { + public static InputValueDto getInputValueWithName() { try { - int numberOfCars = Integer.parseInt(inputNumberOfCars()); + String[] namesOfCars = inputNameOfCars().split(DELIMETER); int numberOfAttempts = Integer.parseInt(inputNumberOfAttempts()); - return new InputValueDto(numberOfCars, numberOfAttempts); + return new InputValueDto(namesOfCars, numberOfAttempts); } catch (NumberFormatException e) { throw new IllegalArgumentException("숫자를 입력해주세요."); } @@ -29,7 +30,7 @@ public static String inputNumberOfAttempts() { } public static String inputNameOfCars() { - System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); + System.out.println("경주할 자동차 이름을 입력하세요. (이름은 쉼표(,)를 기준으로 구분)"); return scanner.nextLine(); } } diff --git a/src/main/java/racing/view/OutputView.java b/src/main/java/racing/view/OutputView.java index dad8b56..e0bf384 100644 --- a/src/main/java/racing/view/OutputView.java +++ b/src/main/java/racing/view/OutputView.java @@ -1,27 +1,44 @@ package racing.view; import racing.domain.GameResult; -import racing.domain.RacingResult; +import racing.domain.PhaseResult; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class OutputView { - private static void printRacingResult(RacingResult racingResultResult) { - String result = racingResultResult.getRaceResults().stream() - .map(OutputView::visualize) - .collect(Collectors.joining("\n")); - - System.out.println(result); - - } public static void printGameResult(GameResult gameResult) { int numberOfPhase = gameResult.getNumberOfPhase(); for (int i = 1; i <= numberOfPhase; i++) { - RacingResult racingResult = gameResult.findRacingResultByPhase(i); - printRacingResult(racingResult); + PhaseResult phaseResult = gameResult.findRacingResultByPhase(i); + printRacingResult(phaseResult); } + + printWinner(gameResult.getWinner()); + } + + public static void printWinner(List winners) { + String winner = winners.stream() + .collect(Collectors.joining(",")); + + System.out.println(winner + "가 최종 우승했습니다."); + } + + private static void printRacingResult(PhaseResult phaseResultResult) { + String result = phaseResultResult.getRaceResults() + .entrySet().stream() + .map(OutputView::mapping) + .collect(Collectors.joining("\n")); + + System.out.println(result); + System.out.println(); + } + + private static String mapping(Map.Entry entry) { + return entry.getKey() + " : " + visualize(entry.getValue()); } public static String visualize(int target) { diff --git a/src/test/java/racing/domain/CarTest.java b/src/test/java/racing/domain/CarTest.java index cd3f2db..c7058d5 100644 --- a/src/test/java/racing/domain/CarTest.java +++ b/src/test/java/racing/domain/CarTest.java @@ -14,7 +14,7 @@ class CarTest { "4, 1", "3, 0" }) void name(int randomNumber, int expectedResult) { - Car car = new Car(); + Car car = new Car("pobi"); int actualResult = car.attemptToMove(randomNumber); diff --git a/src/test/java/racing/domain/GameResultTest.java b/src/test/java/racing/domain/GameResultTest.java new file mode 100644 index 0000000..254eefb --- /dev/null +++ b/src/test/java/racing/domain/GameResultTest.java @@ -0,0 +1,60 @@ +package racing.domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class GameResultTest { + + private static PhaseResult makePhaseResult(int first, int second) { + Map raceResults = new LinkedHashMap<>(); + + raceResults.put("pobi", first); + raceResults.put("crong", second); + + return new PhaseResult(raceResults); + } + + @DisplayName("각 시도에 맞는 phaseResult를 반환한다.") + @Test + void name() { + GameResult gameResult = new GameResult(1); + PhaseResult expectResult = makePhaseResult(1, 0); + gameResult.addEachRacingResult(expectResult); + + PhaseResult result = gameResult.findRacingResultByPhase(1); + assertThat(result).isEqualTo(expectResult); + } + + @DisplayName("시도 횟수보다 크거나, 0 이하인 수는 IllegarArgumentException을 던진다.") + @ParameterizedTest + @ValueSource(ints = {-1, 0, 2}) + void name1(int phaseNumber) { + GameResult gameResult = new GameResult(1); + gameResult.addEachRacingResult(makePhaseResult(1, 0)); + + assertThatThrownBy(() -> gameResult.findRacingResultByPhase(phaseNumber)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage(String.format("존재하지 않는 시도 횟수입니다. - %d \n", phaseNumber)); + } + + @DisplayName("게임 최종 우승자의 이름을 List로 반환한다.") + @Test + void name2() { + GameResult gameResult = new GameResult(2); + gameResult.addEachRacingResult(makePhaseResult(1, 0)); + gameResult.addEachRacingResult(makePhaseResult(2, 1)); + + List winners = gameResult.getWinner(); + assertThat(winners).isEqualTo(Arrays.asList("pobi")); + } +} \ No newline at end of file diff --git a/src/test/java/racing/domain/ParticipateCarsTest.java b/src/test/java/racing/domain/ParticipateCarsTest.java index ef8b55a..e567f7e 100644 --- a/src/test/java/racing/domain/ParticipateCarsTest.java +++ b/src/test/java/racing/domain/ParticipateCarsTest.java @@ -4,19 +4,21 @@ import org.junit.jupiter.api.Test; import racing.domain.common.FixedNumberGenerator; -import java.util.Arrays; -import java.util.List; +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; class ParticipateCarsTest { - - @DisplayName("게임에 참여하는 Car에게 이동을 지시하고 이동 결과를 반환한다") + @DisplayName("게임에 참여하는 Car 에게 이동을 지시하고 이름과 이동 결과의 Map을 반환한다.") @Test - void name() { - int numberOfCars = 2; - ParticipateCars participateCars = new ParticipateCars(numberOfCars); - List result = participateCars.tryMove(new FixedNumberGenerator()); - assertThat(result).isEqualTo(Arrays.asList(1, 0)); + void name1() { + String[] namesOfCars = {"pobi", "crong"}; + ParticipateCars participateCars = new ParticipateCars(namesOfCars); + Map result = participateCars.tryMoveWithName(new FixedNumberGenerator()); + assertAll( + () -> assertThat(result).containsEntry("pobi", 1), + () -> assertThat(result).containsEntry("crong", 0) + ); } } \ No newline at end of file diff --git a/src/test/java/racing/domain/PhaseResultTest.java b/src/test/java/racing/domain/PhaseResultTest.java new file mode 100644 index 0000000..0108694 --- /dev/null +++ b/src/test/java/racing/domain/PhaseResultTest.java @@ -0,0 +1,30 @@ +package racing.domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +class PhaseResultTest { + @DisplayName("PhaseResult의 getCurrentLead 메소드는 현재 선두의 이름을 List의 형태로 반환한다. ") + @Test + void name1() { + Map moveResult = new LinkedHashMap<>(); + moveResult.put("pobi", 1); + moveResult.put("crong", 0); + + PhaseResult phaseResult = new PhaseResult(moveResult); + + List leads = phaseResult.getCurrentLeads(); + + assertAll( + () -> assertThat(leads.size()).isEqualTo(1), + () -> assertThat(leads.get(0)).isEqualTo("pobi") + ); + } +} \ No newline at end of file diff --git a/src/test/java/racing/domain/RacingGameTest.java b/src/test/java/racing/domain/RacingGameTest.java index ecc445a..cc7e5e6 100644 --- a/src/test/java/racing/domain/RacingGameTest.java +++ b/src/test/java/racing/domain/RacingGameTest.java @@ -12,7 +12,7 @@ class RacingGameTest { @DisplayName("startGame 메소드는 게임을 수행하고 결과를 가지고 있는 RacingResult를 반환한다.") @Test void name() { - InputValueDto inputValueDto = new InputValueDto(2, 2); + InputValueDto inputValueDto = new InputValueDto(new String[]{"pobi", "crong"}, 2); RacingGame racingGame = new RacingGame(inputValueDto); assertThat(racingGame.startGame(new FixedNumberGenerator())).isInstanceOf(GameResult.class); diff --git a/src/test/java/racing/domain/RacingPhaseTest.java b/src/test/java/racing/domain/RacingPhaseTest.java index 7f11112..569a251 100644 --- a/src/test/java/racing/domain/RacingPhaseTest.java +++ b/src/test/java/racing/domain/RacingPhaseTest.java @@ -1,20 +1,18 @@ package racing.domain; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.api.Test; import racing.domain.common.FixedNumberGenerator; import static org.assertj.core.api.Assertions.assertThat; class RacingPhaseTest { - @DisplayName("startRace는 이동 시도 결과를 가지고 있는 RacingResult를 반환한다.") - @ParameterizedTest - @ValueSource(ints = {3, 4}) - void name(int numberOfCars) { - RacingPhase racingPhase = new RacingPhase(numberOfCars); - RacingResult result = racingPhase.startRace(new FixedNumberGenerator()); + @DisplayName("startRace는 이동 시도 결과를 가지고 있는 PhaseResult를 반환한다.") + @Test + void name() { + RacingPhase racingPhase = new RacingPhase(new String[]{"pobi", "crong"}); + PhaseResult result = racingPhase.startRace(new FixedNumberGenerator()); - assertThat(result.getRaceResults().size()).isEqualTo(numberOfCars); + assertThat(result.getRaceResults().size()).isEqualTo(2); } } \ No newline at end of file diff --git a/src/test/java/racing/dto/InputValueDtoTest.java b/src/test/java/racing/dto/InputValueDtoTest.java index fb40030..eeb6f58 100644 --- a/src/test/java/racing/dto/InputValueDtoTest.java +++ b/src/test/java/racing/dto/InputValueDtoTest.java @@ -1,23 +1,21 @@ package racing.dto; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThatThrownBy; class InputValueDtoTest { private static final String CAR_EXCEPTION_MESSAGE = "참여할 자동차의 대수는 0 보다 커야합니다."; + private static final String CAR_NAME_EXCEPTION_MESSAGE = "입력된 자동차 이름의 개수는 0 보다 커야합니다."; private static final String ATTEMPT_EXCEPTION_MESSAGE = "시도할 횟수는 0 보다 커야합니다."; - @DisplayName("0 이하 값은 IllegalArgumentException을 던진다") - @ParameterizedTest - @CsvSource({"0,1," + CAR_EXCEPTION_MESSAGE, - "1,-1," + ATTEMPT_EXCEPTION_MESSAGE}) - void name(int numberOfCars, int numberOfAttempts, String message) { - assertThatThrownBy(() -> new InputValueDto(numberOfCars, numberOfAttempts)) + @DisplayName("시도 회수가 0 이하면 IllegalArgumentException을 던진다") + @Test + void name2() { + assertThatThrownBy(() -> new InputValueDto(new String[]{"pobi"}, 0)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage(message); + .hasMessage(ATTEMPT_EXCEPTION_MESSAGE); } } \ No newline at end of file