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
153 changes: 152 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,152 @@
# java-baseball-precourse
# 숫자야구 게임 명세서

---

## 📌 개요

숫자야구 게임은 컴퓨터가 생성한 **서로 다른 3자리 숫자**를 플레이어가 맞히는 게임입니다.
플레이어의 입력에 대해 **스트라이크(Strike)** 와 **볼(Ball)** 개수를 판정하며, **3 스트라이크**가 되면 게임이 종료됩니다.

---

## 🧩 주요 클래스 구성

### 1. `controller.GameManager`

* 게임 전체 흐름과 **Phase 전환**을 관리
* 사용자 입력 검증 및 재입력 루프 처리

---

### 2. `model.NumberGenerator`

**역할**

* 게임에서 사용할 숫자 생성

**규칙(현재 구현 기준)**

* 숫자 범위: **1 ~ 8**
* 생성 개수: **3개**
* 모든 숫자는 **서로 달라야 함**

---

### 3. `model.JudgeManager`

**역할**

* 사용자 입력값과 생성된 숫자를 비교하여 결과 판정

**판정 내용**

* 스트라이크(Strike) 개수
* 볼(Ball) 개수
* 스트라이크 + 볼 = 0 인 경우 `낫씽` 출력

---

### 4. `view.InputManager`

**역할**

* 콘솔에서 사용자 입력 수신 (`Scanner.next()` 사용)

---

### 5. `view.OutputManager`

**역할**

* Phase 시작 메시지, 에러 메시지, 판정 결과 출력

---

## 🔄 Phase 구성 및 흐름

### 1. 시작 단계

* 프로그램은 **`GENERATE_NUMBER` Phase**에서 시작
* 최초 실행 시 **시작 안내 메시지는 출력되지 않고** 바로 숫자 입력을 요청

---

### 2. `GENERATE_NUMBER`

**설명**

* 게임 시작 시 숫자를 생성하는 Phase

**동작**

1. `NumberGenerator.generateNumber()`로 숫자 생성
2. 생성 후 `INPUT_NUMBER` Phase로 이동

---

### 3. `INPUT_NUMBER`

**설명**

* 사용자로부터 숫자를 입력받는 Phase

**검증 조건**

* 입력 길이가 3인가?
* 모든 입력이 **1 ~ 9** 사이의 숫자인가?
* 모든 입력 값이 서로 다른가?

**분기 처리**

* 입력이 **적절한 경우**
* 입력값 저장
* `JUDGE_RESULT` Phase로 이동
* 입력이 **부적절한 경우**
* 에러 메시지 출력
* `INPUT_NUMBER` Phase 유지

---

### 4. `JUDGE_RESULT`

**설명**

* 입력값을 판정하고 결과를 출력하는 Phase

**분기 처리**

* 결과가 **3 Strike**인 경우
* 축하 메시지 출력
* `IDLE` Phase로 이동
* 그 외의 경우
* 결과 출력
* `INPUT_NUMBER` Phase로 이동

---

### 5. `IDLE`

**설명**

* 게임을 새로 시작하거나 종료를 선택하는 Phase

**분기 처리**

* `1` 입력: `GENERATE_NUMBER` Phase로 이동 (새 게임)
* `2` 입력: 프로그램 종료
* 그 외 입력: 에러 메시지 출력 후 재입력

---

## 🧾 출력 메시지

* 입력 요청: `숫자를 입력해주세요 : `
* 잘못된 숫자 입력: `1 ~ 9 사이의 중복되지 않는 세 자리 숫자를 입력해주세요.`
* 게임 재시작/종료 선택: `게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.`
* 정답: `3개의 숫자를 모두 맞히셨습니다! 게임 끝`

---

## 🏁 게임 종료 조건

* `IDLE` Phase에서 `2`를 입력하면 프로그램 종료
Empty file added bin/main/.gitkeep
Empty file.
Binary file added bin/main/App.class
Binary file not shown.
Binary file added bin/main/GameManager.class
Binary file not shown.
Binary file added bin/main/InputManager.class
Binary file not shown.
Binary file added bin/main/JudgeManager.class
Binary file not shown.
Binary file added bin/main/NumberGenerator.class
Binary file not shown.
Binary file added bin/main/TurnPhase.class
Binary file not shown.
Empty file added bin/test/.gitkeep
Empty file.
9 changes: 9 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id 'java'
id 'application'
}

group = 'camp.nextstep.edu'
Expand All @@ -11,6 +12,10 @@ java {
}
}

application {
mainClass = "App"
}

repositories {
mavenCentral()
}
Expand All @@ -20,6 +25,10 @@ dependencies {
testImplementation 'org.assertj:assertj-core:3.25.3'
}

run {
standardInput = System.In
}

test {
useJUnitPlatform()
}
11 changes: 11 additions & 0 deletions src/main/java/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import constant.TurnPhase;
import controller.GameManager;

