diff --git a/docs/README.md b/docs/README.md index e69de29..86f4864 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,35 @@ +# 기능 목록 + +## 입력 +- 경주할 자동차 이름을 ,기준으로 입력받는다. +- 시도할 횟수를 입력받는다. + +## 입력 검증 +- 자동차 이름이 공백이거나 빈값이면 `IllegalArgumentException`을 발생시킨다. +- 자동차 이름이 5자를 초과하면 `IllegalArgumentException`을 발생시킨다. +- 자동차 이름이 중복되면 `IllegalArgumentException`을 발생시킨다. +- 시도할 횟수가 숫자가 아니면 `IllegalArgumentException`을 발생시킨다. +- 시도할 횟수가 1 미만이면 `IllegalArgumentException`을 발생시킨다. + +## 자동차 이동 +- 0~9 사이의 무작위 값을 발생시킨다. +- 무작위 값이 4 이상이면 전진한다. + +## 출력 +- 각 횟수별 실행 결과를 자동차 이름과 함께 출력한다. +- 최종 우승자를 출력한다. +- 우승자가 여러 명일 경우 ,로 구분하여 출력한다. + +## 리팩토링 +- `Input` : 사용자 입력을 받는 책임만 담당하도록 분리한다. +- `Output` : 경기 결과 및 우승자 출력 책임만 담당하도록 분리한다. +- `RunRacingGame` : 게임 흐름 제어 책임만 담당하도록 분리한다. +- `Utils` 클래스를 삭제하고 각 도메인이 자신의 책임을 직접 수행하도록 변경한다. + +### 도메인은 자신이 검증 +- `Car` : 자동차 이름의 유효성(공백, 길이)을 Car 스스로 검증한다. +- `Cars` : 자동차 이름 중복 여부를 Cars 스스로 검증한다. +- `validation` : 시도 횟수 검증은 입력 경계에서 담당한다. + +### 이동횟수 관리 +- 이동 기준값을 매직넘버로 관리한다. \ No newline at end of file diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index a17a52e..22e50b8 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -3,5 +3,6 @@ public class Application { public static void main(String[] args) { // TODO: 프로그램 구현 + new RunRacingGame().run(); } -} +} \ No newline at end of file diff --git a/src/main/java/racingcar/RunRacingGame.java b/src/main/java/racingcar/RunRacingGame.java new file mode 100644 index 0000000..eded30d --- /dev/null +++ b/src/main/java/racingcar/RunRacingGame.java @@ -0,0 +1,36 @@ +package racingcar; + + +import java.util.ArrayList; +import java.util.List; +import racingcar.entity.Car; +import racingcar.entity.Cars; +import racingcar.view.racingCarInput; +import racingcar.view.racingCarOutput; + +public class RunRacingGame { + private racingCarInput input = new racingCarInput(); + private racingCarOutput output = new racingCarOutput(); + + public void run() { + String[] carNames = input.readCarNames(); + int tryCount = input.readTryCount(); + + Cars cars = createCars(carNames); + + System.out.println("\n실행 결과"); + for (int i = 0; i < tryCount; i++) { + cars.moveAllCars(); + output.printRaceResult(cars); + } + output.printWinner(cars.getWinners()); + } + + private Cars createCars(String[] carNames) { + List carList = new ArrayList<>(); + for (String name : carNames) { + carList.add(new Car(name)); + } + return new Cars(carList); + } +} diff --git a/src/main/java/racingcar/entity/Car.java b/src/main/java/racingcar/entity/Car.java new file mode 100644 index 0000000..6af4d52 --- /dev/null +++ b/src/main/java/racingcar/entity/Car.java @@ -0,0 +1,37 @@ +package racingcar.entity; + +import camp.nextstep.edu.missionutils.Randoms; + +public class Car { + private final String name; + private int moveCnt; + private static final int MOVE_THRESHOLD = 4; + + public Car(String name) { + validateName(this.name = name); + this.moveCnt = 0; + } + + public String getName() { + return this.name; + } + + public int getMoveCnt() { + return this.moveCnt; + } + + public void setMoveCnt() { + if (Randoms.pickNumberInRange(0, 9) >= MOVE_THRESHOLD) { + this.moveCnt++; + } + } + + private void validateName(String name) { + if (name.isBlank() || name.contains(" ")) { + throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다."); + } + if (name.length() > 5) { + throw new IllegalArgumentException("5글자 초과했습니다."); + } + } +} diff --git a/src/main/java/racingcar/entity/Cars.java b/src/main/java/racingcar/entity/Cars.java new file mode 100644 index 0000000..d962177 --- /dev/null +++ b/src/main/java/racingcar/entity/Cars.java @@ -0,0 +1,52 @@ +package racingcar.entity; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class Cars { + private List cars; + + public Cars(List cars) { + validateDuplicate(cars); + this.cars = cars; + } + public List getCars() { + return cars; + } + public void moveAllCars() { + for (Car car : this.cars) { + car.setMoveCnt(); + } + } + + private int findMaxMoveCnt() { + int max = 0; + for (Car car : this.cars) { + if (car.getMoveCnt() > max) { + max = car.getMoveCnt(); + } + } + return max; + } + + public List getWinners() { + int max = findMaxMoveCnt(); + List winners = new ArrayList<>(); + for (Car car : this.cars) { + if (car.getMoveCnt() == max) { + winners.add(car.getName()); + } + } + return winners; + } + + private void validateDuplicate(List cars) { + HashSet set = new HashSet<>(); + for (Car car : cars) { + if (!set.add(car.getName())) { + throw new IllegalArgumentException("이름 중복은 허용 안됩니다."); + } + } + } +} diff --git a/src/main/java/racingcar/validation/TryCountValidation.java b/src/main/java/racingcar/validation/TryCountValidation.java new file mode 100644 index 0000000..364af0b --- /dev/null +++ b/src/main/java/racingcar/validation/TryCountValidation.java @@ -0,0 +1,15 @@ +package racingcar.validation; + +public class TryCountValidation { + public static int validate(String input) { + try { + int number = Integer.parseInt(input); + if (number < 1) { + throw new IllegalArgumentException("1 미만의 숫자는 입력할 수 없습니다."); + } + return number; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("숫자를 입력해야 합니다."); + } + } +} \ No newline at end of file diff --git a/src/main/java/racingcar/view/racingCarInput.java b/src/main/java/racingcar/view/racingCarInput.java new file mode 100644 index 0000000..099a4c9 --- /dev/null +++ b/src/main/java/racingcar/view/racingCarInput.java @@ -0,0 +1,15 @@ +package racingcar.view; + +import camp.nextstep.edu.missionutils.Console; +import racingcar.validation.TryCountValidation; + +public class racingCarInput { + public String[] readCarNames() { + System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + return Console.readLine().split(","); + } + public int readTryCount() { + System.out.println("시도할 회수는 몇회인가요?"); + return TryCountValidation.validate(Console.readLine()); + } +} \ No newline at end of file diff --git a/src/main/java/racingcar/view/racingCarOutput.java b/src/main/java/racingcar/view/racingCarOutput.java new file mode 100644 index 0000000..584eb60 --- /dev/null +++ b/src/main/java/racingcar/view/racingCarOutput.java @@ -0,0 +1,19 @@ +package racingcar.view; + +import java.util.List; +import racingcar.entity.Car; +import racingcar.entity.Cars; + +public class racingCarOutput { + + public void printRaceResult(Cars cars) { + for (Car car : cars.getCars()) { + System.out.println(car.getName() + " : " + "-".repeat(car.getMoveCnt())); + } + System.out.println(); + } + + public void printWinner(List winners) { + System.out.println("최종 우승자 : " + String.join(", ", winners)); + } +} \ No newline at end of file