diff --git a/yeonju/docs/README.md b/yeonju/docs/README.md index e69de29bb..a7ff1ccec 100644 --- a/yeonju/docs/README.md +++ b/yeonju/docs/README.md @@ -0,0 +1,16 @@ +## 기능 목록 + +- [x] 랜덤 숫자 생성 기능 +- [x] 사용자 입력값 받는 기능 +- [x] 입력값 유효성 검증 기능 +- [x] 결과 계산 기능 +- [x] 출력 기능 +- [x] 재시작 기능 + +## 예외 목록 + +- 정답값 입력시 + - [x] 중복되는 숫자가 있을 경우 + - [x] 3자리가 아닐 경우 +- 재시작 여부 입력시 + - [x] 1, 2가 아닌 다른 값일 경우 diff --git a/yeonju/src/App.js b/yeonju/src/App.js index f53916abe..0e3ffb1bd 100644 --- a/yeonju/src/App.js +++ b/yeonju/src/App.js @@ -1,5 +1,15 @@ +const BaseballGameController = require("./controller/BaseballGameController"); + class App { - play() {} + #baseballGame; + + play() { + this.#baseballGame = new BaseballGameController(); + this.#baseballGame.startGame(); + } } module.exports = App; + +const app = new App(); +app.play(); diff --git a/yeonju/src/constants/Constants.js b/yeonju/src/constants/Constants.js new file mode 100644 index 000000000..8d9ccdab0 --- /dev/null +++ b/yeonju/src/constants/Constants.js @@ -0,0 +1,16 @@ +const MESSAGE_MC = Object.freeze({ + START: "숫자 야구 게임을 시작합니다.", + INPUT: "숫자를 입력해주세요 : ", + END: "3개의 숫자를 모두 맞히셨습니다! 게임 종료", + RESTART: "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.", +}); + +const MESSAGE_ERROR = Object.freeze({ + NO_THREE_DIGIT_NUMBER: + "입력값이 유효하지 않습니다. 3자리 숫자를 입력해주세요.", + HAS_REPEATED_DIGITS: + "입력값이 유효하지 않습니다. 서로 다른 숫자를 입력해주세요.", + RESTART: "입력값이 유효하지 않습니다. 1, 2 중에 한 개만 입력주세요.", +}); + +module.exports = { MESSAGE_MC, MESSAGE_ERROR }; diff --git a/yeonju/src/controller/BaseballGameController.js b/yeonju/src/controller/BaseballGameController.js new file mode 100644 index 000000000..a95de9d82 --- /dev/null +++ b/yeonju/src/controller/BaseballGameController.js @@ -0,0 +1,63 @@ +const { Console } = require("@woowacourse/mission-utils"); +const { MESSAGE_MC } = require("../constants/Constants"); +const BaseballGame = require("../model/BaseballGame"); +const BaseballGameView = require("../view/BaseballGameView"); +const generateRandomNumber = require("../utils/RandomNumberGenerator"); +const { Validator } = require("../utils/Validator"); + +class BaseballGameController { + #baseballGame; + #baseballGameView; + + constructor() { + this.#baseballGame = new BaseballGame(generateRandomNumber()); + this.#baseballGameView = new BaseballGameView(); + } + + startGame() { + this.#baseballGameView.displayWelcomeMessage(); + this.inputNumber(); + } + + endGame() { + this.#baseballGameView.displayGameRestart(); + this.inputRestartNumber(); + } + + inputNumber() { + Console.readLine(MESSAGE_MC.INPUT, (playerInput) => { + Validator.validateBaseballInput(playerInput); + + const playerInputArray = [...playerInput].map((input) => Number(input)); + this.handlePlayerInputResult(playerInputArray); + }); + } + + inputRestartNumber() { + Console.readLine("", (playerInput) => { + const numericInput = Number(playerInput); + + Validator.validateRestartInput(numericInput); + + if (numericInput === 1) { + this.#baseballGame.reset(); + this.startGame(); + } + }); + } + + handlePlayerInputResult(playerInputArray) { + const { strikes, balls } = + this.#baseballGame.getStrikesAndBalls(playerInputArray); + + this.#baseballGameView.displayResult(strikes, balls); + + if (strikes === 3) { + this.endGame(); + } else { + this.inputNumber(); + } + } +} + +module.exports = BaseballGameController; diff --git a/yeonju/src/model/BaseballGame.js b/yeonju/src/model/BaseballGame.js new file mode 100644 index 000000000..8f7c3c725 --- /dev/null +++ b/yeonju/src/model/BaseballGame.js @@ -0,0 +1,30 @@ +const generateRandomNumber = require("../utils/RandomNumberGenerator"); + +class BaseballGame { + #answer; + + constructor(answer) { + this.#answer = answer; + } + + getStrikesAndBalls(userGuess) { + let strikes = 0; + let balls = 0; + + for (let i = 0; i < this.#answer.length; i++) { + if (this.#answer[i] === userGuess[i]) { + strikes++; + } else if (this.#answer.includes(userGuess[i])) { + balls++; + } + } + + return { strikes, balls }; + } + + reset() { + this.#answer = generateRandomNumber(); + } +} + +module.exports = BaseballGame; diff --git a/yeonju/src/utils/RandomNumberGenerator.js b/yeonju/src/utils/RandomNumberGenerator.js new file mode 100644 index 000000000..9fd2f42e0 --- /dev/null +++ b/yeonju/src/utils/RandomNumberGenerator.js @@ -0,0 +1,14 @@ +const { Random } = require("@woowacourse/mission-utils"); + +const generateRandomNumber = () => { + const uniqueNumbers = new Set(); + + while (uniqueNumbers.size < 3) { + const number = Random.pickNumberInRange(1, 9); + uniqueNumbers.add(number); + } + + return Array.from(uniqueNumbers); +}; + +module.exports = generateRandomNumber; diff --git a/yeonju/src/utils/Validator.js b/yeonju/src/utils/Validator.js new file mode 100644 index 000000000..c84e42be2 --- /dev/null +++ b/yeonju/src/utils/Validator.js @@ -0,0 +1,31 @@ +const { MESSAGE_ERROR } = require("../constants/Constants"); + +class Validator { + static validateBaseballInput(input) { + if (!Validator.isValidThreeDigitNumber(input)) { + throw new Error(MESSAGE_ERROR.NO_THREE_DIGIT_NUMBER); + } + + if (!Validator.hasNoRepeatedDigits(input)) { + throw new Error(MESSAGE_ERROR.HAS_REPEATED_DIGITS); + } + } + + static isValidThreeDigitNumber(input) { + const REGEX = /^[1-9]{3}$/; + return REGEX.test(input); + } + + static hasNoRepeatedDigits(input) { + const digits = new Set([...input.toString()]); + return digits.size === 3; + } + + static validateRestartInput(input) { + if (input !== 1 && input !== 2) { + throw new Error(MESSAGE_ERROR.RESTART); + } + } +} + +module.exports = { Validator }; diff --git a/yeonju/src/view/BaseballGameView.js b/yeonju/src/view/BaseballGameView.js new file mode 100644 index 000000000..cc960693e --- /dev/null +++ b/yeonju/src/view/BaseballGameView.js @@ -0,0 +1,37 @@ +const { Console } = require("@woowacourse/mission-utils"); +const { MESSAGE_MC } = require("../constants/Constants"); + +class BaseballGameView { + displayWelcomeMessage() { + Console.print(MESSAGE_MC.START); + } + + displayResult(strikes, balls) { + let message = ""; + + if (strikes === 0 && balls === 0) { + message = "낫싱"; + } + + if (balls > 0) { + message += `${balls}볼 `; + } + + if (strikes > 0) { + message += `${strikes}스트라이크`; + } + + Console.print(message.trim()); + } + + displayGameStart() { + Console.print(MESSAGE_MC.START); + } + + displayGameRestart() { + Console.print(MESSAGE_MC.END); + Console.print(MESSAGE_MC.RESTART); + } +} + +module.exports = BaseballGameView;