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

## 구현 기능 목록

### Model

#### RacingCar

- 레이싱카 객체
- 변수
- 자동차 이름
- 현재 위치 (=전진한 회수)
- 메서드
- 현재 위치 출력 : "자동차 이름 : (현재 위치만큼 - 출력)" 의 조건으로 출력
- 전진 : 전진할지 말지 판단하는 메서드, 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우 전진


#### RacingCarGame

- 레이싱카게임 객체
- 변수
- 게임에 참가하는 레이싱카 객체 리스트
- 시도할 회수 (몇번의 이동을 할 것인지)
- 현재까지 시도한 회수
- 메서드
- 회수 진행 : 1번의 전진 회차를 진행
- 우승자 판단 : 모든 시도 회수가 끝난 후 우승자를 판단하여 반환
- 게임 종료 판단 : 모든 회차를 진행하여 게임이 종료됐는지 판단

### View

#### GameInterface

- 출력 및 입력 기능을 담당하는 게임 인터페이스 객체
- 출력 기능
- 전진 회수 진행 시, 현재 레이싱카들의 전진 상태 출력
- 최종 우승자 결과 출력
- 오류 메세지 출력
- 입력 기능
- 게임에 참가할 n개의 자동차 입력
- 시도할 회수 입력

### Controller

#### GameExecutor

- 앱 최초 실행 시 main 함수에서 호출하는 exec 메서드 구현
- model과 view를 연결하는 기능
12 changes: 12 additions & 0 deletions src/main/java/app/RacingCarApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app;

import app.controller.GameExecutor;
import app.model.RacingCarGame;
import app.view.GameInterface;

public class RacingCarApplication {
public static void main(String[] args) {
GameExecutor gameExecutor = new GameExecutor(new GameInterface(), new RacingCarGame());
gameExecutor.exec();
}
}
56 changes: 56 additions & 0 deletions src/main/java/app/controller/GameExecutor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package app.controller;

import app.model.RacingCarGame;
import app.view.GameInterface;

public class GameExecutor {
private GameInterface gameInterface;
private RacingCarGame racingCarGame;

public GameExecutor(GameInterface gameInterface, RacingCarGame racingCarGame) {
this.gameInterface = gameInterface;
this.racingCarGame = racingCarGame;
}

public void step1() {
while (racingCarGame.getCarList() == null) {
try {
racingCarGame.setCarList(gameInterface.getRacingCarNames());
} catch (IllegalArgumentException e) {
gameInterface.printErrorMessage(e.getMessage());
}
}
}

public void step2() {
while (racingCarGame.getAttemptCnt() == 0) {
try {
racingCarGame.setAttemptCnt(gameInterface.getAttemptCount());
} catch (NumberFormatException e) {
gameInterface.printErrorMessage("숫자만 입력해주세요.");
} catch (IllegalArgumentException e) {
gameInterface.printErrorMessage(e.getMessage());
}
}
}

public void step3() {
gameInterface.printMessage("\n실행 결과");
while (!racingCarGame.isFinished()) {
racingCarGame.proceed();
gameInterface.printAttemptResult(racingCarGame.getCarList());
}
}

public void step4() {
gameInterface.printWinner(racingCarGame.getWinnerList());
}

public void exec() {
step1(); // 1. 자동차 이름 입력
step2(); // 2. 시도할 회수 입력
step3(); // 3. 게임 진행 (경주)
step4(); // 4. 최종 우승자 출력
}

}
31 changes: 31 additions & 0 deletions src/main/java/app/model/RacingCar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package app.model;

import java.util.Random;

public class RacingCar {
private String name;
private int location;

public RacingCar(String name) {
this.name = name;
this.location = 0;
}

public void printCurLocation() {
System.out.println(this.name + " : " + "-".repeat(location));
}

public void moveForward() { // 전진할지 말지 판단한 후, 전진하면 location 값 +1
if (new Random().nextInt(10) >= 4) {
this.location++;
}
}

public String getName() {
return name;
}

public int getLocation() {
return location;
}
}
65 changes: 65 additions & 0 deletions src/main/java/app/model/RacingCarGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package app.model;

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

