Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,41 @@

자동차 경주 미션 저장소

## 패키지 구조
### [Model]
#### Car
- 'Name'과 'Position'을 담은 객체
#### Cars
- 게임에 참여하는 'Car'들을 묶은 객체
#### Name
- 'Car'의 이름을 담은 객체
#### Position
- 'Car'의 위치를 담은 객체
#### RandomNumber
- 전진 조건이 되는 수를 생성하는 객체
#### TryCount
- 게임 진행 횟수를 담은 객체

### [View]
#### InputView
- 사용자의 입력을 받음
#### OutputView
- 안내 문구 및 결과 출력
#### ViewMessage(enum)
- 입출력 문구 모음

### [Controller]
#### RacingController
- 게임 진행

### [Util]
#### ErrorMessage(enum)
- 에러 문구 모음
#### Validation
- Model과 View 검증

## 필요 기능
1. 자동차 정보 입력
2. 시도 횟수 입력
3. 실행 결과 출력
4. 우승자 출력
9 changes: 7 additions & 2 deletions src/main/java/RacingMain.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import controller.RacingController;

import java.io.IOException;

public class RacingMain {

public static void main(String[] args) {
public static void main(String[] args) throws IOException {
// TODO: MVC 패턴을 기반으로 자동차 경주 미션 구현해보기
System.out.println("Hello, World!");
final var racingController = new RacingController();
racingController.run();
}
}
44 changes: 44 additions & 0 deletions src/main/java/controller/RacingController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package controller;

import domain.Cars;
import domain.TryCount;
import view.InputView;
import view.OutputView;

import java.io.IOException;
import java.util.List;

public class RacingController {
public void run() throws IOException {
Cars cars = new Cars(createCars());
TryCount tryCount = new TryCount(setTryCount());
racingResult(tryCount, cars);
findWinners(cars);
}

// 자동차 정보 입력
private List<String> createCars() throws IOException {
return InputView.getCarName();
}

// 시도 횟수 입력
private int setTryCount() throws IOException {
return InputView.getTryCount();
}

// 시행 결과 출력
private void racingResult(TryCount tryCount, Cars cars) {
OutputView.printRacingResult();

while(tryCount.isPlayable()) {
tryCount.decreaseTryCount();
cars.moveCars();
OutputView.printRacingStatus(cars.getCars());
}
}

// 우승자 출력
private void findWinners(Cars cars) {
OutputView.printRacingWinner(cars.findWinnerName());
}
}
33 changes: 33 additions & 0 deletions src/main/java/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package domain;

import util.Validation;

public class Car {
// 자동차
private static final int MINIMUM_MOVE_POWER = 4;
private final Name name;
private final Position position;

public Car(String name) {
Validation.validationNameSize(name);
this.name = new Name(name);
this.position = new Position();
}

// 자동차 이름 반환
public String getCarName() {
return name.name();
}

// 자동차 위치 반환
public int getCarPosition() {
return position.getPosition();
}

// 자동차 전진
public void moveCar(int number) {
if (number >= MINIMUM_MOVE_POWER) {
position.increasePosition();
}
}
}
64 changes: 64 additions & 0 deletions src/main/java/domain/Cars.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package domain;

import util.Validation;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class Cars {
// 자동차 경주에 참여하는 자동차들
private static final int DEFAULT_POSITION = 0;
private final List<Car> cars;
public Cars(List<String> carNames) {
Validation.validationCarNumber(carNames);
Validation.validationDuplicatedName(carNames);

cars = new ArrayList<>();
generateCars(carNames, cars);
}

// 자동차 생성
private void generateCars(List<String> carNames, List<Car> cars) {
for(String name: carNames) {
Car car = new Car(name);
cars.add(car);
}
}

// 자동차 리스트 반환
public List<Car> getCars() {
return cars;
}

// 자동차 전진
public void moveCars() {
for (Car c: cars) {
int number = RandomNumber.getRandomNumber();
c.moveCar(number);
}
}

// 우승자 이름 반환
public List<String> findWinnerName() {
return findWinner().stream()
.map(Car::getCarName)
.collect(Collectors.toList());
}

// 우승자 반환
private List<Car> findWinner() {
int winnerPosition = getWinnerPosition();
return cars.stream()
.filter(car -> car.getCarPosition() == winnerPosition)
.collect(Collectors.toList());
}

// 우승자 위치 반환
private int getWinnerPosition() {
return cars.stream()
.mapToInt(Car::getCarPosition)
.max()
.orElse(DEFAULT_POSITION);
}
}
7 changes: 7 additions & 0 deletions src/main/java/domain/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package domain;

/**
* @param name 자동차 이름
*/
public record Name(String name) {
}
21 changes: 21 additions & 0 deletions src/main/java/domain/Position.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package domain;

public class Position {
// 자동차 위치
private static final int INITIAL_POSITION = 0;
private int position;

public Position() {
position = INITIAL_POSITION;
}

// 위치 반환
public int getPosition() {
return position;
}

// 위치 증가(전진)
public void increasePosition() {
position++;
}
}
13 changes: 13 additions & 0 deletions src/main/java/domain/RandomNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package domain;

import java.util.Random;

public class RandomNumber {
private static final int NUMBER_UPPER_BOUND = 10;
private static final Random random = new Random();

// 1~10 난수 반환
public static int getRandomNumber() {
return random.nextInt(NUMBER_UPPER_BOUND);
}
}
23 changes: 23 additions & 0 deletions src/main/java/domain/TryCount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package domain;

import util.Validation;

public class TryCount {
private static final int PLAYABLE_LOWER_BOUND = 1;
private int tryCount;

public TryCount(int tryCount) {
Validation.validationTryCount(tryCount);
this.tryCount = tryCount;
}

// 시도 횟수 감소
public void decreaseTryCount() {
tryCount--;
}

// 시도 가능 여부 반환
public boolean isPlayable() {
return PLAYABLE_LOWER_BOUND <= tryCount;
}
}
20 changes: 20 additions & 0 deletions src/main/java/util/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package util;

public enum ErrorMessage {
NAME_SIZE_ERROR("이름은 1글자 이상 5글자 이하로 작성해주세요."),
NAME_DUPLICATE_ERROR("이름은 중복될 수 없습니다."),
CAR_NUMBER_ERROR("자동차는 1대 이상이어야 합니다."),
TRY_TYPE_ERROR("입력값은 정수여야 합니다."),
TRY_RANGE_ERROR("시도 횟수는 양의 정수여야 합니다.");

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

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

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

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static util.ErrorMessage.*;

public class Validation {
private static final int COUNT_LOWER_BOUND = 0;
private static final int NAME_MAX_SIZE = 5;

// 이름 길이 유효 여부 검사
public static void validationNameSize(String name) {
if (name == null || name.isEmpty() || name.length() > NAME_MAX_SIZE) {
throw new IllegalArgumentException(NAME_SIZE_ERROR.getMessage());
}
}

// 자동차 존재 여부 검사
public static void validationCarNumber(List<String> names) {
if (names.isEmpty()) {
throw new IllegalArgumentException(CAR_NUMBER_ERROR.getMessage());
}
}

// 자동차 이름 중복 검사
public static void validationDuplicatedName(List<String> names) {
Set<String> deduplicate = new HashSet<>(names);
if (deduplicate.size() != names.size()) {
throw new IllegalArgumentException(NAME_DUPLICATE_ERROR.getMessage());
}
}

// 정수 입력 검사
public static Integer parseInteger(String input) {
try {
return Integer.parseInt(input);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(TRY_TYPE_ERROR.getMessage());
}
}

// 시도 횟수가 양의 정수인지 검사
public static void validationTryCount(int tryCount) {
if (tryCount <= COUNT_LOWER_BOUND) {
throw new IllegalArgumentException(TRY_RANGE_ERROR.getMessage());
}
}
}
36 changes: 36 additions & 0 deletions src/main/java/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package view;

import util.Validation;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static view.ViewMessage.*;

public class InputView {

private static final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));

// 자동차 이름 입력
public static List<String> getCarName() throws IOException {
System.out.println(INPUT_CAR_NAME_MESSAGE.getMessage());
return splitNames(bufferedReader.readLine());
}

// 분리된 자동차 이름 반환
private static List<String> splitNames(String names) {
return Arrays.stream(names.split(SEPARATOR_VALUE.getMessage()))
.map(String::trim)
.collect(Collectors.toList());
}

// 시도 횟수 입력
public static int getTryCount() throws IOException {
System.out.println(TRY_COUNT_MESSAGE.getMessage());
return Validation.parseInteger(bufferedReader.readLine());
}
}
Loading