Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b54030a
README 파일 위치 수정 및 랜덤변수 상수화, 변수명 수정(forwardCount)
Sep 13, 2025
be7dab9
refactor: Car 클래스 캡슐화 적용
Sep 14, 2025
b6c587f
refactor: race 메서드를 역할에 따라 분리
Sep 14, 2025
f4008b0
Car 테스트 코드 작성을 위한 수정
Sep 15, 2025
752c8ff
테스트 코드를 위한 Car 클래스 코드 수정
Sep 15, 2025
dfb8eff
테스트 코드를 위한 Car 클래스 수정
Sep 15, 2025
3d04c89
Car 클래스 테스트 코드
Sep 15, 2025
17908bd
given when then 추가 및 테스트 명 변경
Sep 16, 2025
9a52efc
README파일 위치 수정
Sep 16, 2025
f49d534
GameManage 수정 및 테스트 코드 작성
Sep 16, 2025
c9aa77c
GameManage 수정 및 테스트 코드 작성
Sep 16, 2025
59f0f6b
GameManage 수정 및 테스트 코드 작성
Sep 16, 2025
5802688
GameManage 수정 및 테스트 코드 작성
Sep 16, 2025
d4a1d27
given when then 추가 및 테스트 명 변경
Sep 16, 2025
9bdb50d
README파일 위치 수정
Sep 16, 2025
ec25b46
김태우 3,4 단계 완성
Sep 17, 2025
440de18
테스트 코드 추가
Sep 18, 2025
5067417
README수정
Sep 18, 2025
0741dfc
InputView 입력 및 예외 처리 추가
Sep 21, 2025
f88cc82
네이밍 룰에 맞는 메서드 명 수정
Sep 21, 2025
d91abd6
네이밍 룰에 맞는 메서드 명 수정
Sep 21, 2025
9141db8
position별 자동차 그룹화 및 Winners 캡슐화 개선, 테스트 코드 수정
Sep 21, 2025
86dbc22
README Generater → GenerateNumber 클래스명 변경
Sep 21, 2025
0317ab8
refactor: 입력값 처리 시 쉼표 뒤 공백만 제거하도록 replaceAll 수정
Sep 22, 2025
637c951
refactor: 입력값 처리 시 쉼표 뒤 공백만 제거하도록 replaceAll 수정
Sep 23, 2025
9667e7b
refactor(Car): String carName 대신 CarName 객체를 사용하도록 변경
Sep 23, 2025
c3eea9e
자동차 이름을 CarName 값 객체로 분리하여 유효성 검사 추가
Sep 23, 2025
3332542
refactor(Cars): carName 공백 제거 후 중복 검사 및 List.copyOf 반환으로 캡슐화 강화
Sep 23, 2025
183e363
잘못된 입력 시 안내 메시지 출력 및 재입력 처리 추가
Sep 23, 2025
cf2d38b
InputView 변경에 맞게 Cars 객체 직접 사용하도록 수정
Sep 23, 2025
423daa1
README에 CarName 클래스 설명 추가
Sep 23, 2025
b455832
test(CarName): 유효한 이름·null·공백·길이 초과 검증 테스트 추가
Sep 23, 2025
97c8af5
test(Cars): Car.createCarByCarName 호출 시 String 대신 CarName 전달하도록 수정
Sep 23, 2025
2b71ca3
test: CarTest에서 CarName을 사용하도록 수정
Sep 23, 2025
d5a1b45
자동차 이름 입력 로직 개선 (trim 사용)
Sep 27, 2025
1a045b4
GameManage의 race 메서드를 Main으로 이동하여 Model과 Controller 분리
Sep 27, 2025
61a2844
Merge branch 'tae-wooo' into taewooo1
tae-wooo Sep 27, 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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
## 클래스 구성

- **Car** → 자동차 1대 관리 (이름, 위치, 이동 로직)
- **Cars** → 자동차 리스트 관리 (생성, 조회)
- **CarName** ->
- **Cars** → 자동차 이름을 표현·검증하는 값 객체(공백·길이 제한 등 유효성 검사 담당)
- **GameManage** → 경주 전체 진행 (라운드별 이동, 결과 출력, 우승자 계산)
- **Winners** → 우승자 저장소
- **Generater** → 랜덤 숫자 생성 (0~9)
- **GenerateNumber** → 랜덤 숫자 생성 (0~9)
- **InputView** → 사용자 입력 (자동차 이름, 시도 횟수)
- **ResultView** → 결과 출력 (라운드별, 최종 우승자)
- **Main** → 게임 실행 흐름
Expand Down
20 changes: 8 additions & 12 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@
import view.InputView;
import view.ResultView;

