diff --git a/README.md b/README.md
index 90a5236..313cc02 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
- 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. •자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다.
- 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
- 전진하는 조건은 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이
-하의 값이면 멈춘다.
+ 하의 값이면 멈춘다.
- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다.
@@ -19,39 +19,39 @@
## 🎱 프로그래밍 요구사항 - 1주차와 동일
- 자바 코드 컨벤션을 지키면서 프로그래밍한다.
- - 기본적으로 [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) 문서와 [네이버 핵데이 Java 컨벤션](https://naver.github.io/hackday-conventions-java/)을 원칙으로 한다.
- - 단, 들여쓰기는 '2 spaces'가 아닌 '4 spaces'로 한다.
+ - 기본적으로 [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) 문서와 [네이버 핵데이 Java 컨벤션](https://naver.github.io/hackday-conventions-java/)을 원칙으로 한다.
+ - 단, 들여쓰기는 '2 spaces'가 아닌 '4 spaces'로 한다.
- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
- - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
- - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.
+ - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
+ - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.
- 3항 연산자를 쓰지 않는다.
- 함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라.
- System.exit 메소드를 사용하지 않는다.
- 비정상적 입력에 대해서는 IllegalArgumentException을 발생시킨다.
### 프로그래밍 요구사항 - 2주차 추가
-- 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다.
- - 함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다.
+- 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다.
+ - 함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다.
- else 예약어를 쓰지 않는다.
- - 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
- - else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
+ - 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
+ - else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
### 프로그래밍 요구사항 - 객체
-- 다음 Car 객체를 활용해 구현해야 한다.
-- Car 기본 생성자를 추가할 수 없다.
-- name, position 변수의 접근 제어자인 private을 변경할 수 없다.
+- 다음 Car 객체를 활용해 구현해야 한다.
+- Car 기본 생성자를 추가할 수 없다.
+- name, position 변수의 접근 제어자인 private을 변경할 수 없다.
- 가능하면 setPosition(int position) 메소드를 추가하지 않고 구현한다.
```java
public class Car {
- private final String name;
- private int position = 0;
-
- public Car(String name) {
- this.name = name;
- }
-
- // 추가 기능 구현
+ private final String name;
+ private int position = 0;
+
+ public Car(String name) {
+ this.name = name;
+ }
+
+ // 추가 기능 구현
}
```
@@ -61,10 +61,37 @@ public class Car {
- 미션은 현재 저장소를 fork & clone해서 시작한다.
- 기능을 구현하기 전에 java-baseball-precourse/README.md 파일에 구현할 기능 목록을 정리해 추가한다.
- git의 commit 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가한다.
- - [AngularJS Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 참고해 commit log를 남긴다.
+ - [AngularJS Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 참고해 commit log를 남긴다.
## 📝 License
This project is [MIT](https://github.com/woowacourse/java-baseball-precourse/blob/master/LICENSE) licensed.
+
+
+
+### 기능 순서
+- 입력
+ - 자동차 이름
+ - 몇 번 이동할 것인지 시도할 횟수
+- 시도 횟수만큼 반복
+ - random 값 구하고 전진/멈춤
+ - 출력: 한 판에 대한 실행 결과
+- 출력: 우승자(1명 이상)
+
+### 기능 목록
+- [x] 입력 - 자동차 이름, 횟수
+ - [x] 자동차 이름 글자수 예외
+- [x] 자동차: 이름, 위치
+- [x] 경주 게임
+ - [x] 각 자동차의 0-9 사이 랜덤값 구하기
+ - [x] 자동차들 위치 이동 - 전진 or 멈춤
+ - [x] 실행 - 결과 출력
+- [x] 최종 우승자 구하기 및 출력
+
+### 예외
+
+- 자동차 이름
+ - 5글자 이하만 가능
+ - 공백일 경우
diff --git a/src/main/java/Application.java b/src/main/java/Application.java
new file mode 100644
index 0000000..6aac089
--- /dev/null
+++ b/src/main/java/Application.java
@@ -0,0 +1,14 @@
+import domain.CarFactory;
+import domain.RacingCarGame;
+import ui.Receiver;
+
+public class Application {
+ public static void main(String[] args) {
+ Receiver receiver = new Receiver();
+ CarFactory carFactory = new CarFactory(receiver.getCarNames());
+ RacingCarGame racingCarGame = new RacingCarGame(carFactory.getCars(), receiver.getRound());
+
+ racingCarGame.proceedRounds();
+ racingCarGame.printWinners();
+ }
+}
diff --git a/src/main/java/domain/Car.java b/src/main/java/domain/Car.java
index e5b4a0a..2797eaf 100644
--- a/src/main/java/domain/Car.java
+++ b/src/main/java/domain/Car.java
@@ -1,12 +1,40 @@
package domain;
-public class Car {
+import domain.exception.NotBlankException;
+
+public class Car implements Comparable {
private final String name;
private int position = 0;
public Car(String name) {
this.name = name;
+ validateName();
+ }
+
+ public void moveForward() {
+ position += 1;
+ }
+
+ private void validateName() {
+ if (name.length() > 5) {
+ throw new IllegalArgumentException(name + ": 자동차 이름은 5글자 이하여야 합니다.");
+ }
+
+ if (name.isBlank()) {
+ throw new NotBlankException("공백으로만 이루어진 이름을 생성할 수 없습니다.");
+ }
}
- // 추가 기능 구현
+ public String getName() {
+ return name;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ @Override
+ public int compareTo(Car o) {
+ return o.position - position;
+ }
}
diff --git a/src/main/java/domain/CarFactory.java b/src/main/java/domain/CarFactory.java
new file mode 100644
index 0000000..a145b04
--- /dev/null
+++ b/src/main/java/domain/CarFactory.java
@@ -0,0 +1,40 @@
+package domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CarFactory {
+ private final String DELIMITER = ",";
+
+ private final List cars;
+ private final String[] carNames;
+
+ public CarFactory(String input) {
+ this.carNames = splitCarNames(input);
+ trimCarNames();
+ cars = createCars();
+ }
+
+ private String[] splitCarNames(String answer) {
+ return answer.split(DELIMITER);
+ }
+
+ private void trimCarNames() {
+ for (int i = 0; i < carNames.length; i++) {
+ carNames[i] = carNames[i].trim();
+ }
+ }
+
+ private List createCars() {
+ List cars = new ArrayList<>();
+ for (String carName : carNames) {
+ cars.add(new Car(carName));
+ }
+
+ return cars;
+ }
+
+ public List getCars() {
+ return cars;
+ }
+}
diff --git a/src/main/java/domain/RacingCarGame.java b/src/main/java/domain/RacingCarGame.java
new file mode 100644
index 0000000..5afeec1
--- /dev/null
+++ b/src/main/java/domain/RacingCarGame.java
@@ -0,0 +1,70 @@
+package domain;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import utils.RandomUtils;
+
+public class RacingCarGame {
+ private static final String RESULT_START_MESSAGE = "\n실행 결과";
+ private static final String RESULT_END_MESSAGE = "가 최종 우승했습니다.";
+ private static final String COLON = " : ";
+ private static final String DASH = "-";
+
+ private final List cars;
+ private final int round;
+
+ public RacingCarGame(List cars, int round) {
+ this.cars = cars;
+ this.round = round;
+ }
+
+ private void movePosition(int idx) {
+ int randomValue = RandomUtils.generateNumber();
+
+ if (randomValue >= 4) {
+ cars.get(idx).moveForward();
+ }
+ }
+
+ private void proceedOneRound() {
+ IntStream.range(0, cars.size()).forEach(this::movePosition);
+ }
+
+ public void proceedRounds() {
+ System.out.println(RESULT_START_MESSAGE);
+
+ IntStream.range(0, round).forEach(r -> {
+ proceedOneRound();
+ printCurrentPositions();
+ });
+ }
+
+ private void printCurrentPositions() {
+ for (Car car : cars) {
+ System.out.print(car.getName() + COLON);
+
+ IntStream.range(0, car.getPosition()).mapToObj(j -> DASH).forEach(System.out::print);
+ System.out.println();
+ }
+
+ System.out.println();
+ }
+
+ public void printWinners() {
+ Collections.sort(cars);
+
+ int max = cars.get(0).getPosition();
+ System.out.print(cars.get(0).getName());
+
+ for (int i = 1; i < cars.size(); i++) {
+ if (cars.get(i).getPosition() < max) {
+ break;
+ }
+ System.out.print(", " + cars.get(i).getName());
+ }
+
+ System.out.println(RESULT_END_MESSAGE);
+ }
+}
diff --git a/src/main/java/domain/exception/NotBlankException.java b/src/main/java/domain/exception/NotBlankException.java
new file mode 100644
index 0000000..22740bb
--- /dev/null
+++ b/src/main/java/domain/exception/NotBlankException.java
@@ -0,0 +1,7 @@
+package domain.exception;
+
+public class NotBlankException extends IllegalArgumentException {
+ public NotBlankException(String s) {
+ super(s);
+ }
+}
diff --git a/src/main/java/ui/Receiver.java b/src/main/java/ui/Receiver.java
new file mode 100644
index 0000000..57b492f
--- /dev/null
+++ b/src/main/java/ui/Receiver.java
@@ -0,0 +1,39 @@
+package ui;
+
+import java.util.Scanner;
+
+public class Receiver {
+ private static final String REQUEST_CAR_NAME = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)";
+ private static final String REQUEST_ROUND = "시도할 횟수는 몇회인가요?";
+
+ private static final Scanner scanner = new Scanner(System.in);
+
+ private String carNames;
+ private int round;
+
+
+ public Receiver() {
+ receiveCarNames();
+ receiveRound();
+ }
+
+ public void receiveCarNames() {
+ System.out.println(REQUEST_CAR_NAME);
+ carNames = scanner.nextLine();
+// return carNames;
+ }
+
+ public void receiveRound() {
+ System.out.println(REQUEST_ROUND);
+ round = scanner.nextInt();
+// return round;
+ }
+
+ public String getCarNames() {
+ return carNames;
+ }
+
+ public int getRound() {
+ return round;
+ }
+}
diff --git a/src/main/java/utils/RandomUtils.java b/src/main/java/utils/RandomUtils.java
new file mode 100644
index 0000000..30ee101
--- /dev/null
+++ b/src/main/java/utils/RandomUtils.java
@@ -0,0 +1,15 @@
+package utils;
+
+import java.util.Random;
+
+public class RandomUtils {
+ private static final int UPPER_BOUND = 10;
+ private static final Random RANDOM = new Random();
+
+ private RandomUtils() {
+ }
+
+ public static int generateNumber(){
+ return RANDOM.nextInt(UPPER_BOUND);
+ }
+}
diff --git a/src/test/java/domain/CarFactoryTest.java b/src/test/java/domain/CarFactoryTest.java
new file mode 100644
index 0000000..78aa889
--- /dev/null
+++ b/src/test/java/domain/CarFactoryTest.java
@@ -0,0 +1,23 @@
+package domain;
+
+import java.util.List;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class CarFactoryTest {
+
+ private CarFactory carFactory;
+ private String input = " lee, chan, gyu ";
+
+ @Test
+ public void 차를_생성한다() throws Exception {
+ carFactory = new CarFactory(input);
+
+ List cars = carFactory.getCars();
+
+ Assertions.assertThat(cars.get(0).getName()).isEqualTo("lee");
+ Assertions.assertThat(cars.get(1).getName()).isEqualTo("chan");
+ Assertions.assertThat(cars.get(2).getName()).isEqualTo("gyu");
+ }
+}
diff --git a/src/test/java/domain/CarTest.java b/src/test/java/domain/CarTest.java
new file mode 100644
index 0000000..8de9d5a
--- /dev/null
+++ b/src/test/java/domain/CarTest.java
@@ -0,0 +1,41 @@
+package domain;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+import domain.exception.NotBlankException;
+
+public class CarTest {
+
+ private Car car;
+
+ @Test
+ public void moveForward() throws Exception {
+ String name = "green";
+
+ car = new Car(name);
+ car.moveForward();
+ car.moveForward();
+
+ assertThat(car.getPosition()).isEqualTo(2);
+ }
+
+ @Test
+ public void 이름이_공백인_경우_NotBlankException을_던진다() {
+ String name = " ";
+
+ assertThatThrownBy(() -> new Car(name))
+ .isInstanceOf(NotBlankException.class)
+ .hasMessageContaining("공백으로만 이루어진 이름을 생성할 수 없습니다.");
+ }
+
+ @Test
+ public void 이름이_5글자_이상인_경우_Exception을_던진다() throws Exception {
+ String name = "softee";
+
+ assertThatThrownBy(() -> new Car(name))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("자동차 이름은 5글자 이하여야 합니다.");
+ }
+}
diff --git a/src/test/java/domain/RacingCarGameTest.java b/src/test/java/domain/RacingCarGameTest.java
new file mode 100644
index 0000000..b880b32
--- /dev/null
+++ b/src/test/java/domain/RacingCarGameTest.java
@@ -0,0 +1,39 @@
+package domain;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class RacingCarGameTest {
+
+ private RacingCarGame racingCarGame;
+
+ @BeforeEach
+ void setUp() {
+ int round = 5;
+ List cars = new ArrayList<>();
+ cars.add(new Car("lee"));
+ cars.add(new Car("chan"));
+ cars.add(new Car("gyu"));
+
+ racingCarGame = new RacingCarGame(cars, round);
+ }
+
+ @Test
+ public void 라운드를_진행한다() throws Exception {
+ racingCarGame.proceedRounds();
+ }
+
+ @Test
+ public void 우승자를_정한다() throws Exception {
+ //given
+ racingCarGame.proceedRounds();
+
+ //when
+ racingCarGame.printWinners();
+ }
+}
\ No newline at end of file