Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8a0ef1c
docs: README.md 작성
tmdcheol Oct 22, 2024
06eede0
feat: 자동차 이름 입력 안내문구 출력 기능 추가
tmdcheol Oct 22, 2024
5ac21cc
refactor(outputview): println 메서드의 파라미터에 final 키워드 추가
tmdcheol Oct 22, 2024
fa4da88
feat: 자동차 이름 입력 기능 추가
tmdcheol Oct 22, 2024
ebe0c68
feat: 자동차 생성 기능 추가
tmdcheol Oct 24, 2024
b0d789e
feat: 자동차 이름 길이 검증 기능 추가
tmdcheol Oct 24, 2024
c6832b6
feat: 시도 횟수 입력 안내문구 출력 기능 추가
tmdcheol Oct 24, 2024
978bd40
feat: 이동 횟수 입력 기능 추가
tmdcheol Oct 24, 2024
6c3e681
feat: 랜덤 숫자 생성 기능 추가
tmdcheol Oct 24, 2024
2716991
feat: 무작위 값에 따라 자동차 전진 로직 추가
tmdcheol Oct 24, 2024
d2ebbf5
feat: 모든 자동차를 한 번 이동시도 수행
tmdcheol Oct 24, 2024
f2dec67
docs: README.md 수정
tmdcheol Oct 24, 2024
ed9ee04
feat: 모든 차 상태 출력 기능 추가
tmdcheol Oct 24, 2024
bd7194a
feat: 입력한 횟수만큼 이동시도 반복 수행 기능 추가
tmdcheol Oct 24, 2024
cf44795
feat: 실행 결과 출력 기능 추가
tmdcheol Oct 24, 2024
f9b7052
feat: 최종 우승자 판별 기능 추가
tmdcheol Oct 24, 2024
103a65f
feat: 최종 우승자 출력 기능 추가
tmdcheol Oct 28, 2024
158d119
feat: 시도 횟수 검증 로직 추가
tmdcheol Oct 28, 2024
886c058
test: 문자열 학습 테스트 추가
tmdcheol Oct 28, 2024
e7f7466
feat: 자동차 이름 입력이 존재하지 않을 때 검증 및 기존 split 함수 일부 기능 수정
tmdcheol Oct 28, 2024
0e00658
feat: CarName 유효성 검사 기능 상세화
tmdcheol Oct 28, 2024
d114a43
refactor: CarArgumentResolver와 AttemptCountArgumentResolver에 공통 인터페이스…
tmdcheol Oct 28, 2024
b90dab6
refactor: RangeValidator와 SizeValidator에 Validator 인터페이스 적용
tmdcheol Oct 28, 2024
c9c96a2
refactor: CarConverter를 유틸성 클래스로 변경
tmdcheol Oct 28, 2024
51abe18
refactor: Car 내에 있는 이동 규정을 분리
tmdcheol Oct 28, 2024
ed350f5
refactor: AllCarMover 생성자 주입 코드 추가
tmdcheol Oct 28, 2024
3e55fa0
refactor: 우승자 결정 로직을 WinningPolicy 인터페이스로 분리
tmdcheol Oct 28, 2024
becfdc1
test: AllCarMover 테스트에 Mock MovePolicy 적용
tmdcheol Oct 28, 2024
717f2e9
refactor: 생성자 주입 방식 도입
tmdcheol Oct 28, 2024
724bb22
refactor: 클래스 패키지 구조 개선 및 재배치
tmdcheol Oct 28, 2024
d17afcd
refactor: Controller 클래스 run 메서드를 기능별 private 메서드로 분리
tmdcheol Oct 28, 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
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
# java-racingcar-precourse
# java-racingcar-precourse

## 기능 목록
- [X] 자동차 이름 입력 안내문구를 출력한다
- [X] 경주할 자동차 이름을 입력 받는다
- [X] 경주할 자동차를 생성한다
- [X] 경주할 각 자동차 이름 길이를 검증한다 (5자 이하)
- [X] 시도 횟수 입력 안내문구를 출력한다
- [X] 몇 번을 이동할 지 입력 받는다
- [X] 무작위 값을 생성한다
- [X] 무작위 값에 따라 하나의 자동차를 전진 혹은 정지시킨다
- [X] 한 번의 이동시도를 수행한다. 입력받은 모든 자동차를 이동시도한다
- [X] 모든 차의 상태를 출력한다
- [X] 입력한 횟수 만큼의 이동시도 수행을 반복한다
- [X] 이동시도 수행을 마치고 실행 결과를 출력한다
- [X] 최종 우승자(들)을 판별한다
- [X] 최종 우승자(들)을 출력한다

---

