Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[자동차 경주] 박재형 미션 제출합니다. #1474

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,38 @@
# java-racingcar-precourse

초간단 자동차 경주 게임을 구현한다.

### 경주 준비
- [ ] 사용자 입력(자동차 이름, 시도할 횟수)
- 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능
```
경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)
pobi,woni,jun
시도할 횟수는 몇 회인가요?
5
```


### 경주 시작
입력받은 자동차 순서대로 아래 과정을 반복.
- [ ] 0~9 랜덤값 생성
- 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우에만 전진
- [ ] 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력
```
실행 결과
pobi : -
woni :
jun : -

pobi : --
woni : -
jun : --
```

### 경주 종료
- [ ] 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. (우승자는 한 명 이상일 수 있다)
- 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분
- [ ] 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션은 종료
```
최종 우승자 : pobi, jun
```
7 changes: 7 additions & 0 deletions src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package racingcar;


import racingcar.config.AppConfig;
import racingcar.controller.GameController;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
AppConfig appConfig = new AppConfig();
GameController gameController = appConfig.getGameController();
gameController.run();
}
}
29 changes: 29 additions & 0 deletions src/main/java/racingcar/config/AppConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package racingcar.config;

import racingcar.controller.GameController;
import racingcar.domain.RacingGame;
import racingcar.view.InputParser;
import racingcar.view.InputValidator;
import racingcar.view.InputView;

public class AppConfig {
private final InputView inputView;
private final InputParser inputParser;
private final InputValidator inputValidator;
private final RacingGame racingGame;
private final GameController gameController;

public AppConfig() {
this.inputView = new InputView();
this.inputParser = new InputParser();
this.inputValidator = new InputValidator();
this.racingGame = new RacingGame();
this.gameController = new GameController(
inputView
);
}

public GameController getGameController() {
return gameController;
}
}
42 changes: 42 additions & 0 deletions src/main/java/racingcar/controller/GameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package racingcar.controller;

import java.math.BigInteger;
import java.util.List;
import racingcar.domain.Car;
import racingcar.domain.RacingGame;
import racingcar.domain.factory.CarFactory;
import racingcar.view.InputParser;
import racingcar.view.InputView;
import racingcar.view.OutputView;

public class GameController {
private final InputView inputView;

public GameController(InputView inputView) {
this.inputView = inputView;
}

public void run() {
// 자동차 이름 입력
String inputName = inputView.requestCarNames();
List<String> carNames = InputParser.parseCarNames(inputName);

// 진행할 라운드 수 입력
String inputRound = inputView.requestMaxRound();
BigInteger round = InputParser.parseMaxRound(inputRound);

// 입력받은 자동차 이름 수 만큼 자동차 생성
List<Car> cars = CarFactory.createCars(carNames);

// 자동차 경주 시작
RacingGame.play(cars, round);

// 자동차 경주 우승자 선출
List<Car> winners = RacingGame.getWinners(cars);
if (round.equals(new BigInteger("0")))
winners = cars;

// 우승자 출력
OutputView.printWinners(winners);
}
}
32 changes: 32 additions & 0 deletions src/main/java/racingcar/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package racingcar.domain;

public class Car {
private String name;
private int position = 0;
private int MOVE_STANDARD = 4;

public Car(String name) {
this.name = name;
}

public String getName() {
return name;
}

public int getPosition() {
return position;
}

public void move(Integer value) {
if (canMove(value)) {
position++;
}
}

public boolean canMove(Integer value) {
if (value >= MOVE_STANDARD) {
return true;
}
return false;
}
}
31 changes: 31 additions & 0 deletions src/main/java/racingcar/domain/RacingGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package racingcar.domain;

import camp.nextstep.edu.missionutils.Randoms;
import java.math.BigInteger;
import java.util.List;
import java.util.stream.Collectors;
import racingcar.view.OutputView;

public class RacingGame {
private static final int RANDOM_START = 0;
private static final int RANDOM_END = 9;

public static void play(List<Car> cars, BigInteger round) {
for (BigInteger i = new BigInteger("0"); i.compareTo(round) < 0; i = i.add(BigInteger.ONE)) {
for (Car car : cars) {
car.move(Randoms.pickNumberInRange(RANDOM_START, RANDOM_END));
OutputView.printRaceStatus(car);
}
}
}

public static List<Car> getWinners(List<Car> cars) {
int maxPosition = cars.stream()
.mapToInt(Car::getPosition)
.max()
.orElse(0);
return cars.stream()
.filter(car -> car.getPosition() == maxPosition)
.collect(Collectors.toList());
}
}
14 changes: 14 additions & 0 deletions src/main/java/racingcar/domain/factory/CarFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package racingcar.domain.factory;

