diff --git a/README.md b/README.md index 82131a37f3d..803c14f52ca 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,18 @@ # 자동차 경주 게임 + ## 진행 방법 + * 자동차 경주 게임 요구사항을 파악한다. * 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 코드 리뷰 요청을 한다. * 코드 리뷰 피드백에 대한 개선 작업을 하고 다시 PUSH한다. * 모든 피드백을 완료하면 다음 단계를 도전하고 앞의 과정을 반복한다. ## 온라인 코드 리뷰 과정 + * [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview) ## 기능 요구사항 + * 초간단 자동차 경주 게임을 구현한다. * 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. * 사용자는 몇 대의 자동차로 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. @@ -16,7 +20,10 @@ * 자동차의 상태를 화면에 출력한다. 어느 시점에 출력할 것인지에 대한 제약은 없다. ## 기능 구현사항 -- 자동차 대수와 시도 횟수를 입력받는다. -- 0-9 사이가 아닌 숫자 또는 빈값을 입력하는 경우 오류가 발생한다. -- 0-9 사이의 랜덤 값을 생성하여 4이상일 경우 전진한다. -- 시도 횟수만큼 모든 자동차의 상태를 출력한다. \ No newline at end of file + +- [x] 자동차 이름과 시도 횟수를 입력받는다. +- [x] 자동차 이름 길이 5 제한 +- [x] 0-9 사이가 아닌 숫자 또는 빈값을 입력하는 경우 오류가 발생한다. +- [x] 0-9 사이의 랜덤 값을 생성하여 4이상일 경우 전진한다. +- [x] 시도 횟수만큼 모든 자동차의 상태를 출력한다. +- [x] 경주 종료 후 우승를 출력한다. diff --git a/src/main/java/calculator/Calculator.java b/src/main/java/calculator/Calculator.java deleted file mode 100644 index 7cb9b1c57fc..00000000000 --- a/src/main/java/calculator/Calculator.java +++ /dev/null @@ -1,49 +0,0 @@ -package calculator; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class Calculator { - public static int calculate(String text){ - if (isBlank(text)) { - return 0; - } - return sum(toInts(split(text))); - } - - private static boolean isBlank(String text) { - return text == null || text.isBlank(); - } - - private static String[] split(String text) { - Matcher m = Pattern.compile("//(.)\n(.*)").matcher(text); - if (m.find()) { - String customDelimiter = m.group(1); - return m.group(2).split(customDelimiter); - } - return text.split(",|:"); - } - - private static int sum(int[] numbers){ - int result = 0; - for(int number : numbers) { - result += number; - } - return result; - } - - private static int[] toInts(String[] values){ - int[] numbers = new int[values.length]; - for(int i = 0; i < values.length; i++){ - numbers[i] = isPositive(Integer.parseInt(values[i])); - } - return numbers; - } - - private static int isPositive(Integer number){ - if(number < 0){ - throw new RuntimeException(); - } - return number; - } -} diff --git a/src/main/java/racingcar/Car.java b/src/main/java/racingcar/Car.java index 8f51575dab5..1c57d73c870 100644 --- a/src/main/java/racingcar/Car.java +++ b/src/main/java/racingcar/Car.java @@ -3,7 +3,21 @@ public class Car { private static final int MOVE_STANDARD = 4; private static final int DEFAULT_DISTANCE = 1; - private int position = 0; + + private final String name; + private int position; + + public Car(String name, int position) { + if (name.length() > 5) { + throw new IllegalArgumentException("자동차 이름의 길이를 5 이하로 입력해주세요."); + } + this.name = name; + this.position = position; + } + + public String getName() { + return this.name; + } public void move(int number) { if (number >= MOVE_STANDARD) { @@ -14,4 +28,13 @@ public void move(int number) { public int getPosition() { return this.position; } -} + + public int getMax(int max) { + return Math.max(max, this.position); + } + + public boolean isMaxPosition(int max) { + return this.position == max; + } + +} \ No newline at end of file diff --git a/src/main/java/racingcar/Cars.java b/src/main/java/racingcar/Cars.java new file mode 100644 index 00000000000..49182aa3186 --- /dev/null +++ b/src/main/java/racingcar/Cars.java @@ -0,0 +1,43 @@ +package racingcar; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Cars { + + private static final String COMMA = ","; + private final List carList; + + public Cars(List carList) { + this.carList = carList; + } + + public static List makeCarList(String names) { + List carList = new ArrayList<>(); + for (String name : splitNames(names)) { + checkCarName(name); + carList.add(new Car(name, 0)); + } + return carList; + } + + private static void checkCarName(String name) { + if (isNullOrBlank(name)) { + throw new IllegalArgumentException(); + } + } + + private static boolean isNullOrBlank(String name) { + return name == null || name.isBlank(); + } + + public static List splitNames(String names) { + return new ArrayList<>(Arrays.asList(names.split(COMMA))); + } + + public int size() { + return carList.size(); + } + +} diff --git a/src/main/java/racingcar/InputValue.java b/src/main/java/racingcar/InputValue.java index 4af872cecde..d6cc20c27ac 100644 --- a/src/main/java/racingcar/InputValue.java +++ b/src/main/java/racingcar/InputValue.java @@ -1,19 +1,21 @@ package racingcar; public class InputValue { - private final int numberOfCars; + private final String names; private final int tryCount; - public InputValue(int numberOfCars, int tryCount){ - this.numberOfCars = numberOfCars; + public InputValue(String names, int tryCount) { + this.names = names; this.tryCount = tryCount; } - public int getNumberOfCars(){ - return numberOfCars; + public String getNameOfCars() { + return names; } - public int getTryCount(){ + public int getTryCount() { return tryCount; } -} + + +} \ No newline at end of file diff --git a/src/main/java/racingcar/InputView.java b/src/main/java/racingcar/InputView.java index 33ba2346862..0ba9e57800b 100644 --- a/src/main/java/racingcar/InputView.java +++ b/src/main/java/racingcar/InputView.java @@ -3,19 +3,20 @@ import java.util.Scanner; public class InputView { - private final static Scanner scanner = new Scanner(System.in); - static Validator validator = new Validator(); + private static final Scanner SCANNER = new Scanner(System.in); + private static final NumberValidator validator = new NumberValidator(); - public static String numberOfCar() { - System.out.println("자동차 대수는 몇 대 인가요?"); - return scanner.nextLine(); + public static String nameOfCars() { + System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); + return SCANNER.nextLine(); } public static String tryCntInput() { System.out.println("시도할 횟 수는 몇 회 인가요?"); - return scanner.nextLine(); + return SCANNER.nextLine(); } + public static int inputNumber(String value) { return numberCheck(value); } @@ -25,4 +26,4 @@ public static Integer numberCheck(String value) { validator.nullCheck(value); return Integer.parseInt(value); } -} +} \ No newline at end of file diff --git a/src/main/java/racingcar/NumberValidator.java b/src/main/java/racingcar/NumberValidator.java new file mode 100644 index 00000000000..58c59edc7cf --- /dev/null +++ b/src/main/java/racingcar/NumberValidator.java @@ -0,0 +1,31 @@ +package racingcar; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class NumberValidator { + private static final Pattern NUMERIC_PATTERN = Pattern.compile("\\d"); + public static final int MIN_DISTANCE = 0; + + public void nullCheck(String input) { + if (input == null || input.isBlank()) { + throw new RuntimeException("빈 값이 입력되었습니다."); + } + } + + public void numericCheck(String input) { + Matcher matcher = NUMERIC_PATTERN.matcher(input); + if (!matcher.find()) { + throw new RuntimeException("숫자만 입력해주세요."); + } + numberCheck(input); + } + + private void numberCheck(String input) { + Integer number = Integer.parseInt(input); + if (number < MIN_DISTANCE) { + throw new RuntimeException("0-9 사이의 숫자를 입력해주세요."); + } + } + +} diff --git a/src/main/java/racingcar/RacingApplication.java b/src/main/java/racingcar/RacingApplication.java index 48959c60c94..dd355c0c252 100644 --- a/src/main/java/racingcar/RacingApplication.java +++ b/src/main/java/racingcar/RacingApplication.java @@ -4,6 +4,8 @@ public class RacingApplication { public static void main(String[] args) { RacingGame game = new RacingGame(); - game.start(new InputValue(InputView.inputNumber(InputView.numberOfCar()), InputView.inputNumber(InputView.tryCntInput()))); + String namesOfCar = (InputView.nameOfCars()); + int tryCntInput = InputView.inputNumber(InputView.tryCntInput()); + game.start(new InputValue(namesOfCar, tryCntInput)); } -} +} \ No newline at end of file diff --git a/src/main/java/racingcar/RacingGame.java b/src/main/java/racingcar/RacingGame.java index 25d41025a48..25216367e45 100644 --- a/src/main/java/racingcar/RacingGame.java +++ b/src/main/java/racingcar/RacingGame.java @@ -4,24 +4,24 @@ import java.util.List; public class RacingGame { - private RandomUtil randomUtil = new RandomUtil(); private List cars = new ArrayList<>(); public void start(InputValue input) { - for (int i = 0; i < input.getNumberOfCars(); i++) { - cars.add(new Car()); - } + cars = Cars.makeCarList(input.getNameOfCars()); + ResultView.printResultMessage(); for (int i = 0; i < input.getTryCount(); i++) { forward(); System.out.println(); } + ResultView.printWinners(Record.getRecord(cars)); + } public void forward() { for (Car car : cars) { - car.move(this.randomUtil.randomCount(10)); + car.move(RandomUtil.randomCount(10)); } ResultView.printResult(cars); } -} +} \ No newline at end of file diff --git a/src/main/java/racingcar/RandomUtil.java b/src/main/java/racingcar/RandomUtil.java index 94da5fc2fa1..b351347244c 100644 --- a/src/main/java/racingcar/RandomUtil.java +++ b/src/main/java/racingcar/RandomUtil.java @@ -5,6 +5,9 @@ public class RandomUtil { private final static Random random = new Random(); + private RandomUtil() { + } + public static int randomCount(int number) { return random.nextInt(number); } diff --git a/src/main/java/racingcar/Record.java b/src/main/java/racingcar/Record.java new file mode 100644 index 00000000000..8a1f306923b --- /dev/null +++ b/src/main/java/racingcar/Record.java @@ -0,0 +1,34 @@ +package racingcar; + +import java.util.ArrayList; +import java.util.List; + +public class Record { + public static List getRecord(List carList) { + return getWinnerList(carList, findMaxPosition(carList)); + } + + public static int findMaxPosition(List carList) { + int max = 0; + for (Car car : carList) { + max = car.getMax(max); + } + return max; + } + + private static List getWinnerList(List carList, int max) { + List winnerList = new ArrayList<>(); + + for (Car car : carList) { + makeWinnerList(winnerList, max, car); + } + return winnerList; + } + + private static List makeWinnerList(List winnerList, int max, Car car) { + if (car.isMaxPosition(max)) { + winnerList.add(car.getName()); + } + return winnerList; + } +} diff --git a/src/main/java/racingcar/ResultView.java b/src/main/java/racingcar/ResultView.java index 53f92602843..2d91b57f11e 100644 --- a/src/main/java/racingcar/ResultView.java +++ b/src/main/java/racingcar/ResultView.java @@ -11,6 +11,8 @@ public static void printResult(List cars) { } public static void printCarResult(Car car) { + + System.out.print(car.getName() + " : "); for (int i = 0; i < car.getPosition(); i++) { System.out.print("-"); } @@ -20,4 +22,8 @@ public static void printCarResult(Car car) { public static void printResultMessage() { System.out.println("실행 결과"); } + + public static void printWinners(List winnerList) { + System.out.println(String.join(",", winnerList) + "가 최종 우승했습니다."); + } } diff --git a/src/test/java/calculator/CalculatorTest.java b/src/test/java/calculator/CalculatorTest.java deleted file mode 100644 index 001f086a0bb..00000000000 --- a/src/test/java/calculator/CalculatorTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package calculator; - -import org.junit.jupiter.api.Test; - -import static calculator.Calculator.calculate; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -public class CalculatorTest { - - @Test - public void custom_구분자() throws Exception { - assertThat(calculate("//;\n1;2;3")).isEqualTo(6); - assertThat(calculate("//-\n1-2-3-4")).isEqualTo(10); - } - - @Test - public void 숫자_이외의_값_또는_음수() throws Exception { - assertThatThrownBy(() -> calculate("-1,2,3")) - .isInstanceOf(RuntimeException.class); - } - - @Test - void 쉼표_또는_콜론_구분자(){ - assertThat(calculate("1,2:3")).isEqualTo(6); - } - - @Test - void 콜론_구분자(){ - assertThat(calculate("1:2")).isEqualTo(3); - } - - @Test - void 쉼표_구분자(){ - assertThat(calculate("1,2")).isEqualTo(3); - } - - @Test - void 문자_하나(){ - assertThat(calculate("1")).isEqualTo(1); - } - @Test - void null_또는_빈문자(){ - assertThat(calculate(null)).isEqualTo(0); - assertThat(calculate("")).isEqualTo(0); - } -} diff --git a/src/test/java/racingcar/RacingCarTest.java b/src/test/java/racingcar/RacingCarTest.java deleted file mode 100644 index 1084d517c8f..00000000000 --- a/src/test/java/racingcar/RacingCarTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package racingcar; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import static org.assertj.core.api.Assertions.assertThat; - -public class RacingCarTest { - - @ParameterizedTest - @DisplayName("랜덤값이 4이상일 경우 전진") - @ValueSource(ints = {4,5,6,7,8,9}) - void careMove(int number){ - Car car = new Car(); - assertThat(car.getPosition()).isEqualTo(0); - car.move(number); - assertThat(car.getPosition()).isEqualTo(1); - } - - @ParameterizedTest - @DisplayName("랜덤값이 4미만일 경우 정지") - @ValueSource(ints = {1,2,3}) - void carNotMove(int number){ - Car car = new Car(); - assertThat(car.getPosition()).isEqualTo(0); - car.move(number); - assertThat(car.getPosition()).isEqualTo(0); - } -} diff --git a/src/test/java/racingcar/RacingGameTest.java b/src/test/java/racingcar/RacingGameTest.java new file mode 100644 index 00000000000..aeb4a9d2fa4 --- /dev/null +++ b/src/test/java/racingcar/RacingGameTest.java @@ -0,0 +1,59 @@ +package racingcar; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class RacingGameTest { + @DisplayName("자동차리스트 생성") + @Test + void makeCarListTest() { + List carList = Cars.makeCarList("pobi,crong,honux"); + assertThat(carList.size()).isEqualTo(3); + } + + @DisplayName("공백 자동차리스트 생성") + @ParameterizedTest + @ValueSource(strings = {"", " "}) + void carNameTest(String names) { + assertThatThrownBy(() -> Cars.makeCarList(names)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("거리 최대값 확인") + @Test + void getMaxPositionTest() { + List carList = Arrays.asList( + new Car("pobi", 2), + new Car("crong", 3), + new Car("honux", 1)); + assertThat(Record.findMaxPosition(carList)).isEqualTo(3); + } + + @DisplayName("단일 우승자") + @Test + void winnerTest() { + List carList = Arrays.asList( + new Car("pobi", 2), + new Car("crong", 3), + new Car("honux", 1)); + assertThat(Record.getRecord(carList)).containsExactly("crong"); + } + + @DisplayName("다중 우승자") + @Test + void winnersTest() { + List carList = Arrays.asList( + new Car("pobi", 3), + new Car("crong", 3), + new Car("honux", 1)); + assertThat(Record.getRecord(carList)).hasSize(2); + } +} \ No newline at end of file