From 41c1cc83fb2d5e6371f5aa33e1b75e0af79e0b1a Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Sun, 27 Oct 2024 15:20:27 +0900 Subject: [PATCH 01/14] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=20=EC=82=AC=ED=95=AD,=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [기능 요구 사항] 자동차 경주 문제에 대한 로직을 기능 별로 분리 및 순차 정리 - 초기 입력 - 전진에 따른 난수 생성 및 전진 여부 판별 - 1회 시도마다 전진 현황 출력 - 우승자 선정, 최종 우승자 출력 [예외 케이스] - 자동차 이름 문자열이 쉼표로 구분되지 않을 경우 구분 시 5자 이하가 아닐 경우 - 시도할 횟수 양의 정수가 아닌 경우 --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index d0286c859f..c55a254be7 100644 --- a/README.md +++ b/README.md @@ -1 +1,36 @@ # java-racingcar-precourse + +## 기능 요구 사항 +1. 경주할 **자동차 이름**과 **시도할 횟수**를 입력받는다. + 1-1. 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 종료되어야 한다. + + +2. 각 자동차마다 **0에서 9** 사이의 난수를 생성한다. +3. 생성된 난수가 **4 이상**이면 해당 자동차를 **전진**시킨다. +4. 모든 자동차의 1회 시도가 끝나면, 자동차 이름과 함께 **누적 전진**한 칸만큼 "-"를 출력한다. + (출력 형식 → chae : ---) + + +*(입력받은 시도 횟수만큼 **2, 3, 4**의 과정을 반복한다.)* + + +5. 경주한 자동차 중 최종적으로 **전진한 값**이 가장 높은 자동차를 우승자로 선정한다. + 5-1. 여러 자동차가 동시에 가장 높은 값을 가졌을 경우 **공동 우승자**로 선정한다. + + +6. 우승한 자동차의 이름을 **우승자 안내** 문구와 함께 출력한다. + (출력 형식 → 최종 우승자 : chae, morol) + + +## 예외 케이스 + +**[자동차 이름 입력]** +- 쉼표가 포함되지 않은 문자열 +- 구분한 결과가 5자 초과 +- 비어 있는 값 + +**[시도할 횟수 입력]** +- 0 또는 음수 +- 정수가 아닌 모든 수 +- 문자, 문자열 등 숫자가 아닌 값 +- 비어 있는 값 \ No newline at end of file From a6574ca42d2014e33c0e369c6f1e3317ffbb63c2 Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:30:29 +0900 Subject: [PATCH 02/14] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84,=20=EC=8B=9C=EB=8F=84=20=ED=9A=9F=EC=88=98?= =?UTF-8?q?=20=EC=9E=85=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 경주할 자동차의 이름과 시도할 횟수를 입력 받음 - 시도할 횟수를 숫자로 포맷하는 과정에서 에러가 날 경우 Exception 발생 --- src/main/java/racingcar/Application.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index a17a52e724..d5ca58c531 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,7 +1,16 @@ package racingcar; +import camp.nextstep.edu.missionutils.Console; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + String carsName = Console.readLine(); + System.out.println("시도할 횟수는 몇 회인가요?"); + try { + int raceRoundCount = Integer.parseInt(Console.readLine()); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(); + } } } From 3c22f8874fdf69721bb2a601b04263b7facab0bd Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:54:39 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feat:=20=EA=B0=9C=EB=B3=84=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=20=EC=BB=A8=ED=85=8C=EC=9D=B4=EB=84=88=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98=20=EB=B0=8F=20=EC=B4=88=EA=B8=B0=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EC=97=90=20=EB=8C=80=ED=95=9C=20split=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 개별 자동차에 대한 컨테이너를 Map 형태로 선언 - 초기 입력 문자열에 split 함수를 이용하여 String 배열 저장 - String 배열 검사, 5 이하일 경우에만 cars 컨테이너에 입력 값 저장 --- src/main/java/racingcar/Application.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index d5ca58c531..f049a4a732 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,16 +1,30 @@ package racingcar; import camp.nextstep.edu.missionutils.Console; +import java.util.HashMap; +import java.util.Map; public class Application { public static void main(String[] args) { System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); - String carsName = Console.readLine(); + String carsInput = Console.readLine(); System.out.println("시도할 횟수는 몇 회인가요?"); + int raceRoundCount; try { - int raceRoundCount = Integer.parseInt(Console.readLine()); + raceRoundCount = Integer.parseInt(Console.readLine()); } catch (NumberFormatException e) { throw new IllegalArgumentException(); } + + Map cars = new HashMap<>(); + + String[] carsName = carsInput.split(","); + + for (String car : carsName) { + if (car.length() > 5) { + throw new IllegalArgumentException(); + } + cars.put(car, 0); + } } } From 21820b48a6806a10c55bcc8af6255ea6dbb143b2 Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:02:30 +0900 Subject: [PATCH 04/14] =?UTF-8?q?feat:=20=EA=B0=81=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=B0=A8=EB=A7=88=EB=8B=A4=20=EB=82=9C=EC=88=98=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=EC=A0=84=EC=A7=84=20=EC=97=AC=EB=B6=80?= =?UTF-8?q?=20=ED=8C=90=EB=B3=84=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 각 자동차마다 pickNumberInRange() 메소드로 난수 생성 - 4 이상일 경우에만 car 컨테이너의 value 값에 1을 더함 - 입력 받은 시도 횟수(경기를 진행하는 수)만큼 반복 수행 --- src/main/java/racingcar/Application.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index f049a4a732..04890393bf 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,6 +1,7 @@ package racingcar; import camp.nextstep.edu.missionutils.Console; +import camp.nextstep.edu.missionutils.Randoms; import java.util.HashMap; import java.util.Map; @@ -26,5 +27,13 @@ public static void main(String[] args) { } cars.put(car, 0); } + + for (int count = 0; count < raceRoundCount; count++) { + for (String car : cars.keySet()) { + if (Randoms.pickNumberInRange(0, 9) >= 4) { + cars.put(car, cars.get(car) + 1); + } + } + } } } From ebb9435442227be362446cb4b4fcbcb5b7bb348f Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:18:59 +0900 Subject: [PATCH 05/14] =?UTF-8?q?feat:=201=ED=9A=8C=20=EC=8B=9C=EB=8F=84?= =?UTF-8?q?=EB=A7=88=EB=8B=A4=20=EC=9E=90=EB=8F=99=EC=B0=A8=20=EB=B3=84?= =?UTF-8?q?=EB=A1=9C=20=EB=88=84=EC=A0=81=20=EC=A0=84=EC=A7=84=ED=95=9C=20?= =?UTF-8?q?=EC=B9=B8=20=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 각 자동차의 이름과 전진 값을 map 컨테이너 이용하여 출력 - "-" 문자를 출력할 때 repeat() 메소드로 전진 값(value)만큼 반복하도록 함 --- src/main/java/racingcar/Application.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index 04890393bf..e3c42c7d4c 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -34,6 +34,10 @@ public static void main(String[] args) { cars.put(car, cars.get(car) + 1); } } + for (Map.Entry entry : cars.entrySet()) { + System.out.println(entry.getKey() + " : " + "-".repeat(entry.getValue())); + } + System.out.println(); } } -} +} \ No newline at end of file From b3501afa95b1114756f683f5b82458bd3c2a1a4b Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:50:39 +0900 Subject: [PATCH 06/14] =?UTF-8?q?feat:=20=EC=B5=9C=EC=A2=85=20=EC=A0=84?= =?UTF-8?q?=EC=A7=84=20=EA=B1=B0=EB=A6=AC=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EC=9A=B0=EC=8A=B9=EC=9E=90=20=EC=84=A0=EC=A0=95=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Collections.max()를 사용하여 최대 전진 거리 계산 - Stream API로 최대 전진 거리와 동일한 자동차들을 우승자로 선정 --- src/main/java/racingcar/Application.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index e3c42c7d4c..53cd99a2fe 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -2,7 +2,9 @@ import camp.nextstep.edu.missionutils.Console; import camp.nextstep.edu.missionutils.Randoms; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; public class Application { @@ -39,5 +41,12 @@ public static void main(String[] args) { } System.out.println(); } + + int maxValue = Collections.max(cars.values()); + + List winners = cars.entrySet().stream() + .filter(entry -> entry.getValue() == maxValue) + .map(Map.Entry::getKey) + .toList(); } } \ No newline at end of file From 7de07678363c1422ed6e01aa8712dbe64350fa7c Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:53:21 +0900 Subject: [PATCH 07/14] =?UTF-8?q?feat:=20=EC=B5=9C=EC=A2=85=20=EC=9A=B0?= =?UTF-8?q?=EC=8A=B9=EC=9E=90=20=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 최대 전진 거리를 value로 가지는 자동차(우승자) 리스트 출력 - String.join() 메소드를 통해 우승자가 여러 명일 경우 쉼표로 구분 --- src/main/java/racingcar/Application.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index 53cd99a2fe..bd4e37d37b 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -48,5 +48,7 @@ public static void main(String[] args) { .filter(entry -> entry.getValue() == maxValue) .map(Map.Entry::getKey) .toList(); + + System.out.println("최종 우승자 : " + String.join(", ", winners)); } } \ No newline at end of file From 4681a92030a486bd7825a1b73c3934930013579c Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:34:57 +0900 Subject: [PATCH 08/14] =?UTF-8?q?refactor:=20Main=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EC=97=90=20=EC=9E=91=EC=84=B1=EB=90=9C=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=EB=A5=BC=20MVC=20=ED=8C=A8=ED=84=B4=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Main] - Application 클래스: 메인 로직 실행 [Model] - Car 클래스: 자동차 객체 생성 및 이동 로직 구현 - RacingGame 클래스: 게임 진행, 자동차 관리, 우승자 결정 로직 구현 [View] - RacingGameView 클래스: 사용자 입력 프롬프트 및 게임 결과 출력 [Controller] - RacingGameController 클래스: 사용자 입력 처리, Model과 View 간 상호작용 조정 --- src/main/java/racingcar/Application.java | 53 +++---------------- .../controller/RacingGameController.java | 52 ++++++++++++++++++ src/main/java/racingcar/model/Car.java | 27 ++++++++++ src/main/java/racingcar/model/RacingGame.java | 48 +++++++++++++++++ .../java/racingcar/view/RacingGameView.java | 22 ++++++++ 5 files changed, 156 insertions(+), 46 deletions(-) create mode 100644 src/main/java/racingcar/controller/RacingGameController.java create mode 100644 src/main/java/racingcar/model/Car.java create mode 100644 src/main/java/racingcar/model/RacingGame.java create mode 100644 src/main/java/racingcar/view/RacingGameView.java diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index bd4e37d37b..43d9ba1695 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,54 +1,15 @@ package racingcar; -import camp.nextstep.edu.missionutils.Console; -import camp.nextstep.edu.missionutils.Randoms; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import racingcar.controller.RacingGameController; +import racingcar.model.RacingGame; +import racingcar.view.RacingGameView; public class Application { public static void main(String[] args) { - System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); - String carsInput = Console.readLine(); - System.out.println("시도할 횟수는 몇 회인가요?"); - int raceRoundCount; - try { - raceRoundCount = Integer.parseInt(Console.readLine()); - } catch (NumberFormatException e) { - throw new IllegalArgumentException(); - } + RacingGameView view = new RacingGameView(); + RacingGame model = new RacingGame(); + RacingGameController controller = new RacingGameController(model, view); - Map cars = new HashMap<>(); - - String[] carsName = carsInput.split(","); - - for (String car : carsName) { - if (car.length() > 5) { - throw new IllegalArgumentException(); - } - cars.put(car, 0); - } - - for (int count = 0; count < raceRoundCount; count++) { - for (String car : cars.keySet()) { - if (Randoms.pickNumberInRange(0, 9) >= 4) { - cars.put(car, cars.get(car) + 1); - } - } - for (Map.Entry entry : cars.entrySet()) { - System.out.println(entry.getKey() + " : " + "-".repeat(entry.getValue())); - } - System.out.println(); - } - - int maxValue = Collections.max(cars.values()); - - List winners = cars.entrySet().stream() - .filter(entry -> entry.getValue() == maxValue) - .map(Map.Entry::getKey) - .toList(); - - System.out.println("최종 우승자 : " + String.join(", ", winners)); + controller.runGame(); } } \ No newline at end of file diff --git a/src/main/java/racingcar/controller/RacingGameController.java b/src/main/java/racingcar/controller/RacingGameController.java new file mode 100644 index 0000000000..b237dc811c --- /dev/null +++ b/src/main/java/racingcar/controller/RacingGameController.java @@ -0,0 +1,52 @@ +package racingcar.controller; + +import racingcar.model.RacingGame; +import racingcar.view.RacingGameView; +import camp.nextstep.edu.missionutils.Console; + +import java.util.List; + +public class RacingGameController { + private final RacingGame racingGame; + private final RacingGameView racingGameView; + + public RacingGameController(RacingGame racingGame, RacingGameView racingGameView) { + this.racingGame = racingGame; + this.racingGameView = racingGameView; + } + + public void runGame() { + initializeGame(); + playGame(); + announceWinners(); + } + + private void initializeGame() { + racingGameView.printCarNameInputPrompt(); + String carNames = Console.readLine(); + racingGameView.printRoundCountPrompt(); + int roundCount = getRoundCount(); + + racingGame.initialize(carNames, roundCount); + } + + private int getRoundCount() { + try { + return Integer.parseInt(Console.readLine()); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(); + } + } + + private void playGame() { + for (int round = 0; round < racingGame.getRoundCount(); round++) { + racingGame.moveAllCars(); + racingGameView.printRoundResult(racingGame.getCarStates()); + } + } + + private void announceWinners() { + List winners = racingGame.getWinners(); + racingGameView.printWinners(winners); + } +} \ No newline at end of file diff --git a/src/main/java/racingcar/model/Car.java b/src/main/java/racingcar/model/Car.java new file mode 100644 index 0000000000..9ddb1d3fd8 --- /dev/null +++ b/src/main/java/racingcar/model/Car.java @@ -0,0 +1,27 @@ +package racingcar.model; + +import camp.nextstep.edu.missionutils.Randoms; + +public class Car { + private final String name; + private int position; + + public Car(String name) { + this.name = name; + this.position = 0; + } + + public void move() { + if (Randoms.pickNumberInRange(0, 9) >= 4) { + position++; + } + } + + public String getName() { + return name; + } + + public int getPosition() { + return position; + } +} \ No newline at end of file diff --git a/src/main/java/racingcar/model/RacingGame.java b/src/main/java/racingcar/model/RacingGame.java new file mode 100644 index 0000000000..235085509a --- /dev/null +++ b/src/main/java/racingcar/model/RacingGame.java @@ -0,0 +1,48 @@ +package racingcar.model; + +import java.util.List; +import java.util.stream.Collectors; + +public class RacingGame { + private List cars; + private int roundCount; + + public void initialize(String carNames, int roundCount) { + this.cars = createCars(carNames); + this.roundCount = roundCount; + } + + private List createCars(String carNames) { + return List.of(carNames.split(",")) + .stream() + .map(String::trim) + .map(Car::new) + .collect(Collectors.toList()); + } + + public void moveAllCars() { + cars.forEach(Car::move); + } + + public List getCarStates() { + return cars.stream() + .map(car -> car.getName() + " : " + "-".repeat(car.getPosition())) + .collect(Collectors.toList()); + } + + public List getWinners() { + int maxPosition = cars.stream() + .mapToInt(Car::getPosition) + .max() + .orElse(0); + + return cars.stream() + .filter(car -> car.getPosition() == maxPosition) + .map(Car::getName) + .collect(Collectors.toList()); + } + + public int getRoundCount() { + return roundCount; + } +} \ No newline at end of file diff --git a/src/main/java/racingcar/view/RacingGameView.java b/src/main/java/racingcar/view/RacingGameView.java new file mode 100644 index 0000000000..57eb388a8a --- /dev/null +++ b/src/main/java/racingcar/view/RacingGameView.java @@ -0,0 +1,22 @@ +package racingcar.view; + +import java.util.List; + +public class RacingGameView { + public void printCarNameInputPrompt() { + System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + } + + public void printRoundCountPrompt() { + System.out.println("시도할 횟수는 몇 회인가요?"); + } + + public void printRoundResult(List carStates) { + carStates.forEach(System.out::println); + System.out.println(); + } + + public void printWinners(List winners) { + System.out.println("최종 우승자 : " + String.join(", ", winners)); + } +} \ No newline at end of file From cdc255c3cbf117e57645668fffca7217e11c0153 Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:41:11 +0900 Subject: [PATCH 09/14] =?UTF-8?q?refactor:=20=EC=A0=84=EC=A7=84=20?= =?UTF-8?q?=ED=8C=90=EB=B3=84=20=EC=9E=84=EA=B3=84=EA=B0=92,=20=EB=82=9C?= =?UTF-8?q?=EC=88=98=20=EC=83=9D=EC=84=B1=20=EB=B2=94=EC=9C=84=20=EC=B5=9C?= =?UTF-8?q?=EB=8C=93=EA=B0=92=20=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MOVE_THRESHOLD: 난수를 생성했을 때 전진 여부를 판별하는 임계값(4)에 대한 상수 - RANDOM_BOUND: 난수를 생성할 수 있는 범위의 최댓값(9)에 대한 상수 --- src/main/java/racingcar/model/Car.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/racingcar/model/Car.java b/src/main/java/racingcar/model/Car.java index 9ddb1d3fd8..ffd6a88b94 100644 --- a/src/main/java/racingcar/model/Car.java +++ b/src/main/java/racingcar/model/Car.java @@ -3,6 +3,9 @@ import camp.nextstep.edu.missionutils.Randoms; public class Car { + private static final int MOVE_THRESHOLD = 4; + private static final int RANDOM_BOUND = 9; + private final String name; private int position; @@ -12,7 +15,7 @@ public Car(String name) { } public void move() { - if (Randoms.pickNumberInRange(0, 9) >= 4) { + if (Randoms.pickNumberInRange(0, RANDOM_BOUND) >= MOVE_THRESHOLD) { position++; } } From 9ed302a564d1800d1a2a897e75766f2f18151c66 Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:47:35 +0900 Subject: [PATCH 10/14] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EA=B5=AC=EB=B6=84=20=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=EA=B0=80=205=EC=9E=90=20=EC=B4=88=EA=B3=BC=20=EC=8B=9C=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EB=B0=9C=EC=83=9D=EC=8B=9C=ED=82=A4?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - validateName(String name) 메소드로 name의 길이 검사 - name의 길이가 5를 초과할 시 IllegalArgumentException 발생 --- src/main/java/racingcar/model/Car.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/racingcar/model/Car.java b/src/main/java/racingcar/model/Car.java index ffd6a88b94..6906346c25 100644 --- a/src/main/java/racingcar/model/Car.java +++ b/src/main/java/racingcar/model/Car.java @@ -10,10 +10,17 @@ public class Car { private int position; public Car(String name) { + validateName(name); this.name = name; this.position = 0; } + private void validateName(String name) { + if (name.length() > 5) { + throw new IllegalArgumentException(); + } + } + public void move() { if (Randoms.pickNumberInRange(0, RANDOM_BOUND) >= MOVE_THRESHOLD) { position++; From c2a4c5ef3028526aacf4acb5f1dac9ce5d4b4295 Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:49:35 +0900 Subject: [PATCH 11/14] =?UTF-8?q?refactor:=20=EC=9E=90=EB=8F=99=EC=B0=A8?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=20=EA=B8=B8=EC=9D=B4=20=EC=B5=9C=EB=8C=93?= =?UTF-8?q?=EA=B0=92=20=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MAX_NAME_LENGTH: 자동차 이름의 길이가 5자가 넘는지 판별 시 최댓값에 대한 상수 --- src/main/java/racingcar/model/Car.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/racingcar/model/Car.java b/src/main/java/racingcar/model/Car.java index 6906346c25..eb79738f32 100644 --- a/src/main/java/racingcar/model/Car.java +++ b/src/main/java/racingcar/model/Car.java @@ -3,6 +3,7 @@ import camp.nextstep.edu.missionutils.Randoms; public class Car { + private static final int MAX_NAME_LENGTH = 5; private static final int MOVE_THRESHOLD = 4; private static final int RANDOM_BOUND = 9; @@ -16,7 +17,7 @@ public Car(String name) { } private void validateName(String name) { - if (name.length() > 5) { + if (name.length() > MAX_NAME_LENGTH) { throw new IllegalArgumentException(); } } From 75ee95b05ac441b90fb6b27c4604673123db9ad4 Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 19:37:29 +0900 Subject: [PATCH 12/14] =?UTF-8?q?docs:=20=EC=9E=85=EC=B6=9C=EB=A0=A5=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D=20=EA=B4=80=EB=A0=A8=20=EA=B5=AC=EC=B2=B4?= =?UTF-8?q?=EC=A0=81=20=EB=82=B4=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기능 요구 사항의 입력, 출력 단계에 대해 구체적으로 기술함 --- README.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c55a254be7..f472898ede 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,22 @@ ## 기능 요구 사항 1. 경주할 **자동차 이름**과 **시도할 횟수**를 입력받는다. + +> **[입력 형식]** +경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분) +chae,morol +시도할 횟수는 몇 회인가요? +3 + 1-1. 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 종료되어야 한다. 2. 각 자동차마다 **0에서 9** 사이의 난수를 생성한다. 3. 생성된 난수가 **4 이상**이면 해당 자동차를 **전진**시킨다. -4. 모든 자동차의 1회 시도가 끝나면, 자동차 이름과 함께 **누적 전진**한 칸만큼 "-"를 출력한다. - (출력 형식 → chae : ---) - +4. 모든 자동차의 1회 시도가 끝나면, 자동차 이름과 함께 **누적 전진**한 칸만큼 "-"를 출력한다. +> **[출력 형식]** +chae : --- +morol : -- *(입력받은 시도 횟수만큼 **2, 3, 4**의 과정을 반복한다.)* @@ -18,8 +26,9 @@ 5-1. 여러 자동차가 동시에 가장 높은 값을 가졌을 경우 **공동 우승자**로 선정한다. -6. 우승한 자동차의 이름을 **우승자 안내** 문구와 함께 출력한다. - (출력 형식 → 최종 우승자 : chae, morol) +6. 우승한 자동차의 이름을 **우승자 안내** 문구와 함께 출력한다. +> **[출력 형식]** +최종 우승자 : chae, morol ## 예외 케이스 From bf5feb03d1b0bc8b311424c970c3a2630cb960bd Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 23:27:57 +0900 Subject: [PATCH 13/14] =?UTF-8?q?refactor:=20Validator(=EC=98=88=EC=99=B8?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC)=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - validateInputString 메소드: 입력 문자열에 ","가 없는지 검사 - validateCarName 메소드: 자동차 이름이 비어 있거나 최대 글자수를 넘는지 검사 - validateRoundCount 메소드: 시도 횟수가 0 이하인지 검사 - validateCarPosition 메소드: 자동차의 위치가 음수인지 검사 --- src/main/java/racingcar/model/Car.java | 10 ++----- src/main/java/racingcar/model/RacingGame.java | 6 ++++ src/main/java/racingcar/model/Validator.java | 29 +++++++++++++++++++ 3 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 src/main/java/racingcar/model/Validator.java diff --git a/src/main/java/racingcar/model/Car.java b/src/main/java/racingcar/model/Car.java index eb79738f32..0ba3d23058 100644 --- a/src/main/java/racingcar/model/Car.java +++ b/src/main/java/racingcar/model/Car.java @@ -3,7 +3,6 @@ import camp.nextstep.edu.missionutils.Randoms; public class Car { - private static final int MAX_NAME_LENGTH = 5; private static final int MOVE_THRESHOLD = 4; private static final int RANDOM_BOUND = 9; @@ -11,18 +10,13 @@ public class Car { private int position; public Car(String name) { - validateName(name); + Validator.validateCarName(name); this.name = name; this.position = 0; } - private void validateName(String name) { - if (name.length() > MAX_NAME_LENGTH) { - throw new IllegalArgumentException(); - } - } - public void move() { + Validator.validateCarPosition(position); if (Randoms.pickNumberInRange(0, RANDOM_BOUND) >= MOVE_THRESHOLD) { position++; } diff --git a/src/main/java/racingcar/model/RacingGame.java b/src/main/java/racingcar/model/RacingGame.java index 235085509a..979047b564 100644 --- a/src/main/java/racingcar/model/RacingGame.java +++ b/src/main/java/racingcar/model/RacingGame.java @@ -8,10 +8,16 @@ public class RacingGame { private int roundCount; public void initialize(String carNames, int roundCount) { + validate(carNames, roundCount); this.cars = createCars(carNames); this.roundCount = roundCount; } + private void validate(String carNames, int roundCount) { + Validator.validateInputString(carNames); + Validator.validateRoundCount(roundCount); + } + private List createCars(String carNames) { return List.of(carNames.split(",")) .stream() diff --git a/src/main/java/racingcar/model/Validator.java b/src/main/java/racingcar/model/Validator.java new file mode 100644 index 0000000000..d9030bb045 --- /dev/null +++ b/src/main/java/racingcar/model/Validator.java @@ -0,0 +1,29 @@ +package racingcar.model; + +public class Validator { + private static final int MAX_NAME_LENGTH = 5; + + public static void validateInputString(String carNames) { + if (!carNames.contains(",")) { + throw new IllegalArgumentException(); + } + } + + public static void validateCarName(String carName) { + if (carName.isEmpty() || carName.length() > MAX_NAME_LENGTH) { + throw new IllegalArgumentException(); + } + } + + public static void validateRoundCount(int roundCount) { + if (roundCount <= 0) { + throw new IllegalArgumentException(); + } + } + + public static void validateCarPosition(int position) { + if (position < 0) { + throw new IllegalArgumentException(); + } + } +} From 528d2da7a089ca0128557b8f3c4b285d30a160c0 Mon Sep 17 00:00:00 2001 From: Kim Chaewon <101501925+Dim-chae@users.noreply.github.com> Date: Mon, 28 Oct 2024 23:40:34 +0900 Subject: [PATCH 14/14] =?UTF-8?q?test:=20=EC=98=88=EC=99=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이름 길이 초과 예외 테스트: 이름 길이가 5자 초과일 경우 - 빈 이름 예외 테스트: 입력 문자열을 분리한 결과 빈 문자열이 있을 경우 - 시도 횟수 예외 테스트: 시도 횟수를 입력한 값이 문자열일 경우 --- src/test/java/racingcar/ApplicationTest.java | 32 ++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/test/java/racingcar/ApplicationTest.java b/src/test/java/racingcar/ApplicationTest.java index 1d35fc33fe..284c743bc3 100644 --- a/src/test/java/racingcar/ApplicationTest.java +++ b/src/test/java/racingcar/ApplicationTest.java @@ -31,6 +31,38 @@ class ApplicationTest extends NsTest { ); } + @Test + void 이름_길이_초과_예외_테스트() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("pobi,woni,javaji,longname,tooLongName", "1")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + + @Test + void 빈_이름_예외_테스트() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("pobi,,woni", "1")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + + @Test + void 음수_시도_횟수_예외_테스트() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("pobi,woni", "-1")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + + @Test + void 시도_횟수_예외_테스트() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("pobi,woni", "abc")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + @Override public void runMain() { Application.main(new String[]{});