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
29 changes: 29 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## 기능명세
### 1. 자동차 이름을 입력받기 위한 화면을 구성한다.
- 자동차 이름 입력받기
- 자동차 이름이 5자 이하인 경우에만 입력받기
- 자동차 이름에 쉼표(,)로 구분된 이름이 1개 이상인 경우에만 입력받기
- 같은 이름의 자동차가 존재하지 않는 경우에만 입력받기
- 자동차 이름 저장하기
- 자동차 이름을 쉼표(,)로 구분하여 저장하기
- 예외 발생 시 에러 던지고 종료

### 2. 시도할 회수를 입력받기 위한 화면을 구성한다.
- 시도할 회수 입력받기
- 시도할 회수가 1 이상인 경우에만 입력받기
- 시도할 회수가 숫자인 경우에만 입력받기
- 시도할 회수 저장하기
- 시도할 회수를 저장하기
- 정수로 저장하기
- 예외 발생 시 에러 던지고 종료

### 3. 자동차 경주를 진행한다.
- 시도할 회수를 입력 받은 대로 자동차를 전진시킨다.
- 차수별 자동차 이름과 전진한 거리를 출력한다.

### 4. 경주 결과를 출력한다.
- 경주 결과를 출력한다.
- 우승자를 출력한다.

### 5. 경주 게임을 종료한다.
- 경주 게임을 종료한다.
20 changes: 19 additions & 1 deletion src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
package racingcar;

import racingcar.controller.InputController;
import racingcar.model.RacingCar;
import racingcar.view.ResultView;

public class Application {

public static void main(String[] args) {
// TODO: 프로그램 구현
startGame();
}

// 게임 시작
public static void startGame() {
InputController.createRacingCar();
int round = InputController.setRoundNum();
ResultView.printResult();
for (int i = 0; i < round; i++) {
RacingCar.moveCars();
System.out.println();
}
RacingCar.getWinners();
}
Comment on lines +15 to 24
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Controller 객체를 만들지 않고 Application.java에서 바로 시작한 이유가 있나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

가독성과 동작에 크게 영향을 주지 않는다고 생각 했습니다

}
}
18 changes: 18 additions & 0 deletions src/main/java/racingcar/controller/InputController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package racingcar.controller;
import racingcar.model.NameValid;
import racingcar.model.NumberVaild;
import racingcar.model.RacingCar;
import racingcar.view.InputView;

public class InputController {
// 레이싱 자동차를 생성한다.
public static void createRacingCar() {
NameValid nameValid = new NameValid(InputView.carNameInput());
new RacingCar(nameValid.getNames());
}

public static int setRoundNum() {
NumberVaild validation = new NumberVaild(Integer.parseInt(InputView.tryCountInput()));
return validation.getNumber();
}
}
28 changes: 28 additions & 0 deletions src/main/java/racingcar/model/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package racingcar.model;

public class Car{
private final String name;
private int position;

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

public void move(){
// 매개변수로 랜덤 값을 주면 테스트하기 좋아진다.
// 랜덤 값이 4 이상이면 전진한다.
if(RandomNumber.getRandomNumber() >= 4){
position++;
}
}

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

public String getName() {
return name.replace(" ", "");
}
}
49 changes: 49 additions & 0 deletions src/main/java/racingcar/model/NameValid.java
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 취향차이일 수도 있는데, Name의 검증과 관련된 부분은 Car 객체를 생성하는 과정에 넣는 게 더 좋지 않나 싶습니다!

그럴 일은 잘 없겠지만 Controller에서 NameValid를 사용하는 것을 까먹고 바로 Car를 생성할 수도 있는 거고, Car에 해당 검증 로직을 넣으면 원터치로 검증이 가능하기 때문에 좋아보입니다.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validation은 Controller에서 제외하는 것이 좋다는 것에 동의합니다. Controller는 Request를 넘겨주는 entry point의 역할만 수행하도록 만드는게 좋다고 생각합니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package racingcar.model;

import java.util.ArrayList;
import java.util.Arrays;

public class NameValid {
final ArrayList<String> names;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리스트의 불변성 관련 검색 키워드

