Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
193cdb0
docs: 구현 기능 목록 정리
wvssm Jun 10, 2024
2d5de4a
chore: 프로그램 실행 시작점 추가
wvssm Jun 10, 2024
41e6a63
docs: 구현 기능 목록 수정
wvssm Jun 10, 2024
f4be75c
feat: 자동차 전진 기능 추가
wvssm Jun 10, 2024
ad58285
add: Game 모델 생성
wvssm Jun 10, 2024
7673b5e
feat: 경주 참여 자동차 추가
wvssm Jun 10, 2024
23c7fcb
feat: 시도 횟수 설정
wvssm Jun 10, 2024
6e6045d
feat: 현재 실행 횟수 증가
wvssm Jun 10, 2024
8953f0f
feat: 현재 실행 횟수와 목표 실행 횟수 비교
wvssm Jun 10, 2024
9bda17b
feat: 경주 자동차 이동
wvssm Jun 10, 2024
08fe183
feat: 최대 위치 얻기
wvssm Jun 10, 2024
4425c9d
feat: 우승자 정보 얻기
wvssm Jun 10, 2024
abb32da
feat: 자동차 이름 parser
wvssm Jun 10, 2024
b8a335f
feat: 시도 횟수 parser
wvssm Jun 10, 2024
953b015
feat: 난수 생성기
wvssm Jun 10, 2024
bcccc79
feat: 자동차 이름 입력 유효성 검사
wvssm Jun 10, 2024
59bd813
feat: 시도 횟수 입력 유효성 검사
wvssm Jun 10, 2024
fde0098
feat: 자동차 이름 입력
wvssm Jun 10, 2024
3e7f58f
feat: 시도 횟수 입력
wvssm Jun 10, 2024
cb867a2
feat: 실행 결과 출력
wvssm Jun 10, 2024
a8cf0fd
feat: 우승자 출력
wvssm Jun 10, 2024
9d4b855
feat: 자동차 이름 유효성 검사 및 입력 받기
wvssm Jun 10, 2024
f040f34
feat: 시도 횟수 유효성 검사 및 입력 받기
wvssm Jun 10, 2024
9de8d7e
feat: 경주 자동차 등록
wvssm Jun 10, 2024
5ed0d6c
feat: 경주 진행(입력 처리, 경주 시작, 우승자 출력)
wvssm Jun 10, 2024
c5ed775
add: 자동차 경주 게임 실행 시작점 추가
wvssm Jun 10, 2024
9d2f513
add: Validator 테스트 코드 추가
wvssm Jun 10, 2024
84cd992
add: Car 테스트 코드 추가
wvssm Jun 10, 2024
f7660be
add: Game 테스트 코드 추가
wvssm Jun 10, 2024
7c34bb5
fix: 자동차 이름 공백 입력 처리 수정
wvssm Jun 10, 2024
2f2d9bb
test: ValidatorTest 에러 메시지 수정
wvssm Jun 10, 2024
3867d1c
chore: 코드 형태 수정(스페이스)
wvssm Jun 10, 2024
89b6299
refactor: 차량 이동 및 게임 횟수 증가 Controller로 이동
wvssm Jun 10, 2024
a1032b9
feat: add 시도 횟수, 수행 횟수 getter
wvssm Jun 10, 2024
71315f6
test: add 시도 횟수 설정 test
wvssm Jun 10, 2024
f94746a
test: add 수행 횟수 증가 test
wvssm Jun 10, 2024
82e8864
fix: 게임 종료 판단 method 변경
wvssm Jun 10, 2024
ce7fc08
test: add 경주 게임 종료 여부 test
wvssm Jun 10, 2024
8829500
test: 자동차 이름 유효 test로 테스트 이름 변경
wvssm Jun 10, 2024
e31b682
chore: UTF-8 설정 추가
wvssm Jun 10, 2024
8dbb3c7
refactor: Parser 클래스 생략 수정
wvssm Jun 10, 2024
d6e1adb
docs: README 게임 기능 내용 수정
wvssm Jun 10, 2024
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
54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,53 @@
# java-racingcar-precourse
# java-racingcar-precourse

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

