Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
22fe2b2
docs: add feature list to README
Huiyeongkim Oct 24, 2025
0434fe1
test: add Name value object tests
Huiyeongkim Oct 24, 2025
2a2aa25
feat: add Name value object for car naming
Huiyeongkim Oct 24, 2025
aa22576
docs: check off completed Name VO tasks
Huiyeongkim Oct 24, 2025
283b465
test: add Position value object tests
Huiyeongkim Oct 25, 2025
3e6a24f
feat: add Position value object for car naming
Huiyeongkim Oct 25, 2025
154ce96
docs: check off completed Position VO tasks
Huiyeongkim Oct 25, 2025
d659a11
test: add Car value object tests
Huiyeongkim Oct 25, 2025
07dbde4
feat: add Car Entity
Huiyeongkim Oct 25, 2025
ab4df65
feat: add Car domain with move strategy pattern
Huiyeongkim Oct 25, 2025
681cbf0
test: add missing test cases for Position
Huiyeongkim Oct 25, 2025
c7aa5ff
feat: add position display function
Huiyeongkim Oct 25, 2025
92cf438
test: add missing test cases for Car
Huiyeongkim Oct 25, 2025
0ac885e
feat: add Car display function
Huiyeongkim Oct 25, 2025
fff61b1
test: add CarsTest with winner finding logic
Huiyeongkim Oct 25, 2025
ea4fb64
feat: add Cars collection for managing multiple cars
Huiyeongkim Oct 25, 2025
423b4b0
feat: add InputView for car names and round count
Huiyeongkim Oct 25, 2025
a2165ca
feat: add OutputView for car winners
Huiyeongkim Oct 25, 2025
de2ee3c
feat: add RacingGame controller
Huiyeongkim Oct 25, 2025
dbfcd25
feat: add racing game run method
Huiyeongkim Oct 25, 2025
2800aab
docs: check off completed tasks
Huiyeongkim Oct 25, 2025
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
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,39 @@
# java-racingcar-precourse

## 기능 목록

### 1. 자동차 이름 입력 및 검증
- [X] 자동차 이름은 쉼표(,) 기준으로 구분
- [X] 이름은 최대 5자
- [X] 잘못된 입력 시 `IllegalArgumentException` 발생

### 2. 자동차 이동 로직
- [X] 0~9 사이 랜덤 값 >= 4일 때 전진
- [X] 4 이하인 경우 정지

### 3. 위치(Position) VO
- [X] 초기 위치 = 0
- [X] 이동 시 불변 객체 반환
- [X] 위치 출력 시 `-` 문자를 사용하여 표현

### 4. Car 클래스
- [X] 자동차 이름(Name VO)과 위치(Position VO) 관리
- [X] move() 메서드에서 MoveStrategy를 통해 전진 여부 결정

### 5. Cars 컬렉션
- [X] 여러 대의 Car를 관리
- [X] 각 라운드마다 모든 자동차 이동 수행
- [X] 우승자 계산 기능

### 6. 게임 진행
- [X] 시도할 횟수만큼 라운드 반복
- [X] 각 라운드 결과 출력
- [X] 최종 우승자 출력

### 7. 입력/출력
- [X] 사용자 입력 처리
- 자동차 이름
- 시도 횟수
- [X] 실행 결과 출력
- 각 자동차의 위치
- 우승자가 여러 명일 경우 ','로 구분하여 공동 우승 표시
5 changes: 4 additions & 1 deletion src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package racingcar;

import racingcar.controller.RacingGame;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
RacingGame racingGame = new RacingGame();
racingGame.run();
}
}
40 changes: 40 additions & 0 deletions src/main/java/racingcar/controller/RacingGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package racingcar.controller;

import racingcar.domain.Cars;
import racingcar.view.InputView;
import racingcar.view.OutputView;

import java.util.List;

public class RacingGame {

private final InputView inputView;
private final OutputView outputView;

public RacingGame() {
this.inputView = new InputView();
this.outputView = new OutputView();
}

public void run() {
List<String> carNames = inputView.inputCarNames();
int roundCount = inputView.inputRoundCount();

Cars cars = new Cars(carNames);

playRounds(cars, roundCount);
showWinners(cars);
}

private void playRounds(Cars cars, int roundCount) {
for (int i = 0; i < roundCount; i++) {
cars.moveAll();
outputView.printRoundResults(cars.getCars());
}
}

private void showWinners(Cars cars) {
List<String> winners = cars.getWinners();
outputView.printWinners(winners);
}
}
33 changes: 33 additions & 0 deletions src/main/java/racingcar/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package racingcar.domain;

import racingcar.strategy.MoveStrategy;

