diff --git a/README.md b/README.md index 15bb106b5..c1c1b3d37 100644 --- a/README.md +++ b/README.md @@ -1 +1,66 @@ # javascript-lotto-precourse + +# ๐ŸŽฐ ๋กœ๋˜ + +## ๐Ÿ“‹ ๊ตฌํ˜„ ๊ธฐ๋Šฅ ๋ชฉ๋ก + +--- + +### 1๏ธโƒฃ ๋กœ๋˜ ๊ตฌ์ž… ๊ธˆ์•ก ์ž…๋ ฅ + +- [x] ๊ธˆ์•ก ์ž…๋ ฅ ๋ฐ›๊ธฐ +- [x] 1,000์› ๋‹จ์œ„์ธ์ง€ ๊ฒ€์ฆ +- [x] 1,000์› ๋ฏธ๋งŒ ๋˜๋Š” 1,000์œผ๋กœ ๋‚˜๋ˆ„์–ด๋–จ์–ด์ง€์ง€ ์•Š์œผ๋ฉด `[ERROR]` ์ถœ๋ ฅ ํ›„ **ํ•ด๋‹น ์ž…๋ ฅ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋ฐ›๊ธฐ** + +--- + +### 2๏ธโƒฃ ๋กœ๋˜ ๋ฐœํ–‰ + +- [x] ๊ตฌ์ž… ๊ธˆ์•ก รท 1,000 = ๋ฐœํ–‰ ๊ฐœ์ˆ˜ ๊ณ„์‚ฐ +- [x] ๋žœ๋ค์œผ๋กœ ๋กœ๋˜ ๋ฒˆํ˜ธ ์ƒ์„ฑ +- [x] 1๊ฐœ ๋กœ๋˜๋Š” ์ค‘๋ณต ์—†๋Š” 6๊ฐœ ๋ฒˆํ˜ธ +- [x] ๋ฒˆํ˜ธ๋Š” **์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ**ํ•ด์„œ ๋ณด๊ด€ +- [x] `N๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.` ์ถœ๋ ฅ ํ›„ ๊ฐ ๋กœ๋˜ ๋ฒˆํ˜ธ๋ฅผ `[1, 2, 3, 4, 5, 6]` ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅ + +--- + +### 3๏ธโƒฃ ๋‹น์ฒจ ๋ฒˆํ˜ธ ์ž…๋ ฅ + +- [x] ๋‹น์ฒจ ๋ฒˆํ˜ธ ์ž…๋ ฅ ๋ฐ›๊ธฐ +- [x] ์‰ผํ‘œ(,) ๊ธฐ์ค€์œผ๋กœ 6๊ฐœ์ธ์ง€ ๊ฒ€์ฆ +- [x] ๊ฐ ์ˆซ์ž๊ฐ€ 1~45 ๋ฒ”์œ„์ธ์ง€ ๊ฒ€์ฆ +- [x] ์ค‘๋ณต ์ˆซ์ž ์—†๋„๋ก ๊ฒ€์ฆ +- [x] ์ž˜๋ชป๋˜๋ฉด `[ERROR] ...` ์ถœ๋ ฅ ํ›„ **๋‹น์ฒจ ๋ฒˆํ˜ธ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋ฐ›๊ธฐ** + +--- + +### 4๏ธโƒฃ ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ์ž…๋ ฅ + +- [x] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ ์ž…๋ ฅ ๋ฐ›๊ธฐ +- [x] 1~45 ๋ฒ”์œ„ ๊ฒ€์ฆ +- [x] ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ **๊ฒน์น˜์ง€ ์•Š๋„๋ก** ๊ฒ€์ฆ +- [x] ์ž˜๋ชป๋˜๋ฉด `[ERROR] ...` ์ถœ๋ ฅ ํ›„ **๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋ฐ›๊ธฐ** + +--- + +### 5๏ธโƒฃ ๋‹น์ฒจ ํ†ต๊ณ„ ๊ณ„์‚ฐ + +- [x] ์‚ฌ์šฉ์ž๊ฐ€ ๊ตฌ๋งคํ•œ ๋ชจ๋“  ๋กœ๋˜์™€ ๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ๋น„๊ต +- [x] ์ผ์น˜ ๊ฐœ์ˆ˜์— ๋”ฐ๋ผ 3๊ฐœ/4๊ฐœ/5๊ฐœ/5๊ฐœ+๋ณด๋„ˆ์Šค/6๊ฐœ ์ง‘๊ณ„ +- [x] ๋“ฑ์ˆ˜๋ณ„ ์ƒ๊ธˆ ํ•ฉ๊ณ„ ๊ณ„์‚ฐ + +--- + +### 6๏ธโƒฃ ์ˆ˜์ต๋ฅ  ๊ณ„์‚ฐ ๋ฐ ์ถœ๋ ฅ + +- [x] ์ด ์ƒ๊ธˆ รท ๊ตฌ์ž… ๊ธˆ์•ก ร— 100 +- [x] ์†Œ์ˆ˜์  ๋‘˜์งธ ์ž๋ฆฌ์—์„œ ๋ฐ˜์˜ฌ๋ฆผํ•ด **์†Œ์ˆ˜ ์ฒซ์งธ ์ž๋ฆฌ๊นŒ์ง€๋งŒ** ์ถœ๋ ฅ (์˜ˆ: `62.5%`) +- [x] `์ด ์ˆ˜์ต๋ฅ ์€ 62.5%์ž…๋‹ˆ๋‹ค.` ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅ + +--- + +### 7๏ธโƒฃ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐ ์žฌ์ž…๋ ฅ + +- [x] ์ž˜๋ชป๋œ ๊ฐ’ ์ž…๋ ฅ ์‹œ `[ERROR]`๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅ +- [x] **์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋˜**(throw), `App`์—์„œ ์žก์•„์„œ ํ•ด๋‹น ๋‹จ๊ณ„๋งŒ ๋‹ค์‹œ ์ž…๋ ฅ +- [x] `process.exit()` ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ diff --git a/__tests__/ApplicationTest.js b/__tests__/ApplicationTest.js index 872380c9c..990a4b060 100644 --- a/__tests__/ApplicationTest.js +++ b/__tests__/ApplicationTest.js @@ -94,4 +94,56 @@ describe("๋กœ๋˜ ํ…Œ์ŠคํŠธ", () => { test("์˜ˆ์™ธ ํ…Œ์ŠคํŠธ", async () => { await runException("1000j"); }); + + test("๊ตฌ์ž… ๊ธˆ์•ก์ด 1000์› ๋‹จ์œ„๊ฐ€ ์•„๋‹ˆ๋ฉด ๋‹ค์‹œ ์ž…๋ ฅ์„ ๋ฐ›๋Š”๋‹ค", async () => { + const logSpy = getLogSpy(); + mockRandoms([ + [1, 2, 3, 4, 5, 6], + [7, 8, 9, 10, 11, 12], + [13, 14, 15, 16, 17, 18], + [19, 20, 21, 22, 23, 24], + [25, 26, 27, 28, 29, 30], + ]); + mockQuestions(["8500", "2000", "1,2,3,4,5,6", "7"]); + + const app = new App(); + await app.run(); + + expect(logSpy).toHaveBeenCalledWith( + expect.stringContaining("[ERROR] ๊ตฌ์ž… ๊ธˆ์•ก์€ 1,000์› ๋‹จ์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + ); + expect(logSpy).toHaveBeenCalledWith( + expect.stringContaining("2๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.") + ); + }); + + test("๋‹น์ฒจ ๋ฒˆํ˜ธ๊ฐ€ 6๊ฐœ๊ฐ€ ์•„๋‹ˆ๋ฉด ๋‹ค์‹œ ์ž…๋ ฅ์„ ๋ฐ›๋Š”๋‹ค", async () => { + const logSpy = getLogSpy(); + mockRandoms([[1, 2, 3, 4, 5, 6]]); + mockQuestions(["1000", "1,2,3,4,5", "1,2,3,4,5,6", "7"]); + + const app = new App(); + await app.run(); + + expect(logSpy).toHaveBeenCalledWith( + expect.stringContaining("[ERROR] ๋‹น์ฒจ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + ); + expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("๋‹น์ฒจ ํ†ต๊ณ„")); + }); + + test("๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๊ฐ€ ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ์ค‘๋ณต๋˜๋ฉด ๋‹ค์‹œ ์ž…๋ ฅ์„ ๋ฐ›๋Š”๋‹ค", async () => { + const logSpy = getLogSpy(); + mockRandoms([[1, 2, 3, 4, 5, 6]]); + mockQuestions(["1000", "1,2,3,4,5,6", "3", "7"]); + + const app = new App(); + await app.run(); + + expect(logSpy).toHaveBeenCalledWith( + expect.stringContaining( + "[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ์ค‘๋ณต๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + ) + ); + expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("๋‹น์ฒจ ํ†ต๊ณ„")); + }); }); diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 409aaf69b..d96a7f8b6 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -14,5 +14,16 @@ describe("๋กœ๋˜ ํด๋ž˜์Šค ํ…Œ์ŠคํŠธ", () => { }).toThrow("[ERROR]"); }); - // TODO: ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„์— ๋”ฐ๋ฅธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ + test("๋กœ๋˜ ๋ฒˆํ˜ธ๊ฐ€ 6๊ฐœ ๋ณด๋‹ค ์ ์œผ๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.", () => { + expect(() => new Lotto([1, 2, 3, 4, 5]).toThrow("[ERROR]")); + }); + + test("๋กœ๋˜ ๋ฒˆํ˜ธ๊ฐ€ 1~45 ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.", () => { + expect(() => new Lotto([0, 2, 3, 4, 5, 6])).toThrow("[ERROR]"); + expect(() => new Lotto([1, 2, 3, 4, 5, 100])).toThrow("[ERROR]"); + }); + + test("์œ ํšจํ•œ ๋กœ๋˜ ๋ฒˆํ˜ธ 6๊ฐœ๋ผ๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.", () => { + expect(() => new Lotto([1, 2, 3, 4, 5, 6])).not.toThrow(); + }); }); diff --git a/src/App.js b/src/App.js index 091aa0a5d..1e13c9daa 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,37 @@ +import { LOTTO_PRICE } from "./constants/constants.js"; +import InputHandler from "./InputHandler.js"; +import LottoService from "./LottoService.js"; +import { printNewLine } from "./utils/output.js"; + class App { - async run() {} + #inputHandler; + #lottoService; + + constructor() { + this.#inputHandler = new InputHandler(); + this.#lottoService = new LottoService(); + } + + async run() { + const purchaseAmount = await this.#inputHandler.readPurchaseAmount(); + const ticketCount = purchaseAmount / LOTTO_PRICE; + printNewLine(); + + const tickets = this.#lottoService.publishLottos(ticketCount); + this.#lottoService.printTickets(tickets); + + const winningNumbers = await this.#inputHandler.readWinningNumbers(); + const bonusNumber = await this.#inputHandler.readBonusNumber( + winningNumbers + ); + + const stats = this.#lottoService.calculateStats( + tickets, + winningNumbers, + bonusNumber + ); + this.#lottoService.printStats(stats, purchaseAmount); + } } export default App; diff --git a/src/InputHandler.js b/src/InputHandler.js new file mode 100644 index 000000000..bfc192676 --- /dev/null +++ b/src/InputHandler.js @@ -0,0 +1,117 @@ +import { Console } from "@woowacourse/mission-utils"; +import { + LOTTO_COUNT, + LOTTO_MAX, + LOTTO_MIN, + LOTTO_PRICE, + NUMBER_REGEX, +} from "./constants/constants.js"; +import { ERROR_MESSAGES, INPUT_MESSAGES } from "./constants/messages.js"; +import { printNewLine } from "./utils/output.js"; + +class InputHandler { + async readPurchaseAmount() { + while (true) { + const input = await Console.readLineAsync(INPUT_MESSAGES.PURCHASE_AMOUNT); + try { + return this.#parsePurchaseAmount(input); + } catch (error) { + Console.print(error.message); + } + } + } + + #trimInput(input) { + return (input ?? "").trim(); + } + + #parseNumber(input, errorMessage = ERROR_MESSAGES.LOTTO_NUMBER_OUT_OF_RANGE) { + if (!NUMBER_REGEX.test(input)) { + throw new Error(errorMessage); + } + return Number(input); + } + + #parsePurchaseAmount(input) { + const trimmedInput = this.#trimInput(input); + const amount = this.#parseNumber( + trimmedInput, + ERROR_MESSAGES.PURCHASE_AMOUNT_NOT_NUMBER + ); + + if (amount < LOTTO_PRICE) { + throw new Error(ERROR_MESSAGES.PURCHASE_AMOUNT_TOO_LOW); + } + if (amount % LOTTO_PRICE !== 0) { + throw new Error(ERROR_MESSAGES.PURCHASE_AMOUNT_NOT_DIVISIBLE); + } + return amount; + } + + async readWinningNumbers() { + printNewLine(); + while (true) { + const input = await Console.readLineAsync(INPUT_MESSAGES.WINNING_NUMBERS); + try { + return this.#parseWinningNumbers(input); + } catch (error) { + Console.print(error.message); + } + } + } + + #parseWinningNumbers(input) { + const trimmedInput = this.#trimInput(input); + const parts = trimmedInput.split(",").map((value) => value.trim()); + if (parts.length !== LOTTO_COUNT) { + throw new Error(ERROR_MESSAGES.WINNING_NUMBERS_COUNT_INVALID); + } + + const numbers = parts.map((numberString) => + this.#parseNumber(numberString) + ); + this.#validateLottoNumbers(numbers); + + const unique = new Set(numbers); + if (unique.size !== LOTTO_COUNT) { + throw new Error(ERROR_MESSAGES.WINNING_NUMBERS_DUPLICATE); + } + return numbers; + } + + #validateLottoNumbers(numbers) { + if ( + !numbers.every( + (number) => + Number.isInteger(number) && number >= LOTTO_MIN && number <= LOTTO_MAX + ) + ) { + throw new Error(ERROR_MESSAGES.LOTTO_NUMBER_OUT_OF_RANGE); + } + } + + async readBonusNumber(winningNumbers) { + printNewLine(); + while (true) { + const input = await Console.readLineAsync(INPUT_MESSAGES.BONUS_NUMBER); + try { + return this.#parseBonusNumber(input, winningNumbers); + } catch (error) { + Console.print(error.message); + } + } + } + + #parseBonusNumber(input, winningNumbers) { + const trimmedInput = this.#trimInput(input); + const bonus = this.#parseNumber(trimmedInput); + this.#validateLottoNumbers([bonus]); + + if (winningNumbers.includes(bonus)) { + throw new Error(ERROR_MESSAGES.BONUS_NUMBER_DUPLICATE); + } + return bonus; + } +} + +export default InputHandler; diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e..58f11c5bc 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -1,3 +1,6 @@ +import { LOTTO_COUNT, LOTTO_MAX, LOTTO_MIN } from "./constants/constants.js"; +import { ERROR_MESSAGES } from "./constants/messages.js"; + class Lotto { #numbers; @@ -7,12 +10,24 @@ class Lotto { } #validate(numbers) { - if (numbers.length !== 6) { - throw new Error("[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + if (numbers.length !== LOTTO_COUNT) { + throw new Error(ERROR_MESSAGES.LOTTO_NUMBERS_COUNT_INVALID); + } + + if ( + !numbers.every( + (number) => + Number.isInteger(number) && number >= LOTTO_MIN && number <= LOTTO_MAX + ) + ) { + throw new Error(ERROR_MESSAGES.LOTTO_NUMBER_OUT_OF_RANGE); } - } - // TODO: ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ + const uniqueCount = new Set(numbers).size; + if (uniqueCount !== LOTTO_COUNT) { + throw new Error(ERROR_MESSAGES.LOTTO_NUMBERS_DUPLICATE); + } + } } export default Lotto; diff --git a/src/LottoService.js b/src/LottoService.js new file mode 100644 index 000000000..3399ecfac --- /dev/null +++ b/src/LottoService.js @@ -0,0 +1,115 @@ +import { Console, Random } from "@woowacourse/mission-utils"; +import { + LOTTO_COUNT, + LOTTO_MAX, + LOTTO_MIN, + PRIZE_TABLE, +} from "./constants/constants.js"; +import Lotto from "./Lotto.js"; +import { printNewLine } from "./utils/output.js"; + +class LottoService { + publishLottos(count) { + const tickets = []; + for (let i = 0; i < count; i += 1) { + const numbers = Random.pickUniqueNumbersInRange( + LOTTO_MIN, + LOTTO_MAX, + LOTTO_COUNT + ); + const sorted = [...numbers].sort((first, second) => first - second); + new Lotto(sorted); + tickets.push(sorted); + } + return tickets; + } + + calculateStats(tickets, winningNumbers, bonusNumber) { + const stats = { + three: 0, + four: 0, + five: 0, + fiveBonus: 0, + six: 0, + }; + + for (const ticket of tickets) { + const matchCount = this.#countMatch(ticket, winningNumbers); + const hasBonus = ticket.includes(bonusNumber); + this.#applyStat(stats, matchCount, hasBonus); + } + return stats; + } + + #countMatch(ticket, winningNumbers) { + let matchedCount = 0; + for (const number of ticket) { + if (winningNumbers.includes(number)) { + matchedCount += 1; + } + } + return matchedCount; + } + + #applyStat(stats, matchCount, hasBonus) { + if (matchCount === 6) { + stats.six += 1; + return; + } + if (matchCount === 5 && hasBonus) { + stats.fiveBonus += 1; + return; + } + if (matchCount === 5) { + stats.five += 1; + return; + } + + if (matchCount === 4) { + stats.four += 1; + return; + } + if (matchCount === 3) { + stats.three += 1; + } + } + + printTickets(tickets) { + Console.print(`${tickets.length}๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.`); + for (const ticket of tickets) { + Console.print(`[${ticket.join(", ")}]`); + } + } + + printStats(stats, purchaseAmount) { + printNewLine(); + Console.print("๋‹น์ฒจ ํ†ต๊ณ„"); + Console.print("---"); + Console.print(`${PRIZE_TABLE.three.label}${stats.three}๊ฐœ`); + Console.print(`${PRIZE_TABLE.four.label}${stats.four}๊ฐœ`); + Console.print(`${PRIZE_TABLE.five.label}${stats.five}๊ฐœ`); + Console.print(`${PRIZE_TABLE.fiveBonus.label}${stats.fiveBonus}๊ฐœ`); + Console.print(`${PRIZE_TABLE.six.label}${stats.six}๊ฐœ`); + + const profitRate = this.#calculateProfitRate(stats, purchaseAmount); + Console.print(`์ด ์ˆ˜์ต๋ฅ ์€ ${profitRate}%์ž…๋‹ˆ๋‹ค.`); + } + + #calculateProfitRate(stats, purchaseAmount) { + const totalPrize = + stats.three * PRIZE_TABLE.three.money + + stats.four * PRIZE_TABLE.four.money + + stats.five * PRIZE_TABLE.five.money + + stats.fiveBonus * PRIZE_TABLE.fiveBonus.money + + stats.six * PRIZE_TABLE.six.money; + + const rate = (totalPrize / purchaseAmount) * 100; + const rounded = Math.round(rate * 10) / 10; + return new Intl.NumberFormat("ko-KR", { + minimumFractionDigits: 1, + maximumFractionDigits: 1, + }).format(rounded); + } +} + +export default LottoService; diff --git a/src/constants/constants.js b/src/constants/constants.js new file mode 100644 index 000000000..e366c16c4 --- /dev/null +++ b/src/constants/constants.js @@ -0,0 +1,18 @@ +export const LOTTO_PRICE = 1000; +export const LOTTO_MIN = 1; +export const LOTTO_MAX = 45; +export const LOTTO_COUNT = 6; + +export const NUMBER_REGEX = /^\d+$/; + +export const PRIZE_TABLE = { + three: { match: 3, money: 5000, label: "3๊ฐœ ์ผ์น˜ (5,000์›) - " }, + four: { match: 4, money: 50000, label: "4๊ฐœ ์ผ์น˜ (50,000์›) - " }, + five: { match: 5, money: 1500000, label: "5๊ฐœ ์ผ์น˜ (1,500,000์›) - " }, + fiveBonus: { + match: 5, + money: 30000000, + label: "5๊ฐœ ์ผ์น˜, ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜ (30,000,000์›) - ", + }, + six: { match: 6, money: 2000000000, label: "6๊ฐœ ์ผ์น˜ (2,000,000,000์›) - " }, +}; diff --git a/src/constants/messages.js b/src/constants/messages.js new file mode 100644 index 000000000..188affaa0 --- /dev/null +++ b/src/constants/messages.js @@ -0,0 +1,19 @@ +export const ERROR_MESSAGES = { + PURCHASE_AMOUNT_NOT_NUMBER: "[ERROR] ๊ตฌ์ž… ๊ธˆ์•ก์€ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + PURCHASE_AMOUNT_TOO_LOW: "[ERROR] ๊ตฌ์ž… ๊ธˆ์•ก์€ 1,000์› ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + PURCHASE_AMOUNT_NOT_DIVISIBLE: "[ERROR] ๊ตฌ์ž… ๊ธˆ์•ก์€ 1,000์› ๋‹จ์œ„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + WINNING_NUMBERS_COUNT_INVALID: "[ERROR] ๋‹น์ฒจ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + WINNING_NUMBERS_DUPLICATE: "[ERROR] ๋‹น์ฒจ ๋ฒˆํ˜ธ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + LOTTO_NUMBER_OUT_OF_RANGE: + "[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 1๋ถ€ํ„ฐ 45 ์‚ฌ์ด์˜ ์ˆซ์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + LOTTO_NUMBERS_COUNT_INVALID: "[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", + LOTTO_NUMBERS_DUPLICATE: "[ERROR] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” ์ค‘๋ณต๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", + BONUS_NUMBER_DUPLICATE: + "[ERROR] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ์ค‘๋ณต๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", +}; + +export const INPUT_MESSAGES = { + PURCHASE_AMOUNT: "๊ตฌ์ž…๊ธˆ์•ก์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.\n", + WINNING_NUMBERS: "๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.\n", + BONUS_NUMBER: "๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.\n", +}; diff --git a/src/utils/output.js b/src/utils/output.js new file mode 100644 index 000000000..7eb191361 --- /dev/null +++ b/src/utils/output.js @@ -0,0 +1,5 @@ +import { Console } from "@woowacourse/mission-utils"; + +export const printNewLine = () => { + Console.print(""); +}; diff --git a/types/woowacourse__mission-utils.d.ts b/types/woowacourse__mission-utils.d.ts new file mode 100644 index 000000000..fa45d5336 --- /dev/null +++ b/types/woowacourse__mission-utils.d.ts @@ -0,0 +1,15 @@ +declare module "@woowacourse/mission-utils" { + export const Console: { + readLineAsync(prompt?: string): Promise; + print(message: string): void; + }; + + export const Random: { + pickNumberInRange(minInclusive: number, maxInclusive: number): number; + pickUniqueNumbersInRange( + minInclusive: number, + maxInclusive: number, + count: number + ): number[]; + }; +}