From 0aa9ad8913f2190c7e1cca052cf144dcb7738231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=EB=B3=91=EC=9E=AC?= Date: Sat, 27 May 2023 23:21:33 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20=EA=B2=8C?= =?UTF-8?q?=EC=9E=84=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 ++++ src/main/java/racingcar/Application.java | 3 +- src/main/java/racingcar/Car.java | 13 +++ src/main/java/racingcar/CarState.java | 31 ++++++ src/main/java/racingcar/Game.java | 107 +++++++++++++++++++ src/main/java/racingcar/JudgementResult.java | 16 +++ src/main/java/racingcar/Message.java | 24 +++++ src/main/java/racingcar/Referee.java | 13 +++ src/main/java/racingcar/Validator.java | 23 ++++ src/main/java/racingcar/View.java | 25 +++++ 10 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 src/main/java/racingcar/CarState.java create mode 100644 src/main/java/racingcar/Game.java create mode 100644 src/main/java/racingcar/JudgementResult.java create mode 100644 src/main/java/racingcar/Message.java create mode 100644 src/main/java/racingcar/Referee.java create mode 100644 src/main/java/racingcar/Validator.java create mode 100644 src/main/java/racingcar/View.java diff --git a/README.md b/README.md index ac237bb906..4b72853d71 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,28 @@ - 미션은 **기능 요구사항, 프로그래밍 요구사항, 과제 진행 요구사항** 세 가지로 구성되어 있다. - 세 개의 요구사항을 만족하기 위해 노력한다. 특히 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행한다. + + +## 기능 목록 +- 게임 + - 주어진 횟수 동안 게임을 진행한다. +- 심판 + - 우승자를 판단한다 +- 화면 + - 경주할 자동차 이름을 입력하라는 메시지를 출력한다. + - 각 차수별 실행 결과를 출력한다. + - 시도할 회수를 입력하라는 메시지를 출력한다. + - 최종 우승자를 출력한다. +- 자동차 + - 이름을 설정한다. + - 전진 또는 멈춘다. + - 자신의 이름과 위치를 반환한다. +- 유효성 검사기 + - 사용자가 잘못된 값을 입력한지 판단한다. + - 시도 횟수로 정수가 아닌 값을 입력한 경우 + - 자동차 이름이 5를 넘어가는 경우 + + ## ✉️ 미션 제출 방법 - 미션 구현을 완료한 후 GitHub을 통해 제출해야 한다. diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index b9ed0456a3..f12e9f0d85 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -2,6 +2,7 @@ public class Application { public static void main(String[] args) { - // TODO 구현 진행 + Game game = new Game(); + game.proceed(); } } diff --git a/src/main/java/racingcar/Car.java b/src/main/java/racingcar/Car.java index ab3df94921..6e2f8ae565 100644 --- a/src/main/java/racingcar/Car.java +++ b/src/main/java/racingcar/Car.java @@ -1,5 +1,7 @@ package racingcar; +import camp.nextstep.edu.missionutils.Randoms; + public class Car { private final String name; private int position = 0; @@ -9,4 +11,15 @@ public Car(String name) { } // 추가 기능 구현 + public void move() { + int randomNumber = Randoms.pickNumberInRange(0, 9); + + if (randomNumber >= 4) { + position += 1; + } + } + + public CarState getCarState() { + return new CarState(name, position); + } } diff --git a/src/main/java/racingcar/CarState.java b/src/main/java/racingcar/CarState.java new file mode 100644 index 0000000000..4329e08b1c --- /dev/null +++ b/src/main/java/racingcar/CarState.java @@ -0,0 +1,31 @@ +package racingcar; + +public class CarState { + private final String name; + + private final int position; + + public CarState(String name, int position) { + this.name = name; + this.position = position; + } + + public String getName() { + return name; + } + + public int getPosition() { + return position; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(name); + stringBuilder.append(" : "); + for (int i = 0; i < position; i++) { + stringBuilder.append("-"); + } + return stringBuilder.toString(); + } +} diff --git a/src/main/java/racingcar/Game.java b/src/main/java/racingcar/Game.java new file mode 100644 index 0000000000..31494839a4 --- /dev/null +++ b/src/main/java/racingcar/Game.java @@ -0,0 +1,107 @@ +package racingcar; + +import camp.nextstep.edu.missionutils.Console; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +public class Game { + + private List cars; + + private Referee referee; + + private int leftTrialTimes; + + + public void proceed() { + initializeProperty(); + doBeforeRun(); + while (leftTrialTimes > 0) { + run(); + } + close(); + } + + private void initializeProperty() { + initializeCar(); + initializeReferee(); + initializeTrialTimes(); + } + + private void initializeCar() { + View.print(Message.INPUT_CAR_NAME); + String inputCarNames = Console.readLine(); + String[] carNames = inputCarNames.split(","); + + try { + Validator.checkCarNameLength(carNames); + createCars(carNames); + } catch (IllegalArgumentException e) { + View.print(e.getMessage()); + initializeCar(); + } + } + + private void createCars(String[] carNames) { + cars = new LinkedList<>(); + for (String carName : carNames) { + cars.add(new Car(carName)); + } + } + + private void initializeReferee() { + referee = new Referee(); + } + + private void initializeTrialTimes() { + View.print(Message.INQUIRY_TRY_TIMES); + String inputTryTimes = Console.readLine(); + + try { + Validator.checkTypeConverting(inputTryTimes); + leftTrialTimes = Integer.parseInt(inputTryTimes); + } catch (IllegalArgumentException e) { + View.print(e.getMessage()); + initializeTrialTimes(); + } + } + + private void doBeforeRun() { + printInitialMessage(); + } + + private void printInitialMessage() { + View.print(Message.EXECUTION_RESULT); + } + + private void run() { + moveCars(); + printCarStates(); + decreaseTrialTimes(); + } + + private void moveCars() { + for(Car car: cars) { + car.move(); + } + } + + private void printCarStates() { + List carStates = cars.stream().map(it -> it.getCarState()).collect(Collectors.toList()); + View.print(carStates); + } + + private void decreaseTrialTimes() { + leftTrialTimes -= 1; + } + + private void close() { + JudgementResult judgementResult = referee.judge(cars); + printWinner(judgementResult); + } + + private void printWinner(JudgementResult judgementResult) { + View.print(judgementResult); + } +} diff --git a/src/main/java/racingcar/JudgementResult.java b/src/main/java/racingcar/JudgementResult.java new file mode 100644 index 0000000000..6d8308e6f3 --- /dev/null +++ b/src/main/java/racingcar/JudgementResult.java @@ -0,0 +1,16 @@ +package racingcar; + +import java.util.List; + +public class JudgementResult { + + private List winnerNames; + + public JudgementResult(List winnerNames) { + this.winnerNames = winnerNames; + } + + public List getWinnerNames() { + return winnerNames; + } +} diff --git a/src/main/java/racingcar/Message.java b/src/main/java/racingcar/Message.java new file mode 100644 index 0000000000..1457e4b438 --- /dev/null +++ b/src/main/java/racingcar/Message.java @@ -0,0 +1,24 @@ +package racingcar; + +public enum Message { + + INPUT_CAR_NAME("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"), + + INQUIRY_TRY_TIMES("시도할 회수는 몇회인가요?"), + + EXECUTION_RESULT("실행 결과"), + + CAR_NAME_LENGTH_ERROR("[ERROR] 자동차 이름은 5자 이하만 가능하다."), + TRIAL_TIMES_NOT_NUMBER_ERROR("[ERROR] 시도 횟수는 숫자여야 한다."); + + + private String body; + + Message(String body) { + this.body = body; + } + + public String getBody() { + return this.body; + } +} diff --git a/src/main/java/racingcar/Referee.java b/src/main/java/racingcar/Referee.java new file mode 100644 index 0000000000..cbb17de00c --- /dev/null +++ b/src/main/java/racingcar/Referee.java @@ -0,0 +1,13 @@ +package racingcar; + +import java.util.List; +import java.util.stream.Collectors; + +public class Referee { + + public JudgementResult judge(List cars) { + int maxPosition = cars.stream().mapToInt(car -> car.getCarState().getPosition()).max().orElse(-1); + List winnerCarNames = cars.stream().filter(it -> it.getCarState().getPosition() == maxPosition).map(it -> it.getCarState().getName()).collect(Collectors.toList()); + return new JudgementResult(winnerCarNames); + } +} diff --git a/src/main/java/racingcar/Validator.java b/src/main/java/racingcar/Validator.java new file mode 100644 index 0000000000..51f0ad3e90 --- /dev/null +++ b/src/main/java/racingcar/Validator.java @@ -0,0 +1,23 @@ +package racingcar; + +import java.util.Arrays; + +import static racingcar.Message.CAR_NAME_LENGTH_ERROR; +import static racingcar.Message.TRIAL_TIMES_NOT_NUMBER_ERROR; + +public class Validator { + + public static void checkTypeConverting(String input) { + if (input == null || !input.matches("[0-9]+")) { + throw new IllegalArgumentException(TRIAL_TIMES_NOT_NUMBER_ERROR.getBody()); + } + } + + public static void checkCarNameLength(String[] names) { + boolean isCarNameLengthOverFive = Arrays.stream(names).anyMatch(it -> it.length() > 5); + + if (isCarNameLengthOverFive) { + throw new IllegalArgumentException(CAR_NAME_LENGTH_ERROR.getBody()); + } + } +} diff --git a/src/main/java/racingcar/View.java b/src/main/java/racingcar/View.java new file mode 100644 index 0000000000..13dd6c5cc2 --- /dev/null +++ b/src/main/java/racingcar/View.java @@ -0,0 +1,25 @@ +package racingcar; + +import java.util.List; + +public class View { + + public static void print(String message) { + System.out.println(message); + } + public static void print(Message message) { + System.out.println(message.getBody()); + } + + public static void print(List carStates) { + for (CarState carState : carStates) { + System.out.println(carState); + } + System.out.println(); + } + + public static void print(JudgementResult judgementResult) { + String winnerMessage = "최종 우승자 : " + String.join(", ", judgementResult.getWinnerNames()); + System.out.println(winnerMessage); + } +}