public class Car {

private final Name name;
private Position position;

public Car(String nameValue) {
name = new Name(nameValue);
position = new Position();
}

public void move(MoveStrategy strategy) {
if (strategy.isMovable()) {
position = position.move();
}
}

public int getPosition() {
return position.getValue();
}

public String getName() {
return name.getValue();
}

public String displayCar() {
return name.getValue() + " : " + position.displayPosition();
}

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

import racingcar.strategy.RandomNumberMoveStrategy;

import java.util.List;

public class Cars {

private final List<Car> cars;

public Cars(List<String> names) {
this.cars = names.stream()
.map(Car::new)
.toList();
}

public int getSize() {
return cars.size();
}

public List<Car> getCars() {
return cars;
}

public void moveAll() {
for (Car car : cars) {
car.move(new RandomNumberMoveStrategy());
}
}

public List<String> getWinners() {
int maxPosition = findMaxPosition();
return cars.stream()
.filter(car -> car.getPosition() == maxPosition)
.map(Car::getName)
.toList();
}

private int findMaxPosition() {
return cars.stream()
.mapToInt(Car::getPosition)
.max()
.orElse(0);
}
}
33 changes: 33 additions & 0 deletions src/main/java/racingcar/domain/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package racingcar.domain;

public class Name {

private static final int MAX_NAME_LENGTH = 5;
private static final String EMPTY_NAME_MESSAGE = "자동차 이름은 빈 값일 수 없습니다.";
private static final String LENGTH_EXCEED_MESSAGE = "자동차 이름은 5자 이하만 가능합니다.";

private final String value;

public Name(String value) {
validate(value);
this.value = value.trim();
}

private void validate(String value) {
if (isNullOrEmpty(value)) {
throw new IllegalArgumentException(EMPTY_NAME_MESSAGE);
}
if (value.trim().length() > MAX_NAME_LENGTH) {
throw new IllegalArgumentException(LENGTH_EXCEED_MESSAGE);
}
}

public String getValue() {
return value;
}

private static boolean isNullOrEmpty(String str) {
return str == null || str.isBlank();
}

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

public class Position {

private static final int INITIAL_POSITION = 0;
private static final int MOVE_DISTANCE = 1;
private static final String POSITION_SYMBOL = "-";
private static final String NEGATIVE_POSITION_MESSAGE = "위치는 음수일 수 없습니다.";

private final int value;

public Position() {
this(INITIAL_POSITION);
}

private Position(int value) {
validate(value);
this.value = value;
}

public Position move() {
return new Position(value + MOVE_DISTANCE);
}

public int getValue() {
return value;
}

public String displayPosition() {
return POSITION_SYMBOL.repeat(value);
}

private void validate(int value) {
if (value < 0) {
throw new IllegalArgumentException(NEGATIVE_POSITION_MESSAGE);
}
}

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

@FunctionalInterface
public interface MoveStrategy {
boolean isMovable();
}
16 changes: 16 additions & 0 deletions src/main/java/racingcar/strategy/RandomNumberMoveStrategy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package racingcar.strategy;

import camp.nextstep.edu.missionutils.Randoms;

public class RandomNumberMoveStrategy implements MoveStrategy {

private static final int MIN_NUMBER = 0;
private static final int MAX_NUMBER = 9;
private static final int MOVE_THRESHOLD = 4;

@Override
public boolean isMovable() {
int randomNumber = Randoms.pickNumberInRange(MIN_NUMBER, MAX_NUMBER);
return randomNumber >= MOVE_THRESHOLD;
}
}
27 changes: 27 additions & 0 deletions src/main/java/racingcar/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package racingcar.view;

import camp.nextstep.edu.missionutils.Console;

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

public class InputView {

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

public List<String> inputCarNames() {
System.out.println(CAR_NAMES_INPUT_MESSAGE);
String input = Console.readLine();
return Arrays.stream(input.split(DELIMITER))
.map(String::trim)
.toList();
}

public int inputRoundCount() {
System.out.println(ROUND_COUNT_INPUT_MESSAGE);
String input = Console.readLine();
return Integer.parseInt(input);
}
}
24 changes: 24 additions & 0 deletions src/main/java/racingcar/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package racingcar.view;

import racingcar.domain.Car;

import java.util.List;

public class OutputView {

private static final String RESULT_OUTPUT_MESSAGE = "\n실행 결과";
private static final String WINNER_OUTPUT_MESSAGE = "최종 우승자 : ";
private static final String DELIMITER = ", ";

public void printRoundResults(List<Car> cars) {
System.out.println(RESULT_OUTPUT_MESSAGE);
cars.forEach(car -> System.out.println(car.displayCar()));
System.out.println();
}

public void printWinners(List<String> winners) {
String winner = String.join(DELIMITER, winners);
System.out.println(WINNER_OUTPUT_MESSAGE + winner);
}

}
Loading