Skip to content
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
```
117 changes: 116 additions & 1 deletion src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
@@ -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<String> carNames = getCarNames();
// 시도 횟수 입력
int attempts = getAttempts();
// 입력 값 기준으로 게임 초기 세팅
Map<String, Integer> 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<String> 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<String, Integer> initializeCarPositions(List<String> names) {
Map<String, Integer> carPositions = new HashMap<>();
for (String name : names) {
carPositions.put(name, 0);
}
return carPositions;
}


// 경주 게임 시작
private static void runRace(List<String> names, Map<String, Integer> 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<String> names, Map<String, Integer> 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<String> names, Map<String, Integer> 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));
}
}
7 changes: 7 additions & 0 deletions src/test/java/racingcar/ApplicationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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[]{});
Expand Down