diff --git a/README.md b/README.md index d0286c859f..d37415cb8e 100644 --- a/README.md +++ b/README.md @@ -1 +1,84 @@ # java-racingcar-precourse + +## 자동차 경주 + +초간단 자동차 경주 게임을 구현한다. + +* 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. +* 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. +* 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다. +* 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. +* 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우이다. +* 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. +* 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다. +* 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션은 종료되어야 한다. + +* camp.nextstep.edu.missionutils에서 제공하는 Randoms 및 Console API를 사용하여 구현해야 한다. + * Random 값 추출은 camp.nextstep.edu.missionutils.Randoms의 pickNumberInRange()를 활용한다. + * 사용자가 입력하는 값은 camp.nextstep.edu.missionutils.Console의 readLine()을 활용한다. + + **사용 예시** + ``` + 0에서 9까지의 정수 중 한 개의 정수 반환 + Randoms.pickNumberInRange(0, 9); + ``` + + + +### 입출력 요구 사항 + +**입력** + +* 경주할 자동차 이름(이름은 쉼표(,) 기준으로 구분) +``` +pobi,woni,jun +``` + +* 시도할 횟수 +``` +5 +``` + +**출력** + +* 차수별 실행 결과 +``` +pobi : -- +woni : ---- +jun : --- +``` + +* 단독 우승자 안내 문구 +``` +최종 우승자 : pobi +``` + +* 공동 우승자 안내 문구 +``` +최종 우승자 : pobi, jun +``` + +* 실행 결과 예시 +``` +경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분) +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..97d0bb02aa 100644 --- a/src/main/java/racingcar/Application.java +++ b/src/main/java/racingcar/Application.java @@ -1,7 +1,122 @@ package racingcar; +import camp.nextstep.edu.missionutils.Console; +import camp.nextstep.edu.missionutils.Randoms; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + try { + // 자동차 이름 입력 + List carNames = getCarNames(); + // 시도 횟수 입력 + int attempts = getAttempts(); + // 입력 값 기준으로 게임 초기 세팅 + Map carPositions = initializeCarPositions(carNames); + + // 경주 게임 시작 + runRace(carNames, carPositions, attempts); + // 우승자 안내 문구 출력 + announceWinners(carNames, carPositions); + + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + + + } + + // 자동차 이름 입력 + // 입력 값 검사 + private static void validateCarNames(String input) { + if (!input.matches("([가-힣\\w-_.]{1,5})(,[가-힣\\w-_.]{1,5})*")) { + throw new IllegalArgumentException("잘못된 입력입니다."); + } + } + + private static List getCarNames() { + System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + + String input = Console.readLine(); + + // 정규 표현식 검사 + validateCarNames(input); // 검사 메서드 호출 + + String[] nameArray = input.split(","); + return new ArrayList<>(List.of(nameArray)); // 배열을 리스트로 변환 + } + + + // 시도 횟수 입력 + private static int getAttempts() { + System.out.println("시도할 횟수는 몇 회인가요?"); + String input = Console.readLine(); + return validateAttempts(input); + } + + private static int validateAttempts(String input) { + try { + int attempts = Integer.parseInt(input); + if (attempts <= 0) { + throw new IllegalArgumentException("시도 횟수는 1 이상의 정수여야 합니다."); + } + return attempts; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("잘못된 입력입니다."); + } + } + + // 입력 값 기준으로 게임 초기 세팅 + private static Map initializeCarPositions(List names) { + Map carPositions = new HashMap<>(); + for (String name : names) { + carPositions.put(name, 0); + } + return carPositions; + } + + + // 경주 게임 시작 + private static void runRace(List names, Map carPositions, int attempts) { + for (int i = 0; i < attempts; i++) { + // 각 자동차에 대해 이동 여부 결정 + for (String name : names) { + int picked = Randoms.pickNumberInRange(0, 9); + if (picked >= 4) { + // 이동 거리를 1 증가 + carPositions.put(name, carPositions.get(name) + 1); + } + } + + // 차수별 실행 결과 출력 + printPositions(names, carPositions); + } + } + + // 차수별 실행 결과 출력 + private static void printPositions(List names, Map carPositions) { + for (String name : names) { + int position = carPositions.get(name); + System.out.print(name + " : "); + System.out.println("-".repeat(position)); + } + System.out.println(); + } + + + // 우승자 안내 문구 출력 + private static void announceWinners(List names, Map carPositions) { + int maxPosition = carPositions.values().stream().max(Integer::compare).orElse(0); + StringBuilder winners = new StringBuilder(); + for (String name : names) { + if (carPositions.get(name) == maxPosition) { + winners.append(name).append(", "); + } + } + + System.out.println("최종 우승자 : " + winners.substring(0, winners.length() - 2)); } } diff --git a/src/test/java/racingcar/ApplicationTest.java b/src/test/java/racingcar/ApplicationTest.java index 1d35fc33fe..875423f605 100644 --- a/src/test/java/racingcar/ApplicationTest.java +++ b/src/test/java/racingcar/ApplicationTest.java @@ -31,6 +31,13 @@ class ApplicationTest extends NsTest { ); } + @Test + void 자동차_이름_길이_초과_예외_테스트() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("pobi,javajii", "1")) + .isInstanceOf(IllegalArgumentException.class) + ); + } @Override public void runMain() { Application.main(new String[]{});