From 3887b57aff1a569fb9bfbd0c748e67e75cd77685 Mon Sep 17 00:00:00 2001 From: ichangyu Date: Fri, 12 Mar 2021 04:02:28 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EA=B2=BD=EC=A3=BC=20=EA=B2=8C=EC=9E=84=20=EC=A0=9C=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 14 ++++ src/main/java/domain/Car.java | 32 ++++++++- src/main/java/domain/CarFactory.java | 34 +++++++++ src/main/java/domain/RacingCarGame.java | 72 +++++++++++++++++++ .../domain/exception/NotBlankException.java | 7 ++ src/main/java/ui/Receiver.java | 35 +++++++++ src/main/java/utils/RandomUtils.java | 26 +++++++ src/test/java/domain/CarFactoryTest.java | 23 ++++++ src/test/java/domain/CarTest.java | 41 +++++++++++ src/test/java/domain/RacingCarGameTest.java | 39 ++++++++++ 10 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 src/main/java/Application.java create mode 100644 src/main/java/domain/CarFactory.java create mode 100644 src/main/java/domain/RacingCarGame.java create mode 100644 src/main/java/domain/exception/NotBlankException.java create mode 100644 src/main/java/ui/Receiver.java create mode 100644 src/main/java/utils/RandomUtils.java create mode 100644 src/test/java/domain/CarFactoryTest.java create mode 100644 src/test/java/domain/CarTest.java create mode 100644 src/test/java/domain/RacingCarGameTest.java 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..8a2f71f --- /dev/null +++ b/src/main/java/domain/CarFactory.java @@ -0,0 +1,34 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; + +public class CarFactory { + public static final String COMMA = ","; + public static final String BLANK = " "; + private final List cars; + private final String[] carNames; + + public CarFactory(String input) { + this.carNames = splitCarNames(input); + cars = createCars(); + } + + private String[] splitCarNames(String input) { + String s = input.replaceAll(BLANK, ""); + return s.split(COMMA); + } + + 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..6ee8ae7 --- /dev/null +++ b/src/main/java/domain/RacingCarGame.java @@ -0,0 +1,72 @@ +package domain; + +import java.util.Collections; +import java.util.List; + +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 int makeRandomValue() { + return RandomUtils.nextInt(0, 9); + } + + private void movePosition(int idx) { + int randomValue = makeRandomValue(); + if (randomValue >= 4) { + cars.get(idx).moveForward(); + } + } + + private void proceedOneRound() { + for (int idx = 0; idx < cars.size(); idx++) { + movePosition(idx); + } + } + + public void proceedRounds() { + System.out.println(RESULT_START_MESSAGE); + for (int r = 0; r < round; r++) { + proceedOneRound(); + printCurrentPositions(); + } + } + + private void printCurrentPositions() { + for (Car car : cars) { + System.out.print(car.getName() + COLON); + + for (int j = 0; j < car.getPosition(); j++) { + System.out.print(DASH); + } + 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..625944d --- /dev/null +++ b/src/main/java/ui/Receiver.java @@ -0,0 +1,35 @@ +package ui; + +import java.util.Scanner; + +public class Receiver { + public static final String REQUEST_CAR_NAME = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"; + public static final String REQUEST_ROUND = "시도할 횟수는 몇회인가요?"; + private static final Scanner scanner = new Scanner(System.in); + + private String carNames; + private int round; + + public Receiver() { + receiveCarNames(); + receiveRound(); + } + + private void receiveCarNames() { + System.out.println(REQUEST_CAR_NAME); + carNames = scanner.nextLine(); + } + + private void receiveRound() { + System.out.println(REQUEST_ROUND); + round = scanner.nextInt(); + } + + 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..63ba351 --- /dev/null +++ b/src/main/java/utils/RandomUtils.java @@ -0,0 +1,26 @@ +package utils; + +import java.util.Random; + +public class RandomUtils { + private static final Random RANDOM = new Random(); + + private RandomUtils() { + } + + public static int nextInt(final int startInclusive, final int endInclusive) { + if (startInclusive > endInclusive) { + throw new IllegalArgumentException(); + } + + if (startInclusive < 0) { + throw new IllegalArgumentException(); + } + + if (startInclusive == endInclusive) { + return startInclusive; + } + + return startInclusive + RANDOM.nextInt(endInclusive - startInclusive + 1); + } +} 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 From a6810a2fbbaa7293c079363f12e5f9fedbbb85bb Mon Sep 17 00:00:00 2001 From: ichangyu Date: Sun, 28 Mar 2021 14:25:13 +0900 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20=EC=9D=BC?= =?UTF-8?q?=EB=B6=80=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 69 +++++++++++++++++-------- src/main/java/domain/CarFactory.java | 16 ++++-- src/main/java/domain/RacingCarGame.java | 24 ++++----- src/main/java/ui/Receiver.java | 12 +++-- src/main/java/utils/RandomUtils.java | 17 ++---- 5 files changed, 81 insertions(+), 57 deletions(-) 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/domain/CarFactory.java b/src/main/java/domain/CarFactory.java index 8a2f71f..a145b04 100644 --- a/src/main/java/domain/CarFactory.java +++ b/src/main/java/domain/CarFactory.java @@ -4,19 +4,25 @@ import java.util.List; public class CarFactory { - public static final String COMMA = ","; - public static final String BLANK = " "; + 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 input) { - String s = input.replaceAll(BLANK, ""); - return s.split(COMMA); + 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() { diff --git a/src/main/java/domain/RacingCarGame.java b/src/main/java/domain/RacingCarGame.java index 6ee8ae7..5afeec1 100644 --- a/src/main/java/domain/RacingCarGame.java +++ b/src/main/java/domain/RacingCarGame.java @@ -2,6 +2,7 @@ import java.util.Collections; import java.util.List; +import java.util.stream.IntStream; import utils.RandomUtils; @@ -10,6 +11,7 @@ public class RacingCarGame { 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; @@ -18,40 +20,35 @@ public RacingCarGame(List cars, int round) { this.round = round; } - private int makeRandomValue() { - return RandomUtils.nextInt(0, 9); - } - private void movePosition(int idx) { - int randomValue = makeRandomValue(); + int randomValue = RandomUtils.generateNumber(); + if (randomValue >= 4) { cars.get(idx).moveForward(); } } private void proceedOneRound() { - for (int idx = 0; idx < cars.size(); idx++) { - movePosition(idx); - } + IntStream.range(0, cars.size()).forEach(this::movePosition); } public void proceedRounds() { System.out.println(RESULT_START_MESSAGE); - for (int r = 0; r < round; r++) { + + IntStream.range(0, round).forEach(r -> { proceedOneRound(); printCurrentPositions(); - } + }); } private void printCurrentPositions() { for (Car car : cars) { System.out.print(car.getName() + COLON); - for (int j = 0; j < car.getPosition(); j++) { - System.out.print(DASH); - } + IntStream.range(0, car.getPosition()).mapToObj(j -> DASH).forEach(System.out::print); System.out.println(); } + System.out.println(); } @@ -67,6 +64,7 @@ public void printWinners() { } System.out.print(", " + cars.get(i).getName()); } + System.out.println(RESULT_END_MESSAGE); } } diff --git a/src/main/java/ui/Receiver.java b/src/main/java/ui/Receiver.java index 625944d..57b492f 100644 --- a/src/main/java/ui/Receiver.java +++ b/src/main/java/ui/Receiver.java @@ -3,26 +3,30 @@ import java.util.Scanner; public class Receiver { - public static final String REQUEST_CAR_NAME = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"; - public static final String REQUEST_ROUND = "시도할 횟수는 몇회인가요?"; + 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(); } - private void receiveCarNames() { + public void receiveCarNames() { System.out.println(REQUEST_CAR_NAME); carNames = scanner.nextLine(); +// return carNames; } - private void receiveRound() { + public void receiveRound() { System.out.println(REQUEST_ROUND); round = scanner.nextInt(); +// return round; } public String getCarNames() { diff --git a/src/main/java/utils/RandomUtils.java b/src/main/java/utils/RandomUtils.java index 63ba351..30ee101 100644 --- a/src/main/java/utils/RandomUtils.java +++ b/src/main/java/utils/RandomUtils.java @@ -3,24 +3,13 @@ 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 nextInt(final int startInclusive, final int endInclusive) { - if (startInclusive > endInclusive) { - throw new IllegalArgumentException(); - } - - if (startInclusive < 0) { - throw new IllegalArgumentException(); - } - - if (startInclusive == endInclusive) { - return startInclusive; - } - - return startInclusive + RANDOM.nextInt(endInclusive - startInclusive + 1); + public static int generateNumber(){ + return RANDOM.nextInt(UPPER_BOUND); } }