From 0556a700da1328f1d802cd9cce972e10afb0d866 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 6 Dec 2022 20:38:54 +0900 Subject: [PATCH 01/16] =?UTF-8?q?docs:=20=EC=B6=94=EA=B0=80=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EB=AA=A9=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..524ff36aa --- /dev/null +++ b/docs/README.md @@ -0,0 +1,20 @@ +# 자동차 경주 게임 + +## 기능 목록 + +### 자동차 게임 기능 +- [x] 주어진 횟수를 입력받는 기능 + - [x] 횟수가 숫자가 아닐시 예외 발생 기능 + - [x] 횟수가 음수 또는 너무 큰 수 일시 예외 발생 기능 +- [x] 주어진 횟수 동안 n대의 자동차는 전진 또는 멈춤 기능 + - [x] 움직인 결과 출력 기능 +- [x] 자동차 경주 게임을 완료한 후 누가 우승했는지 출력하는 기능 + - [x] 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분하여 출력하는 기능 + +### 자동차 기능 +- [x] 자동차에 이름을 입력받는 기능 + - [x] 자동차 이름은 쉼표(,)를 기준으로 구분하는 기능 + - [x] 쉼표(,) 여러개를 입력해도 인식 가능한 기능 + - [x] 이름은 5자 초과시 예외 발생 기능 +- [x] 자동차는 전진 또는 멈춤 기능 + - [x] 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 때 전진 기능 \ No newline at end of file From 8f1220ea173b5a3e581102773953295220b5acb5 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 6 Dec 2022 20:41:35 +0900 Subject: [PATCH 02/16] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80=20skeleton?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/racingcar/controller/RacingCarController.java | 5 +++++ src/main/java/racingcar/{ => domain}/Car.java | 2 +- src/main/java/racingcar/domain/RacingCarGame.java | 4 ++++ src/main/java/racingcar/view/InputView.java | 4 ++++ src/main/java/racingcar/view/OutputView.java | 4 ++++ 5 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/main/java/racingcar/controller/RacingCarController.java rename src/main/java/racingcar/{ => domain}/Car.java (87%) create mode 100644 src/main/java/racingcar/domain/RacingCarGame.java create mode 100644 src/main/java/racingcar/view/InputView.java create mode 100644 src/main/java/racingcar/view/OutputView.java diff --git a/src/main/java/racingcar/controller/RacingCarController.java b/src/main/java/racingcar/controller/RacingCarController.java new file mode 100644 index 000000000..5ba61eafe --- /dev/null +++ b/src/main/java/racingcar/controller/RacingCarController.java @@ -0,0 +1,5 @@ +package racingcar.controller; + +public class RacingCarController { + +} diff --git a/src/main/java/racingcar/Car.java b/src/main/java/racingcar/domain/Car.java similarity index 87% rename from src/main/java/racingcar/Car.java rename to src/main/java/racingcar/domain/Car.java index ab3df9492..7ab69bf08 100644 --- a/src/main/java/racingcar/Car.java +++ b/src/main/java/racingcar/domain/Car.java @@ -1,4 +1,4 @@ -package racingcar; +package racingcar.domain; public class Car { private final String name; diff --git a/src/main/java/racingcar/domain/RacingCarGame.java b/src/main/java/racingcar/domain/RacingCarGame.java new file mode 100644 index 000000000..f1a48f1c1 --- /dev/null +++ b/src/main/java/racingcar/domain/RacingCarGame.java @@ -0,0 +1,4 @@ +package racingcar.domain; + +public class RacingCarGame { +} diff --git a/src/main/java/racingcar/view/InputView.java b/src/main/java/racingcar/view/InputView.java new file mode 100644 index 000000000..2361ba2f5 --- /dev/null +++ b/src/main/java/racingcar/view/InputView.java @@ -0,0 +1,4 @@ +package racingcar.view; + +public class InputView { +} diff --git a/src/main/java/racingcar/view/OutputView.java b/src/main/java/racingcar/view/OutputView.java new file mode 100644 index 000000000..abf938a66 --- /dev/null +++ b/src/main/java/racingcar/view/OutputView.java @@ -0,0 +1,4 @@ +package racingcar.view; + +public class OutputView { +} From 7935b9fd861c1e8ce1fd6d24e77e366a6dfa555e Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 6 Dec 2022 22:21:10 +0900 Subject: [PATCH 03/16] =?UTF-8?q?fix:=20=EB=B3=80=EA=B2=BD=20=EC=9E=90?= =?UTF-8?q?=EB=B0=94=EB=B2=84=EC=A0=84=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 45d61697f..edc026cd8 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ dependencies { java { toolchain { - languageVersion = JavaLanguageVersion.of(8) + languageVersion = JavaLanguageVersion.of(11) } } From db4cb0217aac0bc2e5745534f615f0bd7254565c Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 6 Dec 2022 23:17:36 +0900 Subject: [PATCH 04/16] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=EC=97=90=20=EC=9D=B4=EB=A6=84=EC=9D=84=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EB=B0=9B=EB=8A=94=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/racingcar/Application.java | 6 ++- .../controller/RacingCarController.java | 17 +++++++ .../controller/ReEnterProcessor.java | 24 ++++++++++ src/main/java/racingcar/domain/Car.java | 15 +++++- src/main/java/racingcar/domain/Cars.java | 47 +++++++++++++++++++ .../exception/CarNameLengthException.java | 10 ++++ .../CarsDuplicatedNameException.java | 10 ++++ src/main/java/racingcar/view/InputView.java | 8 ++++ src/main/java/racingcar/view/OutputView.java | 10 ++++ 9 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 src/main/java/racingcar/controller/ReEnterProcessor.java create mode 100644 src/main/java/racingcar/domain/Cars.java create mode 100644 src/main/java/racingcar/exception/CarNameLengthException.java create mode 100644 src/main/java/racingcar/exception/CarsDuplicatedNameException.java diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index b9ed0456a..c862b4f47 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,7 +1,11 @@ package racingcar; +import racingcar.controller.RacingCarController; + public class Application { + public static void main(String[] args) { - // TODO 구현 진행 + RacingCarController racingCarController = new RacingCarController(); + racingCarController.runGame(); } } diff --git a/src/main/java/racingcar/controller/RacingCarController.java b/src/main/java/racingcar/controller/RacingCarController.java index 5ba61eafe..8783ba9ad 100644 --- a/src/main/java/racingcar/controller/RacingCarController.java +++ b/src/main/java/racingcar/controller/RacingCarController.java @@ -1,5 +1,22 @@ package racingcar.controller; +import racingcar.domain.Cars; +import racingcar.view.InputView; +import racingcar.view.OutputView; + +import java.util.function.Supplier; + public class RacingCarController { + private final InputView inputView = new InputView(); + private final OutputView outputView = new OutputView(); + + public void runGame() { + askCarName(); + } + + private Cars askCarName() { + outputView.printInputCarName(); + return new ReEnterProcessor<>(inputView::readCarName, outputView::printExceptionMessage).process(); + } } diff --git a/src/main/java/racingcar/controller/ReEnterProcessor.java b/src/main/java/racingcar/controller/ReEnterProcessor.java new file mode 100644 index 000000000..d06f54816 --- /dev/null +++ b/src/main/java/racingcar/controller/ReEnterProcessor.java @@ -0,0 +1,24 @@ +package racingcar.controller; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class ReEnterProcessor { + private final Supplier processor; + private final Consumer consumer; + + public ReEnterProcessor(Supplier processor, Consumer consumer) { + this.processor = processor; + this.consumer = consumer; + } + + public T process() { + while(true){ + try { + return processor.get(); + }catch (IllegalArgumentException exception){ + consumer.accept(exception); + } + } + } +} diff --git a/src/main/java/racingcar/domain/Car.java b/src/main/java/racingcar/domain/Car.java index 7ab69bf08..fb1408c79 100644 --- a/src/main/java/racingcar/domain/Car.java +++ b/src/main/java/racingcar/domain/Car.java @@ -1,12 +1,25 @@ package racingcar.domain; +import racingcar.exception.CarNameLengthException; + public class Car { + + private static final int CAR_NAME_LENGTH = 5; private final String name; private int position = 0; public Car(String name) { + validate(name); this.name = name; } - // 추가 기능 구현 + private void validate(String name) { + validateLength(name); + } + + private void validateLength(String name) { + if(name.length() > CAR_NAME_LENGTH) { + throw new CarNameLengthException(); + } + } } diff --git a/src/main/java/racingcar/domain/Cars.java b/src/main/java/racingcar/domain/Cars.java new file mode 100644 index 000000000..f80893c18 --- /dev/null +++ b/src/main/java/racingcar/domain/Cars.java @@ -0,0 +1,47 @@ +package racingcar.domain; + +import racingcar.exception.CarsDuplicatedNameException; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class Cars { + + private static final String DELIMITER = ","; + private static final String DUPLICATED_DELIMITER_REGEX = ",+"; + private final List cars; + + private Cars(List cars) { + this.cars = cars; + } + + public static Cars createCarNameByWord(String input) { + List cars = new ArrayList<>(); + String[] words = divideWord(input); + validate(words); + + for (String carName : words) { + cars.add(new Car(carName)); + } + return new Cars(cars); + } + + private static void validate(String[] words) { + validateDuplicatedWord(words); + } + + private static void validateDuplicatedWord(String[] words) { + Set uniqueWord = new HashSet<>(); + for (String word : words) { + if (!uniqueWord.add(word)) { + throw new CarsDuplicatedNameException(); + } + } + } + + private static String[] divideWord(String word) { + return word.replaceAll(DUPLICATED_DELIMITER_REGEX, DELIMITER).split(DELIMITER); + } +} diff --git a/src/main/java/racingcar/exception/CarNameLengthException.java b/src/main/java/racingcar/exception/CarNameLengthException.java new file mode 100644 index 000000000..ac0e8b44a --- /dev/null +++ b/src/main/java/racingcar/exception/CarNameLengthException.java @@ -0,0 +1,10 @@ +package racingcar.exception; + +public class CarNameLengthException extends IllegalArgumentException{ + + private static final String EXCEPTION_MESSAGE_CAR_NAME_LENGTH = "[ERROR] 자동차이름은 5글자 이하입니다"; + + public CarNameLengthException() { + super(EXCEPTION_MESSAGE_CAR_NAME_LENGTH); + } +} diff --git a/src/main/java/racingcar/exception/CarsDuplicatedNameException.java b/src/main/java/racingcar/exception/CarsDuplicatedNameException.java new file mode 100644 index 000000000..9c01eb08c --- /dev/null +++ b/src/main/java/racingcar/exception/CarsDuplicatedNameException.java @@ -0,0 +1,10 @@ +package racingcar.exception; + +public class CarsDuplicatedNameException extends IllegalArgumentException { + + private static final String EXCEPTION_MESSAGE_CARS_DUPLICATED_NAME = "[ERROR] 자동차 이름은 중복될 수 없습니다"; + + public CarsDuplicatedNameException() { + super(EXCEPTION_MESSAGE_CARS_DUPLICATED_NAME); + } +} \ No newline at end of file diff --git a/src/main/java/racingcar/view/InputView.java b/src/main/java/racingcar/view/InputView.java index 2361ba2f5..2deced5e3 100644 --- a/src/main/java/racingcar/view/InputView.java +++ b/src/main/java/racingcar/view/InputView.java @@ -1,4 +1,12 @@ package racingcar.view; +import racingcar.domain.Cars; + +import static camp.nextstep.edu.missionutils.Console.readLine; + public class InputView { + + public Cars readCarName() { + return Cars.createCarNameByWord(readLine()); + } } diff --git a/src/main/java/racingcar/view/OutputView.java b/src/main/java/racingcar/view/OutputView.java index abf938a66..727945024 100644 --- a/src/main/java/racingcar/view/OutputView.java +++ b/src/main/java/racingcar/view/OutputView.java @@ -1,4 +1,14 @@ package racingcar.view; public class OutputView { + + private static final String MESSAGE_INPUT_CAR_NAME = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"; + + public void printInputCarName() { + System.out.println(MESSAGE_INPUT_CAR_NAME); + } + + public void printExceptionMessage(IllegalArgumentException exceptionMessage) { + exceptionMessage.printStackTrace(); + } } From ca3eda7f968b1746da5e756cbf312e970c23bb17 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 01:47:43 +0900 Subject: [PATCH 05/16] =?UTF-8?q?test:=20=EC=B6=94=EA=B0=80=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=EC=97=90=20=EC=9D=B4=EB=A6=84=EC=9D=84=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EB=B0=9B=EB=8A=94=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/racingcar/CarTest.java | 36 +++++++++++++++++++++++++++ src/test/java/racingcar/CarsTest.java | 35 ++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/test/java/racingcar/CarTest.java create mode 100644 src/test/java/racingcar/CarsTest.java diff --git a/src/test/java/racingcar/CarTest.java b/src/test/java/racingcar/CarTest.java new file mode 100644 index 000000000..1788555eb --- /dev/null +++ b/src/test/java/racingcar/CarTest.java @@ -0,0 +1,36 @@ +package racingcar; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import racingcar.domain.Car; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class CarTest { + + private static final String EXCEPTION_MESSAGE_CAR_NAME_LENGTH = "[ERROR] 자동차이름은 5글자 이하입니다"; + + @DisplayName("Car 객체를 성공적으로 생성한다.") + @ParameterizedTest + @ValueSource(strings = {"pobii", "p", "pob", "3%$^1", "세글자", "k l"}) + void createCarSuccess(String input) { + boolean result = true; + try{ + new Car(input); + }catch (IllegalArgumentException exception) { + result = false; + } + assertThat(result).isEqualTo(true); + } + + @DisplayName("5글자 초과시 Car 생성시 예외를 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"pobiid", "dafasdfasdfasdshgsdfg"}) + void createCarByOverLength(String input) { + assertThatThrownBy(() -> new Car(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(EXCEPTION_MESSAGE_CAR_NAME_LENGTH); + } +} diff --git a/src/test/java/racingcar/CarsTest.java b/src/test/java/racingcar/CarsTest.java new file mode 100644 index 000000000..70933c4ea --- /dev/null +++ b/src/test/java/racingcar/CarsTest.java @@ -0,0 +1,35 @@ +package racingcar; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import racingcar.domain.Cars; + +import static org.assertj.core.api.Assertions.*; + +public class CarsTest { + + private static final String EXCEPTION_MESSAGE_CARS_DUPLICATED_NAME = "[ERROR] 자동차 이름은 중복될 수 없습니다"; + + @DisplayName("Cars 객체를 성공적으로 생성한다.") + @ParameterizedTest + @ValueSource(strings = {"pobii,pop,p", "p", "pob,pb,bb,dcd,wqwqg,xvd,aw,be", "pb,,pob,,,bo"}) + void createCarsSuccess(String input) { + boolean result = true; + try{ + Cars.createCarNameByWord(input); + }catch (IllegalArgumentException exception) { + result = false; + } + assertThat(result).isEqualTo(true); + } + + @DisplayName("Cars 객체 생성시 중복되는 자동차 이름이있다") + @ParameterizedTest + @ValueSource(strings = {"d,gme,d", "wwwww,ef,weah,wwwww,wwwww", "d,d,d,d,d,d,d,d,d,d"}) + void createCarsByDuplicatedName (String input) { + assertThatThrownBy(() -> Cars.createCarNameByWord(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(EXCEPTION_MESSAGE_CARS_DUPLICATED_NAME); + } +} From c117b2b4a8a4f6bcdc1bb43f9c3aa5246f0b4a1f Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 02:08:09 +0900 Subject: [PATCH 06/16] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80=20=EC=A3=BC?= =?UTF-8?q?=EC=96=B4=EC=A7=84=20=ED=9A=9F=EC=88=98=EB=A5=BC=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EB=B0=9B=EB=8A=94=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/RacingCarController.java | 25 ++++++++++-- .../java/racingcar/domain/RacingCarGame.java | 12 ++++++ .../java/racingcar/domain/TryCommand.java | 39 +++++++++++++++++++ .../exception/TryCommandNumberException.java | 10 +++++ .../exception/TryCommandRangeException.java | 10 +++++ src/main/java/racingcar/view/InputView.java | 5 +++ src/main/java/racingcar/view/OutputView.java | 9 +++++ 7 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 src/main/java/racingcar/domain/TryCommand.java create mode 100644 src/main/java/racingcar/exception/TryCommandNumberException.java create mode 100644 src/main/java/racingcar/exception/TryCommandRangeException.java diff --git a/src/main/java/racingcar/controller/RacingCarController.java b/src/main/java/racingcar/controller/RacingCarController.java index 8783ba9ad..8a3cd401f 100644 --- a/src/main/java/racingcar/controller/RacingCarController.java +++ b/src/main/java/racingcar/controller/RacingCarController.java @@ -1,21 +1,38 @@ package racingcar.controller; import racingcar.domain.Cars; +import racingcar.domain.RacingCarGame; +import racingcar.domain.TryCommand; import racingcar.view.InputView; import racingcar.view.OutputView; -import java.util.function.Supplier; - public class RacingCarController { private final InputView inputView = new InputView(); private final OutputView outputView = new OutputView(); + private RacingCarGame racingCarGame; public void runGame() { - askCarName(); + makeRacingCarGame(); + playGame(); + } + + private void playGame() { + + } + + private void makeRacingCarGame() { + racingCarGame = new RacingCarGame(askCar(), askTryCommand()); + outputView.printBlank(); + } + + private TryCommand askTryCommand() { + outputView.printInputTry(); + return new ReEnterProcessor<>(inputView::readTryCommand, outputView::printExceptionMessage).process(); } - private Cars askCarName() { + + private Cars askCar() { outputView.printInputCarName(); return new ReEnterProcessor<>(inputView::readCarName, outputView::printExceptionMessage).process(); } diff --git a/src/main/java/racingcar/domain/RacingCarGame.java b/src/main/java/racingcar/domain/RacingCarGame.java index f1a48f1c1..e4162bfe3 100644 --- a/src/main/java/racingcar/domain/RacingCarGame.java +++ b/src/main/java/racingcar/domain/RacingCarGame.java @@ -1,4 +1,16 @@ package racingcar.domain; public class RacingCarGame { + + private final Cars cars; + private final TryCommand tryCommand; + + public RacingCarGame(Cars cars, TryCommand tryCommand) { + this.cars = cars; + this.tryCommand = tryCommand; + } + + public void moveCars() { + + } } diff --git a/src/main/java/racingcar/domain/TryCommand.java b/src/main/java/racingcar/domain/TryCommand.java new file mode 100644 index 000000000..a6b3e5a34 --- /dev/null +++ b/src/main/java/racingcar/domain/TryCommand.java @@ -0,0 +1,39 @@ +package racingcar.domain; + +import racingcar.exception.TryCommandNumberException; +import racingcar.exception.TryCommandRangeException; + +public class TryCommand { + + private static final int MIN_TRY = 1; + private static final int MAX_TRY = 100000; + private int tryCount; + + private TryCommand(int tryCount) { + this.tryCount = tryCount; + } + + public static TryCommand createTryCommandByString(String input) { + int number = convertInt(input); + validate(number); + return new TryCommand(number); + } + + private static void validate(int number) { + validateRange(number); + } + + private static void validateRange(int number) { + if(number < MIN_TRY || number > MAX_TRY) { + throw new TryCommandRangeException(MIN_TRY, MAX_TRY); + } + } + + private static int convertInt(String input) { + try{ + return Integer.parseInt(input); + }catch (IllegalArgumentException exception) { + throw new TryCommandNumberException(); + } + } +} diff --git a/src/main/java/racingcar/exception/TryCommandNumberException.java b/src/main/java/racingcar/exception/TryCommandNumberException.java new file mode 100644 index 000000000..02e755052 --- /dev/null +++ b/src/main/java/racingcar/exception/TryCommandNumberException.java @@ -0,0 +1,10 @@ +package racingcar.exception; + +public class TryCommandNumberException extends IllegalArgumentException { + + private static final String EXCEPTION_MESSAGE_TRY_COMMAND_NUMBER = "[ERROR] 시도 횟수는 숫자를 입력해야 합니다."; + + public TryCommandNumberException() { + super(EXCEPTION_MESSAGE_TRY_COMMAND_NUMBER); + } +} diff --git a/src/main/java/racingcar/exception/TryCommandRangeException.java b/src/main/java/racingcar/exception/TryCommandRangeException.java new file mode 100644 index 000000000..3b032b86c --- /dev/null +++ b/src/main/java/racingcar/exception/TryCommandRangeException.java @@ -0,0 +1,10 @@ +package racingcar.exception; + +public class TryCommandRangeException extends IllegalArgumentException { + + private static final String EXCEPTION_MESSAGE_TRY_COMMAND_RANGE = "[ERROR] 시도횟수는 최소 %d, 최대 %d 입니다."; + + public TryCommandRangeException(int minTry, int maxTry) { + super(String.format(EXCEPTION_MESSAGE_TRY_COMMAND_RANGE, minTry, maxTry)); + } +} diff --git a/src/main/java/racingcar/view/InputView.java b/src/main/java/racingcar/view/InputView.java index 2deced5e3..36807ae32 100644 --- a/src/main/java/racingcar/view/InputView.java +++ b/src/main/java/racingcar/view/InputView.java @@ -1,6 +1,7 @@ package racingcar.view; import racingcar.domain.Cars; +import racingcar.domain.TryCommand; import static camp.nextstep.edu.missionutils.Console.readLine; @@ -9,4 +10,8 @@ public class InputView { public Cars readCarName() { return Cars.createCarNameByWord(readLine()); } + + public TryCommand readTryCommand() { + return TryCommand.createTryCommandByString(readLine()); + } } diff --git a/src/main/java/racingcar/view/OutputView.java b/src/main/java/racingcar/view/OutputView.java index 727945024..d82a1371c 100644 --- a/src/main/java/racingcar/view/OutputView.java +++ b/src/main/java/racingcar/view/OutputView.java @@ -3,6 +3,7 @@ public class OutputView { private static final String MESSAGE_INPUT_CAR_NAME = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"; + private static final String MESSAGE_INPUT_TRY = "시도할 회수는 몇회인가요?"; public void printInputCarName() { System.out.println(MESSAGE_INPUT_CAR_NAME); @@ -11,4 +12,12 @@ public void printInputCarName() { public void printExceptionMessage(IllegalArgumentException exceptionMessage) { exceptionMessage.printStackTrace(); } + + public void printInputTry() { + System.out.println(MESSAGE_INPUT_TRY); + } + + public void printBlank() { + System.out.println(); + } } From 134df50787e19396fd5155290b7042945d82b1f5 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 02:08:33 +0900 Subject: [PATCH 07/16] =?UTF-8?q?test:=20=EC=B6=94=EA=B0=80=20=EC=A3=BC?= =?UTF-8?q?=EC=96=B4=EC=A7=84=20=ED=9A=9F=EC=88=98=EB=A5=BC=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EB=B0=9B=EB=8A=94=20=EA=B8=B0=EB=8A=A5=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/racingcar/TryCommandTest.java | 47 +++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/test/java/racingcar/TryCommandTest.java diff --git a/src/test/java/racingcar/TryCommandTest.java b/src/test/java/racingcar/TryCommandTest.java new file mode 100644 index 000000000..814a247e5 --- /dev/null +++ b/src/test/java/racingcar/TryCommandTest.java @@ -0,0 +1,47 @@ +package racingcar; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import racingcar.domain.Car; +import racingcar.domain.TryCommand; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class TryCommandTest { + + private static final String EXCEPTION_MESSAGE_TRY_COMMAND_NUMBER = "[ERROR] 시도 횟수는 숫자를 입력해야 합니다."; + private static final String EXCEPTION_MESSAGE_TRY_COMMAND_RANGE = "[ERROR] 시도횟수는 최소 1, 최대 100000 입니다."; + + @DisplayName("TryCommand 객체를 성공적으로 생성한다.") + @ParameterizedTest + @ValueSource(strings = {"1", "3", "100000"}) + void createTryCommandSuccess(String input) { + boolean result = true; + try{ + TryCommand.createTryCommandByString(input); + }catch (IllegalArgumentException exception) { + result = false; + } + assertThat(result).isEqualTo(true); + } + + @DisplayName("숫자가 아닌 입력시 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"pobi", "d"}) + void createTryCommandByNotNumber(String input) { + assertThatThrownBy(() -> TryCommand.createTryCommandByString(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(EXCEPTION_MESSAGE_TRY_COMMAND_NUMBER); + } + + @DisplayName("값의 범위를 넘어갈시 예외가 발생한다") + @ParameterizedTest + @ValueSource(strings = {"-1", "0", "100001"}) + void createTryCommandByOverRange(String input) { + assertThatThrownBy(() -> TryCommand.createTryCommandByString(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(EXCEPTION_MESSAGE_TRY_COMMAND_RANGE); + } +} From 3fc2bae7fae3e53f4725bca41a1d7b006cc03e9d Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 02:39:13 +0900 Subject: [PATCH 08/16] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=EB=8A=94=20=EC=A0=84=EC=A7=84=20=EB=98=90?= =?UTF-8?q?=EB=8A=94=20=EB=A9=88=EC=B6=A4=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/racingcar/domain/Car.java | 11 ++++++++++- .../racingcar/domain/CarMoveNumberGenerator.java | 6 ++++++ .../domain/CarRandomMoveNumberGenerator.java | 14 ++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/main/java/racingcar/domain/CarMoveNumberGenerator.java create mode 100644 src/main/java/racingcar/domain/CarRandomMoveNumberGenerator.java diff --git a/src/main/java/racingcar/domain/Car.java b/src/main/java/racingcar/domain/Car.java index fb1408c79..bcffcc2a3 100644 --- a/src/main/java/racingcar/domain/Car.java +++ b/src/main/java/racingcar/domain/Car.java @@ -5,6 +5,7 @@ public class Car { private static final int CAR_NAME_LENGTH = 5; + private static final int MOVABLE_MIN_NUMBER = 4; private final String name; private int position = 0; @@ -18,8 +19,16 @@ private void validate(String name) { } private void validateLength(String name) { - if(name.length() > CAR_NAME_LENGTH) { + if (name.length() > CAR_NAME_LENGTH) { throw new CarNameLengthException(); } } + + public void move(CarMoveNumberGenerator carMoveNumberGenerator) { + final int number = carMoveNumberGenerator.generate(); + + if (number >= MOVABLE_MIN_NUMBER) { + position++; + } + } } diff --git a/src/main/java/racingcar/domain/CarMoveNumberGenerator.java b/src/main/java/racingcar/domain/CarMoveNumberGenerator.java new file mode 100644 index 000000000..c7be924c9 --- /dev/null +++ b/src/main/java/racingcar/domain/CarMoveNumberGenerator.java @@ -0,0 +1,6 @@ +package racingcar.domain; + +public interface CarMoveNumberGenerator { + + int generate(); +} diff --git a/src/main/java/racingcar/domain/CarRandomMoveNumberGenerator.java b/src/main/java/racingcar/domain/CarRandomMoveNumberGenerator.java new file mode 100644 index 000000000..6646476e8 --- /dev/null +++ b/src/main/java/racingcar/domain/CarRandomMoveNumberGenerator.java @@ -0,0 +1,14 @@ +package racingcar.domain; + +import camp.nextstep.edu.missionutils.Randoms; + +public class CarRandomMoveNumberGenerator implements CarMoveNumberGenerator { + + private static final int RANDOM_LOWER_INCLUSIVE = 0; + private static final int RANDOM_UPPER_INCLUSIVE = 9; + + @Override + public int generate() { + return Randoms.pickNumberInRange(RANDOM_LOWER_INCLUSIVE, RANDOM_UPPER_INCLUSIVE); + } +} From 9f8abc4c52280cff05f19f312a6d8ca8ded5dc9d Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 02:41:46 +0900 Subject: [PATCH 09/16] =?UTF-8?q?test:=20=EC=B6=94=EA=B0=80=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=EB=8A=94=20=EC=A0=84=EC=A7=84=20=EB=98=90?= =?UTF-8?q?=EB=8A=94=20=EB=A9=88=EC=B6=A4=20=EA=B8=B0=EB=8A=A5=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/racingcar/CarTest.java | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/test/java/racingcar/CarTest.java b/src/test/java/racingcar/CarTest.java index 1788555eb..e8afd2ae1 100644 --- a/src/test/java/racingcar/CarTest.java +++ b/src/test/java/racingcar/CarTest.java @@ -1,12 +1,17 @@ package racingcar; 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 racingcar.domain.Car; +import racingcar.domain.CarMoveNumberGenerator; + +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.util.Lists.newArrayList; public class CarTest { @@ -33,4 +38,48 @@ void createCarByOverLength(String input) { .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining(EXCEPTION_MESSAGE_CAR_NAME_LENGTH); } + + @DisplayName("자동차가 4 이상의 숫자가 들어올시 움직인다.") + @Test + void moveCarSuccess() { + Car car = new Car("pobi"); + CarMoveNumberGenerator carMoveNumberGenerator + = new TestNumberGenerator(newArrayList(4, 5, 6, 7, 8, 9)); + car.move(carMoveNumberGenerator); + car.move(carMoveNumberGenerator); + car.move(carMoveNumberGenerator); + car.move(carMoveNumberGenerator); + car.move(carMoveNumberGenerator); + car.move(carMoveNumberGenerator); + + assertThat(car).extracting("position").isEqualTo(6); + } + + @DisplayName("자동차가 4 이하의 숫자가 들어올시 움직이지 않는다.") + @Test + void moveCarFail() { + Car car = new Car("pobi"); + CarMoveNumberGenerator carMoveNumberGenerator + = new TestNumberGenerator(newArrayList(0, 1, 2, 3)); + car.move(carMoveNumberGenerator); + car.move(carMoveNumberGenerator); + car.move(carMoveNumberGenerator); + car.move(carMoveNumberGenerator); + + assertThat(car).extracting("position").isEqualTo(0); + } + + static class TestNumberGenerator implements CarMoveNumberGenerator { + + private final List numbers; + + TestNumberGenerator(List numbers) { + this.numbers = numbers; + } + + @Override + public int generate() { + return numbers.remove(0); + } + } } From 76ad6d5920571f42b402b775b30981fa65277d47 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 03:40:30 +0900 Subject: [PATCH 10/16] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80=20=EC=A3=BC?= =?UTF-8?q?=EC=96=B4=EC=A7=84=20=ED=9A=9F=EC=88=98=20=EB=8F=99=EC=95=88=20?= =?UTF-8?q?n=EB=8C=80=EC=9D=98=20=EC=9E=90=EB=8F=99=EC=B0=A8=EB=8A=94=20?= =?UTF-8?q?=EC=A0=84=EC=A7=84=20=EB=98=90=EB=8A=94=20=EB=A9=88=EC=B6=A4=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/RacingCarController.java | 9 +++++++-- src/main/java/racingcar/domain/Car.java | 8 ++++++++ src/main/java/racingcar/domain/Cars.java | 10 ++++++++++ .../java/racingcar/domain/RacingCarGame.java | 10 ++++++---- .../java/racingcar/domain/TryCommand.java | 8 ++++++++ src/main/java/racingcar/view/OutputView.java | 20 +++++++++++++++++++ 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/main/java/racingcar/controller/RacingCarController.java b/src/main/java/racingcar/controller/RacingCarController.java index 8a3cd401f..29b08b824 100644 --- a/src/main/java/racingcar/controller/RacingCarController.java +++ b/src/main/java/racingcar/controller/RacingCarController.java @@ -1,5 +1,6 @@ package racingcar.controller; +import racingcar.domain.CarRandomMoveNumberGenerator; import racingcar.domain.Cars; import racingcar.domain.RacingCarGame; import racingcar.domain.TryCommand; @@ -18,11 +19,15 @@ public void runGame() { } private void playGame() { - + TryCommand tryCommand = askTryCommand(); + while(tryCommand.tryMove()){ + racingCarGame.move(); + outputView.printResult(racingCarGame.getCars()); + } } private void makeRacingCarGame() { - racingCarGame = new RacingCarGame(askCar(), askTryCommand()); + racingCarGame = new RacingCarGame(askCar()); outputView.printBlank(); } diff --git a/src/main/java/racingcar/domain/Car.java b/src/main/java/racingcar/domain/Car.java index bcffcc2a3..494db6685 100644 --- a/src/main/java/racingcar/domain/Car.java +++ b/src/main/java/racingcar/domain/Car.java @@ -31,4 +31,12 @@ public void move(CarMoveNumberGenerator carMoveNumberGenerator) { position++; } } + + public String getName() { + return name; + } + + public int getPosition() { + return position; + } } diff --git a/src/main/java/racingcar/domain/Cars.java b/src/main/java/racingcar/domain/Cars.java index f80893c18..2cd22485e 100644 --- a/src/main/java/racingcar/domain/Cars.java +++ b/src/main/java/racingcar/domain/Cars.java @@ -44,4 +44,14 @@ private static void validateDuplicatedWord(String[] words) { private static String[] divideWord(String word) { return word.replaceAll(DUPLICATED_DELIMITER_REGEX, DELIMITER).split(DELIMITER); } + + public void move(CarMoveNumberGenerator carMoveNumberGenerator) { + for(Car car : cars) { + car.move(carMoveNumberGenerator); + } + } + + public List getCars() { + return cars; + } } diff --git a/src/main/java/racingcar/domain/RacingCarGame.java b/src/main/java/racingcar/domain/RacingCarGame.java index e4162bfe3..56ecf960d 100644 --- a/src/main/java/racingcar/domain/RacingCarGame.java +++ b/src/main/java/racingcar/domain/RacingCarGame.java @@ -3,14 +3,16 @@ public class RacingCarGame { private final Cars cars; - private final TryCommand tryCommand; - public RacingCarGame(Cars cars, TryCommand tryCommand) { + public RacingCarGame(Cars cars) { this.cars = cars; - this.tryCommand = tryCommand; } - public void moveCars() { + public void move() { + cars.move(new CarRandomMoveNumberGenerator()); + } + public Cars getCars() { + return cars; } } diff --git a/src/main/java/racingcar/domain/TryCommand.java b/src/main/java/racingcar/domain/TryCommand.java index a6b3e5a34..57f121640 100644 --- a/src/main/java/racingcar/domain/TryCommand.java +++ b/src/main/java/racingcar/domain/TryCommand.java @@ -36,4 +36,12 @@ private static int convertInt(String input) { throw new TryCommandNumberException(); } } + + public boolean tryMove() { + if(tryCount > 0) { + tryCount--; + return true; + } + return false; + } } diff --git a/src/main/java/racingcar/view/OutputView.java b/src/main/java/racingcar/view/OutputView.java index d82a1371c..8b082d676 100644 --- a/src/main/java/racingcar/view/OutputView.java +++ b/src/main/java/racingcar/view/OutputView.java @@ -1,9 +1,17 @@ package racingcar.view; +import racingcar.domain.Car; +import racingcar.domain.Cars; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + public class OutputView { private static final String MESSAGE_INPUT_CAR_NAME = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"; private static final String MESSAGE_INPUT_TRY = "시도할 회수는 몇회인가요?"; + private static final String MOVE_MARK = "-"; + private static final String JOIN_NAME_AND_POSITION = " : "; public void printInputCarName() { System.out.println(MESSAGE_INPUT_CAR_NAME); @@ -20,4 +28,16 @@ public void printInputTry() { public void printBlank() { System.out.println(); } + + public void printResult(Cars cars) { + System.out.println("실행 결과"); + for(Car car : cars.getCars()){ + System.out.println(car.getName() + JOIN_NAME_AND_POSITION + convertMoveMark(car.getPosition())); + } + printBlank(); + } + + private String convertMoveMark(int position) { + return Stream.generate(() -> MOVE_MARK).limit(position).collect(Collectors.joining()); + } } From c3f9689b3950673ab567ac9c97cf44ff304e5f2d Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 03:41:04 +0900 Subject: [PATCH 11/16] =?UTF-8?q?test:=20=EC=B6=94=EA=B0=80=20=EC=A3=BC?= =?UTF-8?q?=EC=96=B4=EC=A7=84=20=ED=9A=9F=EC=88=98=20=EB=8F=99=EC=95=88=20?= =?UTF-8?q?n=EB=8C=80=EC=9D=98=20=EC=9E=90=EB=8F=99=EC=B0=A8=EB=8A=94=20?= =?UTF-8?q?=EC=A0=84=EC=A7=84=20=EB=98=90=EB=8A=94=20=EB=A9=88=EC=B6=A4=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/racingcar/CarsTest.java | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/test/java/racingcar/CarsTest.java b/src/test/java/racingcar/CarsTest.java index 70933c4ea..520534759 100644 --- a/src/test/java/racingcar/CarsTest.java +++ b/src/test/java/racingcar/CarsTest.java @@ -1,11 +1,17 @@ package racingcar; 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 racingcar.domain.Car; +import racingcar.domain.CarMoveNumberGenerator; import racingcar.domain.Cars; +import java.util.List; + import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.util.Lists.newArrayList; public class CarsTest { @@ -16,9 +22,9 @@ public class CarsTest { @ValueSource(strings = {"pobii,pop,p", "p", "pob,pb,bb,dcd,wqwqg,xvd,aw,be", "pb,,pob,,,bo"}) void createCarsSuccess(String input) { boolean result = true; - try{ + try { Cars.createCarNameByWord(input); - }catch (IllegalArgumentException exception) { + } catch (IllegalArgumentException exception) { result = false; } assertThat(result).isEqualTo(true); @@ -27,9 +33,24 @@ void createCarsSuccess(String input) { @DisplayName("Cars 객체 생성시 중복되는 자동차 이름이있다") @ParameterizedTest @ValueSource(strings = {"d,gme,d", "wwwww,ef,weah,wwwww,wwwww", "d,d,d,d,d,d,d,d,d,d"}) - void createCarsByDuplicatedName (String input) { + void createCarsByDuplicatedName(String input) { assertThatThrownBy(() -> Cars.createCarNameByWord(input)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining(EXCEPTION_MESSAGE_CARS_DUPLICATED_NAME); } + + @DisplayName("모든 자동차가 정상적으로 움직인다.") + @Test + void moveCarsSuccess() { + Cars cars = Cars.createCarNameByWord("pobi,randi,rudy"); + CarMoveNumberGenerator carMoveNumberGenerator + = new CarTest.TestNumberGenerator(newArrayList(4, 2, 6, 9, 5, 6, 4, 0, 1)); + cars.move(carMoveNumberGenerator); + cars.move(carMoveNumberGenerator); + cars.move(carMoveNumberGenerator); + + assertThat(cars.getCars().get(0)).extracting("position").isEqualTo(3); + assertThat(cars.getCars().get(1)).extracting("position").isEqualTo(1); + assertThat(cars.getCars().get(2)).extracting("position").isEqualTo(2); + } } From d0017287bd9384db04bf6a39f60b2ba76efadb8d Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 04:52:49 +0900 Subject: [PATCH 12/16] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=20=EA=B2=BD=EC=A3=BC=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=EC=9D=84=20=EC=99=84=EB=A3=8C=ED=95=9C=20=ED=9B=84=20=EB=88=84?= =?UTF-8?q?=EA=B0=80=20=EC=9A=B0=EC=8A=B9=ED=96=88=EB=8A=94=EC=A7=80=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/RacingCarController.java | 5 ++++ src/main/java/racingcar/domain/Cars.java | 24 +++++++++++++++---- .../java/racingcar/domain/RacingCarGame.java | 4 ++++ src/main/java/racingcar/domain/Winner.java | 16 +++++++++++++ .../exception/CarsMaxScoreBlankException.java | 10 ++++++++ src/main/java/racingcar/view/OutputView.java | 11 +++++++++ 6 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 src/main/java/racingcar/domain/Winner.java create mode 100644 src/main/java/racingcar/exception/CarsMaxScoreBlankException.java diff --git a/src/main/java/racingcar/controller/RacingCarController.java b/src/main/java/racingcar/controller/RacingCarController.java index 29b08b824..acdcc0977 100644 --- a/src/main/java/racingcar/controller/RacingCarController.java +++ b/src/main/java/racingcar/controller/RacingCarController.java @@ -16,6 +16,11 @@ public class RacingCarController { public void runGame() { makeRacingCarGame(); playGame(); + endGame(); + } + + private void endGame() { + outputView.printWinner(racingCarGame.findWinner()); } private void playGame() { diff --git a/src/main/java/racingcar/domain/Cars.java b/src/main/java/racingcar/domain/Cars.java index 2cd22485e..ce2bbc67d 100644 --- a/src/main/java/racingcar/domain/Cars.java +++ b/src/main/java/racingcar/domain/Cars.java @@ -1,11 +1,10 @@ package racingcar.domain; import racingcar.exception.CarsDuplicatedNameException; +import racingcar.exception.CarsMaxScoreBlankException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; +import java.util.stream.Collectors; public class Cars { @@ -46,11 +45,26 @@ private static String[] divideWord(String word) { } public void move(CarMoveNumberGenerator carMoveNumberGenerator) { - for(Car car : cars) { + for (Car car : cars) { car.move(carMoveNumberGenerator); } } + public Winner findWinner() { + int maxScore = findMaxScore(); + return new Winner(cars.stream() + .filter(car -> (car.getPosition() == maxScore)) + .map(Car::getName) + .collect(Collectors.toList())); + } + + private int findMaxScore() { + return cars.stream() + .max(Comparator.comparingInt(Car::getPosition)) + .map(Car::getPosition) + .orElseThrow(CarsMaxScoreBlankException::new); + } + public List getCars() { return cars; } diff --git a/src/main/java/racingcar/domain/RacingCarGame.java b/src/main/java/racingcar/domain/RacingCarGame.java index 56ecf960d..978811609 100644 --- a/src/main/java/racingcar/domain/RacingCarGame.java +++ b/src/main/java/racingcar/domain/RacingCarGame.java @@ -12,6 +12,10 @@ public void move() { cars.move(new CarRandomMoveNumberGenerator()); } + public Winner findWinner() { + return cars.findWinner(); + } + public Cars getCars() { return cars; } diff --git a/src/main/java/racingcar/domain/Winner.java b/src/main/java/racingcar/domain/Winner.java new file mode 100644 index 000000000..f3924e04f --- /dev/null +++ b/src/main/java/racingcar/domain/Winner.java @@ -0,0 +1,16 @@ +package racingcar.domain; + +import java.util.List; + +public class Winner { + + private final List winner; + + public Winner(List winner) { + this.winner = winner; + } + + public List getWinner() { + return winner; + } +} diff --git a/src/main/java/racingcar/exception/CarsMaxScoreBlankException.java b/src/main/java/racingcar/exception/CarsMaxScoreBlankException.java new file mode 100644 index 000000000..b98ae8a03 --- /dev/null +++ b/src/main/java/racingcar/exception/CarsMaxScoreBlankException.java @@ -0,0 +1,10 @@ +package racingcar.exception; + +public class CarsMaxScoreBlankException extends IllegalArgumentException{ + + private static final String EXCEPTION_MESSAGE_CARS_MAX_SCORE_BLANK = "[ERROR] 우승자를 찾을 수 없습니다."; + + public CarsMaxScoreBlankException() { + super(EXCEPTION_MESSAGE_CARS_MAX_SCORE_BLANK); + } +} diff --git a/src/main/java/racingcar/view/OutputView.java b/src/main/java/racingcar/view/OutputView.java index 8b082d676..3290e904a 100644 --- a/src/main/java/racingcar/view/OutputView.java +++ b/src/main/java/racingcar/view/OutputView.java @@ -2,6 +2,7 @@ import racingcar.domain.Car; import racingcar.domain.Cars; +import racingcar.domain.Winner; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -13,6 +14,10 @@ public class OutputView { private static final String MOVE_MARK = "-"; private static final String JOIN_NAME_AND_POSITION = " : "; + private static final String WINNER_DELIMITER = ","; + private static final String MESSAGE_WINNER_PREFIX = "최종 우승자 : "; + private static final String MESSAGE_WINNER_SUFFIX = ""; + public void printInputCarName() { System.out.println(MESSAGE_INPUT_CAR_NAME); } @@ -40,4 +45,10 @@ public void printResult(Cars cars) { private String convertMoveMark(int position) { return Stream.generate(() -> MOVE_MARK).limit(position).collect(Collectors.joining()); } + + public void printWinner(Winner winner) { + String message = winner.getWinner().stream() + .collect(Collectors.joining(WINNER_DELIMITER, MESSAGE_WINNER_PREFIX, MESSAGE_WINNER_SUFFIX)); + System.out.println(message); + } } From 6cc73d5b432740e4aa3a0edd97c093b0ba46bffd Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 04:53:07 +0900 Subject: [PATCH 13/16] =?UTF-8?q?test:=20=EC=B6=94=EA=B0=80=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=20=EA=B2=BD=EC=A3=BC=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=EC=9D=84=20=EC=99=84=EB=A3=8C=ED=95=9C=20=ED=9B=84=20=EB=88=84?= =?UTF-8?q?=EA=B0=80=20=EC=9A=B0=EC=8A=B9=ED=96=88=EB=8A=94=EC=A7=80=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/racingcar/CarsTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/racingcar/CarsTest.java b/src/test/java/racingcar/CarsTest.java index 520534759..3c7bc8a0c 100644 --- a/src/test/java/racingcar/CarsTest.java +++ b/src/test/java/racingcar/CarsTest.java @@ -8,6 +8,7 @@ import racingcar.domain.CarMoveNumberGenerator; import racingcar.domain.Cars; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.*; @@ -53,4 +54,20 @@ void moveCarsSuccess() { assertThat(cars.getCars().get(1)).extracting("position").isEqualTo(1); assertThat(cars.getCars().get(2)).extracting("position").isEqualTo(2); } + + @DisplayName("우승자를 찾아서 반환한다") + @Test + void findWinnerSuccess() { + Cars cars = Cars.createCarNameByWord("pobi,randi,rudy"); + CarMoveNumberGenerator carMoveNumberGenerator + = new CarTest.TestNumberGenerator(newArrayList(4, 2, 6, 9, 5, 6, 4, 0, 7)); + cars.move(carMoveNumberGenerator); + cars.move(carMoveNumberGenerator); + cars.move(carMoveNumberGenerator); + + List result = new ArrayList<>(); + result.add("pobi"); + result.add("rudy"); + assertThat(cars.findWinner().getWinner()).isEqualTo(result); + } } From 5a0b4323794bcf1218f8554c2b0037a27279ea77 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 04:55:34 +0900 Subject: [PATCH 14/16] =?UTF-8?q?fix:=20=EB=B3=80=EA=B2=BD=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EB=A9=94=EC=84=B8=EC=A7=80=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=EB=B0=A9=EC=8B=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존에는 printStackTrace 로 출력하였으나, 메시지 출력방식을 원해서 변경 TryCommand 클래스에서 String->int 형변환시 예외 catch 를 NumberFormatException 으로 수정 --- src/main/java/racingcar/domain/TryCommand.java | 2 +- src/main/java/racingcar/view/OutputView.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/racingcar/domain/TryCommand.java b/src/main/java/racingcar/domain/TryCommand.java index 57f121640..d70c4ec21 100644 --- a/src/main/java/racingcar/domain/TryCommand.java +++ b/src/main/java/racingcar/domain/TryCommand.java @@ -32,7 +32,7 @@ private static void validateRange(int number) { private static int convertInt(String input) { try{ return Integer.parseInt(input); - }catch (IllegalArgumentException exception) { + }catch (NumberFormatException exception) { throw new TryCommandNumberException(); } } diff --git a/src/main/java/racingcar/view/OutputView.java b/src/main/java/racingcar/view/OutputView.java index 3290e904a..ebdddc2f3 100644 --- a/src/main/java/racingcar/view/OutputView.java +++ b/src/main/java/racingcar/view/OutputView.java @@ -23,7 +23,7 @@ public void printInputCarName() { } public void printExceptionMessage(IllegalArgumentException exceptionMessage) { - exceptionMessage.printStackTrace(); + System.out.println(exceptionMessage.getMessage()); } public void printInputTry() { From e5e4263c739b4c3a45aac856c196bff0141914a8 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 07:50:33 +0900 Subject: [PATCH 15/16] =?UTF-8?q?refactor:=20=EC=88=98=EC=A0=95=20Cars=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cars 객체 생성시 불변값으로 설정 --- src/main/java/racingcar/domain/Cars.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/racingcar/domain/Cars.java b/src/main/java/racingcar/domain/Cars.java index ce2bbc67d..8d571a743 100644 --- a/src/main/java/racingcar/domain/Cars.java +++ b/src/main/java/racingcar/domain/Cars.java @@ -13,7 +13,7 @@ public class Cars { private final List cars; private Cars(List cars) { - this.cars = cars; + this.cars = Collections.unmodifiableList(cars); } public static Cars createCarNameByWord(String input) { From 1f078400a178ce5511f031e98019c1687c58d91a Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 7 Dec 2022 08:05:52 +0900 Subject: [PATCH 16/16] =?UTF-8?q?refactor:=20=EC=88=98=EC=A0=95=20outputVi?= =?UTF-8?q?ew?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 상수화가 안된 메시지가 있어서 수정 --- src/main/java/racingcar/view/OutputView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/racingcar/view/OutputView.java b/src/main/java/racingcar/view/OutputView.java index ebdddc2f3..3c086ba8c 100644 --- a/src/main/java/racingcar/view/OutputView.java +++ b/src/main/java/racingcar/view/OutputView.java @@ -11,9 +11,9 @@ public class OutputView { private static final String MESSAGE_INPUT_CAR_NAME = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"; private static final String MESSAGE_INPUT_TRY = "시도할 회수는 몇회인가요?"; + private static final String MESSAGE_RESULT = "실행 결과"; private static final String MOVE_MARK = "-"; private static final String JOIN_NAME_AND_POSITION = " : "; - private static final String WINNER_DELIMITER = ","; private static final String MESSAGE_WINNER_PREFIX = "최종 우승자 : "; private static final String MESSAGE_WINNER_SUFFIX = ""; @@ -35,7 +35,7 @@ public void printBlank() { } public void printResult(Cars cars) { - System.out.println("실행 결과"); + System.out.println(MESSAGE_RESULT); for(Car car : cars.getCars()){ System.out.println(car.getName() + JOIN_NAME_AND_POSITION + convertMoveMark(car.getPosition())); }