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
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,40 @@
# java-racingcar-precourse
# java-racingcar-precourse

# 기능 요구 사항
초간단 자동차 경주 게임을 구현한다.
- 주어진 횟수 동안 n대의 자동차는 1칸씩 전진 또는 멈출 수 있다.
- 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다.
- 단 중복을 허용하지 않는다.
- 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다.
- 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
- 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우이다.
- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다.
- 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다.
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다.
- Exception 이 아닌 IllegalArgumentException , IllegalStateException 등과 같은 명확한 유형을 처리한다

# 기능 요구 사항
- 경주 시작
- **자동차 이름 입력 받기** (이름은 쉼표 기준으로 구분)
- 경주 인원이 한 명일 때
- IllegalStateException, [ERROR]로 시작하는 에러 메세지 출력, 다시 입력을 받는다.
- "경주는 두 명 이상일 때 할 수 있습니다."
- 경주 인원이 2명이상일 때
- 이름 중복 검사, 이름 제한 검사
- 이름이 중복값일 때, 자동차 이름이 5글자 이상일 떄
- IllegalArgumentException, [ERROR]로 시작하는 에러 메세지 출력, 다시 입력을 받는다.
- "중복된 자동차의 이름이 있습니다."
- "자동차 이름은 5글자 이하만 가능합니다."
- 검사 통과했을 때
- **시도 횟수 입력 받기**
- 숫자가 아닐 때, 2미만일 때
- IllegalArgumentException, [ERROR]로 시작하는 에러 메세지 출력, 다시 입력을 받는다.
- "숫자만 입력할 수 있습니다."
- "정수만 입력할 수 있습니다."
- "2이상의 숫자만 입력할 수 있습니다."
- 검사 통과했을 때
- 주사위 굴리기
- 4미만일 때
- doUnderNum(int diceNum);
- 4이상일 때
- doAboveNum(int diceNum);
12 changes: 12 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import io.Input;
import io.Output;
import repository.CarRepository;
import service.Race;
import validate.Validator;

public class Application {
public static void main(String[] args) {
Race race = new Race(new Input(), new Output(), new Validator(), new CarRepository());
race.execute();
}
}
31 changes: 31 additions & 0 deletions src/main/java/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package domain;

import java.util.Random;

public class Car {
private String name;
private int location = 0;

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

public String getName() {
return name;
}

public int getLocation() {
return location;
}

public void move(){
if (getRandomNum() >= 4){
location += 1;
}
}

private int getRandomNum(){
Random random = new Random();
return random.nextInt(9);
}
}
21 changes: 21 additions & 0 deletions src/main/java/io/Input.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io;

import java.util.Scanner;

public class Input {
private Scanner scanner = new Scanner(System.in);

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

public String getRaceCount(){
System.out.println("시도할 횟수는 몇회인가요?");
return scanner.nextLine();
}

public String deleteSpace(String raceInput){
return raceInput.replace(" ", "");
}
}
26 changes: 26 additions & 0 deletions src/main/java/io/Output.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io;

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

public class Output {
public void printRace(String carName, int progress){
String progressBar = "-".repeat(progress);
System.out.println(carName + " : " + progressBar);
}

public void printWinner(List<Car> winner){
String winnerNames = winner.stream()
.map(Car::getName)
.collect(Collectors.joining(", "));

System.out.println("최종 우승자 : " + winnerNames);
}

public void print(String any){
System.out.println(any);
}
}

22 changes: 22 additions & 0 deletions src/main/java/repository/CarRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package repository;

import domain.Car;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class CarRepository {
private static final Map<String, Car> carList = new LinkedHashMap<>();

public List<Car> findAllCar(){
return new ArrayList<>(carList.values());
}

public void saveCar(Car car){
carList.put(car.getName(), car);
}

public void findByName(){
}
}
109 changes: 109 additions & 0 deletions src/main/java/service/Race.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package service;

import domain.Car;
import io.Input;
import io.Output;
import java.util.ArrayList;
import java.util.List;
import repository.CarRepository;
import validate.Validator;

