diff --git a/README.md b/README.md index e078fd41f..97f2407fb 100644 --- a/README.md +++ b/README.md @@ -1 +1,134 @@ -# javascript-racingcar-precourse +# πŸš— μžλ™μ°¨ κ²½μ£Ό + +## κΈ°λŠ₯ λͺ©λ‘ + +- μžλ™μ°¨ 이름을 λ°›μ•„μ˜€λŠ” ν•¨μˆ˜ + - ν”Œλ ˆμ΄μ–΄λ“€μ„ μ‰Όν‘œλ₯Ό κΈ°μ€€μœΌλ‘œ λ‚˜λˆ„μ–΄ 각 ν”Œλ ˆμ΄μ–΄ 이름이 5자 초과일 경우 error 좜λ ₯ +- 이동 횟수λ₯Ό λ°›μ•„μ˜€λŠ” ν•¨μˆ˜ + - μŒμˆ˜λ‚˜ μˆ«μžκ°€ μ•„λ‹Œ 경우 error +- μžλ™μ°¨ κ²½μ£Ό μ°¨μˆ˜λ³„ μ‹€ν–‰ κ²°κ³Ό 좜λ ₯ ν•¨μˆ˜ + - ν”Œλ ˆμ΄μ–΄λ§ˆλ‹€ 랜덀숫자λ₯Ό 돌렀 랜덀 μˆ«μžκ°€ 3 초과일 경우 μ•žμœΌλ‘œ ν•œμΉΈ μ „μ§„ +- λ ˆμ΄μ‹± κ²°κ³Όλ₯Ό 좜λ ₯ν•˜λŠ” ν•¨μˆ˜ + - ν”Œλ ˆμ΄μ–΄ 이름과 "-"둜 μ „μ§„ 갯수 좜λ ₯ +- 승자 좜λ ₯ ν•¨μˆ˜ + - μ΅œμ’… 우승자의 이름(λ“€)을 좜λ ₯ + +## κΈ°λŠ₯ μš”κ΅¬ 사항 + +μ΄ˆκ°„λ‹¨ μžλ™μ°¨ κ²½μ£Ό κ²Œμž„μ„ κ΅¬ν˜„ν•œλ‹€. + +- μ£Όμ–΄μ§„ 횟수 λ™μ•ˆ nλŒ€μ˜ μžλ™μ°¨λŠ” μ „μ§„ λ˜λŠ” 멈좜 수 μžˆλ‹€. +- 각 μžλ™μ°¨μ— 이름을 λΆ€μ—¬ν•  수 μžˆλ‹€. μ „μ§„ν•˜λŠ” μžλ™μ°¨λ₯Ό 좜λ ₯ν•  λ•Œ μžλ™μ°¨ 이름을 같이 좜λ ₯ν•œλ‹€. +- μžλ™μ°¨ 이름은 μ‰Όν‘œ(,)λ₯Ό κΈ°μ€€μœΌλ‘œ κ΅¬λΆ„ν•˜λ©° 이름은 5자 μ΄ν•˜λ§Œ κ°€λŠ₯ν•˜λ‹€. +- μ‚¬μš©μžλŠ” λͺ‡ 번의 이동을 ν•  것인지λ₯Ό μž…λ ₯ν•  수 μžˆμ–΄μ•Ό ν•œλ‹€. +- μ „μ§„ν•˜λŠ” 쑰건은 0μ—μ„œ 9 μ‚¬μ΄μ—μ„œ λ¬΄μž‘μœ„ 값을 κ΅¬ν•œ ν›„ λ¬΄μž‘μœ„ 값이 4 이상일 κ²½μš°μ΄λ‹€. +- μžλ™μ°¨ κ²½μ£Ό κ²Œμž„μ„ μ™„λ£Œν•œ ν›„ λˆ„κ°€ μš°μŠΉν–ˆλŠ”μ§€λ₯Ό μ•Œλ €μ€€λ‹€. μš°μŠΉμžλŠ” ν•œ λͺ… 이상일 수 μžˆλ‹€. +- μš°μŠΉμžκ°€ μ—¬λŸ¬ λͺ…일 경우 μ‰Όν‘œ(,)λ₯Ό μ΄μš©ν•˜μ—¬ κ΅¬λΆ„ν•œλ‹€. +- μ‚¬μš©μžκ°€ 잘λͺ»λœ 값을 μž…λ ₯ν•  경우 "[ERROR]"둜 μ‹œμž‘ν•˜λŠ” λ©”μ‹œμ§€μ™€ ν•¨κ»˜ Errorλ₯Ό λ°œμƒμ‹œν‚¨ ν›„ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ μ’…λ£Œλ˜μ–΄μ•Ό ν•œλ‹€. + +### μž…μΆœλ ₯ μš”κ΅¬ 사항 + +μž…λ ₯ + +- κ²½μ£Όν•  μžλ™μ°¨ 이름(이름은 μ‰Όν‘œ(,) κΈ°μ€€μœΌλ‘œ ꡬ뢄) + +``` +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 +``` + +## ν”„λ‘œκ·Έλž˜λ° μš”κ΅¬ 사항 1 + +- Node.js 20.17.0 λ²„μ „μ—μ„œ μ‹€ν–‰ κ°€λŠ₯ν•΄μ•Ό ν•œλ‹€. +- ν”„λ‘œκ·Έλž¨ μ‹€ν–‰μ˜ μ‹œμž‘μ μ€ App.js의 run()이닀. +- package.json νŒŒμΌμ€ λ³€κ²½ν•  수 μ—†μœΌλ©°, 제곡된 λΌμ΄λΈŒλŸ¬λ¦¬μ™€ μŠ€νƒ€μΌ 라이브러리 μ΄μ™Έμ˜ μ™ΈλΆ€ λΌμ΄λΈŒλŸ¬λ¦¬λŠ” μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€. +- ν”„λ‘œκ·Έλž¨ μ’…λ£Œ μ‹œ process.exit()λ₯Ό ν˜ΈμΆœν•˜μ§€ μ•ŠλŠ”λ‹€. +- ν”„λ‘œκ·Έλž˜λ° μš”κ΅¬ μ‚¬ν•­μ—μ„œ 달리 λͺ…μ‹œν•˜μ§€ μ•ŠλŠ” ν•œ 파일, νŒ¨ν‚€μ§€ λ“±μ˜ 이름을 λ°”κΎΈκ±°λ‚˜ μ΄λ™ν•˜μ§€ μ•ŠλŠ”λ‹€. +- μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œ μ»¨λ²€μ…˜μ„ μ§€ν‚€λ©΄μ„œ ν”„λ‘œκ·Έλž˜λ°ν•œλ‹€. + - 기본적으둜 JavaScript Style Guideλ₯Ό μ›μΉ™μœΌλ‘œ ν•œλ‹€. + +## ν”„λ‘œκ·Έλž˜λ° μš”κ΅¬ 사항 2 + +- indent(인덴트, λ“€μ—¬μ“°κΈ°) depthλ₯Ό 3이 λ„˜μ§€ μ•Šλ„λ‘ κ΅¬ν˜„ν•œλ‹€. 2κΉŒμ§€λ§Œ ν—ˆμš©ν•œλ‹€. + - 예λ₯Ό λ“€μ–΄ whileλ¬Έ μ•ˆμ— if문이 있으면 λ“€μ—¬μ“°κΈ°λŠ” 2이닀. + - 힌트: indent(인덴트, λ“€μ—¬μ“°κΈ°) depthλ₯Ό μ€„μ΄λŠ” 쒋은 방법은 ν•¨μˆ˜(λ˜λŠ” λ©”μ„œλ“œ)λ₯Ό λΆ„λ¦¬ν•˜λ©΄ λœλ‹€. +- 3ν•­ μ—°μ‚°μžλ₯Ό μ“°μ§€ μ•ŠλŠ”λ‹€. +- ν•¨μˆ˜(λ˜λŠ” λ©”μ„œλ“œ)κ°€ ν•œ κ°€μ§€ 일만 ν•˜λ„λ‘ μ΅œλŒ€ν•œ μž‘κ²Œ λ§Œλ“€μ–΄λΌ. +- Jestλ₯Ό μ΄μš©ν•˜μ—¬ μ •λ¦¬ν•œ κΈ°λŠ₯ λͺ©λ‘μ΄ μ •μƒμ μœΌλ‘œ μž‘λ™ν•˜λŠ”μ§€ ν…ŒμŠ€νŠΈ μ½”λ“œλ‘œ ν™•μΈν•œλ‹€. + - ν…ŒμŠ€νŠΈ 도ꡬ μ‚¬μš©λ²•μ΄ μ΅μˆ™ν•˜μ§€ μ•Šλ‹€λ©΄ μ•„λž˜ λ¬Έμ„œλ₯Ό μ°Έκ³ ν•˜μ—¬ ν•™μŠ΅ν•œ ν›„ ν…ŒμŠ€νŠΈλ₯Ό κ΅¬ν˜„ν•œλ‹€. + - Using Matchers + - Testing Asynchronous Code + - Jest둜 νŒŒλΌλ―Έν„°ν™” ν…ŒμŠ€νŠΈν•˜κΈ°: test.each(), describe.each() + +### 라이브러리 + +- @woowacourse/mission-utilsμ—μ„œ μ œκ³΅ν•˜λŠ” Random 및 Console APIλ₯Ό μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•΄μ•Ό ν•œλ‹€. + - Random κ°’ μΆ”μΆœμ€ Random.pickNumberInRange()λ₯Ό ν™œμš©ν•œλ‹€. + - μ‚¬μš©μžμ˜ 값을 μž…λ ₯ 및 좜λ ₯ν•˜λ €λ©΄ Console.readLineAsync()와 Console.print()λ₯Ό ν™œμš©ν•œλ‹€. + +**μ‚¬μš© μ˜ˆμ‹œ** + +- 0μ—μ„œ 9κΉŒμ§€μ˜ μ •μˆ˜ 쀑 ν•œ 개의 μ •μˆ˜ λ°˜ν™˜ + +``` +MissionUtils.Random.pickNumberInRange(0, 9); +``` diff --git a/src/App.js b/src/App.js index 091aa0a5d..863181c9c 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,70 @@ +import { MissionUtils } from '@woowacourse/mission-utils'; class App { - async run() {} + async run() { + try { + const carNames = await this.getCarNames(); + const attempts = await this.getAttempts(); + this.racing(carNames, attempts); + } catch (error) { + MissionUtils.Console.print(error.message); + } + } + + async getCarNames() { + const carNamesInput = await MissionUtils.Console.readLineAsync( + 'κ²½μ£Όν•  μžλ™μ°¨ 이름을 μž…λ ₯ν•˜μ„Έμš”.(이름은 μ‰Όν‘œ(,) κΈ°μ€€μœΌλ‘œ ꡬ뢄)\n' + ); + const carNameArray = carNamesInput.split(','); + carNameArray.forEach((name) => { + if (name.length > 5) { + throw new Error('[ERROR] 이름은 5자 μ΄ν•˜λ§Œ κ°€λŠ₯ν•©λ‹ˆλ‹€.'); + } + }); + + return carNameArray; + } + async getAttempts() { + const attemptInput = await MissionUtils.Console.readLineAsync( + 'μ‹œλ„ν•  νšŸμˆ˜λŠ” λͺ‡ νšŒμΈκ°€μš”?\n' + ); + + const attemptNum = parseInt(attemptInput); + if (isNaN(attemptNum) || attemptNum <= 0) { + throw new Error('[ERROR] μ‹œλ„ νšŸμˆ˜λŠ” μ–‘μˆ˜λ§Œ κ°€λŠ₯ν•©λ‹ˆλ‹€.'); + } + return attemptNum; + } + + racing(carNames, attempts) { + const cars = carNames.map((name) => ({ name, go: 0 })); + + for (let i = 0; i < attempts; i++) { + cars.forEach((car) => { + const randomNum = MissionUtils.Random.pickNumberInRange(0, 9); + if (randomNum > 3) { + car.go++; + } + }); + this.displayRaceProgress(cars); + } + this.displayWinners(cars); + } + + displayRaceProgress(cars) { + cars.forEach((car) => { + MissionUtils.Console.print(`${car.name} : ${'-'.repeat(car.go)}`); + }); + MissionUtils.Console.print(''); + } + + displayWinners(cars) { + const maxGo = Math.max(...cars.map((car) => car.go)); + const winners = cars + .filter((car) => car.go === maxGo) + .map((car) => car.name); + + MissionUtils.Console.print(`μ΅œμ’… 우승자 : ${winners.join(', ')}`); + } } export default App;