Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions yeonju/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
## 기능 목록

- [x] 랜덤 숫자 생성 기능
- [x] 사용자 입력값 받는 기능
- [x] 입력값 유효성 검증 기능
- [x] 결과 계산 기능
- [x] 출력 기능
- [x] 재시작 기능

## 예외 목록

- 정답값 입력시
- [x] 중복되는 숫자가 있을 경우
- [x] 3자리가 아닐 경우
- 재시작 여부 입력시
- [x] 1, 2가 아닌 다른 값일 경우
12 changes: 11 additions & 1 deletion yeonju/src/App.js
Original file line number Diff line number Diff line change
@@ -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();
16 changes: 16 additions & 0 deletions yeonju/src/constants/Constants.js
Original file line number Diff line number Diff line change
@@ -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 };
63 changes: 63 additions & 0 deletions yeonju/src/controller/BaseballGameController.js
Original file line number Diff line number Diff line change
@@ -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;
30 changes: 30 additions & 0 deletions yeonju/src/model/BaseballGame.js
Original file line number Diff line number Diff line change
@@ -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;
14 changes: 14 additions & 0 deletions yeonju/src/utils/RandomNumberGenerator.js
Original file line number Diff line number Diff line change
@@ -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;
31 changes: 31 additions & 0 deletions yeonju/src/utils/Validator.js
Original file line number Diff line number Diff line change
@@ -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 };
37 changes: 37 additions & 0 deletions yeonju/src/view/BaseballGameView.js
Original file line number Diff line number Diff line change
@@ -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;