  • unmodifiableList
  • (를 이기는) 방어적 복사


public ArrayList<String> toArrayList(String carsString) {
String[] carNames = carsString.trim().split(",");
return new ArrayList<>(Arrays.asList(carNames));
}

public NameValid(String carName) {
this.names = toArrayList(carName);
isValid();
}

// 자동차 이름이 5자 이하인지 확인
public void isNameValid() {
for (String name : names) {
if (name.length() > 5) {
throw new IllegalArgumentException("자동차 이름은 5자 이하만 가능합니다.");
}
}
}

// 자동차 이름이 중복되는지 확인
public void isNameDuplicate() {
for (int i = 0; i < names.size(); i++) {
for (int j = i + 1; j < names.size(); j++) {
if (names.get(i).equals(names.get(j))) {
// 에러 반환
throw new IllegalArgumentException("중복된 이름이 존재합니다.");
}
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자동차 이름이 중복되는건 생각하지 못했는데 저도 기능 명세를 작성할때 더 생각하는 능력을 길러봐야겠어요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니당~


// 자동차 이름이 유효한지 확인
public void isValid() {
isNameValid();
isNameDuplicate();
}

public ArrayList<String> getNames() {
return names;
}
}
34 changes: 34 additions & 0 deletions src/main/java/racingcar/model/NumberVaild.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package racingcar.model;

public class NumberVaild {
private static int number = 0;

public NumberVaild(int number) {
NumberVaild.number = number;
isValid();
}

// 숫자가 맞는지 확인한다.
public void isValid() {
isNumber();
isPositiveNumber();
}

// 숫자만 입력했는지 확인한다.
public void isNumber() {
if (!String.valueOf(number).matches("^[0-9]*$")) {
throw new IllegalArgumentException("숫자만 입력해주세요.");
}
}

// 0보다 큰 숫자인지 확인한다.
public void isPositiveNumber() {
if (number < 0) {
throw new IllegalArgumentException("0보다 큰 숫자를 입력해주세요.");
}
}

public int getNumber() {
return number;
}
}
44 changes: 44 additions & 0 deletions src/main/java/racingcar/model/RacingCar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package racingcar.model;

import racingcar.view.ResultView;

import java.util.ArrayList;

public class RacingCar {
private static final ArrayList<Car> cars = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static 키워드를 붙이면 멀티쓰레드 환경에서 필드의 일관성이 보장되지 않기 때문에 당장 생각할 문제는 아니지만 여러 명이 게임을 플레이한다고 가정했을 때 문제가 될 수 있을 것 같습니다! 제거를 고려해보시면 좋을 것 같아유


public RacingCar(ArrayList<String> cars) {
for (String car : cars) {
RacingCar.cars.add(new Car(car));
}
}

// 자동차들을 이동시킨다.
public static void moveCars() {
for (Car car : cars) {
car.move();
ResultView.printRoundResult(car.getName(), car.getPosition());
}
}

// 우승자를 반환한다.
public static void getWinners() {
ArrayList<String> winners = new ArrayList<>();
int maxPosition = getMaxPosition();
for (Car car : cars) {
if (car.getPosition() == maxPosition) {
winners.add(car.getName());
}
}
ResultView.printWinner(winners);
}
Comment on lines +16 to +34
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Model에서 View를 호출하지 않고 Controller에서 결합하도록 하는 것이 좋다고 생각합니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영하겠습니다~


// 최대 이동값
private static int getMaxPosition() {
int maxPosition = 0;
for (Car car : cars) {
maxPosition = Math.max(maxPosition, car.getPosition());
}
return maxPosition;
}
}
Comment on lines +36 to +44

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 최대값 구하는걸 다른 반복문 안에 같이 집어넣었는데 따로 분리하니까 훨씬 깔끔하고 좋아보이네요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니당~

8 changes: 8 additions & 0 deletions src/main/java/racingcar/model/RandomNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package racingcar.model;
import camp.nextstep.edu.missionutils.Randoms;

public class RandomNumber {
public static int getRandomNumber() {
return Randoms.pickNumberInRange(0,9);
}
}
20 changes: 20 additions & 0 deletions src/main/java/racingcar/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package racingcar.view;
import camp.nextstep.edu.missionutils.Console;

public class InputView {

private InputView() {
}

// 자동차의 이름을 입력받는다.
public static String carNameInput() {
System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");
return Console.readLine();
}

// 시도할 회수를 입력받는다.
public static String tryCountInput() {
System.out.println("시도할 회수는 몇회인가요?");
return Console.readLine();
}
}
32 changes: 32 additions & 0 deletions src/main/java/racingcar/view/ResultView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package racingcar.view;

import java.util.ArrayList;

public class ResultView {

private ResultView() {
}

// 경주 결과를 출력한다.
public static void printResult() {
System.out.println("실행 결과");
}

// 라운드 결과 출력
public static void printRoundResult(String name, int position) {
System.out.print(name + " : ");
System.out.print("-".repeat(position));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repeat 메서드를 사용하는 방법이 있다는 것을 처음 알았네요! 좋은 방법 같습니다

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니당~

System.out.println();
}

// 최종 우승자를 출력한다.
public static void printWinner(ArrayList<String> winners) {
System.out.print("최종 우승자 : ");
for (int i = 0; i < winners.size(); i++) {
System.out.print(winners.get(i));
if (i != winners.size() - 1) {
System.out.print(", ");
}
}
}
}