diff --git a/README.md b/README.md index e078fd41..8158264c 100644 --- a/README.md +++ b/README.md @@ -1 +1,32 @@ -# javascript-racingcar-precourse +# πŸš— + +## μžλ™μ°¨ κ²½μ£Ό κΈ°λŠ₯ κ΅¬ν˜„ λͺ©λ‘ + +### 1. κΈ°λ³Έ μž…μΆœλ ₯ +- μžλ™μ°¨ 이름 μž…λ ₯용 μ•ˆλ‚΄λ¬Έ 좜λ ₯ +- μžλ™μ°¨ 이름 μž…λ ₯ λ°›κΈ° +- μ‹œλ„ 횟수 μž…λ ₯용 μ•ˆλ‚΄λ¬Έ 좜λ ₯ +- μ‹œλ„ν•  횟수 μž…λ ₯ λ°›κΈ° + +### 2. 데이터 처리 및 validation +- μžλ™μ°¨ 이름 뢄리(,) / λ°°μ—΄ 생성 +- μžλ™μ°¨ 이름 validation (5자 μ΄ν•˜) +- μ‹œλ„ 횟수 validation (NaN) + +### 3. μˆ˜ν–‰ 둜직 +- μžλ™μ°¨ 객체 생성 (이름, ν¬μ§€μ…˜) +- λΌμš΄λ“œ μ§„ν–‰ 둜직 κ΅¬ν˜„ (μ‹œλ„ 횟수 만큼 반볡) + - μ „μ§„/멈좀 둜직 κ΅¬ν˜„ + - mission-utils ν™œμš© λ¬΄μž‘μœ„ κ°’ 생성 + - 4 이상일 경우 μ „μ§„ + +### 4. 좜λ ₯ +- Console.print μ‚¬μš©ν•˜μ—¬ λΌμš΄λ“œλ³„ μ‹€ν–‰ κ²°κ³Ό 좜λ ₯ +- μžλ™μ°¨ 객체 쀑 κ°€μž₯ 높은 μ „μ§„ 횟수λ₯Ό κ°€μ§„ 객체 μ„ μ • (곡동 우승 κ°€λŠ₯) +- 우승자 좜λ ₯ + +### 5. μ‹€ν–‰ +- Jest ν™œμš© ν…ŒμŠ€νŠΈ μ½”λ“œ μ§„ν–‰ +- μ˜ˆμ™Έ 처리 +- 였λ₯˜ 문제 ν•΄κ²° + diff --git a/package-lock.json b/package-lock.json index 7159bf0c..e08a7f1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -2969,6 +2970,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001669", "electron-to-chromium": "^1.5.41", diff --git a/src/App.js b/src/App.js index 091aa0a5..50c7f5e6 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,114 @@ +import * as MissionUtils from '@woowacourse/mission-utils'; +import Car from './Car.js'; + + class App { - async run() {} + async run() { + + const carNamesInput = await this.getCarNames(); + const carNames = this.parseAndValidateCarNames(carNamesInput) + + const tryCountInput = await this.getTryCount(); + const tryCount = this.parseAndValidateTryCount(tryCountInput); + + const cars = carNames.map((name) => new Car(name)); + + this.#runRace(cars, tryCount); + + const winnerNames = this.#findWinners(cars); + this.#printWinners(winnerNames); + + } + + async getCarNames() { + const input = await MissionUtils.Console.readLineAsync( + "κ²½μ£Όν•  μžλ™μ°¨ 이름을 μž…λ ₯ν•˜μ„Έμš”.(이름은 μ‰Όν‘œ(,) κΈ°μ€€μœΌλ‘œ ꡬ뢄)" + ); + return input; + } + + async getTryCount() { + const input = await MissionUtils.Console.readLineAsync( + "μ‹œλ„ν•  νšŒμˆ˜λŠ” λͺ‡νšŒμΈκ°€μš”?" + ); + return input; + } + + parseAndValidateCarNames(input) { + + const names = input.split(",").map((name) => name.trim()); + + + if (names.some((name) => name.length > 5)) { + throw new Error("[ERROR] μžλ™μ°¨ 이름은 5자 μ΄ν•˜λ§Œ κ°€λŠ₯ν•©λ‹ˆλ‹€."); + } + + + if (names.some((name) => name.length === 0)) { + throw new Error("[ERROR] μžλ™μ°¨ 이름은 곡백일 수 μ—†μŠ΅λ‹ˆλ‹€."); + } + + + const uniqueNames = new Set(names); + if (uniqueNames.size !== names.length) { + throw new Error("[ERROR] μžλ™μ°¨ 이름은 쀑볡될 수 μ—†μŠ΅λ‹ˆλ‹€."); + } + + return names; + } + + parseAndValidateTryCount(input) { + const count = Number(input); + + if (isNaN(count)) { + throw new Error("[ERROR] μ‹œλ„ νšŸμˆ˜λŠ” μˆ«μžμ—¬μ•Ό ν•©λ‹ˆλ‹€."); + } + + return count; + + } + + #runRace(cars, tryCount) { + MissionUtils.Console.print("\nμ‹€ν–‰ κ²°κ³Ό"); + + for (let i = 0; i < tryCount; i++) { + + for (const car of cars) { + car.move(); + } + + + this.#printRoundResult(cars); + + MissionUtils.Console.print(""); + } + } + + #printRoundResult(cars) { + cars.forEach((car) => { + const positionsString = '-'.repeat(car.getPosition()); + + MissionUtils.Console.print( + `${car.getName()} : ${positionsString}` + ); + }); + }; + + #findWinners(cars) { + const positions = cars.map((car) => car.getPosition()); + const maxPosition = Math.max(...positions); + const winners = cars.filter( + (car) => car.getPosition() === maxPosition + ); + return winners.map((winner) => winner.getName()); + } + + #printWinners(winnerNames) { + const nameString = winnerNames.join(', '); + MissionUtils.Console.print( + `μ΅œμ’… 우승자 : ${nameString}` + ); + } } export default App; diff --git a/src/Car.js b/src/Car.js new file mode 100644 index 00000000..0dd1a11b --- /dev/null +++ b/src/Car.js @@ -0,0 +1,32 @@ +//constructor(#name)으둜 이름을 λ°›κ³  position = 0 으둜 μ΄ˆκΈ°ν™” +//Appμ—μ„œ car.move둜 λͺ…λ Ή λ°›μœΌλ©΄ Carμ—μ„œ 슀슀둜 랜덀 κ°’ λ½‘μ•„μ„œ position 증가 + +import { MissionUtils } from "@woowacourse/mission-utils"; + +class Car { + #name; + #position; + + constructor(name) { + this.#name = name; + this.#position = 0; + } + + move() { + const randomNumber = MissionUtils.Random.pickNumberInRange(0,9); + + if (randomNumber >= 4) { + this.#position += 1; + } + } + + getName() { + return this.#name; + } + + getPosition() { + return this.#position; + } +} + +export default Car; \ No newline at end of file diff --git a/src/index.js b/src/index.js index 02a1d389..fcc548cd 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,14 @@ +import { MissionUtils } from "@woowacourse/mission-utils"; import App from "./App.js"; -const app = new App(); -await app.run(); +class Main { + async run() { + const app = new App(); + await app.run(); + } catch (error) { + MissionUtils.Console.print(error.message); + } +} + +const main = new Main(); +main.run(); \ No newline at end of file