public class App {
private GameManager _gameManager;

public static void main(String[] args) {
GameManager _gameManager = new GameManager(TurnPhase.GENERATE_NUMBER);
_gameManager.playGame();
}
}
6 changes: 6 additions & 0 deletions src/main/java/Constant/ErrorEnum.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package constant;

public enum ErrorEnum {
IDLE_INPUT_ERROR,
USER_INPUT_ERROR
}
4 changes: 4 additions & 0 deletions src/main/java/Constant/JudgeResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package constant;

public record JudgeResult(int strike, int ball) {
}
9 changes: 9 additions & 0 deletions src/main/java/Constant/TurnPhase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package constant;

public enum TurnPhase {
QUIT,
IDLE,
GENERATE_NUMBER,
INPUT_NUMBER,
JUDGE_RESULT
}
106 changes: 106 additions & 0 deletions src/main/java/Controller/GameManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package controller;

import java.util.HashMap;
import java.util.Map;

import constant.ErrorEnum;
import constant.JudgeResult;
import constant.TurnPhase;
import model.JudgeManager;
import model.NumberGenerator;
import view.InputManager;
import view.OutputManager;

public class GameManager {
private static final int BASEBALL_SIZE = 3;

private TurnPhase _turnPhase;
private final NumberGenerator _numberGenerator;
private final InputManager _inputManager;
private final JudgeManager _judgeManager;
private final OutputManager _outputManager;
private String _generatedNumber;
private String _userNumber;
private final Map<TurnPhase, Runnable> _phaseHandler;

public GameManager(TurnPhase turnPhase) {
_turnPhase = turnPhase;
_numberGenerator = new NumberGenerator();
_inputManager = new InputManager();
_judgeManager = new JudgeManager();
_outputManager = new OutputManager();

_phaseHandler = new HashMap<>();
_phaseHandler.put(TurnPhase.IDLE, this::handleIdlePhase);
_phaseHandler.put(TurnPhase.GENERATE_NUMBER, this::handleGenerateNumberPhase);
_phaseHandler.put(TurnPhase.INPUT_NUMBER, this::handleInputNumberPhase);
_phaseHandler.put(TurnPhase.JUDGE_RESULT, this::handleJudgeResultPhase);
}

private void handleIdlePhase() {
while (true) {
String idleInput = _inputManager.getInput();
if (idleInput.equals("1")) {
_turnPhase = TurnPhase.GENERATE_NUMBER;
_generatedNumber = "";
return;
}
if (idleInput.equals("2")) {
_turnPhase = TurnPhase.QUIT;
return;
}
_outputManager.printErrorMessage(ErrorEnum.IDLE_INPUT_ERROR);
}
}

private void handleGenerateNumberPhase() {
_generatedNumber = _numberGenerator.generateNumber();
_turnPhase = TurnPhase.INPUT_NUMBER;
}

private boolean isProperInput(String input) {
if (input.length() != BASEBALL_SIZE) {
return false;
}
Map<Character, String> map = new HashMap<>();
for (int i = 0; i < BASEBALL_SIZE; i++) {
char character = input.charAt(i);
if (character < '1' || character > '9' || map.containsKey(character)) {
return false;
}
map.put(character, "");
}
return true;
}

private void handleInputNumberPhase() {
while (true) {
String userInput = _inputManager.getInput();
if (!isProperInput(userInput)) {
_outputManager.printErrorMessage(ErrorEnum.USER_INPUT_ERROR);
continue;
}
_userNumber = userInput;
break;
}
_turnPhase = TurnPhase.JUDGE_RESULT;
}

private void handleJudgeResultPhase() {
JudgeResult result = _judgeManager.judgeResult(_generatedNumber, _userNumber);
_outputManager.printJudgeResult(result);
if (result.strike() != BASEBALL_SIZE) {
_turnPhase = TurnPhase.INPUT_NUMBER;
return;
}
_turnPhase = TurnPhase.IDLE;
}

public void playGame() {
while (_turnPhase != TurnPhase.QUIT) {
_outputManager.printPhaseStartMessage(_turnPhase);
Runnable handler = _phaseHandler.get(_turnPhase);
handler.run();
}
}
}
30 changes: 30 additions & 0 deletions src/main/java/Model/JudgeManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package model;

import java.util.HashMap;
import java.util.Map;

import constant.JudgeResult;

public class JudgeManager {
private static final int BASEBALL_SIZE = 3;
private static final int PLAYER_CNT = 2;

public JudgeManager() {}

public JudgeResult judgeResult(String number, String user) {
Map<Character, String> map = new HashMap<>();
for (int i = 0; i < BASEBALL_SIZE; i++) {
map.put(number.charAt(i), "");
map.put(user.charAt(i), "");
}
int ball = BASEBALL_SIZE * PLAYER_CNT - map.size();
int strike = 0;
for (int i = 0; i < BASEBALL_SIZE; i++) {
if (number.charAt(i) == user.charAt(i)) {
strike++;
}
}
ball -= strike;
return new JudgeResult(strike, ball);
}
}
Loading