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

[자동차 경주 게임] 김승진 미션 제출합니다. #4

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4bce6c4
docs(README): 기능 목록 추가
ohksj77 Sep 18, 2023
06115e8
feat(CarController): 컨트롤러 클래스 추가
ohksj77 Sep 18, 2023
61fc03e
feat(InputValidator): 자동차 입력값 검증 로직
ohksj77 Sep 18, 2023
776bd52
feat(InputView): 자동차 입력 기능
ohksj77 Sep 18, 2023
2b98a8b
feat(InputManager): 잘못된 입력시 재시도 기능
ohksj77 Sep 18, 2023
e032b0f
feat(ErrorMessage): 에러 메시지 열거형 추가
ohksj77 Sep 18, 2023
abc0791
feat(Car): 자동차 이름 길이 검증
ohksj77 Sep 18, 2023
8f49343
feat(Cars): 자동차 중복 이름 검증
ohksj77 Sep 18, 2023
3c5b96f
feat: 자동차 이름 입력 요청 메시지 출력 기능
ohksj77 Sep 18, 2023
d13c52e
feat(CarRepository): 저장소 클래스 추가
ohksj77 Sep 18, 2023
f8e0248
feat(CarService): 서비스 클래스 추가 및 자동차 저장 기능
ohksj77 Sep 18, 2023
eec4568
feat: 시도 회수 요청 메시지 출력
ohksj77 Sep 18, 2023
1135931
feat(TryCount): 시도 횟수 도메인 추가
ohksj77 Sep 18, 2023
d7c8af0
feat(InputValidator): 시도 횟수 입력값 숫자인지 검증 기능
ohksj77 Sep 18, 2023
aad9b4d
feat(InputView): 시도 횟수 입력 및 재시도 기능
ohksj77 Sep 18, 2023
0341e58
feat: 시도 횟수 저장 기능
ohksj77 Sep 18, 2023
fdbc536
feat: 랜덤 이동 여부 생성 기능
ohksj77 Sep 18, 2023
9c68ef2
fix: 랜덤 이동 여부 생성 기능 수정
ohksj77 Sep 18, 2023
a6a91ad
feat: 이동 기능 추가
ohksj77 Sep 18, 2023
cf70b00
feat: 매 차시 출력 기능 추가
ohksj77 Sep 18, 2023
12c1183
feat: 기능 흐름 연결 완료
ohksj77 Sep 18, 2023
53548bf
test: 테스트 코드 추가
ohksj77 Sep 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
## 기능 목록
- [x] 자동차 이름 요청 메시지 출력
- [x] 자동차 이름 입력 받기
- [x] 쉼표로 구분 됐는지 입력값 검증
- [x] 잘못된 입력의 경우 에러 문구 출력 및 재시도
- [x] 이름의 길이가 5자 이하인지 검증
- [x] 5자 초과의 경우 에러 문구 출력 및 재시도
- [x] 중복되는 이름이 있는지 검증
- [x] 중복시 에러 문구 출력 및 재시도
- [x] 시도 회수 요청 메시지 출력
- [x] 시도 회수 입력 받기
- [x] 입력값 숫자인지 검증
- [x] 자동차 이동
- [x] 차수별 이동
- [x] 차수별 현황 출력
- [x] 최종 우승자 선정
- [x] 최종 우승자 안내 문구 출력
- [x] 공동 우승자의 경우 ", " 로 구분하여 출력

## 구현 클래스 목록
- CarController
- play()

- InputView
- readCars()
- readTryCount()

- InputManager
- readCars()
- readTryCount()

- InputValidator
- validateCars()
- validateTryCount()

- Car
- move()
- getPosition()
- getName()
- hasMaxPosition()
- getCurrentStatus()

- Cars
- getNumberOfCars()
- moveAll()
- findWinners()
- getCurrentDirection()

- OutputView
- printCarRequest()
- printTryCountRequest()
- printCurrentDirection()
- printWinnerCars()

- CarService
- saveCars()
- saveTryCount()
- findTryCount()
- move()
- findWinnerCars()

- CarRepository
- saveCars()
- saveTryCount()
- findCars()
- findTryCount()

- TryCount
- hasNext()

- RandomMoveGenerator
- generate

## 열거형 목록
- ErrorMessage
- GameMessage
- MoveStatus
4 changes: 3 additions & 1 deletion src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package racingcar;

import racingcar.controller.CarController;

public class Application {
public static void main(String[] args) {
// TODO 구현 진행
new CarController().play();
}
}
12 changes: 0 additions & 12 deletions src/main/java/racingcar/Car.java

This file was deleted.

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

