diff --git a/README.md b/README.md index d0286c859f..be58336481 100644 --- a/README.md +++ b/README.md @@ -1 +1,44 @@ # java-racingcar-precourse + +# 기능 목록 + +## 범위 + +- 패키지: `racingcar` (테스트에서 `racingcar.Application`을 호출) +- 입력: `camp.nextstep.edu.missionutils.Console.readLine()` + 1. `경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)` + 2. `시도할 횟수는 몇 회인가요?` +- 출력: + - 시작 시 `실행 결과` + - 차수별 실행 결과 (각 라운드 후 `name : '-'*position`, 라운드 사이 빈 줄 1개) + - 최종 우승자 안내: `최종 우승자 : 이름[, 이름…]` + +--- + +## 기능 목록 (구현 순서 권장) + +1. **입력 안내 & 입력 수신** + - 이름 라인, 시도 횟수 라인 읽기(프롬프트 출력 포함) + - `실행 결과` 문구 출력 +2. **자동차 이름 파싱/검증** + - `,`로 분리 후 각 이름 `trim()` + - 각 이름 길이 **1~5자**만 허용, 빈 토큰 금지 +3. **시도 횟수 파싱/검증** + - 양의 정수(>0)만 허용 (0/음수/실수/문자 → `IllegalArgumentException`) +4. **라운드 실행 + 전진 규칙** + - `tryCount`만큼 반복, 각 차에 대해 랜덤이 **4 이상**이면 `position++` +5. **차수별 실행 결과 출력** + - 라운드마다 `name : '-'*position` 출력 + - 라운드 사이 빈 줄 1개 +6. **우승자 계산 & 최종 출력** + - 최대 position의 이름들을 `,`로 연결해 `최종 우승자 : ...` 출력 + +--- + +## 구현 결정(Assumptions) + +- 이름은 중복 허용 +- 이름의 문자 종류 제한 없음(숫자/특수문자 가능); 단 길이 1~5자 만 검증 +- 입력 앞뒤 공백은 무시(trim) +- 예외 메시지 내용은 채점에 영향 없음(타입만 `IllegalArgumentException` 보장) +- 출력 포맷은 예시와 정확히 일치 (공백/콜론/개행 포함) \ No newline at end of file diff --git a/src/main/java/racingcar/Application.java b/src/main/java/racingcar/Application.java index a17a52e724..7c9844a4e9 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,7 +1,107 @@ package racingcar; +import camp.nextstep.edu.missionutils.Console; +import camp.nextstep.edu.missionutils.Randoms; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + public class Application { + private static final int MOVE_THRESHOLD = 4; + public static void main(String[] args) { - // TODO: 프로그램 구현 + String namesInput = readLine("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + String tryCountInput = readLine("시도할 횟수는 몇 회인가요?"); + + List cars = parseCars(namesInput); + int tryCount = parseTryCount(tryCountInput); + + printExecutionHeader(); + runRounds(cars, tryCount); + printWinners(cars); + } + + private static String readLine(String prompt) { + System.out.println(prompt); + return Console.readLine(); + } + + private static List parseCars(String raw) { + if (raw == null) { + throw new IllegalArgumentException("names required"); + } + String[] nameTokens = raw.split(","); + List cars = new ArrayList<>(); + for (String nameToken : nameTokens) { + String name = nameToken.trim(); + if (name.isEmpty()) { + throw new IllegalArgumentException("empty name"); + } + if (name.length() > 5) { + throw new IllegalArgumentException("name too long: " + name); + } + cars.add(new Car(name)); + } + if (cars.isEmpty()) { + throw new IllegalArgumentException("no cars"); + } + return cars; + } + + private static int parseTryCount(String raw) { + if (raw == null) { + throw new IllegalArgumentException("try count required"); + } + String trimmedInput = raw.trim(); + if (trimmedInput.isEmpty()) { + throw new IllegalArgumentException("try count required"); + } + if (!trimmedInput.chars().allMatch(Character::isDigit)) { + throw new IllegalArgumentException("try count must be positive integer"); + } + int tryCount = Integer.parseInt(trimmedInput); + if (tryCount <= 0) { + throw new IllegalArgumentException("try count must be > 0"); + } + return tryCount; + } + + private static void printExecutionHeader() { + System.out.println(); + System.out.println("실행 결과"); + } + + private static void runRounds(List cars, int tryCount) { + for (int round = 0; round < tryCount; round++) { + for (Car car : cars) { + int pick = Randoms.pickNumberInRange(0, 9); + if (pick >= MOVE_THRESHOLD) { + car.move(); + } + } + printRound(cars); + } + } + + private static void printRound(List cars) { + for (Car car : cars) { + System.out.println(car.getName() + " : " + "-".repeat(car.getPosition())); + } + System.out.println(); + } + + private static void printWinners(List cars) { + int max = cars.stream() + .mapToInt(Car::getPosition) + .max() + .orElse(0); + + String winners = cars.stream() + .filter(c -> c.getPosition() == max) + .map(Car::getName) + .collect(Collectors.joining(", ")); + + System.out.println("최종 우승자 : " + winners); } } diff --git a/src/main/java/racingcar/Car.java b/src/main/java/racingcar/Car.java new file mode 100644 index 0000000000..933e76f7fd --- /dev/null +++ b/src/main/java/racingcar/Car.java @@ -0,0 +1,22 @@ +package racingcar; + +final class Car { + private final String name; + private int position = 0; + + Car(String name) { + this.name = name; + } + + void move() { + position += 1; + } + + String getName() { + return name; + } + + int getPosition() { + return position; + } +}