diff --git a/README.md b/README.md index d0286c859f..21dc80508a 100644 --- a/README.md +++ b/README.md @@ -1 +1,127 @@ -# java-racingcar-precourse +# πŸš— μžλ™μ°¨ κ²½μ£Ό κ²Œμž„ + +## ν”„λ‘œμ νŠΈ κ°œμš” + +* **λͺ©μ **: μ‚¬μš©μžκ°€ μž…λ ₯ν•œ μžλ™μ°¨ μ΄λ¦„μœΌλ‘œ κ²½μ£Όλ₯Ό μ§„ν–‰ν•˜κ³ , μ΅œμ’… 우승자λ₯Ό 좜λ ₯ν•˜λŠ” μ½˜μ†” 기반 κ²Œμž„ +* **μ–Έμ–΄/ν™˜κ²½**: Java 21 +* **라이브러리**: `camp.nextstep.edu.missionutils` (Randoms, Console) +* **ν…ŒμŠ€νŠΈ**: JUnit 5, AssertJ + +--- + +## κΈ°λŠ₯ μš”κ΅¬μ‚¬ν•­ + +1. μžλ™μ°¨ 이름 μž…λ ₯ + + * μ‰Όν‘œ(,)둜 ꡬ뢄 + * 이름 5자 μ΄ν•˜ + * 잘λͺ»λœ μž…λ ₯ μ‹œ `IllegalArgumentException` λ°œμƒ + +2. μ‹œλ„ 횟수 μž…λ ₯ + + * 숫자만 ν—ˆμš© + * 잘λͺ»λœ μž…λ ₯ μ‹œ `IllegalArgumentException` λ°œμƒ + +3. μžλ™μ°¨ 이동 + + * 랜덀 κ°’(0~9) β‰₯ 4 β†’ μ „μ§„ + * 이동 κ²°κ³Ό λ§€ λΌμš΄λ“œ 좜λ ₯ (`-`둜 ν‘œμ‹œ) + +4. 우승자 좜λ ₯ + + * μ΅œμ’… 우승자 1λͺ… λ˜λŠ” 곡동 우승자 + * μ‰Όν‘œ(,)둜 ꡬ뢄 + +--- + +## νŒ¨ν‚€μ§€ ꡬ쑰 + +``` +racingcar + β”œβ”€β”€ Application.java // μ‹€ν–‰ μ§„μž…μ  + β”œβ”€β”€ domain + β”‚ β”œβ”€β”€ Car.java + β”‚ └── RacingGame.java + β”œβ”€β”€ view + β”‚ β”œβ”€β”€ InputView.java + β”‚ └── OutputView.java + └── utils + └── RandomUtil.java +``` + +--- + +## μ‚¬μš© 방법 + +1. ν”„λ‘œμ νŠΈ λΉŒλ“œ 및 μ‹€ν–‰ + +```bash +./gradlew run +``` + +2. μ½˜μ†” μž…λ ₯ + +``` +κ²½μ£Όν•  μžλ™μ°¨ 이름을 μž…λ ₯ν•˜μ„Έμš”.(이름은 μ‰Όν‘œ(,) κΈ°μ€€μœΌλ‘œ ꡬ뢄) +pobi,woni,jun + +μ‹œλ„ν•  νšŸμˆ˜λŠ” λͺ‡ νšŒμΈκ°€μš”? +5 +``` + +3. μ‹€ν–‰ κ²°κ³Ό μ˜ˆμ‹œ + +``` +μ‹€ν–‰ κ²°κ³Ό +pobi : - +woni : +jun : - + +pobi : -- +woni : - +jun : -- + +pobi : --- +woni : -- +jun : --- + +pobi : ---- +woni : --- +jun : ---- + +pobi : ----- +woni : ---- +jun : ----- + +μ΅œμ’… 우승자 : pobi, jun +``` + +--- + +## μ˜ˆμ™Έ 처리 + +* μžλ™μ°¨ 이름 5자 초과 β†’ `IllegalArgumentException` +* 이름 곡백/λΉˆκ°’ β†’ `IllegalArgumentException` +* μ‹œλ„ 횟수 숫자 μ•„λ‹˜ β†’ `IllegalArgumentException` + +--- + +## ν…ŒμŠ€νŠΈ + +* **ApplicationTest** + + * κΈ°λŠ₯ ν…ŒμŠ€νŠΈ: 랜덀 값에 따라 μžλ™μ°¨ 이동 및 우승자 좜λ ₯ 검증 + * μ˜ˆμ™Έ ν…ŒμŠ€νŠΈ: 잘λͺ»λœ μž…λ ₯ μ‹œ IllegalArgumentException λ°œμƒ 확인 + +* **ν…ŒμŠ€νŠΈ μ‹€ν–‰** + +```bash +./gradlew test +``` + +--- + +## μ°Έκ³  + +* 랜덀 값은 `camp.nextstep.edu.missionutils.Randoms.pickNumberInRange(0, 9)` μ‚¬μš© +* μž…λ ₯은 `camp.nextstep.edu.missionutils.Console.readLine()` μ‚¬μš© diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index a17a52e724..cd5c6c6a11 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,7 +1,17 @@ package racingcar; +import racingcar.domain.RacingGame; +import racingcar.view.InputView; +import racingcar.view.OutputView; + public class Application { public static void main(String[] args) { - // TODO: ν”„λ‘œκ·Έλž¨ κ΅¬ν˜„ + String[] names = InputView.readCarNames(); + int count = InputView.readRoundCount(); + + RacingGame racingGame = new RacingGame(names); + racingGame.race(count); + OutputView.printWinners(racingGame.getWinners()); } + } diff --git a/src/main/java/racingcar/domain/Car.java b/src/main/java/racingcar/domain/Car.java new file mode 100644 index 0000000000..2b02a76ed8 --- /dev/null +++ b/src/main/java/racingcar/domain/Car.java @@ -0,0 +1,41 @@ +package racingcar.domain; + +public class Car { + private static final int MOVE_CONDITION = 4; + private final String name; + private int position = 0; + + public Car(String name) { + validateName(name); + this.name = name; + } + + private void validateName(String name) { + if (name == null || name.isBlank() || name.length() > 5) { + throw new IllegalArgumentException("μžλ™μ°¨ 이름은 1~5자 μ΄ν•˜μ—¬μ•Ό ν•©λ‹ˆλ‹€."); + } + } + + public void move(int randomNumber) { + if (randomNumber >= MOVE_CONDITION) { + position++; + } + } + + public String getName() { + return name; + } + + public int getPosition() { + return position; + } + + public boolean isWinner(int maxPosition) { + return this.position == maxPosition; + } + + @Override + public String toString() { + return name + " : " + "-".repeat(position); + } +} diff --git a/src/main/java/racingcar/domain/RacingGame.java b/src/main/java/racingcar/domain/RacingGame.java new file mode 100644 index 0000000000..926c32bfd9 --- /dev/null +++ b/src/main/java/racingcar/domain/RacingGame.java @@ -0,0 +1,46 @@ +package racingcar.domain; + +import racingcar.utils.RandomUtil; +import racingcar.view.OutputView; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class RacingGame { + private final List cars; + + public RacingGame(String[] names) { + this.cars = Arrays.stream(names) + .map(String::trim) + .map(Car::new) + .collect(Collectors.toList()); + } + + public void race(int roundCount) { + OutputView.printResultTitle(); + for (int i = 0; i < roundCount; i++) { + playRound(); + OutputView.printRoundResult(cars); + } + } + + private void playRound() { + for (Car car : cars) { + car.move(RandomUtil.getRandomNumber()); + } + } + + public List getWinners() { + int maxPosition = cars.stream() + .mapToInt(Car::getPosition) + .max() + .orElse(0); + + return cars.stream() + .filter(car -> car.isWinner(maxPosition)) + .map(Car::getName) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/racingcar/utils/RandomUtil.java b/src/main/java/racingcar/utils/RandomUtil.java new file mode 100644 index 0000000000..05ee33094c --- /dev/null +++ b/src/main/java/racingcar/utils/RandomUtil.java @@ -0,0 +1,9 @@ +package racingcar.utils; + +import camp.nextstep.edu.missionutils.Randoms; + +public class RandomUtil { + public static int getRandomNumber() { + return Randoms.pickNumberInRange(0, 9); + } +} diff --git a/src/main/java/racingcar/view/InputView.java b/src/main/java/racingcar/view/InputView.java new file mode 100644 index 0000000000..25f830fae7 --- /dev/null +++ b/src/main/java/racingcar/view/InputView.java @@ -0,0 +1,25 @@ +package racingcar.view; + +import camp.nextstep.edu.missionutils.Console; + +public class InputView { + + public static String[] readCarNames() { + System.out.println("κ²½μ£Όν•  μžλ™μ°¨ 이름을 μž…λ ₯ν•˜μ„Έμš”.(이름은 μ‰Όν‘œ(,) κΈ°μ€€μœΌλ‘œ ꡬ뢄)"); + String input = Console.readLine(); + if (!input.contains(",")) { + throw new IllegalArgumentException("μžλ™μ°¨λŠ” μ΅œμ†Œ 2λŒ€ 이상이어야 ν•©λ‹ˆλ‹€."); + } + return input.split(","); + } + + public static int readRoundCount() { + System.out.println("μ‹œλ„ν•  νšŸμˆ˜λŠ” λͺ‡ νšŒμΈκ°€μš”?"); + String input = Console.readLine(); + try { + return Integer.parseInt(input); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("μ‹œλ„ νšŸμˆ˜λŠ” μˆ«μžμ—¬μ•Ό ν•©λ‹ˆλ‹€."); + } + } +} diff --git a/src/main/java/racingcar/view/OutputView.java b/src/main/java/racingcar/view/OutputView.java new file mode 100644 index 0000000000..b7c44eca6f --- /dev/null +++ b/src/main/java/racingcar/view/OutputView.java @@ -0,0 +1,25 @@ +package racingcar.view; + +import racingcar.domain.Car; + +import java.util.List; +import java.util.stream.Collectors; + +public class OutputView { + + public static void printResultTitle() { + System.out.println("\nμ‹€ν–‰ κ²°κ³Ό"); + } + + public static void printRoundResult(List cars) { + for (Car car : cars) { + System.out.println(car); + } + System.out.println(); + } + + public static void printWinners(List winners) { + String result = String.join(", ", winners); + System.out.println("μ΅œμ’… 우승자 : " + result); + } +}