## 구현 기능 목록
### model
자동차
- [X] 자동차 전진

게임
- [X] 경주 참여 자동차 추가
- [X] 시도 횟수 설정
- [X] 경주 자동차 이동
- [X] 현재 실행 횟수 증가
- [X] 현재 실행 횟수와 시도 횟수 비교
- [X] 최대 위치 얻기
- [X] 우승자 정보 얻기

사용자 입력 유효성 검사
- [X] 자동차 이름 입력 유효성 검사
- [X] 시도 횟수 입력 유효성 검사

### view
입력
- [X] 자동차 이름 입력
- [X] 시도 횟수 입력

출력
- [X] 실행 결과 출력
- [X] 우승자 출력

### controller
- [X] 자동차 이름 유효성 검사 및 입력 받기
- [X] 시도 횟수 유효성 검사 및 입력 받기
- [X] 경주 자동차 등록
- [X] 시도 횟수 설정
- [X] 경주 진행 (입력 처리, 경주 시작, 우승자 출력)

### utils
- [X] 자동차 이름 parser
- [X] 시도 횟수 parser
- [X] 난수 생성기
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,8 @@ dependencies {
test {
useJUnitPlatform()
}

/* 제 PC에서는 추가하지 않으면 실행되지 않아서 추가했습니다. */
tasks.withType(JavaCompile){
options.encoding = "UTF-8"
}
10 changes: 10 additions & 0 deletions src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package racingcar;

import racingcar.controller.Controller;

public class Application {
public static void main(String[] args) {
Controller controller = new Controller();
controller.run();
}
}
76 changes: 76 additions & 0 deletions src/main/java/racingcar/controller/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package racingcar.controller;

import racingcar.model.Car;
import racingcar.model.Game;
import racingcar.model.Validator;
import racingcar.utils.Parser;
import racingcar.view.InputView;
import racingcar.view.OutputView;

import java.util.List;

import static racingcar.utils.Parser.parseTrialNumber;

public class Controller {
private final Validator validator = new Validator();
private final InputView inputView = new InputView();

public void run(){
play(createGame());
}

private Game createGame(){
Game game = new Game();
registerRaceCar(game);
setTrial(game);
return game;
}

private void play(Game game){
OutputView.printHead();
while(!game.isGameEnd()){
game.moveForward();
game.increaseTrialNumber();
OutputView.printScore(game.getRaceCars());
}
OutputView.printWinners(game.getWinners());
}

private void registerRaceCar(Game game){
game.setRaceCars(Parser.parseCarName(getCarNamesUserInput()));
}

private void setTrial(Game game){
game.setTrial(Parser.parseTrialNumber(getTrialNumberUserInput()));
}

private String getCarNamesUserInput() {
String input = inputView.requestCarNamesMessage();
return checkValidationCarNames(input);
}

private String checkValidationCarNames(String input) {
try {
validator.checkCarsName(input);
return input;
} catch (IllegalArgumentException e) {
System.out.println("[ERROR] " + e.getMessage());
return getCarNamesUserInput();
}
}

private String getTrialNumberUserInput() {
String input = inputView.requestTrialNumberMessage();
return checkValidationTrialNumber(input);
}

private String checkValidationTrialNumber(String input) {
try {
validator.checkTrialNumber(input);
return input;
} catch (IllegalArgumentException e) {
System.out.println("[ERROR] " + e.getMessage());
return getTrialNumberUserInput();
}
}
}
26 changes: 26 additions & 0 deletions src/main/java/racingcar/model/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package racingcar.model;

public class Car {
private String name;
private int position;
private static final int FORWARD_CONDITION = 4;

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

public String getName(){
return name;
}

public int getPosition(){
return position;
}

public void move(int condition){
if(condition>=FORWARD_CONDITION){
this.position += 1;
}
}
}
67 changes: 67 additions & 0 deletions src/main/java/racingcar/model/Game.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package racingcar.model;

import racingcar.utils.RandomNumberGenerator;

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

public class Game {
private final List<Car> raceCars;
private static int trial;
private int trialNumber = 0;

public Game(){
Game.trial = 0;
raceCars = new ArrayList<>();
}

public List<Car> getRaceCars(){
return raceCars;
}

public int getTrial(){
return trial;
}

public int getTrialNumber(){
return trialNumber;
}

public void setRaceCars(String[] carsName){
for (String s : carsName) {
raceCars.add(new Car(s));
}
}

public void setTrial(int trial){
Game.trial = trial;
}

public void moveForward(){
for (Car car : raceCars){
car.move(RandomNumberGenerator.generate());
}
}

public void increaseTrialNumber(){
this.trialNumber += 1;
}

public Boolean isGameEnd(){
return trial <= this.trialNumber;
}

public List<Car> getWinners() {
return raceCars.stream()
.filter(c -> c.getPosition() == getMaxPosition(raceCars))
.collect(Collectors.toList());
}

public int getMaxPosition(List<Car> cars){
return cars.stream()
.mapToInt(Car::getPosition)
.max()
.orElse(0);
}
}
34 changes: 34 additions & 0 deletions src/main/java/racingcar/model/Validator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package racingcar.model;

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

public class Validator {
public void checkCarsName(String carsName){
if (carsName.endsWith(",")) {
throw new IllegalArgumentException("입력 문자열의 마지막 문자가 ','일 수 없습니다.");
}
String[] names = carsName.split(",");
Set<String> carSet = new HashSet<>();
for (String name : names) {
if (name.trim().isEmpty() || name.length() > 5) {
throw new IllegalArgumentException("자동차 이름은 1 ~ 5글자로 입력해주세요.");
}
if (!carSet.add(name)) {
throw new IllegalArgumentException("자동차 이름은 중복될 수 없습니다.");
}
}
}

public void checkTrialNumber(String trialNumberInput){
int trialNumber;
try{
trialNumber = Integer.parseInt(trialNumberInput);
} catch (NumberFormatException e){
throw new IllegalArgumentException("1 이상 2,147,483,647 이하의 자연수를 입력해주세요.");
}
if(trialNumber < 1){
throw new IllegalArgumentException("1 이상 2,147,483,647 이하의 자연수를 입력해주세요.");
}
}
}
11 changes: 11 additions & 0 deletions src/main/java/racingcar/utils/Parser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package racingcar.utils;

public class Parser {
public static String[] parseCarName(String input){
return input.split(",");
}

public static int parseTrialNumber(String input){
return Integer.parseInt(input);
}
}
10 changes: 10 additions & 0 deletions src/main/java/racingcar/utils/RandomNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package racingcar.utils;

import java.util.Random;

public class RandomNumberGenerator {
public static int generate(){
Random random = new Random();
return random.nextInt(10);
}
}
25 changes: 25 additions & 0 deletions src/main/java/racingcar/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package racingcar.view;

import java.util.Scanner;

public class InputView {
private final Scanner scanner;

public InputView() {
this.scanner = new Scanner(System.in);
}

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

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

private String getUserInput() {
return scanner.nextLine();
}
}
41 changes: 41 additions & 0 deletions src/main/java/racingcar/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package racingcar.view;

import racingcar.model.Car;

import java.util.List;

public class OutputView {
public static void printHead(){
System.out.println();
System.out.println("실행 결과");
}

public static void printScore(List<Car> cars){
for(Car car : cars) {
printCarScore(car);
}
System.out.println();
}

public static void printWinners(List<Car> winners){
StringBuilder winnerNames = new StringBuilder("최종 우승자 : ");
for(Car car : winners){
winnerNames.append(car.getName()).append(", ");
}
int length = winnerNames.length();
String result = winnerNames.substring(0, length - 2);
System.out.print(result);
}

public static void printCarScore(Car car){
System.out.print(car.getName()+" : ");
printCarPosition(car);
System.out.println();
}

public static void printCarPosition(Car car){
for(int i=0; i<car.getPosition(); i++){
System.out.print("-");
}
}
}
Loading