public class Race {

private int raceNum;
private String raceInput;
private static final int CAR_NAME_NUM = 5;
private static final char INPUT_SYMBOL = ',';
private final Input input;
private final Output output;
private final Validator validator;

private final CarRepository carRepository;

public Race(Input input, Output output, Validator validator, CarRepository carRepository) {
this.input = input;
this.output = output;
this.validator = validator;
this.carRepository = carRepository;
}

public void execute() {
getCarName();
getRaceCount();

List<Car> carList = carRepository.findAllCar();

output.print("실행 결과");
raceStart(carList);

List<Car> winnerList = getWinner();
output.printWinner(winnerList);
}

private void getCarName(){
while (true) {
try {
raceInput = input.getCarName();
validator.validateRaceInput(input.deleteSpace(raceInput), INPUT_SYMBOL, CAR_NAME_NUM);
registCar(raceInput);
break;
} catch (IllegalArgumentException | IllegalStateException e) {
output.print(e.getMessage());
}
}
}

private void getRaceCount(){
while (true) {
try {
String stringRaceNum = input.getRaceCount();
validator.validateRaceCount(stringRaceNum);
raceNum = Integer.parseInt(stringRaceNum);
break;
} catch (IllegalArgumentException | IllegalStateException e) {
output.print(e.getMessage());
}
}
}
public void registCar(String raceInput) {
String[] carList = raceInput.split(Character.toString(INPUT_SYMBOL));
for (String stringCar : carList) {
Car car = new Car(stringCar);
carRepository.saveCar(car);
}
}

public void raceStart(List<Car> carList) {
for (int i = 0; i < raceNum; i++) {
carList.stream().forEach(car -> {
car.move();
output.printRace(car.getName(), car.getLocation());
});
output.print("");
}
}

public List<Car> getWinner() {
List<Car> winnerList = new ArrayList<>();
List<Car> carList = carRepository.findAllCar();
int maxLocation = findMaxLocation();
for (Car car : carList) {
if (car.getLocation() == maxLocation) {
winnerList.add(car);
}
}
return winnerList;
}

private int findMaxLocation() {
int maxLocation = 0;
List<Car> carList = carRepository.findAllCar();
for (Car car : carList) {
int carLocation = car.getLocation();
if (maxLocation < carLocation) {
maxLocation = carLocation;
}
}
return maxLocation;
}
}
61 changes: 61 additions & 0 deletions src/main/java/validate/Validator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package validate;

import java.util.Arrays;

public class Validator {

public boolean validateRaceInput(String raceInput, char symbol, int carNameNum){
validateCarCount(raceInput, symbol);
validateDuplicateCarName(raceInput, symbol);
validateUnderCarNum(raceInput, symbol, carNameNum);
return true;
}
private void validateCarCount(String raceInput, char symbol) {
long carCount = raceInput.chars()
.filter(letter -> letter == symbol)
.count();

if (carCount < 1){
throw new IllegalStateException("[ERROR] 경주는 두 명 이상일 때 할 수 있습니다.");
}
}

private void validateDuplicateCarName(String raceInput, char symbol) {
String[] carList = raceInput.split(Character.toString(symbol));
long distinctCarCount = Arrays.stream(carList).distinct().count();
long totalCarCount = carList.length;
if(distinctCarCount != totalCarCount){
throw new IllegalArgumentException("[ERROR] 중복된 자동차의 이름이 있습니다.");
}
}

private void validateUnderCarNum(String raceInput, char symbol, int carNameNum) {
String[] carList = raceInput.split(Character.toString(symbol));
for (String carName : carList){
if(carName.length() > carNameNum){
throw new IllegalArgumentException("[ERROR] 자동차 이름은 5글자 이하만 가능합니다. 이름 초과 : " + carName);
}
}
}

public boolean validateRaceCount(String raceNum) {
validateIsNum(raceNum);
validateUnderRaceNum(raceNum);
return true;
}

private void validateIsNum(String raceNum) {
for (char c : raceNum.toCharArray()){
if(!Character.isDigit(c)){
throw new IllegalArgumentException("[ERROR] 숫자만 입력할 수 있습니다.");
}
}
}

private void validateUnderRaceNum(String raceNum) {
int intRaceNum = Integer.parseInt(raceNum);
if (intRaceNum < 2){
throw new IllegalArgumentException("[ERROR] 2이상의 숫자만 입력할 수 있습니다.");
}
}
}
Loading