diff --git a/README.md b/README.md index e078fd41..556f4456 100644 --- a/README.md +++ b/README.md @@ -1 +1,19 @@ # javascript-racingcar-precourse +1. 경주할 자동차 이름을 입력받는다. +2. 자동차 이름은 쉼표(,)를 기준으로 분리 +3. 자동차 이름은 5자 이하인지 검증한다.(초과 시 Error) +4. 시도할 횟수를 입력받는다. +5. 시도할 횟수가 유효한 숫자인지 검증한다.(숫자 아님/음수/0등이 적힐 경우 Error) +6. 사용자가 잘못된 값을 입력할 경우 [Error] 메시지와 함께 Error를 발생시킨다. + +7. 주어진 횟수만큼 게임을 반복 실행한다. +8. 자동차별로 0에서 9사이의 무작위 값을 구한다. +9. 무작위 값이 4 이상일 경우 해당 자동차는 전진한다. +10. 각 차수별 실행 결과를 자동차 이름과 전진거리(-)로 출력한다. +11. 매 차수 실행 사이에 빈 줄을 출력하여 구분한다. + +12. 경주 게임 완료 후 가장 많이 전진한 거리를 계산한다. +13. 최대 전진 거리를 가진 자동차들을 우승자로 선정한다. +14. 우승자가 한 명일 경우 우승자 이름을 출력한다. +15. 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분하여 출력한다. +16. 최종 결과를 "최종 우승자:[이름]" 형식으로 출력한다. \ No newline at end of file diff --git a/src/App.js b/src/App.js index 091aa0a5..8cc84c5e 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,33 @@ +import { Console } from "@woowacourse/mission-utils"; +import RacingGame from "./RacingGame.js"; // RacingGame 가져오기 + class App { - async run() {} + async run() { + const game = new RacingGame(); + + try { + // 1.1, 1.4번 기능을 위해 사용자 입력 받기 + const carNames = await Console.readLineAsync("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)\n"); + game.setCars(carNames); + + const attemptsInput = await Console.readLineAsync("시도할 횟수는 몇 회인가요?\n"); + game.setAttempts(attemptsInput); + + // 2.4번 기능: 실행 결과 헤더 출력 + Console.print("\n실행 결과"); + + // 2.1번 기능: 경주 시작 + game.startRace(); + + // 3.1~3.5번 기능: 우승자 출력 + const winners = game.getWinners(); + Console.print(`최종 우승자 : ${winners.join(', ')}`); + + } catch (error) { + // 1.6번 기능: [ERROR] 출력 후 종료 + Console.print(error.message); + } + } } -export default App; +export default App; \ No newline at end of file diff --git a/src/Car.js b/src/Car.js new file mode 100644 index 00000000..b99cefac --- /dev/null +++ b/src/Car.js @@ -0,0 +1,30 @@ +class Car { + constructor(name) { + // 1.3번 기능 구현: 자동차 이름 5자 이하 검증 + if (name.length > 5) { + throw new Error("[ERROR] 자동차 이름은 5자 이하만 가능합니다."); + } + if (name.length === 0) { + throw new Error("[ERROR] 자동차 이름은 공백일 수 없습니다."); + } + + this.name = name; + this.position = 0; + } + // 이어서 전진 로직(9)이 들어갈 메서드 + move() { + // MissionUtils.Random.pickNumberInRange(0, 9)를 사용한다고 가정 + const randomNumber = MissionUtils.Random.pickNumberInRange(0, 9); + + if (randomNumber >= 4) { + this.position += 1; // 9번: 4 이상일 경우 전진 + } + } + + // 이어서 출력 로직(10)이 들어갈 메서드 + getDisplay() { + return `${this.name} : ${'-'.repeat(this.position)}`; + } +} + +export default Car; \ No newline at end of file diff --git a/src/RacingGame.js b/src/RacingGame.js new file mode 100644 index 00000000..4cd19b8f --- /dev/null +++ b/src/RacingGame.js @@ -0,0 +1,76 @@ +// src/RacingGame.js + +import { Random } from "@woowacourse/mission-utils"; +import Car from "./Car.js"; + +class RacingGame { + constructor() { + this.cars = []; + this.attempts = 0; + } + + // 1, 2번 기능이 들어갈 메서드 + setCars(carNamesInput) { + const names = carNamesInput.split(','); + + if (names.some(name => name.length === 0)) { + throw new Error("[ERROR] 자동차 이름은 공백일 수 없습니다."); + } + + // 3번 검증은 Car 생성자에서 처리됨 + this.cars = names.map(name => new Car(name.trim())); + } + + // 4번 기능이 들어갈 메서드 + setAttempts(attemptsInput) { + const attempts = parseInt(attemptsInput.trim(), 10); + + // 5번 기능: 유효한 숫자인지 검증 + if (isNaN(attempts)) { + throw new Error("[ERROR] 시도 횟수는 숫자여야 합니다."); + } + if (attempts <= 0) { + throw new Error("[ERROR] 시도 횟수는 1회 이상이어야 합니다."); + } + + this.attempts = attempts; + } + + // 5번 기능이 들어갈 메서드 + startRace() { + for (let i = 0; i < this.attempts; i++) { + this.playRound(); + this.printRoundResult(); + } + } + // 라운드 처리 로직 분리 (인덴트 깊이 2를 넘지 않도록) + playRound() { + this.cars.forEach(car => car.move()); + } + + // 10, 11번 기능 구현: 라운드별 결과 출력 + printRoundResult() { + this.cars.forEach(car => { + // car.getDisplay()는 Car.js에 구현되어 있습니다. + Console.print(car.getDisplay()); + }); + Console.print(""); // 11번: 차수별 실행 사이에 빈 줄 출력 + } + + // 12번 ~ 15번 기능 구현: 우승자 결정 및 반환 + getWinners() { + // 12. 경주 게임 완료 후 가장 많이 전진한 거리를 계산한다. + const maxPosition = this.cars.reduce((max, car) => { + // car.position은 Car 클래스에 저장된 전진 거리 + return Math.max(max, car.position); + }, 0); // 초기 최대 거리는 0 + + // 13. 최대 전진 거리를 가진 자동차들을 우승자로 선정한다. + const winners = this.cars.filter(car => car.position === maxPosition); + + // 14. 15. 우승자 이름만 추출 (한 명이든 여러 명이든 쉼표로 구분할 이름 리스트 준비) + return winners.map(car => car.name); + } +} + +export default RacingGame; \ No newline at end of file