diff --git a/README.md b/README.md index d0286c859f..7b8f12b413 100644 --- a/README.md +++ b/README.md @@ -1 +1,93 @@ # java-racingcar-precourse + +## 초간단 자동차 경주 게임을 구현한다. + +> 이 문서의 작성 양식은 [프리코스 과제 가이드](https://github.com/woowacourse/woowacourse-docs/blob/e2f102b97f6b65f5ba8da09944ee8cb9b33b696a/precourse/README.md)를 참고했습니다. + +* 취소선 처리한 내용을 검색하면 다른 항목에서 찾을 수 있습니다. + +--- + +### 1. 주어진 횟수 동안 n대의 자동차는 ~~전진 또는 멈출 수 있다~~ 전진할 수 있다. + +> 예: +> +> 2 +> +> \- +> \- +> \- +> +> \-- +> \-- +> \-- + +* 1-1. 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. + +* 1-2. 전진하며 출력한다. + +--- + +### 2. 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. + +> 예: +> +> pobi,woni,jun +> +> pobi : \- +> woni : \- +> jun : \- +> +> pobi : \-\- +> woni : \-\- +> jun : \-\- + +* 2-1. 이름을 입력한다. 자동차 이름은 쉼표(,)를 기준으로 구분한다. + +* 2-2. 이름을 출력한다. + +--- + +### 3. ~~자동차 이름은 쉼표(,)를 기준으로 구분하며~~ ~~이름은 5자 이하만 가능하다.~~ + +--- + +### 4. ~~사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.~~ + +--- + +### 5. 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우이다. + +> 예: +> +> pobi,woni,jun +> +> pobi : \- +> woni : +> jun : \- +> +> pobi : \-- +> woni : \- +> jun : \-- + +* 4 미만일 경우에 멈출 수 있다. + +--- + +### 6. 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. + +> 예: +> +> pobi, jun + +* 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다. + +--- + +### 7. ~~우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다.~~ + +--- + +### 8. 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션은 종료되어야 한다. + +* 이름은 5자 이하만 가능하다. diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index a17a52e724..8b18862bb3 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,7 +1,61 @@ package racingcar; +import static camp.nextstep.edu.missionutils.Console.readLine; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + public class Application { - public static void main(String[] args) { - // TODO: 프로그램 구현 + public static final String lastPrefix = "최종 우승자 : "; + + public static void main(String[] args) throws IllegalArgumentException { + final PrintWriter pw = new PrintWriter(System.out); + String line; + + line = readLine(); + if (line == null || line.isBlank()) { + throw new IllegalArgumentException(); + } + final String[] carNames = line.split(","); + final List racingCars = Arrays.stream(carNames) + .parallel() + .map(String::trim) + .map(RacingCar::new) + .collect(Collectors.toCollection(ArrayList::new)); + + racingCars.parallelStream() + .allMatch(racingCar -> racingCar.getName().length() <= 5); + + line = readLine(); + if (line == null || line.isBlank()) { + throw new IllegalArgumentException(); + } + final int numRounds = Integer.parseInt(line.trim()); + for (int i = 0; i != numRounds; i++) { + racingCars.stream() + .forEach( + racingCar -> { + racingCar.move(); + pw.println(racingCar.getName() + " : " + "-".repeat(racingCar.getMileage())); + } + ); + + pw.println(); + pw.flush(); + } + + final int maxMileage = racingCars.parallelStream() + .max(Comparator.comparing(RacingCar::getMileage)) + .get() + .getMileage(); + pw.println(lastPrefix + racingCars.stream() + .filter(racingCar -> racingCar.getMileage() == maxMileage) + .map(RacingCar::getName) + .collect(Collectors.joining(", ")) + ); + pw.flush(); } } diff --git a/src/main/java/racingcar/RacingCar.java b/src/main/java/racingcar/RacingCar.java new file mode 100644 index 0000000000..55f723d4db --- /dev/null +++ b/src/main/java/racingcar/RacingCar.java @@ -0,0 +1,26 @@ +package racingcar; + +import static camp.nextstep.edu.missionutils.Randoms.pickNumberInRange; + +public class RacingCar { + public RacingCar(final String name) { + this.name = name; + } + + public void move() { + if (pickNumberInRange(0, 9) >= 4) { + mileage++; + } + } + + public int getMileage() { + return mileage; + } + + public String getName() { + return name; + } + + private int mileage; + private String name; +} diff --git a/src/test/java/racingcar/ApplicationTest.java b/src/test/java/racingcar/ApplicationTest.java index 1d35fc33fe..56a8c3b905 100644 --- a/src/test/java/racingcar/ApplicationTest.java +++ b/src/test/java/racingcar/ApplicationTest.java @@ -1,17 +1,93 @@ package racingcar; -import camp.nextstep.edu.missionutils.test.NsTest; -import org.junit.jupiter.api.Test; - import static camp.nextstep.edu.missionutils.test.Assertions.assertRandomNumberInRangeTest; import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import camp.nextstep.edu.missionutils.test.NsTest; class ApplicationTest extends NsTest { private static final int MOVING_FORWARD = 4; private static final int STOP = 3; + @Test + void 전진_테스트() { + final List carNames = List.of("pobi", "woni", "jun"); + final int numRounds = 10; + + assertSimpleTest( + () -> { + run(String.join(",", carNames), String.valueOf(numRounds)); + + final List mileages = Stream.generate(() -> 0) + .limit(carNames.size()) + .collect(Collectors.toCollection(ArrayList::new)); + + final String[] lines = output().split("\n"); + for (int i = 0, j = 0; i < lines.length - 1; i++, j = i % (carNames.size() + 1)) { + assertThat(i <= 5); + final String line = lines[i]; + + if (j == carNames.size()) { + assertThat(line.isBlank()); + continue; + } + + final String[] words = line.split(" : "); + assertEquals(carNames.get(j), words[0]); + + if (words.length == 1) { + assertEquals(mileages.get(j), 0); + continue; + } + assertThat(words.length == 2); + assertEquals("-".repeat(words[1].length()), words[1]); + assertThat(words[1].length() - mileages.get(j) >= 0); + mileages.set(j, words[1].length()); + } + assertEquals(numRounds * (carNames.size() + 1) + 1, lines.length); + + final String lastLine = lines[lines.length - 1]; + assertThat(lastLine.startsWith(Application.lastPrefix)); + + final String[] winnerNames = lastLine.substring(Application.lastPrefix.length()) + .split(", "); + + int maxMileage = -1; + for (int i = 0, j = 0; i != carNames.size(); i++) { + final String carName = carNames.get(i); + + if (j == winnerNames.length || ! carName.equals(winnerNames[j])) { + continue; + } + j++; + + if (maxMileage == -1) { + maxMileage = mileages.get(i); + } + assertThat(maxMileage == mileages.get(i)); + } + + for (int i = 0, j = 0; i != carNames.size(); i++) { + final String carName = carNames.get(i); + + if (j != winnerNames.length && carName.equals(winnerNames[j])) { + j++; + continue; + } + assertThat(maxMileage > mileages.get(i)); + } + + } + ); + } + @Test void 기능_테스트() { assertRandomNumberInRangeTest(