-
Notifications
You must be signed in to change notification settings - Fork 451
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[자동차 경주 1단계] 우아한 테크코스 백엔드 6기 카피 pr 요청 드립니다 (#687)
* docs : 기능 구현 목록 작성 * docs : 기능 구현 목록 추가 * feat : 자동차 이름 입력 기능 구현 * feat : 자동차 게임 시도할 회수 입력 기능 구현 * feat : 랜덤 조건에 따라 자동차를 움직이는 기능 구현 * feat : 자동차 게임 실행 결과 출력하는 기능 구현 * 게임 완료 후 우승자 출력 기능 구현 * refactor : 사용자 입력 전, 입력 메세지 출력 기능 추가 * feat: 자동차 게임 실행 기능 구현 * refactor : moveCar 메서드에 작동 조건에 대한 주석 추가 * refactor : InputView 클래스의 getCarName() 메서드 분리 및 에러 메시지 상수 처리 * refactor : InputView 클래스의 getTryCount() 메서드 분리 및 에러 메시지 상수 처리 * refactor : OutputView 클래스의 에러 메시지 상수 처리 * refactor : GameManger 클래스 생성 및 게임 실행 기능 분리 * refactor : package 분리 * refactor : 출력 메세지 추가 및 format 변경 * refactor : 랜덤 숫자 생성 기능 외부 클래스로 분리 * test : moveCar() 조건에 따라 전진 혹은 정지하는지 테스트 * style : 코드 스타일 정리 * refactor : InputView가 OutputView를 의존하지 않도록 수정 * refactor : 랜덤한 수를 생성하는 기능을 Car 내부에서 분리하고 파라미터로 랜덤한 수를 받도록 수정 * refactor : RandomGenerator 클래스 삭제 * refactor : mock을 사용하지 않고 Car가 움직이는지 검증하는 테스트 작성 * refactor : GameManager의 makeNewCar 메서드가 리스트를 반환하도록 변경하여 클래스의 인스턴스 변수 List<car> 제거 * refactor : 매직넘버를 상수로 분리 * refactor : 메서드가 try 내부에서 얼리리턴하도록 수정 * refactor : 파일 끝 개행문자 추가 * test : 자동차 이름 조건을 테스트하는 코드 작성 * refactor : 테스트 코드 매직넘버 상수 분리 --------- Co-authored-by: tsulocalize <tsulocalize@gmail.com>
- Loading branch information
1 parent
398b573
commit 9982161
Showing
7 changed files
with
279 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package racingcar; | ||
|
||
import racingcar.domain.Car; | ||
import racingcar.view.InputView; | ||
import racingcar.view.OutputView; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.ThreadLocalRandom; | ||
|
||
public class GameManager { | ||
|
||
private static final int MAX_RANDOM_NUMBER = 9; | ||
OutputView outputView = new OutputView(); | ||
InputView inputView = new InputView(); | ||
|
||
public void run() { | ||
outputView.printCarNameInputMessage(); | ||
List<String> carNames = inputView.getCarName(); | ||
List<Car> cars = makeNewCars(carNames); | ||
outputView.printTryCountInputMessage(); | ||
int tryCount = inputView.getTryCount(); | ||
for (int i = 0; i < tryCount; i++) { | ||
moveCars(cars); | ||
outputView.printTryResult(cars); | ||
} | ||
outputView.printWinners(cars); | ||
} | ||
|
||
private void moveCars(List<Car> cars) { | ||
for (Car car : cars) { | ||
car.moveCar(ThreadLocalRandom.current().nextInt(MAX_RANDOM_NUMBER + 1)); | ||
} | ||
} | ||
|
||
private List<Car> makeNewCars(List<String> carNames) { | ||
return carNames.stream() | ||
.map(carName -> new Car(carName)) | ||
.toList(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package racingcar; | ||
|
||
public class RacingcarApplication { | ||
public static void main(String[] args) { | ||
GameManager gameManager = new GameManager(); | ||
gameManager.run(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package racingcar.domain; | ||
|
||
public class Car { | ||
|
||
private static final int ZERO = 0; | ||
private static final int MINIMUM_MOVEMENT_CONDITION = 4; | ||
private final static int MAXIMUM_NAME_LENGTH = 5; | ||
private final static String MESSAGE_LENGTH_OF_CAR_NAME = "자동차 이름은 1자 이상 5자 이하여야 합니다."; | ||
private String name; | ||
private int distance; | ||
|
||
public Car(String name) { | ||
if(name.length() > MAXIMUM_NAME_LENGTH) { | ||
throw new IllegalArgumentException(MESSAGE_LENGTH_OF_CAR_NAME); | ||
} | ||
this.name = name; | ||
this.distance = 0; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public int getDistance() { | ||
return distance; | ||
} | ||
|
||
public void moveCar(int number) { | ||
if (distance < ZERO) { | ||
throw new IllegalArgumentException("이동 거리는 음수가 될 수 없습니다."); | ||
} | ||
if (number >= MINIMUM_MOVEMENT_CONDITION) { | ||
distance++; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package racingcar.view; | ||
|
||
import java.util.List; | ||
import java.util.Scanner; | ||
|
||
public class InputView { | ||
|
||
private final static String MESSAGE_NO_DUPLICATE_CAR_NAMES = "중복된 자동차 이름은 사용할 수 없습니다."; | ||
private final static String MESSAGE_LENGTH_OF_CAR_NAME = "자동차 이름은 1자 이상 5자 이하여야 합니다."; | ||
private final static String MESSAGE_NO_SPACE = "중복된 자동차 이름은 사용할 수 없습니다."; | ||
private final static String MESSAGE_ONLY_NUMBER = "시도할 회수는 숫자여야만 가능합니다."; | ||
private final static String MESSAGE_ONLY_NATURAL_NUMBER = "시도할 회수는 자연수를 입력해 주세요."; | ||
private final static int MAXIMUM_NAME_LENGTH = 5; | ||
private final Scanner scanner = new Scanner(System.in); | ||
|
||
|
||
public List<String> getCarName() { | ||
String input = scanner.nextLine(); | ||
List<String> splitCarNames; | ||
try { | ||
validateNoSpace(input); | ||
splitCarNames = getSplitCarNames(input); | ||
validateLengthOfCarNames(splitCarNames); | ||
validateNoDuplicatedCarNames(splitCarNames); | ||
} catch (IllegalArgumentException e) { | ||
System.out.println(e.getMessage()); | ||
return getCarName(); | ||
} | ||
return splitCarNames; | ||
} | ||
|
||
public int getTryCount() { | ||
String input = scanner.nextLine(); | ||
int tryCount; | ||
try { | ||
tryCount = Integer.parseInt(input); | ||
validateNaturalNumber(tryCount); | ||
return tryCount; | ||
} catch (NumberFormatException e) { | ||
System.out.println(MESSAGE_ONLY_NUMBER); | ||
return getTryCount(); | ||
} catch (IllegalArgumentException e) { | ||
System.out.println(e.getMessage()); | ||
return getTryCount(); | ||
} | ||
} | ||
|
||
private void validateNaturalNumber(int tryCount) { | ||
if (tryCount <= 0) { | ||
throw new IllegalArgumentException(MESSAGE_ONLY_NATURAL_NUMBER); | ||
} | ||
} | ||
|
||
private void validateNoDuplicatedCarNames(List<String> splitCarNames) { | ||
long distinctCarCount = splitCarNames.stream() | ||
.distinct() | ||
.count(); | ||
if (distinctCarCount != splitCarNames.size()) { | ||
throw new IllegalArgumentException(MESSAGE_NO_DUPLICATE_CAR_NAMES); | ||
} | ||
} | ||
|
||
private void validateLengthOfCarNames(List<String> splitCarNames) { | ||
for (String carName : splitCarNames) { | ||
validateLengthOfCarName(carName); | ||
} | ||
} | ||
|
||
private void validateLengthOfCarName(String carName) { | ||
if (carName.isEmpty() || carName.length() > MAXIMUM_NAME_LENGTH) { | ||
throw new IllegalArgumentException(MESSAGE_LENGTH_OF_CAR_NAME); | ||
} | ||
} | ||
|
||
private List<String> getSplitCarNames(String input) { | ||
return List.of(input.split(",")); | ||
} | ||
|
||
private void validateNoSpace(String input) { | ||
if (input.contains(" ")) { | ||
throw new IllegalArgumentException(MESSAGE_NO_SPACE); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package racingcar.view; | ||
|
||
import racingcar.domain.Car; | ||
|
||
import java.util.List; | ||
|
||
public class OutputView { | ||
|
||
private static final String MESSAGE_NOT_EXIST_CAR = "생성된 자동차가 없습니다."; | ||
|
||
public void printTryResult(List<Car> cars) { | ||
System.out.println(); | ||
System.out.println("실행 결과"); | ||
for (Car car : cars) { | ||
System.out.println(car.getName() + " : " + "-".repeat(car.getDistance())); | ||
} | ||
} | ||
|
||
public void printWinners(List<Car> cars) { | ||
int longestDistance = cars.stream() | ||
.mapToInt(Car::getDistance) | ||
.max() | ||
.orElseThrow(() -> new IllegalArgumentException(MESSAGE_NOT_EXIST_CAR)); | ||
|
||
String winnerNames = String.join(", ", | ||
cars.stream() | ||
.filter(car -> car.getDistance() == longestDistance) | ||
.map(Car::getName) | ||
.toList() | ||
); | ||
|
||
System.out.println(winnerNames + "가 최종 우승했습니다."); | ||
} | ||
|
||
public void printCarNameInputMessage() { | ||
System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); | ||
} | ||
|
||
public void printTryCountInputMessage() { | ||
System.out.println("시도할 회수는 몇회인가요?"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package racingcar.domain; | ||
|
||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.Assertions.*; | ||
|
||
class CarTest { | ||
|
||
private static final int MOVE_CONDITION = 5; | ||
private static final int STOP_CONDITION = 3; | ||
|
||
|
||
@Test | ||
@DisplayName("랜덤_숫자가_4_이상인_경우_전진") | ||
void moveCarTest() { | ||
Car car = new Car("capy"); | ||
int initDistance = car.getDistance(); | ||
car.moveCar(MOVE_CONDITION); | ||
int movedDistance = car.getDistance(); | ||
|
||
assertThat(movedDistance).isEqualTo(initDistance + 1); | ||
} | ||
|
||
@Test | ||
@DisplayName("랜덤_숫자가_3_이하인_경우_정지") | ||
void stopCarTest() { | ||
Car car = new Car("capy"); | ||
int initDistance = car.getDistance(); | ||
car.moveCar(STOP_CONDITION); | ||
int movedDistance = car.getDistance(); | ||
|
||
assertThat(movedDistance).isEqualTo(initDistance); | ||
} | ||
|
||
@Test | ||
@DisplayName("자동차_이름이_5자_이하인_경우_통과") | ||
void validCarName() { | ||
assertThatCode(() -> new Car("capy")) | ||
.doesNotThrowAnyException(); | ||
} | ||
|
||
@Test | ||
@DisplayName("자동차_이름이_5자_초과인_경우_에러_발생") | ||
void invalidCarName() { | ||
assertThatThrownBy(() -> new Car("capyeeee")) | ||
.isInstanceOf(IllegalArgumentException.class); | ||
} | ||
} |