## 추가 예외 케이스, 개발 과정에서 수정 예정
- [X] 시도 횟수를 검증한다 (숫자로 변환 가능한지, overflow 검증, 음수가 아닌지)
- [X] 경주할 자동차 이름 입력을 검증한다
- [X] 자동차 이름 입력이 아예 없을 때를 검증한다
- [X] 자동차의 각 이름이 비어있을 때를 검증한다
- [X] 구분자 위치에 따른 다양한 예외 상황을 검증한다
7 changes: 6 additions & 1 deletion src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package racingcar;

import racingcar.config.ControllerConfig;

public class Application {

public static void main(String[] args) {
// TODO: 프로그램 구현
ControllerConfig config = new ControllerConfig();
config.controller().run();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package racingcar.argumentresolver;

public interface ArgumentResolver<T> {

T parse(String parameter);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package racingcar.argumentresolver;

public class AttemptCountArgumentResolver implements ArgumentResolver<Integer> {

@Override
public Integer parse(String parameter) {
try {
return Integer.parseInt(parameter);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("숫자로 변환가능한 입력이어야 합니다.");
}
}

}
28 changes: 28 additions & 0 deletions src/main/java/racingcar/argumentresolver/CarArgumentResolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package racingcar.argumentresolver;

import java.util.Arrays;
import java.util.List;

public class CarArgumentResolver implements ArgumentResolver<List<String>> {

private static final int NEGATIVE = -1;

@Override
public List<String> parse(String parameter) {
checkBlank(parameter);
return splitWithBlankAndTrim(parameter);
}

private List<String> splitWithBlankAndTrim(String parameter) {
return Arrays.stream(parameter.split(",", NEGATIVE))
.map(String::trim)
.toList();
}

private void checkBlank(String parameter) {
if (parameter == null || parameter.isBlank()) {
throw new IllegalArgumentException("비어있는 입력은 불가능합니다.");
}
}

}
85 changes: 85 additions & 0 deletions src/main/java/racingcar/config/ControllerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package racingcar.config;

import java.util.List;
import racingcar.domain.mover.AllCarMover;
import racingcar.domain.mover.CarMover;
import racingcar.controller.Controller;
import racingcar.view.InputView;
import racingcar.domain.winnerdecider.policy.MaxMoveWinningPolicy;
import racingcar.domain.mover.policy.MovePolicy;
import racingcar.view.OutputView;
import racingcar.domain.mover.policy.RandomMovePolicy;
import racingcar.domain.mover.policy.trigger.RandomNumberGenerator;
import racingcar.domain.winnerdecider.WinnersDecider;
import racingcar.domain.winnerdecider.policy.WinningPolicy;
import racingcar.argumentresolver.ArgumentResolver;
import racingcar.argumentresolver.AttemptCountArgumentResolver;
import racingcar.argumentresolver.CarArgumentResolver;
import racingcar.validator.RangeValidator;
import racingcar.validator.SizeValidator;
import racingcar.validator.Validator;

public class ControllerConfig {

public Controller controller() {
return new Controller(
outputView(),
inputView(),
carArgumentResolver(),
attemptCountArgumentResolver(),
sizeValidator(),
rangeValidator(),
allCarMover(),
winnersDecider()
);
}

public OutputView outputView() {
return new OutputView();
}

public InputView inputView() {
return new InputView();
}

public ArgumentResolver<List<String>> carArgumentResolver() {
return new CarArgumentResolver();
}

public ArgumentResolver<Integer> attemptCountArgumentResolver() {
return new AttemptCountArgumentResolver();
}

public Validator<List<String>> sizeValidator() {
return new SizeValidator();
}

public Validator<Integer> rangeValidator() {
return new RangeValidator();
}

public AllCarMover allCarMover() {
return new AllCarMover(carMover());
}

public CarMover carMover() {
return new CarMover(movePolicy());
}

public MovePolicy movePolicy() {
return new RandomMovePolicy(randomNumberGenerator());
}

public RandomNumberGenerator randomNumberGenerator() {
return new RandomNumberGenerator();
}

public WinnersDecider winnersDecider() {
return new WinnersDecider(winningPolicy());
}

public WinningPolicy winningPolicy() {
return new MaxMoveWinningPolicy();
}

}
89 changes: 89 additions & 0 deletions src/main/java/racingcar/controller/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package racingcar.controller;

import java.util.List;
import racingcar.argumentresolver.ArgumentResolver;
import racingcar.domain.Car;
import racingcar.domain.mover.AllCarMover;
import racingcar.util.CarConverter;
import racingcar.domain.winnerdecider.WinnersDecider;
import racingcar.validator.Validator;
import racingcar.view.InputView;
import racingcar.view.OutputView;

public class Controller {

private final OutputView outputView;
private final InputView inputView;
private final ArgumentResolver<List<String>> carArgumentResolver;
private final ArgumentResolver<Integer> attemptCountArgumentResolver;
private final Validator<List<String>> sizeValidator;
private final Validator<Integer> rangeValidator;
private final AllCarMover allCarMover;
private final WinnersDecider winnersDecider;

public Controller(
OutputView outputView,
InputView inputView,
ArgumentResolver<List<String>> carArgumentResolver,
ArgumentResolver<Integer> attemptCountArgumentResolver,
Validator<List<String>> sizeValidator,
Validator<Integer> rangeValidator,
AllCarMover allCarMover,
WinnersDecider winnersDecider
) {
this.outputView = outputView;
this.inputView = inputView;
this.carArgumentResolver = carArgumentResolver;
this.attemptCountArgumentResolver = attemptCountArgumentResolver;
this.sizeValidator = sizeValidator;
this.rangeValidator = rangeValidator;
this.allCarMover = allCarMover;
this.winnersDecider = winnersDecider;
}

public void run() {
List<Car> cars = getCarsFromInput();
int attemptCount = getAttemptCountFromInput();
runRace(cars, attemptCount);
printWinners(cars);
}

private List<Car> getCarsFromInput() {
outputView.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");
String racingCarNamesRequest = inputView.read();

List<String> carNames = carArgumentResolver.parse(racingCarNamesRequest);
sizeValidator.check(carNames);

return CarConverter.toCars(carNames);
}

private int getAttemptCountFromInput() {
outputView.println("시도할 횟수는 몇 회인가요?");
String attemptCountRequest = inputView.read();

int attemptCount = attemptCountArgumentResolver.parse(attemptCountRequest);
rangeValidator.check(attemptCount);

return attemptCount;
}

private void runRace(List<Car> cars, int attemptCount) {
outputView.endLine();
outputView.println("실행 결과");

for (int count = 0; count < attemptCount; count++) {
allCarMover.run(cars);
outputView.printCarsStatus(cars);
outputView.endLine();
}
}

private void printWinners(List<Car> cars) {
List<Car> winners = winnersDecider.run(cars);
List<String> winnerNames = CarConverter.toNames(winners);

outputView.print("최종 우승자 : ");
outputView.printNames(winnerNames);
}
}
25 changes: 25 additions & 0 deletions src/main/java/racingcar/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package racingcar.domain;

public class Car {

private final String name;
private int moveCount;


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

public void move() {
moveCount++;
}

public String getName() {
return name;
}

public int getMoveCount() {
return moveCount;
}

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

import java.util.List;
import racingcar.domain.Car;

public class AllCarMover {

private final CarMover carMover;

public AllCarMover(CarMover carMover) {
this.carMover = carMover;
}

public void run(List<Car> cars) {
cars.forEach(carMover::run);
}

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

import racingcar.domain.mover.policy.MovePolicy;
import racingcar.domain.Car;

public class CarMover {

private final MovePolicy movePolicy;

public CarMover(MovePolicy movePolicy) {
this.movePolicy = movePolicy;
}

public void run(final Car car) {
if (movePolicy.canMove()) {
car.move();
}
}

}
7 changes: 7 additions & 0 deletions src/main/java/racingcar/domain/mover/policy/MovePolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package racingcar.domain.mover.policy;

public interface MovePolicy {

boolean canMove();

}
20 changes: 20 additions & 0 deletions src/main/java/racingcar/domain/mover/policy/RandomMovePolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package racingcar.domain.mover.policy;

import racingcar.domain.mover.policy.trigger.RandomNumberGenerator;

public class RandomMovePolicy implements MovePolicy {

private static final int MOVE_THRESHOLD = 4;
private final RandomNumberGenerator randomNumberGenerator;

public RandomMovePolicy(RandomNumberGenerator randomNumberGenerator) {
this.randomNumberGenerator = randomNumberGenerator;
}

@Override
public boolean canMove() {
int randomValue = randomNumberGenerator.run();
return randomValue >= MOVE_THRESHOLD;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package racingcar.domain.mover.policy.trigger;

import camp.nextstep.edu.missionutils.Randoms;

public class RandomNumberGenerator {

public int run() {
return Randoms.pickNumberInRange(0, 9);
}

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

import java.util.List;
import racingcar.domain.Car;
import racingcar.domain.winnerdecider.policy.WinningPolicy;

public class WinnersDecider {

private final WinningPolicy winningPolicy;

public WinnersDecider(WinningPolicy winningPolicy) {
this.winningPolicy = winningPolicy;
}

public List<Car> run(final List<Car> cars) {
return winningPolicy.determineWinners(cars);
}

}
Loading