public enum ErrorMessage {
INVALID_CAR_INPUT("자동차 이름을 입력할 시 쉼표로 구분해야 합니다."),
INVALID_CARS_NUM("자동차 이름에 중복이 있습니다."),
INVALID_CAR_NAME_LENGTH("자동차 이름의 길이가 잘못됐습니다."),
INVALID_TRY_COUNT_INPUT("시도 회수의 입력값은 숫자만 가능합니다."),
HAS_NO_MOVE_STATUS("다음 MoveStatus가 존재하지 않습니다."),
INVALID_MOVE_STATUS_SIZE("MoveStatus의 개수가 잘못되었습니다.");

private static final String ERROR_PREFIX = "[ERROR] ";
private final String message;

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

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

public enum GameMessage {
CAR_INPUT_REQUEST("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"),
TRY_COUNT_REQUEST("시도할 회수는 몇회인가요?"),
WINNER_CARS("최종 우승자 : %s");

private final String message;

GameMessage(final String message) {
this.message = message;
}

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

public enum MoveStatus {
MOVE, STOP;

private static final Integer moveDivider = 4;

public static MoveStatus getMoveStatus(final int randomNumber) {
if (moveDivider <= randomNumber) {
return MOVE;
}
return STOP;
}

public boolean isMove() {
return this == MOVE;
}
}
47 changes: 47 additions & 0 deletions src/main/java/racingcar/controller/CarController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package racingcar.controller;

import racingcar.domain.Cars;
import racingcar.domain.TryCount;
import racingcar.io.InputManager;
import racingcar.io.OutputView;
import racingcar.service.CarService;

public class CarController {

private final InputManager inputManager = new InputManager();
private final OutputView outputView = new OutputView();
private final CarService carService = new CarService();

public void play() {
createCars();
createTryCount();
moveCars();
findWinnerCars();
}

private void moveCars() {
final TryCount tryCount = carService.findTryCount();

while(tryCount.hasNext()) {
final String currentDirection = carService.move();
outputView.printCurrentDirection(currentDirection);
}
}

private void findWinnerCars() {
final String winnerCars = carService.findWinnerCars();
outputView.printWinnerCars(winnerCars);
}

private void createTryCount() {
outputView.printTryCountRequest();
final TryCount tryCount = inputManager.readTryCount();
carService.saveTryCount(tryCount);
}

private void createCars() {
outputView.printCarRequest();
final Cars cars = inputManager.readCars();
carService.saveCars(cars);
}
}
66 changes: 66 additions & 0 deletions src/main/java/racingcar/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package racingcar.domain;

import racingcar.constant.ErrorMessage;
import racingcar.constant.MoveStatus;

import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Car {

private static final Integer MAX_SIZE = 5;
private static final Integer START_INDEX = 0;
private static final String DIRECTION_TAG = "-";
private static final String NAME_DELIMITER = " : ";
private final String name;
private int position = 0;

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

private void validateName(final String name) {
if (name.length() > MAX_SIZE) {
throw new IllegalArgumentException(ErrorMessage.INVALID_CAR_NAME_LENGTH.getMessage());
}
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Car car = (Car) o;
return position == car.position && Objects.equals(name, car.name);
}

@Override
public int hashCode() {
return Objects.hash(name, position);
}

public void move(final MoveStatus moveStatus) {
if (moveStatus.isMove()) {
this.position++;
}
}

public Integer getPosition() {
return this.position;
}

public String getName() {
return this.name;
}

public boolean hasMaxPosition(final int maxPosition) {
return this.position == maxPosition;
}

public String getCurrentStatus() {
return this.name + NAME_DELIMITER + IntStream.range(START_INDEX, position)
.mapToObj(i -> DIRECTION_TAG)
.collect(Collectors.joining());
}
}
68 changes: 68 additions & 0 deletions src/main/java/racingcar/domain/Cars.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package racingcar.domain;

import racingcar.constant.ErrorMessage;
import racingcar.constant.MoveStatus;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

public class Cars {

private static final Integer MIN_POSITION = 0;
private static final String WINNER_DELIMITER = ", ";
private static final String NEW_LINE_DELIMITER = "\n";
private final List<Car> cars;

public Cars(final List<Car> cars) {
validateUnique(cars);
this.cars = Collections.unmodifiableList(cars);
}

private void validateUnique(final List<Car> cars) {
if (new HashSet<>(cars).size() != cars.size()) {
throw new IllegalArgumentException(ErrorMessage.INVALID_CARS_NUM.getMessage());
}
}

public Integer getNumberOfCars() {
return cars.size();
}

public void moveAll(final MoveStatuses moveStatuses) {
validateMoveStatusSize(moveStatuses);
cars.forEach(car -> move(car, moveStatuses.getNext()));
}

private void validateMoveStatusSize(final MoveStatuses moveStatuses) {
if (cars.size() != moveStatuses.getSize()) {
throw new IllegalArgumentException(ErrorMessage.INVALID_MOVE_STATUS_SIZE.getMessage());
}
}

private void move(final Car car, final MoveStatus moveStatus) {
car.move(moveStatus);
}

public String findWinners() {
final int maxPosition = getMaxPosition();
return cars.stream()
.filter(car -> car.hasMaxPosition(maxPosition))
.map(Car::getName)
.collect(Collectors.joining(WINNER_DELIMITER));
}

private int getMaxPosition() {
return cars.stream()
.mapToInt(Car::getPosition)
.max()
.orElse(MIN_POSITION);
}

public String getCurrentDirection() {
return cars.stream()
.map(Car::getCurrentStatus)
.collect(Collectors.joining(NEW_LINE_DELIMITER)) + NEW_LINE_DELIMITER;
}
}
31 changes: 31 additions & 0 deletions src/main/java/racingcar/domain/MoveStatuses.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package racingcar.domain;

import racingcar.constant.ErrorMessage;
import racingcar.constant.MoveStatus;

import java.util.ArrayList;
import java.util.List;

public class MoveStatuses {
private static final int REMOVE_INDEX = 0;
private final List<MoveStatus> moveStatuses;

public MoveStatuses(final List<MoveStatus> moveStatuses) {
this.moveStatuses = new ArrayList<>(moveStatuses);
}

public MoveStatus getNext() {
validateHasNext();
return moveStatuses.remove(REMOVE_INDEX);
}

public int getSize() {
return this.moveStatuses.size();
}

private void validateHasNext() {
if (moveStatuses.isEmpty()) {
throw new IllegalStateException(ErrorMessage.HAS_NO_MOVE_STATUS.getMessage());
}
}
}
14 changes: 14 additions & 0 deletions src/main/java/racingcar/domain/TryCount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package racingcar.domain;

public class TryCount {

private Integer tryCount;

public TryCount(final Integer tryCount) {
this.tryCount = tryCount;
}

public boolean hasNext() {
return this.tryCount-- > 0;
}
}
Loading