From 6bf339c3180eb4dac2b70358e133fbb067204c8d Mon Sep 17 00:00:00 2001 From: Regyung Date: Wed, 12 Feb 2025 18:44:43 +0900 Subject: [PATCH 1/6] =?UTF-8?q?docs(README):=20=EA=B3=BC=EC=A0=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EA=B5=AC=ED=98=84=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d0286c8..499712a 100644 --- a/README.md +++ b/README.md @@ -1 +1,86 @@ -# java-racingcar-precourse +# 2주차 미션 : 자동차 경주 +
+ 과제 세부 내용 + +## 과제 +- 초간단 자동차 경주 게임을 구현한다. + - 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. + - 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. + - 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다. + - 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. + - 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우이다. + - 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. + - 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다. + - 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료되어야 한다. +### 입출력 +- 경주 할 자동차 이름(이름은 쉽표(,) 기준으로 구분) + + pobi,woni,jun + +- 시도할 횟수 + + 5 + +- 각 차수별 실행 결과 + + pobi : -- + woni : ---- + jun : --- + +- 단독 우승자 안내 문구 + + 최종 우승자 : pobi + +- 공동 우승자 안내 문구 + + 최종 우승자 : pobi, jun + +### 실행 결과 예시 + 경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분) + pobi,woni,jun + 시도할 회수는 몇회인가요? + 5 + + 실행 결과 + pobi : - + woni : + jun : - + + pobi : -- + woni : - + jun : -- + + pobi : --- + woni : -- + jun : --- + + pobi : ---- + woni : --- + jun : ---- + + pobi : ----- + woni : ---- + jun : ----- + + 최종 우승자 : pobi, jun + +
+ +## 구현할 기능 목록 +### Model + Car() // Class + - name + - count + - getName() + - getCount() + - forward() + - printResult() +### Service + - sliceName() + - getWinner() +### View + - input() + - interimTally() + - output() +### Controller + - startRace() \ No newline at end of file From fa3f1d7882c12e7540f5b21cc3834b1b2a1f698e Mon Sep 17 00:00:00 2001 From: Regyung Date: Wed, 12 Feb 2025 18:51:59 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat(ALL):=20=EC=A0=84=EC=B2=B4=EC=A0=81?= =?UTF-8?q?=EC=9D=B8=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 - Car 객체 생성 - 입출력 기능 - 문자열 슬라이싱 - 우승자 구분 --- src/main/java/racingcar/Application.java | 4 ++- .../racingcar/controller/RaceController.java | 27 ++++++++++++++ src/main/java/racingcar/model/Car.java | 36 +++++++++++++++++++ .../java/racingcar/service/GetWinner.java | 17 +++++++++ .../java/racingcar/service/SliceName.java | 10 ++++++ src/main/java/racingcar/view/RaceView.java | 35 ++++++++++++++++++ 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/main/java/racingcar/controller/RaceController.java create mode 100644 src/main/java/racingcar/model/Car.java create mode 100644 src/main/java/racingcar/service/GetWinner.java create mode 100644 src/main/java/racingcar/service/SliceName.java create mode 100644 src/main/java/racingcar/view/RaceView.java diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index a17a52e..964db17 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,7 +1,9 @@ package racingcar; +import racingcar.controller.RaceController; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + RaceController.startRace(); } } diff --git a/src/main/java/racingcar/controller/RaceController.java b/src/main/java/racingcar/controller/RaceController.java new file mode 100644 index 0000000..094a169 --- /dev/null +++ b/src/main/java/racingcar/controller/RaceController.java @@ -0,0 +1,27 @@ +package racingcar.controller; + +import racingcar.model.Car; +import racingcar.service.GetWinner; +import racingcar.service.SliceName; +import racingcar.view.RaceView; + +import java.util.List; + +public class RaceController { + public static void startRace() { + String p = RaceView.inputCars(); + int times = RaceView.inputTimes(); + List participant = SliceName.slice(p); + + for (String s : participant) { + Car.cars.add(new Car(s)); + } + + System.out.println("실행 결과"); + for (int i = 0; i < times; i++) { + RaceView.interimTally(Car.cars); + } + + RaceView.outputWinner(GetWinner.getWinner(Car.cars.stream(), GetWinner.getMax(Car.cars.stream()))); + } +} diff --git a/src/main/java/racingcar/model/Car.java b/src/main/java/racingcar/model/Car.java new file mode 100644 index 0000000..e701b8e --- /dev/null +++ b/src/main/java/racingcar/model/Car.java @@ -0,0 +1,36 @@ +package racingcar.model; + +import camp.nextstep.edu.missionutils.Randoms; + +import java.util.ArrayList; +import java.util.List; + +public class Car { + public static List cars = new ArrayList<>(); + + String name; + int count; + + public Car(String name) { + this.name = name; + this.count = 0; + } + + public String getName() { + return name; + } + + public int getCount() { + return count; + } + + public void forward() { + if (Randoms.pickNumberInRange(0, 9) >= 4) { + count++; + } + } + + public void printResult() { + System.out.println(name + " : " + "-".repeat(count)); + } +} diff --git a/src/main/java/racingcar/service/GetWinner.java b/src/main/java/racingcar/service/GetWinner.java new file mode 100644 index 0000000..799e26e --- /dev/null +++ b/src/main/java/racingcar/service/GetWinner.java @@ -0,0 +1,17 @@ +package racingcar.service; + +import racingcar.model.Car; + +import java.util.List; +import java.util.stream.Stream; + +public class GetWinner { + public static int getMax(Stream c) { + return c.map(Car::getCount).max(Integer::compare).get(); + } + + public static String getWinner(Stream c, int max) { + List result = c.filter(car -> car.getCount() == max).map(Car::getName).toList(); + return String.join(", ", result); + } +} diff --git a/src/main/java/racingcar/service/SliceName.java b/src/main/java/racingcar/service/SliceName.java new file mode 100644 index 0000000..a6a32ed --- /dev/null +++ b/src/main/java/racingcar/service/SliceName.java @@ -0,0 +1,10 @@ +package racingcar.service; + +import java.util.Arrays; +import java.util.List; + +public class SliceName { + public static List slice(String s) { + return Arrays.asList(s.split(",")); + } +} diff --git a/src/main/java/racingcar/view/RaceView.java b/src/main/java/racingcar/view/RaceView.java new file mode 100644 index 0000000..1c648a4 --- /dev/null +++ b/src/main/java/racingcar/view/RaceView.java @@ -0,0 +1,35 @@ +package racingcar.view; + +import camp.nextstep.edu.missionutils.Console; +import racingcar.model.Car; + +import java.util.List; + +public class RaceView { + public static String inputCars() { + System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + return Console.readLine(); + } + public static int inputTimes() { + System.out.println("시도할 회수는 몇회인가요?"); + String t = Console.readLine(); + + if (Integer.parseInt(t) > 0) return Integer.parseInt(t); + + throw new IllegalArgumentException(); + } + + public static void interimTally(List c) { + for (Car car : c ) { + car.forward(); + } + for (Car car : c ) { + car.printResult(); + } + System.out.println(); + } + + public static void outputWinner(String winner) { + System.out.println("최종 우승자 : " + winner); + } +} From 90d345a09b6168953b8adc84c2c127cc0c4f729c Mon Sep 17 00:00:00 2001 From: Regyung Date: Thu, 13 Feb 2025 21:23:54 +0900 Subject: [PATCH 3/6] =?UTF-8?q?docs(README):=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=9E=AC?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 499712a..04ce620 100644 --- a/README.md +++ b/README.md @@ -78,9 +78,12 @@ ### Service - sliceName() - getWinner() + - checkInput() ### View - input() + - inputTimes() - interimTally() + - outputResult() - output() ### Controller - startRace() \ No newline at end of file From c56d8866265224f3f17ae03b9a950e69809867fe Mon Sep 17 00:00:00 2001 From: Regyung Date: Thu, 13 Feb 2025 21:41:43 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat(CHECK):=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 자동차 이름이 비어있을 때 - 자동차 이름이 하나거나 쉼표가 없을 때 - 자동차 이름이 5자를 초과할 때 - 횟수 입력이 잘못 되었을 때 --- .../java/racingcar/service/CheckInput.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/java/racingcar/service/CheckInput.java diff --git a/src/main/java/racingcar/service/CheckInput.java b/src/main/java/racingcar/service/CheckInput.java new file mode 100644 index 0000000..6d4aa25 --- /dev/null +++ b/src/main/java/racingcar/service/CheckInput.java @@ -0,0 +1,35 @@ +package racingcar.service; + +import java.util.List; +import java.util.regex.Pattern; + +public class CheckInput { + public static List checkName(String s) { + if (s.isEmpty()) throw new IllegalArgumentException("자동차 이름들이 비어있습니다."); + + if (s.split(",").length < 2) throw new IllegalArgumentException("자동차 이름이 부족하거나 구분자가 없습니다."); + + List l = SliceName.slice(s); + + for (String p : l) { + if (Pattern.matches("\\s+", p)) throw new IllegalArgumentException("자동차 이름이 비어있습니다."); + if (p.length() > 5) throw new IllegalArgumentException("자동차 이름이 5자 초과입니다."); + } + + return l; + } + + public static int checkNumber(String s) { + if (s.isEmpty()) throw new IllegalArgumentException("횟수값이 비어있습니다."); + + try { + Integer.parseInt(s); + }catch (NumberFormatException e) { + throw new IllegalArgumentException("횟수값이 숫자가 아니거나 너무 많습니다."); + } + + if (Integer.parseInt(s) <= 0) throw new IllegalArgumentException("횟수값이 양수가 아닙니다."); + + return Integer.parseInt(s); + } +} From c2d297283a1b0fbb10fa2b676c0da9af955a89dc Mon Sep 17 00:00:00 2001 From: Regyung Date: Thu, 13 Feb 2025 21:44:31 +0900 Subject: [PATCH 5/6] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기본적인 기능 테스트 - 자동차 이름이 비어있을 때 - 횟수가 비어있을 때 - 자동자 이름들 중 공란이 있을 때 - 횟수가 오버플로우 됐을 때 - 횟수가 양수가 아닐 때 --- src/test/java/racingcar/ApplicationTest.java | 40 ++++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/test/java/racingcar/ApplicationTest.java b/src/test/java/racingcar/ApplicationTest.java index 1d35fc3..5a12b44 100644 --- a/src/test/java/racingcar/ApplicationTest.java +++ b/src/test/java/racingcar/ApplicationTest.java @@ -13,7 +13,7 @@ class ApplicationTest extends NsTest { private static final int STOP = 3; @Test - void 기능_테스트() { + void functionTest() { assertRandomNumberInRangeTest( () -> { run("pobi,woni", "1"); @@ -24,10 +24,42 @@ class ApplicationTest extends NsTest { } @Test - void 예외_테스트() { + void isEmpty1() { assertSimpleTest(() -> - assertThatThrownBy(() -> runException("pobi,javaji", "1")) - .isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> runException("", "1")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + + @Test + void isEmpty2() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("pobi,woni", " ")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + + @Test + void isEmpty3() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("pobi, ", "1")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + + @Test + void overFlow() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("pobi,woni ", "10000000000000000000")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + + @Test + void notPositiveNumber() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("pobi,woni ", "-1")) + .isInstanceOf(IllegalArgumentException.class) ); } From 34ebfc921e38a54d24d1f9f335ac2cdd916c5a6e Mon Sep 17 00:00:00 2001 From: Regyung Date: Thu, 13 Feb 2025 21:47:31 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor(OUTPUT):=20Controller,=20View=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 실행 결과 출력 코드를 기능의 사용처를 고려해 Controller에서 View로 이동 - 기존 View에서 불필요했던 코드 수정 --- .../racingcar/controller/RaceController.java | 11 +++++------ src/main/java/racingcar/view/RaceView.java | 17 +++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/racingcar/controller/RaceController.java b/src/main/java/racingcar/controller/RaceController.java index 094a169..d8a2931 100644 --- a/src/main/java/racingcar/controller/RaceController.java +++ b/src/main/java/racingcar/controller/RaceController.java @@ -1,6 +1,7 @@ package racingcar.controller; import racingcar.model.Car; +import racingcar.service.CheckInput; import racingcar.service.GetWinner; import racingcar.service.SliceName; import racingcar.view.RaceView; @@ -10,17 +11,15 @@ public class RaceController { public static void startRace() { String p = RaceView.inputCars(); - int times = RaceView.inputTimes(); - List participant = SliceName.slice(p); + int times = CheckInput.checkNumber(RaceView.inputTimes()); + + List participant = CheckInput.checkName(p); for (String s : participant) { Car.cars.add(new Car(s)); } - System.out.println("실행 결과"); - for (int i = 0; i < times; i++) { - RaceView.interimTally(Car.cars); - } + RaceView.outputResult(times); RaceView.outputWinner(GetWinner.getWinner(Car.cars.stream(), GetWinner.getMax(Car.cars.stream()))); } diff --git a/src/main/java/racingcar/view/RaceView.java b/src/main/java/racingcar/view/RaceView.java index 1c648a4..e0f297e 100644 --- a/src/main/java/racingcar/view/RaceView.java +++ b/src/main/java/racingcar/view/RaceView.java @@ -10,25 +10,26 @@ public static String inputCars() { System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); return Console.readLine(); } - public static int inputTimes() { + public static String inputTimes() { System.out.println("시도할 회수는 몇회인가요?"); - String t = Console.readLine(); - - if (Integer.parseInt(t) > 0) return Integer.parseInt(t); - - throw new IllegalArgumentException(); + return Console.readLine(); } public static void interimTally(List c) { for (Car car : c ) { car.forward(); - } - for (Car car : c ) { car.printResult(); } System.out.println(); } + public static void outputResult(int t) { + System.out.println("실행 결과"); + for (int i = 0; i < t; i++) { + RaceView.interimTally(Car.cars); + } + } + public static void outputWinner(String winner) { System.out.println("최종 우승자 : " + winner); }