From aff0ad1fde14e3b10a7bac3457e79f0f90079a41 Mon Sep 17 00:00:00 2001 From: Yerin_Kim Date: Mon, 27 Oct 2025 19:39:50 +0900 Subject: [PATCH 1/5] =?UTF-8?q?docs:=20README.md=EC=97=90=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=B0=A8=20=EA=B2=BD=EC=A3=BC=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 From 465294a4c112ece80c1614141e17b81b564a468f Mon Sep 17 00:00:00 2001 From: Yerin_Kim Date: Mon, 27 Oct 2025 19:47:02 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EC=B0=A8=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EC=9E=85=EB=A0=A5,=20=EB=B6=84=EB=A6=AC?= =?UTF-8?q?=20=EB=B0=8F=205=EC=9E=90=20=EC=9D=B4=ED=95=98=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=A6=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 32 ++++++++++++++++++++++++++++++-- src/Car.js | 25 +++++++++++++++++++++++++ src/RacingGame.js | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 src/Car.js create mode 100644 src/RacingGame.js 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..88621fef --- /dev/null +++ b/src/Car.js @@ -0,0 +1,25 @@ +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; + } + // 이어서 전진 로직(2.3)이 들어갈 메서드 + move() { + // ... + } + + // 이어서 출력 로직(2.4)이 들어갈 메서드 + 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..3a9b3d02 --- /dev/null +++ b/src/RacingGame.js @@ -0,0 +1,40 @@ +// src/RacingGame.js + +import { Random } from "@woowacourse/mission-utils"; +import Car from "./Car.js"; + +class RacingGame { + constructor() { + this.cars = []; + this.attempts = 0; + } + + // 1.1, 1.2번 기능이 들어갈 메서드 + setCars(carNamesInput) { + const names = carNamesInput.split(','); + + if (names.some(name => name.length === 0)) { + throw new Error("[ERROR] 자동차 이름은 공백일 수 없습니다."); + } + + // 1.3번 검증은 Car 생성자에서 처리됨 + this.cars = names.map(name => new Car(name.trim())); + } + + // 1.4번 기능이 들어갈 메서드 + setAttempts(attemptsInput) { + // ... + } + + // 2.1번 기능이 들어갈 메서드 + startRace() { + // ... + } + + // 3.1~3.5번 기능이 들어갈 메서드 + getWinners() { + // ... + } +} + +export default RacingGame; \ No newline at end of file From 7349fb6f5d1c79a8b81c8b3d4da95bd03a902313 Mon Sep 17 00:00:00 2001 From: Yerin_Kim Date: Mon, 27 Oct 2025 19:49:40 +0900 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20=EC=8B=9C=EB=8F=84=20=ED=9A=9F?= =?UTF-8?q?=EC=88=98=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=EC=84=B1=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/RacingGame.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/RacingGame.js b/src/RacingGame.js index 3a9b3d02..06c93be3 100644 --- a/src/RacingGame.js +++ b/src/RacingGame.js @@ -9,7 +9,7 @@ class RacingGame { this.attempts = 0; } - // 1.1, 1.2번 기능이 들어갈 메서드 + // 1, 2번 기능이 들어갈 메서드 setCars(carNamesInput) { const names = carNamesInput.split(','); @@ -17,21 +17,31 @@ class RacingGame { throw new Error("[ERROR] 자동차 이름은 공백일 수 없습니다."); } - // 1.3번 검증은 Car 생성자에서 처리됨 + // 3번 검증은 Car 생성자에서 처리됨 this.cars = names.map(name => new Car(name.trim())); } - // 1.4번 기능이 들어갈 메서드 + // 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; } - // 2.1번 기능이 들어갈 메서드 + // 5번 기능이 들어갈 메서드 startRace() { // ... } - // 3.1~3.5번 기능이 들어갈 메서드 + // 6번 기능이 들어갈 메서드 getWinners() { // ... } From a031f2c5013560bae3c65b876973df68ef486a8e Mon Sep 17 00:00:00 2001 From: Yerin_Kim Date: Mon, 27 Oct 2025 19:52:23 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20=EB=9D=BC=EC=9A=B4=EB=93=9C=20?= =?UTF-8?q?=EB=B0=98=EB=B3=B5,=20=EC=A0=84=EC=A7=84=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EB=B0=8F=20=EC=B0=A8=EC=88=98=EB=B3=84=20=EC=8B=A4=ED=96=89?= =?UTF-8?q?=20=EA=B2=B0=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Car.js | 11 ++++++++--- src/RacingGame.js | 18 +++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/Car.js b/src/Car.js index 88621fef..b99cefac 100644 --- a/src/Car.js +++ b/src/Car.js @@ -11,12 +11,17 @@ class Car { this.name = name; this.position = 0; } - // 이어서 전진 로직(2.3)이 들어갈 메서드 + // 이어서 전진 로직(9)이 들어갈 메서드 move() { - // ... + // MissionUtils.Random.pickNumberInRange(0, 9)를 사용한다고 가정 + const randomNumber = MissionUtils.Random.pickNumberInRange(0, 9); + + if (randomNumber >= 4) { + this.position += 1; // 9번: 4 이상일 경우 전진 + } } - // 이어서 출력 로직(2.4)이 들어갈 메서드 + // 이어서 출력 로직(10)이 들어갈 메서드 getDisplay() { return `${this.name} : ${'-'.repeat(this.position)}`; } diff --git a/src/RacingGame.js b/src/RacingGame.js index 06c93be3..a7ba2dd3 100644 --- a/src/RacingGame.js +++ b/src/RacingGame.js @@ -38,7 +38,23 @@ class RacingGame { // 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번: 차수별 실행 사이에 빈 줄 출력 } // 6번 기능이 들어갈 메서드 From 8033c0cceffc4178e0a2d9cf4af5947ec6bead9c Mon Sep 17 00:00:00 2001 From: Yerin_Kim Date: Mon, 27 Oct 2025 19:56:40 +0900 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=EC=B5=9C=EC=A2=85=20=EC=9A=B0?= =?UTF-8?q?=EC=8A=B9=EC=9E=90=20=EA=B2=B0=EC=A0=95=20=EB=B0=8F=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/RacingGame.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/RacingGame.js b/src/RacingGame.js index a7ba2dd3..4cd19b8f 100644 --- a/src/RacingGame.js +++ b/src/RacingGame.js @@ -57,9 +57,19 @@ class RacingGame { Console.print(""); // 11번: 차수별 실행 사이에 빈 줄 출력 } - // 6번 기능이 들어갈 메서드 + // 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); } }