public class RacingCarGame {
private int attemptCnt; // 시도할 회수
private int curCnt; // 현재까지 시도한 회수
private List<RacingCar> carList;

public RacingCarGame() {
this.curCnt = 0;
this.attemptCnt = 0;
}

public int getAttemptCnt() {
return attemptCnt;
}

public void setAttemptCnt(String attemptCnt) {
int num = Integer.parseInt(attemptCnt);
if (num < 1) throw new IllegalArgumentException("시도 회수는 1 이상이어야 합니다.");
this.attemptCnt = num;
}

public int getCurCnt() {
return curCnt;
}

public void setCurCnt(int curCnt) {
this.curCnt = curCnt;
}

public List<RacingCar> getCarList() {
return carList;
}

public void setCarList(String carNames) {
String[] carNameList = carNames.split(",");
checkCarNameValidation(carNameList);

this.carList = Arrays.stream(carNameList).map(RacingCar::new).collect(Collectors.toList());
}

public void checkCarNameValidation(String[] carNameList) {
Arrays.stream(carNameList).filter(name -> name.length() > 5 || name.length() < 1).findAny().ifPresent(name -> {
throw new IllegalArgumentException("자동차 이름은 1자리 이상 5자리 이하만 가능합니다.");
});
}

public void proceed() {
carList.forEach(RacingCar::moveForward);
this.curCnt++;
}

public List<RacingCar> getWinnerList() {
int maxLocation = carList.stream().mapToInt(RacingCar::getLocation).max().orElse(0);
return carList.stream().filter(car -> car.getLocation() == maxLocation).collect(Collectors.toList());
}

public boolean isFinished() {
return this.attemptCnt == this.curCnt;
}
}
40 changes: 40 additions & 0 deletions src/main/java/app/view/GameInterface.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package app.view;

import app.model.RacingCar;

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

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

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

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

public void printAttemptResult(List<RacingCar> carList) {
carList.stream().forEach(RacingCar::printCurLocation);
System.out.println();
}

public void printWinner(List<RacingCar> winnerList) {
System.out.println("최종 우승자 : " + winnerList.stream()
.map(RacingCar::getName)
.collect(Collectors.joining(", ")));
}

public void printMessage(String message) {
System.out.println(message);
}

public void printErrorMessage(String message) {
System.out.println("[Error] " + message);
}
}
78 changes: 78 additions & 0 deletions src/test/java/app/model/RacingCarGameTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package app.model;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;

public class RacingCarGameTest {

@Test
@DisplayName("5자리 이상 자동차 이름이 입력됐을 경우")
void test1() {
String inputCarNames = "가나,다라마바,사아자차카타,파하";

assertThatThrownBy(() -> {
RacingCarGame racingCarGame = new RacingCarGame();
racingCarGame.setCarList(inputCarNames);
})
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("자동차 이름은 1자리 이상 5자리 이하만 가능합니다.");
}

@Test
@DisplayName("자동차 이름에 공백이 입력됐을 경우")
void test2() {
String inputCarNames1 = "";

assertThatThrownBy(() -> {
RacingCarGame racingCarGame = new RacingCarGame();
racingCarGame.setCarList(inputCarNames1);
})
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("자동차 이름은 1자리 이상 5자리 이하만 가능합니다.");

String inputCarNames2 = "가나,다라마,,바사";

assertThatThrownBy(() -> {
RacingCarGame racingCarGame = new RacingCarGame();
racingCarGame.setCarList(inputCarNames2);
})
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("자동차 이름은 1자리 이상 5자리 이하만 가능합니다.");
}

@Test
@DisplayName("시도 회수에 숫자 외 문자가 입력됐을 경우")
void test3() {
String input = "asd@34";

assertThatThrownBy(() -> {
RacingCarGame racingCarGame = new RacingCarGame();
racingCarGame.setAttemptCnt(input);
})
.isInstanceOf(NumberFormatException.class);
}

@Test
@DisplayName("시도 회수에 1 미만 숫자가 입력됐을 경우")
void test4() {
String input1 = "-1";

assertThatThrownBy(() -> {
RacingCarGame racingCarGame = new RacingCarGame();
racingCarGame.setAttemptCnt(input1);
})
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("시도 회수는 1 이상이어야 합니다.");

String input2 = "0";

assertThatThrownBy(() -> {
RacingCarGame racingCarGame = new RacingCarGame();
racingCarGame.setAttemptCnt(input2);
})
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("시도 회수는 1 이상이어야 합니다.");
}
}