diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..03478cd
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,9 @@
+
구현할 기능 목록
+
+- ### 사용자로부터 자동차 이름 입력받고 유효성 검사하기
+- ### 사용자로부터 시도할 횟수 입력받고 유효성 검사하기
+- ### 시도할 횟수만큼 라운드 반복하기
+- ### 모든 자동차 전진 또는 정지하기
+- ### 자동차의 상태 출력하기
+- ### 최종 우승자 찾기
+- ### 최종 우승자 출력하기
diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java
index b9ed045..8b8ecad 100644
--- a/src/main/java/racingcar/Application.java
+++ b/src/main/java/racingcar/Application.java
@@ -1,7 +1,17 @@
package racingcar;
+import racingcar.game.Car;
+import racingcar.game.Game;
+import racingcar.tool.InputUtils;
+
+import java.util.List;
+
public class Application {
public static void main(String[] args) {
- // TODO 구현 진행
+ List cars = InputUtils.getCarListFromInput();
+ int totalRound = InputUtils.getTotalRoundFromInput();
+ Game game = new Game(cars, totalRound);
+
+ game.start();
}
}
diff --git a/src/main/java/racingcar/Car.java b/src/main/java/racingcar/Car.java
deleted file mode 100644
index ab3df94..0000000
--- a/src/main/java/racingcar/Car.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package racingcar;
-
-public class Car {
- private final String name;
- private int position = 0;
-
- public Car(String name) {
- this.name = name;
- }
-
- // 추가 기능 구현
-}
diff --git a/src/main/java/racingcar/game/Car.java b/src/main/java/racingcar/game/Car.java
new file mode 100644
index 0000000..4b32685
--- /dev/null
+++ b/src/main/java/racingcar/game/Car.java
@@ -0,0 +1,51 @@
+package racingcar.game;
+
+import camp.nextstep.edu.missionutils.Randoms;
+
+import racingcar.tool.StringValidator;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+public class Car {
+ private final String name;
+ private int position = 0;
+
+ public Car(String name) {
+ this.name = name;
+ }
+
+ public static Car createCar(String carName) {
+ StringValidator.cannotUseCarName(carName);
+
+ return new Car(carName);
+ }
+
+ public int getPosition() {
+ return this.position;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String toString() {
+ return String.format("%s : %s",this.name, getMovingPositionLine());
+ }
+
+ public void move() {
+ if (Randoms.pickNumberInRange(0, 9) >= 4) {
+ this.position += 1;
+ }
+ }
+
+ private String getMovingPositionLine() {
+ List movingPositions = Arrays.stream(new String[this.position])
+ .map(s -> "-")
+ .collect(Collectors.toList());
+
+ return String.join("", movingPositions);
+ }
+}
diff --git a/src/main/java/racingcar/game/Game.java b/src/main/java/racingcar/game/Game.java
new file mode 100644
index 0000000..4ad41d0
--- /dev/null
+++ b/src/main/java/racingcar/game/Game.java
@@ -0,0 +1,45 @@
+package racingcar.game;
+
+import racingcar.tool.PrintManager;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class Game {
+
+ private final List cars;
+ private final int totalRound;
+
+ public Game(List cars, int totalRound) {
+ this.cars = cars;
+ this.totalRound = totalRound;
+ }
+
+ public void start() {
+ Round round = new Round(cars);
+
+ PrintManager.printGameResultHead();
+ while (round.getCurrentRound() <= totalRound) {
+ round.play();
+ }
+
+ List winningCars = findWinningCars();
+ PrintManager.printWinningCarsName(winningCars);
+ }
+
+ private List findWinningCars() {
+ if (cars.size() == 0) {
+ return Collections.emptyList();
+ }
+
+ int maxPosition = cars.stream()
+ .map(Car::getPosition)
+ .max(Integer::compareTo)
+ .get();
+
+ return cars.stream()
+ .filter(car -> car.getPosition() == maxPosition)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/racingcar/game/Round.java b/src/main/java/racingcar/game/Round.java
new file mode 100644
index 0000000..e1252fe
--- /dev/null
+++ b/src/main/java/racingcar/game/Round.java
@@ -0,0 +1,30 @@
+package racingcar.game;
+
+import racingcar.tool.PrintManager;
+
+import java.util.List;
+
+public class Round {
+ private int currentRound;
+ private final List cars;
+
+ public Round(List cars) {
+ this.currentRound = 1;
+ this.cars = cars;
+ }
+
+ public int getCurrentRound() {
+ return this.currentRound;
+ }
+
+ public void play() {
+ moveAllCars();
+ PrintManager.printAllCarsStatus(cars);
+ this.currentRound += 1;
+ }
+
+ private void moveAllCars() {
+ cars.forEach(Car::move);
+ }
+
+}
diff --git a/src/main/java/racingcar/tool/InputUtils.java b/src/main/java/racingcar/tool/InputUtils.java
new file mode 100644
index 0000000..48def9b
--- /dev/null
+++ b/src/main/java/racingcar/tool/InputUtils.java
@@ -0,0 +1,40 @@
+package racingcar.tool;
+
+import camp.nextstep.edu.missionutils.Console;
+
+import racingcar.game.Car;
+
+import java.util.List;
+
+public class InputUtils {
+
+ private InputUtils() {}
+
+ public static List getCarListFromInput() {
+ while (true) {
+ PrintManager.printCarNameInputDescription();
+
+ //for to split last comma, ' ' is going to be removed by trim func.
+ String carNames = Console.readLine() + ' ';
+ try {
+ return StringConvertor.convertIntoCars(carNames);
+ } catch (IllegalArgumentException exception) {
+ PrintManager.printErrorMessage(exception.getMessage());
+ }
+ }
+ }
+
+ public static int getTotalRoundFromInput() {
+ while (true) {
+ PrintManager.printTotalRoundInputDescription();
+
+ String roundInput = Console.readLine();
+ try {
+ return StringConvertor.convertIntoNaturalNumber(roundInput);
+ } catch (IllegalArgumentException exception) {
+ PrintManager.printErrorMessage(exception.getMessage());
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/racingcar/tool/ListConvertor.java b/src/main/java/racingcar/tool/ListConvertor.java
new file mode 100644
index 0000000..d7d9cf3
--- /dev/null
+++ b/src/main/java/racingcar/tool/ListConvertor.java
@@ -0,0 +1,20 @@
+package racingcar.tool;
+
+import racingcar.game.Car;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ListConvertor {
+
+ private ListConvertor() {}
+
+ public static String joinCarsName(String delimiter, List cars) {
+ List names = cars.stream()
+ .map(Car::getName)
+ .collect(Collectors.toList());
+
+ return String.join(delimiter, names);
+ }
+
+}
diff --git a/src/main/java/racingcar/tool/PrintManager.java b/src/main/java/racingcar/tool/PrintManager.java
new file mode 100644
index 0000000..5f65b9f
--- /dev/null
+++ b/src/main/java/racingcar/tool/PrintManager.java
@@ -0,0 +1,37 @@
+package racingcar.tool;
+
+import racingcar.game.Car;
+
+import java.util.List;
+
+public class PrintManager {
+
+ private PrintManager() {}
+
+ public static void printCarNameInputDescription() {
+ System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");
+ }
+
+ public static void printTotalRoundInputDescription() {
+ System.out.println("시도할 회수는 몇회인가요?");
+ }
+
+ public static void printAllCarsStatus(List cars) {
+ cars.forEach(System.out::println);
+ System.out.println();
+ }
+
+ public static void printWinningCarsName(List winningCars) {
+ String winningCarsName = ListConvertor.joinCarsName(", ", winningCars);
+
+ System.out.printf("최종 우승자 : %s", winningCarsName);
+ }
+
+ public static void printGameResultHead() {
+ System.out.println("\n실행 결과");
+ }
+
+ public static void printErrorMessage(String message) {
+ System.out.printf("[ERROR] %s\n", message);
+ }
+}
diff --git a/src/main/java/racingcar/tool/StringConvertor.java b/src/main/java/racingcar/tool/StringConvertor.java
new file mode 100644
index 0000000..a6f7acf
--- /dev/null
+++ b/src/main/java/racingcar/tool/StringConvertor.java
@@ -0,0 +1,33 @@
+package racingcar.tool;
+
+import racingcar.game.Car;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class StringConvertor {
+
+ private StringConvertor() {}
+
+ public static List convertIntoCars(String carNames) throws IllegalArgumentException {
+ return Arrays.stream(carNames.split(","))
+ .map(String::trim)
+ .map(Car::createCar)
+ .collect(Collectors.toList());
+ }
+
+ public static Integer convertIntoNaturalNumber(String targetString) throws IllegalArgumentException {
+ try {
+ int number = Integer.parseInt(targetString);
+
+ if (number < 1) {
+ throw new NumberFormatException();
+ }
+
+ return number;
+ } catch (NumberFormatException exception) {
+ throw new IllegalArgumentException("자연수가 아닌 값은 입력할 수 없습니다.");
+ }
+ }
+}
diff --git a/src/main/java/racingcar/tool/StringValidator.java b/src/main/java/racingcar/tool/StringValidator.java
new file mode 100644
index 0000000..a322b19
--- /dev/null
+++ b/src/main/java/racingcar/tool/StringValidator.java
@@ -0,0 +1,14 @@
+package racingcar.tool;
+
+public class StringValidator {
+
+ private StringValidator() {}
+
+ public static void cannotUseCarName(String carName) throws IllegalArgumentException {
+ if (carName.length() == 0) {
+ throw new IllegalArgumentException("자동차 이름은 공백일 수 없습니다.");
+ } else if (carName.length() > 5) {
+ throw new IllegalArgumentException("자동차 이름은 최대 5자리입니다. 불가능한 이름: " + carName);
+ }
+ }
+}