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
69 changes: 48 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
- 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. •자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다.
- 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
- 전진하는 조건은 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이
하의 값이면 멈춘다.
하의 값이면 멈춘다.
- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다.

<br>
Expand All @@ -19,39 +19,39 @@

## 🎱 프로그래밍 요구사항 - 1주차와 동일
- 자바 코드 컨벤션을 지키면서 프로그래밍한다.
- 기본적으로 [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) 문서와 [네이버 핵데이 Java 컨벤션](https://naver.github.io/hackday-conventions-java/)을 원칙으로 한다.
- 단, 들여쓰기는 '2 spaces'가 아닌 '4 spaces'로 한다.
- 기본적으로 [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) 문서와 [네이버 핵데이 Java 컨벤션](https://naver.github.io/hackday-conventions-java/)을 원칙으로 한다.
- 단, 들여쓰기는 '2 spaces'가 아닌 '4 spaces'로 한다.
- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
- 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.
- 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.
- 3항 연산자를 쓰지 않는다.
- 함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라.
- System.exit 메소드를 사용하지 않는다.
- 비정상적 입력에 대해서는 IllegalArgumentException을 발생시킨다.

### 프로그래밍 요구사항 - 2주차 추가
- 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다.
- 함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다.
- 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다.
- 함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다.
- else 예약어를 쓰지 않는다.
- 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
- else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
- 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
- else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.

### 프로그래밍 요구사항 - 객체
- 다음 Car 객체를 활용해 구현해야 한다.
- Car 기본 생성자를 추가할 수 없다.
- name, position 변수의 접근 제어자인 private을 변경할 수 없다.
- 다음 Car 객체를 활용해 구현해야 한다.
- Car 기본 생성자를 추가할 수 없다.
- name, position 변수의 접근 제어자인 private을 변경할 수 없다.
- 가능하면 setPosition(int position) 메소드를 추가하지 않고 구현한다.

```java
public class Car {
private final String name;
private int position = 0;
public Car(String name) {
this.name = name;
}
// 추가 기능 구현
private final String name;
private int position = 0;

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

// 추가 기능 구현
}
```

Expand All @@ -61,10 +61,37 @@ public class Car {
- 미션은 현재 저장소를 fork & clone해서 시작한다.
- 기능을 구현하기 전에 java-baseball-precourse/README.md 파일에 구현할 기능 목록을 정리해 추가한다.
- git의 commit 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가한다.
- [AngularJS Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 참고해 commit log를 남긴다.
- [AngularJS Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 참고해 commit log를 남긴다.

<br>

## 📝 License

This project is [MIT](https://github.com/woowacourse/java-baseball-precourse/blob/master/LICENSE) licensed.

<br>

### 기능 순서
- 입력
- 자동차 이름
- 몇 번 이동할 것인지 시도할 횟수
- 시도 횟수만큼 반복
- random 값 구하고 전진/멈춤
- 출력: 한 판에 대한 실행 결과
- 출력: 우승자(1명 이상)

### 기능 목록
- [x] 입력 - 자동차 이름, 횟수
- [x] 자동차 이름 글자수 예외
- [x] 자동차: 이름, 위치
- [x] 경주 게임
- [x] 각 자동차의 0-9 사이 랜덤값 구하기
- [x] 자동차들 위치 이동 - 전진 or 멈춤
- [x] 실행 - 결과 출력
- [x] 최종 우승자 구하기 및 출력

### 예외

- 자동차 이름
- 5글자 이하만 가능
- 공백일 경우
14 changes: 14 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import domain.CarFactory;
import domain.RacingCarGame;
import ui.Receiver;

public class Application {
public static void main(String[] args) {
Receiver receiver = new Receiver();
CarFactory carFactory = new CarFactory(receiver.getCarNames());
RacingCarGame racingCarGame = new RacingCarGame(carFactory.getCars(), receiver.getRound());

racingCarGame.proceedRounds();
racingCarGame.printWinners();
}
}
32 changes: 30 additions & 2 deletions src/main/java/domain/Car.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
package domain;

public class Car {
import domain.exception.NotBlankException;

public class Car implements Comparable<Car> {
private final String name;
private int position = 0;

public Car(String name) {
this.name = name;
validateName();
Comment on lines 10 to +11
Copy link
Contributor

Choose a reason for hiding this comment

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

큰 차이는 없지만, 검증 후 값을 넣어주는 것이 더 적절한 흐름 아닐까요?

}

public void moveForward() {
position += 1;
}

private void validateName() {
if (name.length() > 5) {
throw new IllegalArgumentException(name + ": 자동차 이름은 5글자 이하여야 합니다.");
}

if (name.isBlank()) {
throw new NotBlankException("공백으로만 이루어진 이름을 생성할 수 없습니다.");
Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분에 대해서만 커스텀 익셉션을 정의한 이유가 있을까요?
일관된 예외처리가 아니라면 무슨 차이인지 혼동을 줄 수 있을 것 같아요.

}
Comment on lines +18 to +25
Copy link
Member

Choose a reason for hiding this comment

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

입력에 대한 예외를 더욱 세분화하면 사용자 입장에서 더 편리할것 같아요✔

  • 입력이 없을 경우
  • 쉼표가 연속으로 있을 경우
  • 영어 이외의 문자가 입력될 경우
  • 쉼표로 시작할 경우
  • 쉼표로 끝날 경우
  • 이름의 길이가 6자 이상일 경우
  • 같은 이름이 입력될 경우

저는 이렇게 이름 입력에 대한 예외를 7가지로 정했습니다!

Comment on lines +18 to +25
Copy link
Member

Choose a reason for hiding this comment

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

이름 입력에 대한 예외를 throw만 해주고 받아주는 곳이 없네요
그러다 보니까 에러 메세지만 띄우고 프로그램이 끝나버려 프로그램이 불친절한 것 같아요.

valiateName 메서드를 Car 객체를 생성할 때 호출하는 것 보다 Receive 클래스에서 실행시켜주면 예외 처리하고 반복적으로 입력을 받기 편할 것 같아요!

}

// 추가 기능 구현
public String getName() {
return name;
}

public int getPosition() {
return position;
}

@Override
public int compareTo(Car o) {
return o.position - position;
}
Comment on lines +37 to +39
Copy link
Member

Choose a reason for hiding this comment

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

사용되지 않는 메서드같아요!

이런 부분을 줄이려면 README에서 필요한 클래스와 메서드를 정리해가며 진행하는 것이 좋은것 같아요😃

}
40 changes: 40 additions & 0 deletions src/main/java/domain/CarFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package domain;

import java.util.ArrayList;
import java.util.List;

public class CarFactory {
private final String DELIMITER = ",";

private final List<Car> cars;
private final String[] carNames;
Copy link
Contributor

Choose a reason for hiding this comment

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

배열 보다는 컬렉션을 사용하는 것은 어떨까요?
그리고 이 경우엔 굳이 인스턴스 변수로 관리할 필요가 없을 것 같네요!


public CarFactory(String input) {
this.carNames = splitCarNames(input);
trimCarNames();
cars = createCars();
}

private String[] splitCarNames(String answer) {
return answer.split(DELIMITER);
}

private void trimCarNames() {
for (int i = 0; i < carNames.length; i++) {
carNames[i] = carNames[i].trim();
}
}

private List<Car> createCars() {
List<Car> cars = new ArrayList<>();
for (String carName : carNames) {
cars.add(new Car(carName));
}

return cars;
}

public List<Car> getCars() {
return cars;
}
}
70 changes: 70 additions & 0 deletions src/main/java/domain/RacingCarGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package domain;

import java.util.Collections;
import java.util.List;
import java.util.stream.IntStream;

import utils.RandomUtils;

public class RacingCarGame {
Copy link
Contributor

Choose a reason for hiding this comment

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

RacingCarGame에선 어떤일을 할까요?

  • 랜덤 숫자를 만들고(makeRandomValue)
  • 자동차를 전진시키고(movePosition)
  • 게임을 진행시키고(proceed)
  • 상태를 출력하고(print)
    다양한 기능을 하고있네요! 하지만 일관된 기능들은 아닌 것 같아요.
    SRP(Single Responsibility Principle)을 지키도록 변경해보면 어떨까요?

private static final String RESULT_START_MESSAGE = "\n실행 결과";
private static final String RESULT_END_MESSAGE = "가 최종 우승했습니다.";
private static final String COLON = " : ";
private static final String DASH = "-";

private final List<Car> cars;
private final int round;

public RacingCarGame(List<Car> cars, int round) {
this.cars = cars;
this.round = round;
}

private void movePosition(int idx) {
int randomValue = RandomUtils.generateNumber();

if (randomValue >= 4) {
cars.get(idx).moveForward();
}
}

private void proceedOneRound() {
IntStream.range(0, cars.size()).forEach(this::movePosition);
}

public void proceedRounds() {
System.out.println(RESULT_START_MESSAGE);

IntStream.range(0, round).forEach(r -> {
proceedOneRound();
printCurrentPositions();
});
}

private void printCurrentPositions() {
for (Car car : cars) {
System.out.print(car.getName() + COLON);

IntStream.range(0, car.getPosition()).mapToObj(j -> DASH).forEach(System.out::print);
System.out.println();
}

System.out.println();
}

public void printWinners() {
Collections.sort(cars);

int max = cars.get(0).getPosition();
System.out.print(cars.get(0).getName());

for (int i = 1; i < cars.size(); i++) {
if (cars.get(i).getPosition() < max) {
Copy link
Contributor

Choose a reason for hiding this comment

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

객체의 값을 꺼내는 것이 아닌 메시지를 던지는 방식으로 변경해보면 어떨까요?

break;
}
System.out.print(", " + cars.get(i).getName());
}

System.out.println(RESULT_END_MESSAGE);
}
}
7 changes: 7 additions & 0 deletions src/main/java/domain/exception/NotBlankException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package domain.exception;

public class NotBlankException extends IllegalArgumentException {
public NotBlankException(String s) {
super(s);
}
}
39 changes: 39 additions & 0 deletions src/main/java/ui/Receiver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ui;

import java.util.Scanner;

public class Receiver {
private static final String REQUEST_CAR_NAME = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)";
private static final String REQUEST_ROUND = "시도할 횟수는 몇회인가요?";

private static final Scanner scanner = new Scanner(System.in);
Copy link
Contributor

Choose a reason for hiding this comment

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

상수 컨벤션을 지켜주세요!


private String carNames;
private int round;


public Receiver() {
receiveCarNames();
receiveRound();
}
Comment on lines +15 to +18
Copy link
Member

Choose a reason for hiding this comment

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

이름을 입력받고 라운드를 입력받기 전에 이름 입력에 대한 예외 처리를 먼저 해주면 더 좋을 것 같아요.

이름 입력에 오류가 있으면 라운드 입력을 받지 않고 진행할 수 있어서 더 효율적인 프로그램이 될 것 같아요!


public void receiveCarNames() {
System.out.println(REQUEST_CAR_NAME);
carNames = scanner.nextLine();
// return carNames;
}

public void receiveRound() {
System.out.println(REQUEST_ROUND);
round = scanner.nextInt();
// return round;
}

public String getCarNames() {
return carNames;
}

public int getRound() {
return round;
}
}
15 changes: 15 additions & 0 deletions src/main/java/utils/RandomUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package utils;

import java.util.Random;

public class RandomUtils {
private static final int UPPER_BOUND = 10;
private static final Random RANDOM = new Random();
Copy link
Contributor

Choose a reason for hiding this comment

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

static 관리 👍🏻


private RandomUtils() {
}
Comment on lines +9 to +10
Copy link
Contributor

Choose a reason for hiding this comment

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

유틸 클래스의 private 생성자 활용 👍🏻


public static int generateNumber(){
return RANDOM.nextInt(UPPER_BOUND);
}
}
23 changes: 23 additions & 0 deletions src/test/java/domain/CarFactoryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package domain;

import java.util.List;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

public class CarFactoryTest {

private CarFactory carFactory;
private String input = " lee, chan, gyu ";

@Test
public void 차를_생성한다() throws Exception {
carFactory = new CarFactory(input);

List<Car> cars = carFactory.getCars();

Assertions.assertThat(cars.get(0).getName()).isEqualTo("lee");
Assertions.assertThat(cars.get(1).getName()).isEqualTo("chan");
Assertions.assertThat(cars.get(2).getName()).isEqualTo("gyu");
}
}
Loading