diff --git a/README.md b/README.md index d0286c859f..252bee3bca 100644 --- a/README.md +++ b/README.md @@ -1 +1,51 @@ # java-racingcar-precourse + +--- + +## 요구사항 분석 +* 입력 처리 클래스 구현 + * 쉼표를 기준으로 경주할 자동자 이름을 분리하여 입력 + * 시도할 횟수 입력 +* Car(자동차) 클래스 구현 + * 이름 + * 현재 위치 +* Race(경주) 클래스 구현 + * 게임 진행 메소드 +* 출력(Race 클래스에서 구현) + * 차수별 실행 결과 + * 단독 우승자 안내 문구 + * 공동 우승자 안내 문구 +* 잘못된 입력 처리 + * 입력 클래스에서 입력값을 확인한 후 예외 발생 +* 각 항목별 테스트 코드 작성 + +### 출력예시: +``` +경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분) +pobi,woni,jun +시도할 횟수는 몇 회인가요? +5 + +실행 결과 +pobi : - +woni : +jun : - + +pobi : -- +woni : - +jun : -- + +pobi : --- +woni : -- +jun : --- + +pobi : ---- +woni : --- +jun : ---- + +pobi : ----- +woni : ---- +jun : ----- + +최종 우승자 : pobi, jun +``` \ No newline at end of file diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index a17a52e724..4876938544 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,7 +1,28 @@ package racingcar; +import java.util.ArrayList; +import java.util.List; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + InputHandler inputHandler = new InputHandler(); + + // 입력 받기 + inputHandler.inputNames(); + inputHandler.inputCount(); + + // 입력을 기반으로 Car 인스턴스 생성 + List cars = new ArrayList<>(); + for(String name : inputHandler.getNames()){ + Car car = new Car(name); + cars.add(car); + } + + // Race 인스턴스 생성 + Race race = new Race(cars, inputHandler.getRunCount()); + + // 경주 진행 + race.runRace(); + race.showWinners(); } } diff --git a/src/main/java/racingcar/Car.java b/src/main/java/racingcar/Car.java new file mode 100644 index 0000000000..d96aee81e6 --- /dev/null +++ b/src/main/java/racingcar/Car.java @@ -0,0 +1,37 @@ +package racingcar; + +import camp.nextstep.edu.missionutils.Randoms; + +public class Car { + private String name; + private int location; + + public Car(String name) { + this.name = name; + this.location = 0; + } + + public void moveOnceRandom() { + int num = Randoms.pickNumberInRange(0, 9); + + if (num >= 4) { + location++; + } + } + + public int getLocation() { + return location; + } + + public String getName() { + return name; + } + + public String getNameAndLocation() { + String returnStr = name + " : "; + for (int i = 0; i < location; i++) { + returnStr += "-"; + } + return returnStr; + } +} diff --git a/src/main/java/racingcar/InputHandler.java b/src/main/java/racingcar/InputHandler.java new file mode 100644 index 0000000000..f1dd60e458 --- /dev/null +++ b/src/main/java/racingcar/InputHandler.java @@ -0,0 +1,43 @@ +package racingcar; + +import camp.nextstep.edu.missionutils.Console; + +import java.util.List; + +public class InputHandler { + private String input; + private List names; + private int runCount; + + public void inputNames(){ + System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + this.input = Console.readLine(); + this.names = InputHandler.commaSeparator(input); + } + + public void inputCount(){ + System.out.println("시도할 횟수는 몇 회인가요?"); + this.runCount = Integer.parseInt(Console.readLine()); + } + + public static List commaSeparator(String input){ + List names = List.of(input.split(",")); + for(String name : names){ + if(name.trim().isEmpty()){ + throw new IllegalArgumentException("이름이 비었습니다."); + } + if(name.length() > 5){ + throw new IllegalArgumentException("이름은 5자 이하만 가능합니다."); + } + } + return names; + } + + public Integer getRunCount() { + return runCount; + } + + public List getNames() { + return names; + } +} diff --git a/src/main/java/racingcar/Race.java b/src/main/java/racingcar/Race.java new file mode 100644 index 0000000000..4201837ea2 --- /dev/null +++ b/src/main/java/racingcar/Race.java @@ -0,0 +1,51 @@ +package racingcar; + +import org.junit.platform.commons.util.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +public class Race { + private List cars; + private int count; + + public Race(List cars, int count) { + this.cars = cars; + this.count = count; + } + + public void runOneRound(){ + for(Car car : cars){ + car.moveOnceRandom(); + } + } + + public void printLocations(){ + for(Car car : cars){ + System.out.println(car.getNameAndLocation()); + } + } + + public void runRace(){ + System.out.println("실행 결과"); + for(int i = 0; i < count; i++){ + runOneRound(); + printLocations(); + System.out.println(); + } + } + + public void showWinners(){ + int max = cars.stream().map(Car::getLocation).max(Integer::compareTo).orElse(Integer.MIN_VALUE); + + List winners = new ArrayList<>(); + for(Car car : cars){ + if(car.getLocation() == max){ + winners.add(car.getName()); + } + } + + String winnersOutput = String.join(", ", winners); + System.out.println("최종 우승자 : " + winnersOutput); + } +} diff --git a/src/test/java/racingcar/CarTest.java b/src/test/java/racingcar/CarTest.java new file mode 100644 index 0000000000..bad6714125 --- /dev/null +++ b/src/test/java/racingcar/CarTest.java @@ -0,0 +1,42 @@ +package racingcar; + +import camp.nextstep.edu.missionutils.Randoms; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static camp.nextstep.edu.missionutils.test.Assertions.assertRandomNumberInRangeTest; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class CarTest { + private Car car; + + @BeforeEach + void setUp() { + car = new Car("pobi"); + } + + @Test + void 자동차의_이름을_반환한다() { + assertThat(car.getName()).isEqualTo("pobi"); + } + + @Test + void 자동차의_초기_위치는_0이다() { + assertThat(car.getLocation()).isEqualTo(0); + } + + @Test + void 자동차는_랜덤숫자가_4이상일_경우_이동한다() { + assertRandomNumberInRangeTest( + () -> { + car.moveOnceRandom(); + assertThat(car.getLocation()).isEqualTo(1); + + car.moveOnceRandom(); + assertThat(car.getLocation()).isEqualTo(1); + }, + 4, 3 + ); + } +} \ No newline at end of file diff --git a/src/test/java/racingcar/InputHandlerTest.java b/src/test/java/racingcar/InputHandlerTest.java new file mode 100644 index 0000000000..ea59c40464 --- /dev/null +++ b/src/test/java/racingcar/InputHandlerTest.java @@ -0,0 +1,46 @@ +package racingcar; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + +class InputHandlerTest { + + private InputHandler inputHandler; + + @BeforeEach + void setUp() { + inputHandler = new InputHandler(); + } + + @Test + void 자동차_이름을_쉼표로_구분하여_입력할_수_있다() { + String input = "pobi,woni"; + List expectedNames = List.of("pobi", "woni"); + + List names = InputHandler.commaSeparator(input); + + assertThat(names).isEqualTo(expectedNames); + } + + @Test + void 자동차_이름은_빈_문자열일_수_없다() { + String input = "pobi,,woni"; + + assertThatThrownBy(() -> InputHandler.commaSeparator(input)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 자동차_이름은_5자_이하만_허용된다() { + String input = "pobi,woni,longname"; + + assertThatThrownBy(() -> InputHandler.commaSeparator(input)) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file diff --git a/src/test/java/racingcar/RaceTest.java b/src/test/java/racingcar/RaceTest.java new file mode 100644 index 0000000000..57deb10dac --- /dev/null +++ b/src/test/java/racingcar/RaceTest.java @@ -0,0 +1,38 @@ +package racingcar; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Arrays; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class RaceTest { + private Race race; + private ByteArrayOutputStream outputStream; + + @BeforeEach + void setUp() { + Car car1 = new Car("pobi"); + Car car2 = new Car("woni"); + race = new Race(Arrays.asList(car1, car2), 5); + + outputStream = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outputStream)); + } + + @Test + void 경주가_정상적으로_진행되는지_테스트() { + race.runRace(); + race.showWinners(); + + String output = outputStream.toString(); + assertThat(output).contains("실행 결과"); // 경주 시작 메시지 확인 + assertThat(output).contains("pobi : ", "woni : "); // 자동차의 위치 정보가 출력되었는지 확인 + + assertThat(output).contains("최종 우승자 : "); // 최종 우승자 메시지 확인 + } +} \ No newline at end of file