import java.util.List;
import java.util.stream.Collectors;
import racingcar.domain.Car;

public class CarFactory {
public static List<Car> createCars(List<String> carNames) {
return carNames.stream()
.map(Car::new)
.collect(Collectors.toList());
}
}

21 changes: 21 additions & 0 deletions src/main/java/racingcar/exception/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package racingcar.exception;

public enum ErrorMessage {
EMPTY_INPUT("입력이 비어 있습니다."),
LENGTH_OVER("이름이 최대 길이인 5자를 넘었습니다."),
INVALID_FORMAT("입력 가능한 이름 양식인 알파벳, 숫자 타입이 아닙니다."),

// ------
NOT_NUMERIC("숫자만 포함해야 합니다."),
NEGATIVE_OR_ZERO("양의 정수여야 합니다.");

private final String message;

ErrorMessage(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}
20 changes: 20 additions & 0 deletions src/main/java/racingcar/view/InputParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package racingcar.view;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;

public class InputParser {
private static String DELIMITER = ",";

public static List<String> parseCarNames(String input) {
List<String> carNames = Arrays.asList(input.split(DELIMITER));
InputValidator.validateCarNames(carNames);
return carNames;
}

public static BigInteger parseMaxRound(String input) {
InputValidator.validateMaxRound(input);
return new BigInteger(input);
}
}
56 changes: 56 additions & 0 deletions src/main/java/racingcar/view/InputValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package racingcar.view;

import java.math.BigInteger;
import java.util.List;
import racingcar.exception.ErrorMessage;

public class InputValidator {
private static final int MAX_LENGTH = 5;
private static final String VALID_NAME_FORMAT = "^[a-zA-Z0-9]+$";

public static void validateCarNames(List<String> carNames) {
for (String name : carNames) {
isEmpty(name);
isLengthOver(name);
isValidFormat(name);
}
}

public static void validateMaxRound(String inputRound) {
isEmpty(inputRound);
isNumeric(inputRound);
isPositiveInteger(inputRound);
}

public static void isEmpty(String input) {
if (input == null || input.isEmpty()) {
throw new IllegalArgumentException(ErrorMessage.EMPTY_INPUT.getMessage());
}
}

public static void isLengthOver(String carName) {
if (carName.length() > MAX_LENGTH) {
throw new IllegalArgumentException(ErrorMessage.LENGTH_OVER.getMessage());
}
}

public static void isValidFormat(String carName) {
if (!carName.matches(VALID_NAME_FORMAT)) {
throw new IllegalArgumentException(ErrorMessage.INVALID_FORMAT.getMessage());
}
}

// -------------------

public static void isNumeric(String value) {
if (!value.matches("^[0-9]+$")) {
throw new IllegalArgumentException(ErrorMessage.NOT_NUMERIC.getMessage());
}
}

public static void isPositiveInteger(String value) {
if (Integer.parseInt(value) <= 0) {
throw new IllegalArgumentException(ErrorMessage.NEGATIVE_OR_ZERO.getMessage());
}
}
}
15 changes: 15 additions & 0 deletions src/main/java/racingcar/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package racingcar.view;

import camp.nextstep.edu.missionutils.Console;

public class InputView {
public String requestCarNames() {
System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");
return Console.readLine();
}

public String requestMaxRound() {
System.out.println("시도할 횟수는 몇 회인가요?");
return Console.readLine();
}
}
20 changes: 20 additions & 0 deletions src/main/java/racingcar/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package racingcar.view;

import java.util.List;
import java.util.stream.Collectors;
import racingcar.domain.Car;

public class OutputView {

public static void printRaceStatus(Car car) {
System.out.println(car.getName() + " : " + "-".repeat(car.getPosition()));
System.out.println();
}

public static void printWinners(List<Car> winners) {
String winnerNames = winners.stream()
.map(Car::getName)
.collect(Collectors.joining(", "));
System.out.println("최종 우승자 : " + winnerNames);
}
}
Loading