import java.util.List;

public class Main {
public static void main(String[] args) {

List<String> carNames = InputView.inputCarName();
Cars cars = InputView.inputCarName();
int roundCount = InputView.inputRound();

Cars cars = Cars.carsCreate(carNames);
Winners winners = Winners.winnersCreate();

GameManage game = new GameManage(cars, winners);

game.race(roundCount);
ResultView.printWinners(game.getWinners().getWinners());

GameManage game = new GameManage(cars);
for (int i = 0; i < roundCount; i++) {
game.raceOneRound();
ResultView.printRoundResult(cars.getCars());
}
Winners winners = game.createWinners();

Choose a reason for hiding this comment

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

멋지게 바꾸어 주셨네요!

ResultView.printWinners(winners.getWinners());
}
}
15 changes: 7 additions & 8 deletions src/main/java/domain/Car.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
package domain;

import util.Generater;

import util.GenerateNumber;

public class Car {

Choose a reason for hiding this comment

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

domain 패키지에도 Car가 있고 racingcar 패키지에도 Car가 있네요?

Copy link
Author

Choose a reason for hiding this comment

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

전에 racingcar 패키지에서 Car를 만들었었는데, 이번 미션을 진행하면서는 처음부터 설계 방향을 다시 잡고자 새로 구현했습니다. 그래서 이전 미션에서 생성된 Car가 깃허브에 남아 있는 것 같습니다.

private static final int STANDARD = 4;

private final String carName;
private final CarName carName;
private int carPosition;

private Car(String carName) {
private Car(CarName carName) {
this.carName = carName;
this.carPosition = 0;
}

public static Car namePositionOf(String carName) {
public static Car createCarByCarName(CarName carName) {
return new Car(carName);
}

public void move() {
int randomNumber = Generater.generateNumber();
public void moveCar() {
int randomNumber = GenerateNumber.generateNumber();
if (randomNumber >= STANDARD) {
carPosition++;
}
}

public String getCarName() {
return carName;
return carName.getCarName();
}

public int getCarPosition() {
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/domain/CarName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package domain;

public class CarName {
private final String carName;

public CarName(String carName) {
checkNull(carName);
checkLength(carName);
this.carName = carName;
}

private static void checkNull(String carName) {
if (carName == null || carName.isBlank()) {
throw new IllegalArgumentException("이름은 공백으로 입력될 수 없습니다.");
}
}

private static void checkLength(String carName) {
if (carName.length() > 5) {
throw new IllegalArgumentException("자동차 이름은 최대 5글자까지만 가능합니다. 입력값:" + carName);
}
}

public String getCarName() {
return carName;
}
}
17 changes: 13 additions & 4 deletions src/main/java/domain/Cars.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
package domain;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Cars {
private List<Car> cars;
private final List<Car> cars;

private Cars() {
this.cars = new ArrayList<>();
}

public static Cars carsCreate(List<String> carNames) {
public static Cars createCars(List<String> carNames) {
Cars cars = new Cars();
Set<String> existingNames = new HashSet<>();
for (String name : carNames) {
cars.addCar(Car.namePositionOf(name));
String trimmed = name.trim();
if (existingNames.contains(trimmed)) {
throw new IllegalArgumentException("중복된 자동차 이름이 있습니다: " + name);
}
existingNames.add(trimmed);
CarName nameObj = new CarName(trimmed);
cars.addCar(Car.createCarByCarName(nameObj));
}
return cars;
}
Expand All @@ -23,6 +32,6 @@ public void addCar(Car car) {
}

public List<Car> getCars() {
return cars;
return List.copyOf(cars);
}
}
38 changes: 15 additions & 23 deletions src/main/java/domain/GameManage.java
Original file line number Diff line number Diff line change
@@ -1,47 +1,39 @@
package domain;

import view.ResultView;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GameManage {
private final Cars cars;
private final Winners winners;

public GameManage(Cars cars, Winners winners) {
public GameManage(Cars cars) {
this.cars = cars;
this.winners = winners;
}

public void raceOneRound() {
for (Car car : cars.getCars()) {
car.move();
car.moveCar();
}
}

public void race(int round) {
for (int i = 0; i < round; i++) {
raceOneRound();
ResultView.printRoundResult(cars.getCars());
}
findWinner();
private Map<Integer, List<Car>> groupPosition() {
return cars.getCars().stream().collect(Collectors.groupingBy(Car::getCarPosition));
}

private int maxPosition() {
return cars.getCars().stream().mapToInt(Car::getCarPosition).max().orElse(0);
}
public Winners createWinners() {
Map<Integer, List<Car>> carsByPosition = groupPosition();

public void findWinner() {
List<String> winnerNames = cars.getCars().stream()
.filter(car -> car.getCarPosition() == maxPosition())
List<Car> winnersGroup = carsByPosition.entrySet().stream()
.max(Map.Entry.comparingByKey())
.map(Map.Entry::getValue)
.orElse(Collections.emptyList());

List<String> winnerNames = winnersGroup.stream()
.map(Car::getCarName)
.collect(Collectors.toList());

winners.setWinners(winnerNames);
}

public Winners getWinners() {
return winners;
return Winners.of(winnerNames);
}
}
15 changes: 4 additions & 11 deletions src/main/java/domain/Winners.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,14 @@
public class Winners {
private List<String> winners;

private Winners() {
this.winners = new ArrayList<>();
private Winners(List<String> winners) {
this.winners = List.copyOf(winners);
}

public static Winners winnersCreate() {
return new Winners();
public static Winners of(List<String> winnerNames) {
return new Winners(winnerNames);
}


public void setWinners(List<String> winnerNames) {
this.winners.clear();
this.winners.addAll(winnerNames);
}


public List<String> getWinners() {
return winners;
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/util/GenerateNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package util;

import java.util.Random;

public class GenerateNumber {
private static final Random random = new Random();

public static int generateNumber() {
return random.nextInt(10);
}
}
34 changes: 29 additions & 5 deletions src/main/java/view/InputView.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,44 @@
package view;

import domain.Cars;

import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;

public class InputView {
private static final Scanner scanner = new Scanner(System.in);

public static List<String> inputCarName() {
System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).");
String inputName = scanner.nextLine();
return Arrays.asList(inputName.split(","));
public static Cars inputCarName() {
while (true) {
try {
System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).");
String[] inputName = scanner.nextLine().split(",");
for (int i = 0; i < inputName.length; i++) {
inputName[i] = inputName[i].trim();
}
List<String> names = Arrays.asList(inputName);

return Cars.createCars(names);

} catch (IllegalArgumentException input) {
System.out.println("입력 오류이므로 다시 입력해주세요.");
}
}
}

public static int inputRound() {
System.out.println("시도할 회수는 몇회인가요?");
return scanner.nextInt();
while (true) {
try {
int round = scanner.nextInt();
scanner.nextLine();
return round;
} catch (InputMismatchException input) {
System.out.println("회수는 숫자로 입력해 주세요!!");
scanner.nextLine();
}
}
}
}
25 changes: 25 additions & 0 deletions src/test/java/domain/CarNameTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package domain;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class CarNameTest {

@Test
void 정상적인_이름이면_생성된다() {
CarName carName = new CarName("car1");
assertEquals("car1", carName.getCarName());
}

@Test
void null이나공백이면_예외가_발생한다() {
assertThrows(IllegalArgumentException.class, () -> new CarName(null));
assertThrows(IllegalArgumentException.class, () -> new CarName(" "));
}

@Test
void 다섯글자를_초과하면_예외가_발생한다() {
assertThrows(IllegalArgumentException.class, () -> new CarName("aaaaaa"));
}
}
30 changes: 17 additions & 13 deletions src/test/java/domain/CarTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,38 @@

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import java.util.Arrays;
import java.util.List;

class CarTest {
import static org.junit.jupiter.api.Assertions.*;

class CarsTest {
@Test
void 자동차는이름과초기위치를가진다() {
void 이름리스트로Cars를생성한다() {
// given
String name = "car1";
List<String> carNames = Arrays.asList("car1", "car2", "car3");

// when
Car car = Car.namePositionOf(name);
Cars cars = Cars.createCars(carNames);

// then
assertThat(car.getCarName()).isEqualTo("car1");
assertThat(car.getCarPosition()).isZero();
assertEquals(3, cars.getCars().size());
assertEquals("car1", cars.getCars().get(0).getCarName());
assertEquals("car2", cars.getCars().get(1).getCarName());
assertEquals("car3", cars.getCars().get(2).getCarName());
}

@Test
void 랜덤숫자가4이상이면전진할수있다() {
void 자동차를추가할수있다() {
// given
Car car = Car.namePositionOf("car1");
Cars cars = Cars.createCars(Arrays.asList("car1"));
Car car2 = Car.createCarByCarName(new CarName("car2"));

// when
for (int i = 0; i < 10; i++) {
car.move();
}
cars.addCar(car2);

// then
assertThat(car.getCarPosition()).isGreaterThanOrEqualTo(0);
assertEquals(2, cars.getCars().size());
assertEquals("car2", cars.getCars().get(1).getCarName());
}
}
Loading