From d348eb265ece34e6c9824e2b843efe1e524ea592 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Wed, 28 Jan 2026 16:20:45 +0900 Subject: [PATCH 01/22] fix README --- README.md | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d7e8aee..e9017135 100644 --- a/README.md +++ b/README.md @@ -1 +1,136 @@ -# java-baseball-precourse \ No newline at end of file +# 숫자야구 게임 명세서 + +--- + +## 📌 개요 + +숫자야구 게임은 컴퓨터가 생성한 **서로 다른 3자리 숫자(1~9)**를 플레이어가 맞히는 게임입니다. +플레이어의 입력에 대해 **스트라이크(Strike)** 와 **볼(Ball)** 개수를 판정하며, **3 스트라이크**가 되면 게임이 종료됩니다. + +--- + +## 🧩 Manager 구성 + +### 1. Game Manager + +* 게임 전체 흐름을 관리 +* 현재 Phase를 관리하고 다음 Phase로 전환 + +--- + +### 2. Number Generator Manager (`numberGenerator`) + +**역할** + +* 게임에서 사용할 숫자를 생성 + +**규칙** + +* 숫자 범위: **1 ~ 9** +* 생성 개수: **3개** +* 모든 숫자는 **서로 달라야 함** +* 이전에 생성된 숫자를 다시 생성하지 않음 + +--- + +### 3. Input Manager (`inputManager`) + +**역할** + +* 사용자의 입력값이 올바른지 검증 + +**검증 항목** + +* 입력 길이가 3인가? +* 모든 입력이 **1 ~ 9** 사이의 숫자인가? +* 모든 입력 값이 서로 다른가? + +**결과** + +* 입력이 적절한 경우: `true` 반환 +* 입력이 부적절한 경우: `false` 반환 + +--- + +### 4. Input Judge Manager (`inputJudge`) + +**역할** + +* 사용자의 입력값과 생성된 숫자를 비교하여 결과 판정 + +**판정 내용** + +* 스트라이크(Strike) 개수 +* 볼(Ball) 개수 +* 스트라이크 + 볼 = 0 인 경우 `Nothing` + +--- + +## 🔄 Phase 구성 + +### 1. `generateNumber` + +**설명** + +* 게임 시작 시 숫자를 생성하는 Phase + +**동작** + +1. `numberGenerator`를 통해 숫자 생성 +2. 숫자 생성 완료 후 `inputNumber` Phase로 이동 + +--- + +### 2. `inputNumber` + +**설명** + +* 사용자로부터 숫자를 입력받는 Phase + +**동작** + +1. 사용자 입력 수신 +2. `inputManager`를 통해 입력 검증 + +**분기 처리** + +* 입력이 **적절한 경우** + + * 입력값 저장 + * `printResult` Phase로 이동 + +* 입력이 **부적절한 경우** + + * 에러 메시지 출력 + * `inputNumber` Phase 유지 + +--- + +### 3. `printResult` + +**설명** + +* 입력값을 판정하고 결과를 출력하는 Phase + +**동작** + +1. `inputJudge`를 통해 스트라이크 / 볼 판정 + +**분기 처리** + +* 결과가 **3 Strike**인 경우 + + * 게임 종료 + +* 그 외의 경우 + + * 결과 출력 + * `inputNumber` Phase로 이동 + +--- + +## 🏁 게임 종료 조건 + +* 스트라이크 개수가 **3개**가 되었을 때 게임 종료 + +--- \ No newline at end of file From c821dbb3fd22c27cbfb2b87e495b6689b5c88d7b Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Wed, 28 Jan 2026 16:55:13 +0900 Subject: [PATCH 02/22] fix README: add new phase idle --- README.md | 36 ++++++++++++++++++++++++++---------- src/main/java/App.java | 0 2 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 src/main/java/App.java diff --git a/README.md b/README.md index e9017135..dca73892 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,23 @@ ## 🔄 Phase 구성 -### 1. `generateNumber` +### 1. `idle` + +**설명** + +* 게임을 시작할지 프로그램을 종료할지 선택하는 Phase + +**동작** + +* 프로그램 최초 실행 시 기본적으로 `generateNumber` Phase로 이동 +* 사용자 입력에 따라 다음과 같이 분기 + + * `1` 입력: `generateNumber` Phase로 이동 + * `2` 입력: 프로그램 종료 + +--- + +### 2. `generateNumber` **설명** @@ -81,7 +97,7 @@ --- -### 2. `inputNumber` +### 3. `inputNumber` **설명** @@ -96,17 +112,17 @@ * 입력이 **적절한 경우** - * 입력값 저장 - * `printResult` Phase로 이동 + * 입력값 저장 + * `printResult` Phase로 이동 * 입력이 **부적절한 경우** - * 에러 메시지 출력 - * `inputNumber` Phase 유지 + * 에러 메시지 출력 + * `inputNumber` Phase 유지 --- -### 3. `printResult` +### 4. `printResult` **설명** @@ -120,12 +136,12 @@ * 결과가 **3 Strike**인 경우 - * 게임 종료 + * 게임 종료 * 그 외의 경우 - * 결과 출력 - * `inputNumber` Phase로 이동 + * 결과 출력 + * `inputNumber` Phase로 이동 --- diff --git a/src/main/java/App.java b/src/main/java/App.java new file mode 100644 index 00000000..e69de29b From 12150a0f6732a004b73acb1a3224b2c65eb351be Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Wed, 28 Jan 2026 17:05:44 +0900 Subject: [PATCH 03/22] modify build setting (can execute with command 'run') --- build.gradle | 5 +++++ src/main/java/App.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/build.gradle b/build.gradle index 20a92c9e..01839ece 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id 'java' + id 'application' } group = 'camp.nextstep.edu' @@ -11,6 +12,10 @@ java { } } +application { + mainClass = "App" +} + repositories { mavenCentral() } diff --git a/src/main/java/App.java b/src/main/java/App.java index e69de29b..a6d58e2d 100644 --- a/src/main/java/App.java +++ b/src/main/java/App.java @@ -0,0 +1,5 @@ +public class App { + public static void main (String[] args){ + System.out.println("Hello"); + } +} \ No newline at end of file From f056bf194cad1846b8ad816ae9d9e3157610ae5d Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Wed, 28 Jan 2026 17:18:56 +0900 Subject: [PATCH 04/22] manager, enum add --- src/main/java/GameManager.java | 8 ++++++++ src/main/java/InputManager.java | 3 +++ src/main/java/JudgeManager.java | 3 +++ src/main/java/NumberGenerator.java | 3 +++ src/main/java/TurnPhase.java | 3 +++ 5 files changed, 20 insertions(+) create mode 100644 src/main/java/GameManager.java create mode 100644 src/main/java/InputManager.java create mode 100644 src/main/java/JudgeManager.java create mode 100644 src/main/java/NumberGenerator.java create mode 100644 src/main/java/TurnPhase.java diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java new file mode 100644 index 00000000..3f3e6b2a --- /dev/null +++ b/src/main/java/GameManager.java @@ -0,0 +1,8 @@ +public class GameManager { + private TurnPhase _turnPhase; + + public GameManager(){ + _turnPhase = TurnPhase.generateNumber; + } + +} diff --git a/src/main/java/InputManager.java b/src/main/java/InputManager.java new file mode 100644 index 00000000..e70deab2 --- /dev/null +++ b/src/main/java/InputManager.java @@ -0,0 +1,3 @@ +public class InputManager { + public InputManager() {} +} diff --git a/src/main/java/JudgeManager.java b/src/main/java/JudgeManager.java new file mode 100644 index 00000000..4c801312 --- /dev/null +++ b/src/main/java/JudgeManager.java @@ -0,0 +1,3 @@ +public class JudgeManager { + public JudgeManager() {} +} diff --git a/src/main/java/NumberGenerator.java b/src/main/java/NumberGenerator.java new file mode 100644 index 00000000..1277f46a --- /dev/null +++ b/src/main/java/NumberGenerator.java @@ -0,0 +1,3 @@ +public class NumberGenerator { + public NumberGenerator() {} +} diff --git a/src/main/java/TurnPhase.java b/src/main/java/TurnPhase.java new file mode 100644 index 00000000..e0d46265 --- /dev/null +++ b/src/main/java/TurnPhase.java @@ -0,0 +1,3 @@ +public enum TurnPhase { + idle, generateNumber, inputNumber, judgeResult +} From 6ddb3b5d1edca904c23510a148bb308cfca9cc95 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Wed, 28 Jan 2026 17:21:47 +0900 Subject: [PATCH 05/22] phase 'printResult' renamed as 'judgeResult' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dca73892..f6abe753 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ --- -### 4. `printResult` +### 4. `judgeResult` **설명** From f4f5f3273aca0688f955af7d5651c3771e3865b6 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Wed, 28 Jan 2026 17:59:20 +0900 Subject: [PATCH 06/22] GenerateNumber finished --- src/main/java/App.java | 3 ++- src/main/java/GameManager.java | 12 ++++++++++-- src/main/java/NumberGenerator.java | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/App.java b/src/main/java/App.java index a6d58e2d..f75f28e0 100644 --- a/src/main/java/App.java +++ b/src/main/java/App.java @@ -1,5 +1,6 @@ public class App { + private GameManager _gameManager; public static void main (String[] args){ - System.out.println("Hello"); + GameManager _gameManager = new GameManager(); } } \ No newline at end of file diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 3f3e6b2a..a75e48af 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -1,8 +1,16 @@ public class GameManager { private TurnPhase _turnPhase; - + private NumberGenerator _numberGenerator; + private InputManager _inputManager; + private JudgeManager _judgeManager; + private String _generatedNumber; public GameManager(){ _turnPhase = TurnPhase.generateNumber; + _numberGenerator = new NumberGenerator(); + _inputManager = new InputManager(); + _judgeManager = new JudgeManager(); + } + public String GenerateRandomNumber(){ + return _numberGenerator.GenerateNumber(); } - } diff --git a/src/main/java/NumberGenerator.java b/src/main/java/NumberGenerator.java index 1277f46a..4c196737 100644 --- a/src/main/java/NumberGenerator.java +++ b/src/main/java/NumberGenerator.java @@ -1,3 +1,19 @@ +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + public class NumberGenerator { public NumberGenerator() {} + public String GenerateNumber() { + String result = ""; + Map map = new HashMap<>(); + Random random = new Random(); + while(result.length() < 3) { + String randomNumber =random.nextInt(1, 9) + ""; + if (map.get(randomNumber) != null) continue; + map.put(randomNumber, ""); + result += randomNumber; + } + return result; + } } From 6ee98a5eeac2308cbdd303c15cfe0d956971b808 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Wed, 28 Jan 2026 18:20:50 +0900 Subject: [PATCH 07/22] idlePhase input process --- build.gradle | 4 ++++ src/main/java/App.java | 1 + src/main/java/GameManager.java | 19 ++++++++++++++++++- src/main/java/InputManager.java | 23 ++++++++++++++++++++++- src/main/java/TurnPhase.java | 2 +- 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 01839ece..82eb7572 100644 --- a/build.gradle +++ b/build.gradle @@ -25,6 +25,10 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.25.3' } +run { + standardInput = System.In +} + test { useJUnitPlatform() } diff --git a/src/main/java/App.java b/src/main/java/App.java index f75f28e0..5312ac43 100644 --- a/src/main/java/App.java +++ b/src/main/java/App.java @@ -2,5 +2,6 @@ public class App { private GameManager _gameManager; public static void main (String[] args){ GameManager _gameManager = new GameManager(); + _gameManager.PlayGame(); } } \ No newline at end of file diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index a75e48af..aef2ba11 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -5,7 +5,7 @@ public class GameManager { private JudgeManager _judgeManager; private String _generatedNumber; public GameManager(){ - _turnPhase = TurnPhase.generateNumber; + _turnPhase = TurnPhase.idle; _numberGenerator = new NumberGenerator(); _inputManager = new InputManager(); _judgeManager = new JudgeManager(); @@ -13,4 +13,21 @@ public GameManager(){ public String GenerateRandomNumber(){ return _numberGenerator.GenerateNumber(); } + private void idlePhasePlay() { + if (_turnPhase != TurnPhase.idle) return; + boolean idleFlag = _inputManager.IdleInput(); + if (idleFlag){ + _turnPhase = TurnPhase.generateNumber; + return; + } + _turnPhase = TurnPhase.quit; + } + public void PlayGame(){ + while(true){ + if (_turnPhase == TurnPhase.quit) break; + if (_turnPhase == TurnPhase.idle) { + idlePhasePlay(); + } + } + } } diff --git a/src/main/java/InputManager.java b/src/main/java/InputManager.java index e70deab2..65e9d1b4 100644 --- a/src/main/java/InputManager.java +++ b/src/main/java/InputManager.java @@ -1,3 +1,24 @@ +import java.util.Scanner; + public class InputManager { - public InputManager() {} + Scanner scanner; + public InputManager() { + scanner = new Scanner(System.in); + } + public boolean IdleInput(){ + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요"); + int flag = -1; + while(true){ + flag = scanner.nextInt(); + // 게임 플레이 + if (flag == 1){ + return true; + } + // 게임 종료 + if (flag == 2){ + return false; + } + System.out.println("1 혹은 2를 입력해주세요"); + } + } } diff --git a/src/main/java/TurnPhase.java b/src/main/java/TurnPhase.java index e0d46265..8adf6e3c 100644 --- a/src/main/java/TurnPhase.java +++ b/src/main/java/TurnPhase.java @@ -1,3 +1,3 @@ public enum TurnPhase { - idle, generateNumber, inputNumber, judgeResult + quit, idle, generateNumber, inputNumber, judgeResult } From 7a7791e97e6c2fb61f2d42a489da11c2b42ea23a Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Wed, 28 Jan 2026 18:42:30 +0900 Subject: [PATCH 08/22] number baseball framework finished --- src/main/java/GameManager.java | 27 ++++++++++++++++++++++++--- src/main/java/InputManager.java | 22 ++++++++++++++++++++++ src/main/java/JudgeManager.java | 3 +++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index aef2ba11..79664797 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -4,29 +4,50 @@ public class GameManager { private InputManager _inputManager; private JudgeManager _judgeManager; private String _generatedNumber; + private String _userNumber; public GameManager(){ _turnPhase = TurnPhase.idle; _numberGenerator = new NumberGenerator(); _inputManager = new InputManager(); _judgeManager = new JudgeManager(); } - public String GenerateRandomNumber(){ - return _numberGenerator.GenerateNumber(); - } private void idlePhasePlay() { if (_turnPhase != TurnPhase.idle) return; boolean idleFlag = _inputManager.IdleInput(); if (idleFlag){ _turnPhase = TurnPhase.generateNumber; + _generatedNumber = ""; return; } _turnPhase = TurnPhase.quit; } + public void PlayGame(){ while(true){ if (_turnPhase == TurnPhase.quit) break; if (_turnPhase == TurnPhase.idle) { idlePhasePlay(); + continue; + } + if (_turnPhase == TurnPhase.generateNumber) { + _generatedNumber = _numberGenerator.GenerateNumber(); + _turnPhase = TurnPhase.inputNumber; + continue; + } + if (_turnPhase == TurnPhase.inputNumber) { + _userNumber = _inputManager.PredictionInput(); + System.out.println(_userNumber); + _turnPhase = TurnPhase.judgeResult; + continue; + } + if (_turnPhase == TurnPhase.judgeResult){ + boolean result = _judgeManager.JudgeResult(_generatedNumber, _userNumber); + if (result) { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝"); + _turnPhase = TurnPhase.idle; + continue; + } + _turnPhase = TurnPhase.inputNumber; } } } diff --git a/src/main/java/InputManager.java b/src/main/java/InputManager.java index 65e9d1b4..1ffb4e10 100644 --- a/src/main/java/InputManager.java +++ b/src/main/java/InputManager.java @@ -1,4 +1,6 @@ import java.util.Scanner; +import java.util.HashMap; +import java.util.Map; public class InputManager { Scanner scanner; @@ -21,4 +23,24 @@ public boolean IdleInput(){ System.out.println("1 혹은 2를 입력해주세요"); } } + private boolean IsProperInput(String s){ + if (s.length() != 3) return false; + Map map = new HashMap<>(); + for (int i=0; i<3; i++){ + if ((49 > s.charAt(i) || s.charAt(i) > 57) || map.get(s.charAt(i)) != null) return false; + map.put(s.charAt(i), ""); + } + return true; + } + public String PredictionInput(){ + System.out.print("숫자를 입력해주세요 : "); + while(true) { + String userInput = scanner.next(); + if (!IsProperInput((userInput))) { + System.out.println("1 ~ 9 사이의 중복되지 않는 세 자리 숫자를 입력해주세요."); + continue; + } + return userInput; + } + } } diff --git a/src/main/java/JudgeManager.java b/src/main/java/JudgeManager.java index 4c801312..a51cde79 100644 --- a/src/main/java/JudgeManager.java +++ b/src/main/java/JudgeManager.java @@ -1,3 +1,6 @@ public class JudgeManager { public JudgeManager() {} + public boolean JudgeResult(String number, String user){ + return true; + } } From fd631ebf687615469b7ef70c578c714fa25aa1d8 Mon Sep 17 00:00:00 2001 From: Cha Dae Gyu Date: Thu, 29 Jan 2026 00:32:55 +0900 Subject: [PATCH 09/22] GameManager refactoring --- bin/main/.gitkeep | 0 bin/main/App.class | Bin 0 -> 464 bytes bin/main/GameManager.class | Bin 0 -> 3069 bytes bin/main/InputManager.class | Bin 0 -> 1997 bytes bin/main/JudgeManager.class | Bin 0 -> 432 bytes bin/main/NumberGenerator.class | Bin 0 -> 1565 bytes bin/main/TurnPhase.class | Bin 0 -> 1058 bytes bin/test/.gitkeep | 0 src/main/java/GameManager.java | 68 +++++++++++++++++---------------- 9 files changed, 36 insertions(+), 32 deletions(-) create mode 100644 bin/main/.gitkeep create mode 100644 bin/main/App.class create mode 100644 bin/main/GameManager.class create mode 100644 bin/main/InputManager.class create mode 100644 bin/main/JudgeManager.class create mode 100644 bin/main/NumberGenerator.class create mode 100644 bin/main/TurnPhase.class create mode 100644 bin/test/.gitkeep diff --git a/bin/main/.gitkeep b/bin/main/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/bin/main/App.class b/bin/main/App.class new file mode 100644 index 0000000000000000000000000000000000000000..e203d85e3e5da66815b5dfa78a839a3a48e46a83 GIT binary patch literal 464 zcmZut+e*Vg5IvLT(x&OfRO9uk_x5X^E-eXZd15!4L4G z#MxA+55COIncX?(%zS;ne*!qfjst^GIG#=&n1uRBJc~{&lBjbv7|CHq@a`iqmKP!s zkxU7d@N5aY1p7cGDm!A1W~)yyPbLr2MFC|G4vK_Ys1kWO8xLf9BL=Y~_~B$I;=V|g z#=lK7dsI&ZD`Y3kYL10U2to5MTsrDysY;@5tM8yeDF5-{!be$$z{9#$EndgsMSox_ zkw(ni_=kz$_9nA*C{L9(R%GpcEr(t3K71d70Sh))2G_g~#}cCsXX0$N=Wt*1XOE+u zH~B_fdy5aKqQ=x&xc7#&B}p|`Hd)JJ5<4dg76aJ8CJ*Wt M?Mi#tVr*dh2dv0aNB{r; literal 0 HcmV?d00001 diff --git a/bin/main/GameManager.class b/bin/main/GameManager.class new file mode 100644 index 0000000000000000000000000000000000000000..2e70ca53d495c5fd863cabcdfffafb7d9cda5de2 GIT binary patch literal 3069 zcma)8Yj+b>6y1~7PMZvE>5E5cO(}&EO3OoDwpIlx1yiULc~r4Z+aVoDCn1@j^^Fuo zKn0(GP+ve1bS>>Nut1l~&n`dv1N=zqKX8fr-kCHLVX^#>nLFp6d(J-l?0av1`{&j# z03N}2Dtrn8oAhC$OSklhkx-GZpme`}NNSw{e`+w20U{i>c)n$# zh?Bw?biykr3umGB*a_2$&@a%JN*alb%Z$FbK;5ZZgHeOnN}MGr+l;n!>2dlO^_US$ zXMHSfS?+9`r&3RNts6b^A=3<_T zYNnYcO+yU|=xGvB5fnVA;Q3a%cK;@Zr1${iwl(yiesY-iVnRW?itq*tKaq2XyMfP*R1F2pVcY@LEV z8fKtaL7~t^M^uj}P2F(H6j9IcgQGuzU1jR)-fMFHUT%03G+Zfhh zAx0u%LJ5^l+s#-@H+Qbhc>GORdA=4OA+NxYp{`0pvJ|DD0Nxsm6MBKY(uvK zxf7gLyA_1+qJ|N?M3HzV6)d_(AdfCHp?eGQih?yOZ-0M&>cW}e)Uj(*W2YuB{T!UU zdS&wTso>=J*k5DErjA~jI-Z_9acuI$#k%0_iIY=fqru6;7kFAEr0&?|?x;Q@wv^a4 zZ)iA-H%UyyATbNQP+awU+vJ*5j8doB12A(c1#kp!iOpL{qMSyO%?eL38Bd;G{+?JW zF<^98JWX*02?oB`Q9m!L^;!&?jwYv$oGQ3`*Nr)^<_D zA!+-XHhIMJGTji>lSzY{;Tr`FcaeQB%2ZraP9Q9s+J+Z60q-XX(8f`FDuYr$XVqz~>!-Kz@m*in(EF%*!$Er4t3{ zg5Jn4QBZk^km|4Fd7@%}))Q@(r(&szAUUcd(D@!7%BOjte%+8gZpa!Dl0+D33{7A^ zKZdR&&fpz6!JWz*7D1fzr_h;CxYrTp!7Lch>feGY*PcxEhn z*~urwmSwt@f@YIsn=7!Cd^a=aGAzJyT32{jZ*p^&a{kq6)+y}2F^`1fwP{32;t_}% z#xa**gj{QH;&mT>#gXumn>eaKn5crwcmB*msp1~vzbclqno3*4{{gEAW1R;=gA1X8 z`{`{QV^Y!heE9OJxau8_eK?L2e1~ZLfVL0u2|kshGx!YW<>&&wz?X9L6)xd2#_2DP Lrz^OMZ!zazE12E6 literal 0 HcmV?d00001 diff --git a/bin/main/InputManager.class b/bin/main/InputManager.class new file mode 100644 index 0000000000000000000000000000000000000000..1afe6b7c981f03b02ff96f7d58059a5e2e083d27 GIT binary patch literal 1997 zcmaJ>ZBrXn6n<_J*koDW!dnG_)dEcbi_|x0Xtc(*L_;0_{lNbe^9OGZnlt&)h~DVo^$Rw&w0*s z@2`LV_!EFbNC z61=EkaA-P1UB050?6HtWjkK!F21H1x&cVwPp2E|#PiBduU7RCn zO*d?uZnQBB{<(h1T$(c%=VbG<3%MKDW%Kjv=F;W+R~K^2H*?=?$i3aN`PKQ{%B5Y? zf!wWovbl6Vw|t9?=G-0g+7%HU@Cn#QbFkte1BovTs$WiA=ofi?&U$ye5VphoPmWI%A?XPlzCQ3am5#bCJ{4@p}tu4XH$=q-&Y(yP>^_sxno(d4t3*whF0^!x8~A(p}2RYB_EWz#6Ogva3z;mO6GcvNtnbb z8ZXzYNY{Ew!t;2+jcJBRul$MJFPopPnTs3d;(~16yqx>tc5Z&bTscMNoHpkWhT15K`Fl(^QKO6cQUp!kt#B4hvNo6_OxQ zVK1uCfNJv9Qh_?iwDY0df>56?V?z+B*IpbT5YJIIH=GY3vWilQp)uIdexoWb@{VFT0If%OmjBVl2kTbZ7U{!Bd^Cp5TXtBOk{VS;Lwtny6)olzq@C!e)WAYx~#)uOq z=bWs$^v1)VU2BxwWi`@5B!i%d#E+NQX(0GPv|^b4PZCtlVP_tU-2lPD3A{~Ey*P$Z zigHlXA-qFPImwsjJntJPA8)f9CE{O@1cX@|tD&Rs;*{O%#}vZH(9UUoZxbKnhcFT8 zq~_IYsNnXvMgJdN-%((G0F9PN+K9joqJAIt5Zy98+k4SfKzh54xr#=jS(rH*4;=0X PXcXw#W0)a>1E>E1dsYH> literal 0 HcmV?d00001 diff --git a/bin/main/JudgeManager.class b/bin/main/JudgeManager.class new file mode 100644 index 0000000000000000000000000000000000000000..7e480b9f739d909148c904da6d0e0e540b119e36 GIT binary patch literal 432 zcmZWlyH3ME5S(?K7#u?$Ko1oO1^$2lLPDZI1|)(~(4C!=xyYQQv&~o0P$5z90elo< z?-D7I(#+mIW@q+(|Gs|!T;eEzM~Lp4c`omT7P&M5d_sRA-bGvpoyU*qLS{9gbD^}V zuL!Ntct-GV%DD{D!fu2%I)q-Lw0vmZQfZz=T1dh$DKk;bgi$tM75(~ERfPRyQ*%P- zy8KC2O~GQPqh#%1S{tSF$#!M@!nU-Nv}#)ncG*iHiQv1a;?dA#hd Un0BI%f!pR`$S-T&XX5J;8E=63geoIdx_{rk!BuK=E6)kK#-|4MUjOZm@~ zt9+?F--IDB@JhaxMMt_j#TQ$zR80${XKmNka{{Tt!L)YyPbkK-_yku3Ojo_p6_=@X7b=y>N{&VO zEQ_o7TwrWZ?y9oq)}-FFb)CCFOIMTlNTJe!R4*p*rHN|-eP^7=CyP9;vt&Dp*W4(y zWD}RQ)QXj;Laduv6fnuaMw5Y$I|TkOs2l{Q!<24a07+`u0+MK2`6Ma}Gq_`-cv{nF zDq>p}cX5xS;V5@U*Q3#>@aU_c>5zA>9iKjXvJp1j`)3RTGn>iv1ClGHLvN{)S?{@^6-UOoe8LJFxH_$|mLo@=*1g`$KD~BLXl`nvU!uJStamW9K(&VYgm9HP&Q%A`B5}7T^&>YHM z%53bwwT~zMD(I&Sga0ICH`mqNK=lK1KOJFs`2$9{j;$Qv{%vER=Ma~V@hR}cxHWFP z#}{4r4e0}n@st~Qj~gj$PLCVMm;$QPhq#@7_wkSEpNVN8m}|M7`zzCCHz30#q)Ds{sQCw0E7*M AZ~y=R literal 0 HcmV?d00001 diff --git a/bin/main/TurnPhase.class b/bin/main/TurnPhase.class new file mode 100644 index 0000000000000000000000000000000000000000..5b702eddd57b09b2b465427caf05555b7f1697be GIT binary patch literal 1058 zcmZ`%T~8B16g|VXyX~?9RzbcML2V0ysNhE{fsmRI3m6xgYxZ}87( zd4OmnKKrALcgD4>5B6d2oay~I=brib>+2epGg$BcX_zV3J=b@`H3ltTsL_PYc0**4Ho=gya053P^m3dslCNITw8Oyl zo29KnElas07Shl&FeDhWU`UXWVA4WHf~*9$Eo3DyCAe$Bgf35W7W!c^3|3t~7PZF@ zq|{usUFTkn2d>2G(u9T_F%1vh4v{)nOMN0frku33C^dTP#jrU!Xt8k z2LV5=w~tR5ib-X=2Q5(#OIr!Cf3HX_gP}(5ejqu?vUnkd#DXQ&rxup6!myIe-Sl{; zQ%Vfz6*60Q5 z>toU@fFjwXA~~cYnWG~40t}5ySEwRI4qn3m)ejQ-L|Fcs-@u&QkamviXBbxCR!V_U z1;*0~Oeip=D=@9V9YcYc%y;Ubbunx^sV+usC*8$_?dV-h+m6x2jD3dLFEpwT_vmX< zl;;g1a$lV!q9+;?TPAr@pi!KkJja8pLY)#27g_3TATJftV=SN;m#@-RWcf%Jv(6i> zc>7PF|lHDYsEcyF5?op&1Im^tk;su`k0Q-MkA68Y*XLzpSi{Eav B(LewI literal 0 HcmV?d00001 diff --git a/bin/test/.gitkeep b/bin/test/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 79664797..aeb2ffea 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -1,3 +1,6 @@ +import java.util.Map; +import java.util.HashMap; + public class GameManager { private TurnPhase _turnPhase; private NumberGenerator _numberGenerator; @@ -5,50 +8,51 @@ public class GameManager { private JudgeManager _judgeManager; private String _generatedNumber; private String _userNumber; + private Map _phaseHandler; public GameManager(){ _turnPhase = TurnPhase.idle; _numberGenerator = new NumberGenerator(); _inputManager = new InputManager(); _judgeManager = new JudgeManager(); + + _phaseHandler = new HashMap<>(); + _phaseHandler.put(TurnPhase.idle, this::handleIdlePhase); + _phaseHandler.put(TurnPhase.generateNumber, this::handleGenerateNumberPhase); + _phaseHandler.put(TurnPhase.inputNumber, this::handleInputNumberPhase); + _phaseHandler.put(TurnPhase.judgeResult, this::handleJudgeResultPhase); } - private void idlePhasePlay() { - if (_turnPhase != TurnPhase.idle) return; + private void handleIdlePhase() { boolean idleFlag = _inputManager.IdleInput(); - if (idleFlag){ - _turnPhase = TurnPhase.generateNumber; - _generatedNumber = ""; + + _turnPhase = idleFlag ? TurnPhase.generateNumber : TurnPhase.quit; + _generatedNumber = idleFlag ? "" : _generatedNumber; + } + + private void handleGenerateNumberPhase() { + _generatedNumber = _numberGenerator.GenerateNumber(); + _turnPhase = TurnPhase.inputNumber; + } + + private void handleInputNumberPhase() { + _userNumber = _inputManager.PredictionInput(); + System.out.println(_userNumber); + _turnPhase = TurnPhase.judgeResult; + } + + private void handleJudgeResultPhase() { + boolean result = _judgeManager.JudgeResult(_generatedNumber, _userNumber); + if (!result) { + _turnPhase = TurnPhase.inputNumber; return; } - _turnPhase = TurnPhase.quit; + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝"); + _turnPhase = TurnPhase.idle; } public void PlayGame(){ - while(true){ - if (_turnPhase == TurnPhase.quit) break; - if (_turnPhase == TurnPhase.idle) { - idlePhasePlay(); - continue; - } - if (_turnPhase == TurnPhase.generateNumber) { - _generatedNumber = _numberGenerator.GenerateNumber(); - _turnPhase = TurnPhase.inputNumber; - continue; - } - if (_turnPhase == TurnPhase.inputNumber) { - _userNumber = _inputManager.PredictionInput(); - System.out.println(_userNumber); - _turnPhase = TurnPhase.judgeResult; - continue; - } - if (_turnPhase == TurnPhase.judgeResult){ - boolean result = _judgeManager.JudgeResult(_generatedNumber, _userNumber); - if (result) { - System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝"); - _turnPhase = TurnPhase.idle; - continue; - } - _turnPhase = TurnPhase.inputNumber; - } + while(_turnPhase != TurnPhase.quit){ + Runnable handler = _phaseHandler.get(_turnPhase); + handler.run(); } } } From 43263e9a81c61812e5199f7cbd0de4ac7d14a7ef Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Thu, 29 Jan 2026 00:43:14 +0900 Subject: [PATCH 10/22] input change string from integer --- src/main/java/GameManager.java | 1 - src/main/java/InputManager.java | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index aeb2ffea..91c77b68 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -35,7 +35,6 @@ private void handleGenerateNumberPhase() { private void handleInputNumberPhase() { _userNumber = _inputManager.PredictionInput(); - System.out.println(_userNumber); _turnPhase = TurnPhase.judgeResult; } diff --git a/src/main/java/InputManager.java b/src/main/java/InputManager.java index 1ffb4e10..925778a6 100644 --- a/src/main/java/InputManager.java +++ b/src/main/java/InputManager.java @@ -8,19 +8,19 @@ public InputManager() { scanner = new Scanner(System.in); } public boolean IdleInput(){ - System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요"); - int flag = -1; - while(true){ - flag = scanner.nextInt(); + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + String flag = ""; + while(true) { + flag = scanner.next(); // 게임 플레이 - if (flag == 1){ + if (flag.equals("1")) { return true; } // 게임 종료 - if (flag == 2){ + if (flag.equals("2")) { return false; } - System.out.println("1 혹은 2를 입력해주세요"); + System.out.println("1 혹은 2를 입력해주세요."); } } private boolean IsProperInput(String s){ From 7363a220d469e81d71c2b16e7163981d75b92dc2 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Thu, 29 Jan 2026 01:00:33 +0900 Subject: [PATCH 11/22] judgemanager implementation --- src/main/java/GameManager.java | 8 +++++--- src/main/java/JudgeManager.java | 17 +++++++++++++++-- src/main/java/JudgeResult.java | 2 ++ 3 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 src/main/java/JudgeResult.java diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 91c77b68..f56ed5a4 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -10,7 +10,7 @@ public class GameManager { private String _userNumber; private Map _phaseHandler; public GameManager(){ - _turnPhase = TurnPhase.idle; + _turnPhase = TurnPhase.generateNumber; _numberGenerator = new NumberGenerator(); _inputManager = new InputManager(); _judgeManager = new JudgeManager(); @@ -39,9 +39,11 @@ private void handleInputNumberPhase() { } private void handleJudgeResultPhase() { - boolean result = _judgeManager.JudgeResult(_generatedNumber, _userNumber); - if (!result) { + JudgeResult result = _judgeManager.JudgeResult(_generatedNumber, _userNumber); + if (result.strike() != 3) { _turnPhase = TurnPhase.inputNumber; + String resultString = result.strike() + result.ball() == 0 ? "낫씽" : result.strike() + "스트라이크 " + result.ball() + "볼"; + System.out.println(resultString); return; } System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝"); diff --git a/src/main/java/JudgeManager.java b/src/main/java/JudgeManager.java index a51cde79..ef32e173 100644 --- a/src/main/java/JudgeManager.java +++ b/src/main/java/JudgeManager.java @@ -1,6 +1,19 @@ +import java.util.Map; +import java.util.HashMap; public class JudgeManager { public JudgeManager() {} - public boolean JudgeResult(String number, String user){ - return true; + public JudgeResult JudgeResult(String number, String user){ + Map map = new HashMap<>(); + for (int i=0; i<3; i++){ + map.put(number.charAt(i), ""); + map.put(user.charAt(i), ""); + } + int ball = 6 - map.size(); + int strike = 0; + for (int i=0; i<3; i++){ + if (number.charAt(i) == user.charAt(i)) strike ++; + } + ball -= strike; + return new JudgeResult(strike, ball); } } diff --git a/src/main/java/JudgeResult.java b/src/main/java/JudgeResult.java new file mode 100644 index 00000000..9712195a --- /dev/null +++ b/src/main/java/JudgeResult.java @@ -0,0 +1,2 @@ +public record JudgeResult(int strike, int ball) { +} From f6ad9c124409f814de1836a8b3426be1541d5451 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Thu, 29 Jan 2026 12:43:01 +0900 Subject: [PATCH 12/22] final keyword add --- src/main/java/GameManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index f56ed5a4..13fe1aa1 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -3,12 +3,12 @@ public class GameManager { private TurnPhase _turnPhase; - private NumberGenerator _numberGenerator; - private InputManager _inputManager; - private JudgeManager _judgeManager; + private final NumberGenerator _numberGenerator; + private final InputManager _inputManager; + private final JudgeManager _judgeManager; private String _generatedNumber; private String _userNumber; - private Map _phaseHandler; + private final Map _phaseHandler; public GameManager(){ _turnPhase = TurnPhase.generateNumber; _numberGenerator = new NumberGenerator(); From d8930ca85b4c3777a1f36a303131dfad967d1029 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Thu, 29 Jan 2026 12:54:47 +0900 Subject: [PATCH 13/22] wrong player input error message change --- src/main/java/InputManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/InputManager.java b/src/main/java/InputManager.java index 925778a6..0142589c 100644 --- a/src/main/java/InputManager.java +++ b/src/main/java/InputManager.java @@ -37,7 +37,7 @@ public String PredictionInput(){ while(true) { String userInput = scanner.next(); if (!IsProperInput((userInput))) { - System.out.println("1 ~ 9 사이의 중복되지 않는 세 자리 숫자를 입력해주세요."); + System.out.print("1 ~ 9 사이의 중복되지 않는 세 자리 숫자를 입력해주세요.\n숫자를 입력해주세요 : "); continue; } return userInput; From 20c832df8a8c4ad35fea5fddd0b68e01dbc99157 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Thu, 29 Jan 2026 12:55:30 +0900 Subject: [PATCH 14/22] turnphase added to gamemanager constructor parameter for test code: --- src/main/java/App.java | 2 +- src/main/java/GameManager.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/App.java b/src/main/java/App.java index 5312ac43..02839779 100644 --- a/src/main/java/App.java +++ b/src/main/java/App.java @@ -1,7 +1,7 @@ public class App { private GameManager _gameManager; public static void main (String[] args){ - GameManager _gameManager = new GameManager(); + GameManager _gameManager = new GameManager(TurnPhase.generateNumber); _gameManager.PlayGame(); } } \ No newline at end of file diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index 13fe1aa1..f2a0be2d 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -9,8 +9,8 @@ public class GameManager { private String _generatedNumber; private String _userNumber; private final Map _phaseHandler; - public GameManager(){ - _turnPhase = TurnPhase.generateNumber; + public GameManager(TurnPhase turnPhase){ + _turnPhase = turnPhase; _numberGenerator = new NumberGenerator(); _inputManager = new InputManager(); _judgeManager = new JudgeManager(); From 5962991f6de5738638a6a1ff61ba39367688592a Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Mon, 2 Feb 2026 17:27:38 +0900 Subject: [PATCH 15/22] input/output responsibillity divide --- src/main/java/ErrorEnum.java | 3 +++ src/main/java/GameManager.java | 45 ++++++++++++++++++++++++++------ src/main/java/InputManager.java | 39 ++------------------------- src/main/java/OutputManager.java | 34 ++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 45 deletions(-) create mode 100644 src/main/java/ErrorEnum.java create mode 100644 src/main/java/OutputManager.java diff --git a/src/main/java/ErrorEnum.java b/src/main/java/ErrorEnum.java new file mode 100644 index 00000000..bd9c7f1c --- /dev/null +++ b/src/main/java/ErrorEnum.java @@ -0,0 +1,3 @@ +public enum ErrorEnum { + idleInputError, userInputError +} diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index f2a0be2d..a3ff8b10 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -6,6 +6,7 @@ public class GameManager { 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 _phaseHandler; @@ -14,6 +15,7 @@ public GameManager(TurnPhase turnPhase){ _numberGenerator = new NumberGenerator(); _inputManager = new InputManager(); _judgeManager = new JudgeManager(); + _outputManager = new OutputManager(); _phaseHandler = new HashMap<>(); _phaseHandler.put(TurnPhase.idle, this::handleIdlePhase); @@ -21,11 +23,21 @@ public GameManager(TurnPhase turnPhase){ _phaseHandler.put(TurnPhase.inputNumber, this::handleInputNumberPhase); _phaseHandler.put(TurnPhase.judgeResult, this::handleJudgeResultPhase); } + private void handleIdlePhase() { - boolean idleFlag = _inputManager.IdleInput(); - - _turnPhase = idleFlag ? TurnPhase.generateNumber : TurnPhase.quit; - _generatedNumber = idleFlag ? "" : _generatedNumber; + while (true) { + String idleInput = _inputManager.GetInput(); + if (idleInput.equals("1")) { + _turnPhase = TurnPhase.generateNumber; + _generatedNumber = ""; + return; + } + if (idleInput.equals("2")) { + _turnPhase = TurnPhase.quit; + return; + } + _outputManager.PrintErrorMessage(ErrorEnum.idleInputError); + } } private void handleGenerateNumberPhase() { @@ -33,25 +45,42 @@ private void handleGenerateNumberPhase() { _turnPhase = TurnPhase.inputNumber; } + private boolean IsProperInput(String s){ + if (s.length() != 3) return false; + Map map = new HashMap<>(); + for (int i=0; i<3; i++){ + if ((49 > s.charAt(i) || s.charAt(i) > 57) || map.get(s.charAt(i)) != null) return false; + map.put(s.charAt(i), ""); + } + return true; + } + private void handleInputNumberPhase() { - _userNumber = _inputManager.PredictionInput(); + while(true) { + String userInput = _inputManager.GetInput(); + if (!IsProperInput((userInput))) { + _outputManager.PrintErrorMessage(ErrorEnum.userInputError); + continue; + } + _userNumber = userInput; + break; + } _turnPhase = TurnPhase.judgeResult; } private void handleJudgeResultPhase() { JudgeResult result = _judgeManager.JudgeResult(_generatedNumber, _userNumber); + _outputManager.PrintJudgeResult(result); if (result.strike() != 3) { _turnPhase = TurnPhase.inputNumber; - String resultString = result.strike() + result.ball() == 0 ? "낫씽" : result.strike() + "스트라이크 " + result.ball() + "볼"; - System.out.println(resultString); return; } - System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝"); _turnPhase = TurnPhase.idle; } public void PlayGame(){ while(_turnPhase != TurnPhase.quit){ + _outputManager.PrintPhaseStartMessage(_turnPhase); Runnable handler = _phaseHandler.get(_turnPhase); handler.run(); } diff --git a/src/main/java/InputManager.java b/src/main/java/InputManager.java index 0142589c..a5c673d4 100644 --- a/src/main/java/InputManager.java +++ b/src/main/java/InputManager.java @@ -1,46 +1,11 @@ import java.util.Scanner; -import java.util.HashMap; -import java.util.Map; public class InputManager { Scanner scanner; public InputManager() { scanner = new Scanner(System.in); } - public boolean IdleInput(){ - System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); - String flag = ""; - while(true) { - flag = scanner.next(); - // 게임 플레이 - if (flag.equals("1")) { - return true; - } - // 게임 종료 - if (flag.equals("2")) { - return false; - } - System.out.println("1 혹은 2를 입력해주세요."); - } - } - private boolean IsProperInput(String s){ - if (s.length() != 3) return false; - Map map = new HashMap<>(); - for (int i=0; i<3; i++){ - if ((49 > s.charAt(i) || s.charAt(i) > 57) || map.get(s.charAt(i)) != null) return false; - map.put(s.charAt(i), ""); - } - return true; - } - public String PredictionInput(){ - System.out.print("숫자를 입력해주세요 : "); - while(true) { - String userInput = scanner.next(); - if (!IsProperInput((userInput))) { - System.out.print("1 ~ 9 사이의 중복되지 않는 세 자리 숫자를 입력해주세요.\n숫자를 입력해주세요 : "); - continue; - } - return userInput; - } + public String GetInput() { + return scanner.next(); } } diff --git a/src/main/java/OutputManager.java b/src/main/java/OutputManager.java new file mode 100644 index 00000000..3a8a73f5 --- /dev/null +++ b/src/main/java/OutputManager.java @@ -0,0 +1,34 @@ +import java.util.HashMap; +import java.util.Map; + +public class OutputManager { + // errorEnumStringMap의 string에는 뒤에 \n을 넣어 출력 메서드는 println이 아닌 print를 사용 + private final Map _errorEnumStringMap; + private final Map _phaseStartMessageMap; + public OutputManager () { + _errorEnumStringMap = new HashMap<>(); + _errorEnumStringMap.put(ErrorEnum.idleInputError, "1 혹은 2를 입력해주세요.\n"); + _errorEnumStringMap.put(ErrorEnum.userInputError, "1 ~ 9 사이의 중복되지 않는 세 자리 숫자를 입력해주세요.\n숫자를 입력해주세요 : "); + + _phaseStartMessageMap = new HashMap<>(); + _phaseStartMessageMap.put(TurnPhase.idle, "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.\n"); + _phaseStartMessageMap.put(TurnPhase.inputNumber, "숫자를 입력해주세요 : "); + } + public void PrintErrorMessage(ErrorEnum errorEnum) { + if (_errorEnumStringMap.containsKey((errorEnum))) System.out.print(_errorEnumStringMap.get(errorEnum)); + } + + public void PrintPhaseStartMessage(TurnPhase turnPhase){ + if (_phaseStartMessageMap.containsKey(turnPhase)) System.out.print(_phaseStartMessageMap.get(turnPhase)); + } + + public void PrintJudgeResult(JudgeResult result){ + if (result.strike() == 3) { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝"); + return; + } + String resultString = result.strike() + result.ball() == 0 ? "낫씽" : result.strike() + "스트라이크 " + result.ball() + "볼"; + System.out.println(resultString); + } + +} From a118617820cfef5cd00fff1ed99d7646c31cbe94 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Mon, 2 Feb 2026 17:30:49 +0900 Subject: [PATCH 16/22] magic number delete --- src/main/java/JudgeManager.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/JudgeManager.java b/src/main/java/JudgeManager.java index ef32e173..520158e8 100644 --- a/src/main/java/JudgeManager.java +++ b/src/main/java/JudgeManager.java @@ -2,15 +2,17 @@ import java.util.HashMap; public class JudgeManager { public JudgeManager() {} + private static final int BASEBALL_SIZE = 3; + private static final int PLAYER_CNT = 2; public JudgeResult JudgeResult(String number, String user){ Map map = new HashMap<>(); - for (int i=0; i<3; i++){ + for (int i=0; i Date: Mon, 2 Feb 2026 17:31:43 +0900 Subject: [PATCH 17/22] magic number delete 2 --- src/main/java/NumberGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/NumberGenerator.java b/src/main/java/NumberGenerator.java index 4c196737..354b7ac8 100644 --- a/src/main/java/NumberGenerator.java +++ b/src/main/java/NumberGenerator.java @@ -3,12 +3,13 @@ import java.util.Random; public class NumberGenerator { + private static final int BASEBALL_SIZE = 3; public NumberGenerator() {} public String GenerateNumber() { String result = ""; Map map = new HashMap<>(); Random random = new Random(); - while(result.length() < 3) { + while(result.length() < BASEBALL_SIZE) { String randomNumber =random.nextInt(1, 9) + ""; if (map.get(randomNumber) != null) continue; map.put(randomNumber, ""); From d85b8cef64ae166eea3e57a0ff834d220ee6d0f4 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Mon, 2 Feb 2026 17:32:22 +0900 Subject: [PATCH 18/22] magic number delete 3 --- src/main/java/GameManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/GameManager.java b/src/main/java/GameManager.java index a3ff8b10..b6289166 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/GameManager.java @@ -10,6 +10,7 @@ public class GameManager { private String _generatedNumber; private String _userNumber; private final Map _phaseHandler; + private static final int BASEBALL_SIZE = 3; public GameManager(TurnPhase turnPhase){ _turnPhase = turnPhase; _numberGenerator = new NumberGenerator(); @@ -71,7 +72,7 @@ private void handleInputNumberPhase() { private void handleJudgeResultPhase() { JudgeResult result = _judgeManager.JudgeResult(_generatedNumber, _userNumber); _outputManager.PrintJudgeResult(result); - if (result.strike() != 3) { + if (result.strike() != BASEBALL_SIZE) { _turnPhase = TurnPhase.inputNumber; return; } From cdce441fdfc1aa7a1aa4ce401cf9d22506d0b43b Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Mon, 2 Feb 2026 18:02:11 +0900 Subject: [PATCH 19/22] directory refactored --- src/main/java/App.java | 3 +++ src/main/java/{ => Constant}/ErrorEnum.java | 2 ++ src/main/java/{ => Constant}/JudgeResult.java | 2 ++ src/main/java/{ => Constant}/TurnPhase.java | 2 ++ src/main/java/{ => Controller}/GameManager.java | 10 ++++++++++ src/main/java/{ => Model}/JudgeManager.java | 3 +++ src/main/java/{ => Model}/NumberGenerator.java | 2 ++ src/main/java/{ => View}/InputManager.java | 2 ++ src/main/java/{ => View}/OutputManager.java | 5 +++++ 9 files changed, 31 insertions(+) rename src/main/java/{ => Constant}/ErrorEnum.java (76%) rename src/main/java/{ => Constant}/JudgeResult.java (73%) rename src/main/java/{ => Constant}/TurnPhase.java (81%) rename src/main/java/{ => Controller}/GameManager.java (93%) rename src/main/java/{ => Model}/JudgeManager.java (94%) rename src/main/java/{ => Model}/NumberGenerator.java (97%) rename src/main/java/{ => View}/InputManager.java (93%) rename src/main/java/{ => View}/OutputManager.java (94%) diff --git a/src/main/java/App.java b/src/main/java/App.java index 02839779..6741af74 100644 --- a/src/main/java/App.java +++ b/src/main/java/App.java @@ -1,3 +1,6 @@ +import Constant.TurnPhase; +import Controller.GameManager; + public class App { private GameManager _gameManager; public static void main (String[] args){ diff --git a/src/main/java/ErrorEnum.java b/src/main/java/Constant/ErrorEnum.java similarity index 76% rename from src/main/java/ErrorEnum.java rename to src/main/java/Constant/ErrorEnum.java index bd9c7f1c..77e18bdc 100644 --- a/src/main/java/ErrorEnum.java +++ b/src/main/java/Constant/ErrorEnum.java @@ -1,3 +1,5 @@ +package Constant; + public enum ErrorEnum { idleInputError, userInputError } diff --git a/src/main/java/JudgeResult.java b/src/main/java/Constant/JudgeResult.java similarity index 73% rename from src/main/java/JudgeResult.java rename to src/main/java/Constant/JudgeResult.java index 9712195a..c62e1c8a 100644 --- a/src/main/java/JudgeResult.java +++ b/src/main/java/Constant/JudgeResult.java @@ -1,2 +1,4 @@ +package Constant; + public record JudgeResult(int strike, int ball) { } diff --git a/src/main/java/TurnPhase.java b/src/main/java/Constant/TurnPhase.java similarity index 81% rename from src/main/java/TurnPhase.java rename to src/main/java/Constant/TurnPhase.java index 8adf6e3c..abc63e75 100644 --- a/src/main/java/TurnPhase.java +++ b/src/main/java/Constant/TurnPhase.java @@ -1,3 +1,5 @@ +package Constant; + public enum TurnPhase { quit, idle, generateNumber, inputNumber, judgeResult } diff --git a/src/main/java/GameManager.java b/src/main/java/Controller/GameManager.java similarity index 93% rename from src/main/java/GameManager.java rename to src/main/java/Controller/GameManager.java index b6289166..2530dcba 100644 --- a/src/main/java/GameManager.java +++ b/src/main/java/Controller/GameManager.java @@ -1,3 +1,13 @@ +package Controller; + +import Model.JudgeManager; +import Model.NumberGenerator; +import View.InputManager; +import View.OutputManager; +import Constant.TurnPhase; +import Constant.ErrorEnum; +import Constant.JudgeResult; + import java.util.Map; import java.util.HashMap; diff --git a/src/main/java/JudgeManager.java b/src/main/java/Model/JudgeManager.java similarity index 94% rename from src/main/java/JudgeManager.java rename to src/main/java/Model/JudgeManager.java index 520158e8..29b781b0 100644 --- a/src/main/java/JudgeManager.java +++ b/src/main/java/Model/JudgeManager.java @@ -1,3 +1,6 @@ +package Model; + +import Constant.JudgeResult; import java.util.Map; import java.util.HashMap; public class JudgeManager { diff --git a/src/main/java/NumberGenerator.java b/src/main/java/Model/NumberGenerator.java similarity index 97% rename from src/main/java/NumberGenerator.java rename to src/main/java/Model/NumberGenerator.java index 354b7ac8..17812451 100644 --- a/src/main/java/NumberGenerator.java +++ b/src/main/java/Model/NumberGenerator.java @@ -1,3 +1,5 @@ +package Model; + import java.util.HashMap; import java.util.Map; import java.util.Random; diff --git a/src/main/java/InputManager.java b/src/main/java/View/InputManager.java similarity index 93% rename from src/main/java/InputManager.java rename to src/main/java/View/InputManager.java index a5c673d4..d2883648 100644 --- a/src/main/java/InputManager.java +++ b/src/main/java/View/InputManager.java @@ -1,3 +1,5 @@ +package View; + import java.util.Scanner; public class InputManager { diff --git a/src/main/java/OutputManager.java b/src/main/java/View/OutputManager.java similarity index 94% rename from src/main/java/OutputManager.java rename to src/main/java/View/OutputManager.java index 3a8a73f5..e9c2f1e5 100644 --- a/src/main/java/OutputManager.java +++ b/src/main/java/View/OutputManager.java @@ -1,5 +1,10 @@ +package View; + import java.util.HashMap; import java.util.Map; +import Constant.ErrorEnum; +import Constant.TurnPhase; +import Constant.JudgeResult; public class OutputManager { // errorEnumStringMap의 string에는 뒤에 \n을 넣어 출력 메서드는 println이 아닌 print를 사용 From 1010bb59d638fe464f4f5bfa2dc94c07d1fc7f07 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Mon, 2 Feb 2026 19:28:17 +0900 Subject: [PATCH 20/22] test added --- src/main/java/Model/NumberGenerator.java | 18 +++++++ src/test/java/AppTest.java | 17 +++++++ src/test/java/Model/JudgeManagerTest.java | 51 ++++++++++++++++++++ src/test/java/Model/NumberGeneratorTest.java | 34 +++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 src/test/java/AppTest.java create mode 100644 src/test/java/Model/JudgeManagerTest.java create mode 100644 src/test/java/Model/NumberGeneratorTest.java diff --git a/src/main/java/Model/NumberGenerator.java b/src/main/java/Model/NumberGenerator.java index 17812451..00741363 100644 --- a/src/main/java/Model/NumberGenerator.java +++ b/src/main/java/Model/NumberGenerator.java @@ -19,4 +19,22 @@ public String GenerateNumber() { } return result; } + + public String GenerateFixedNumber(String fixedNumber) { + if (!IsProperNumber(fixedNumber)) { + throw new IllegalArgumentException("Invalid fixed number"); + } + return fixedNumber; + } + + private boolean IsProperNumber(String number) { + if (number == null || number.length() != BASEBALL_SIZE) return false; + Map map = new HashMap<>(); + for (int i = 0; i < BASEBALL_SIZE; i++) { + char c = number.charAt(i); + if (c < '1' || c > '9' || map.containsKey(c)) return false; + map.put(c, ""); + } + return true; + } } diff --git a/src/test/java/AppTest.java b/src/test/java/AppTest.java new file mode 100644 index 00000000..183dec4e --- /dev/null +++ b/src/test/java/AppTest.java @@ -0,0 +1,17 @@ +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import static org.assertj.core.api.Assertions.assertThat; + +class AppTest { + @Test + void mainMethodHasExpectedSignature() throws Exception { + Method main = App.class.getDeclaredMethod("main", String[].class); + + assertThat(main.getReturnType()).isEqualTo(void.class); + assertThat(Modifier.isPublic(main.getModifiers())).isTrue(); + assertThat(Modifier.isStatic(main.getModifiers())).isTrue(); + } +} diff --git a/src/test/java/Model/JudgeManagerTest.java b/src/test/java/Model/JudgeManagerTest.java new file mode 100644 index 00000000..7e95f243 --- /dev/null +++ b/src/test/java/Model/JudgeManagerTest.java @@ -0,0 +1,51 @@ +package Model; + +import Constant.JudgeResult; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +class JudgeManagerTest { + private static Stream judgeCases() { + return Stream.of( + Arguments.of("456", 0, 0), + Arguments.of("415", 0, 1), + Arguments.of("314", 0, 2), + Arguments.of("312", 0, 3), + Arguments.of("145", 1, 0), + Arguments.of("134", 1, 1), + Arguments.of("132", 1, 2), + Arguments.of("124", 2, 0), + Arguments.of("123", 3, 0) + ); + } + + @ParameterizedTest + @MethodSource("judgeCases") + void judgeResultCoversValidStrikeBallCombinations(String userNumber, int strike, int ball) { + JudgeManager judgeManager = new JudgeManager(); + + JudgeResult result = judgeManager.JudgeResult("123", userNumber); + + assertThat(result.strike()).isEqualTo(strike); + assertThat(result.ball()).isEqualTo(ball); + } + + @Test + void twoStrikeOneBallIsNotReachableWithUniqueDigits() { + JudgeManager judgeManager = new JudgeManager(); + String[] permutations = {"123", "132", "213", "231", "312", "321"}; + + for (String userNumber : permutations) { + JudgeResult result = judgeManager.JudgeResult("123", userNumber); + assertThat(result.strike() == 2 && result.ball() == 1) + .as("2S1B should be unreachable for %s", userNumber) + .isFalse(); + } + } +} diff --git a/src/test/java/Model/NumberGeneratorTest.java b/src/test/java/Model/NumberGeneratorTest.java new file mode 100644 index 00000000..48efa72a --- /dev/null +++ b/src/test/java/Model/NumberGeneratorTest.java @@ -0,0 +1,34 @@ +package Model; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class NumberGeneratorTest { + @Test + void generateFixedNumberReturnsSameValueWhenValid() { + NumberGenerator generator = new NumberGenerator(); + + assertThat(generator.GenerateFixedNumber("123")).isEqualTo("123"); + } + + @ParameterizedTest + @ValueSource(strings = {"12", "1234", "012", "11", "1a3", "9 1", "990"}) + void generateFixedNumberRejectsInvalidValues(String value) { + NumberGenerator generator = new NumberGenerator(); + + assertThatThrownBy(() -> generator.GenerateFixedNumber(value)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void generateFixedNumberRejectsNull() { + NumberGenerator generator = new NumberGenerator(); + + assertThatThrownBy(() -> generator.GenerateFixedNumber(null)) + .isInstanceOf(IllegalArgumentException.class); + } +} From be0d052c06cefe0bd475d586ea579b1ce595c4ab Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Tue, 3 Feb 2026 15:40:49 +0900 Subject: [PATCH 21/22] test iteration final --- src/main/java/App.java | 17 +- src/main/java/Constant/ErrorEnum.java | 5 +- src/main/java/Constant/JudgeResult.java | 2 +- src/main/java/Constant/TurnPhase.java | 8 +- src/main/java/Controller/GameManager.java | 183 ++++++++++--------- src/main/java/Model/JudgeManager.java | 46 +++-- src/main/java/Model/NumberGenerator.java | 70 +++---- src/main/java/View/InputManager.java | 18 +- src/main/java/View/OutputManager.java | 75 ++++---- src/test/java/AppTest.java | 18 +- src/test/java/Model/JudgeManagerTest.java | 85 ++++----- src/test/java/Model/NumberGeneratorTest.java | 44 ++--- 12 files changed, 306 insertions(+), 265 deletions(-) diff --git a/src/main/java/App.java b/src/main/java/App.java index 6741af74..d8ba08a3 100644 --- a/src/main/java/App.java +++ b/src/main/java/App.java @@ -1,10 +1,11 @@ -import Constant.TurnPhase; -import Controller.GameManager; +import constant.TurnPhase; +import controller.GameManager; public class App { - private GameManager _gameManager; - public static void main (String[] args){ - GameManager _gameManager = new GameManager(TurnPhase.generateNumber); - _gameManager.PlayGame(); - } -} \ No newline at end of file + private GameManager _gameManager; + + public static void main(String[] args) { + GameManager _gameManager = new GameManager(TurnPhase.GENERATE_NUMBER); + _gameManager.playGame(); + } +} diff --git a/src/main/java/Constant/ErrorEnum.java b/src/main/java/Constant/ErrorEnum.java index 77e18bdc..b8ac14c5 100644 --- a/src/main/java/Constant/ErrorEnum.java +++ b/src/main/java/Constant/ErrorEnum.java @@ -1,5 +1,6 @@ -package Constant; +package constant; public enum ErrorEnum { - idleInputError, userInputError + IDLE_INPUT_ERROR, + USER_INPUT_ERROR } diff --git a/src/main/java/Constant/JudgeResult.java b/src/main/java/Constant/JudgeResult.java index c62e1c8a..3dd28663 100644 --- a/src/main/java/Constant/JudgeResult.java +++ b/src/main/java/Constant/JudgeResult.java @@ -1,4 +1,4 @@ -package Constant; +package constant; public record JudgeResult(int strike, int ball) { } diff --git a/src/main/java/Constant/TurnPhase.java b/src/main/java/Constant/TurnPhase.java index abc63e75..1e76ad0d 100644 --- a/src/main/java/Constant/TurnPhase.java +++ b/src/main/java/Constant/TurnPhase.java @@ -1,5 +1,9 @@ -package Constant; +package constant; public enum TurnPhase { - quit, idle, generateNumber, inputNumber, judgeResult + QUIT, + IDLE, + GENERATE_NUMBER, + INPUT_NUMBER, + JUDGE_RESULT } diff --git a/src/main/java/Controller/GameManager.java b/src/main/java/Controller/GameManager.java index 2530dcba..7e9dee25 100644 --- a/src/main/java/Controller/GameManager.java +++ b/src/main/java/Controller/GameManager.java @@ -1,99 +1,106 @@ -package Controller; +package controller; -import Model.JudgeManager; -import Model.NumberGenerator; -import View.InputManager; -import View.OutputManager; -import Constant.TurnPhase; -import Constant.ErrorEnum; -import Constant.JudgeResult; - -import java.util.Map; 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 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 _phaseHandler; - private static final int BASEBALL_SIZE = 3; - public GameManager(TurnPhase turnPhase){ - _turnPhase = turnPhase; - _numberGenerator = new NumberGenerator(); - _inputManager = new InputManager(); - _judgeManager = new JudgeManager(); - _outputManager = new OutputManager(); + 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 _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); + } - _phaseHandler = new HashMap<>(); - _phaseHandler.put(TurnPhase.idle, this::handleIdlePhase); - _phaseHandler.put(TurnPhase.generateNumber, this::handleGenerateNumberPhase); - _phaseHandler.put(TurnPhase.inputNumber, this::handleInputNumberPhase); - _phaseHandler.put(TurnPhase.judgeResult, 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 handleIdlePhase() { - while (true) { - String idleInput = _inputManager.GetInput(); - if (idleInput.equals("1")) { - _turnPhase = TurnPhase.generateNumber; - _generatedNumber = ""; - return; - } - if (idleInput.equals("2")) { - _turnPhase = TurnPhase.quit; - return; - } - _outputManager.PrintErrorMessage(ErrorEnum.idleInputError); - } - } + private void handleGenerateNumberPhase() { + _generatedNumber = _numberGenerator.generateNumber(); + _turnPhase = TurnPhase.INPUT_NUMBER; + } - private void handleGenerateNumberPhase() { - _generatedNumber = _numberGenerator.GenerateNumber(); - _turnPhase = TurnPhase.inputNumber; - } + private boolean isProperInput(String input) { + if (input.length() != BASEBALL_SIZE) { + return false; + } + Map 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 boolean IsProperInput(String s){ - if (s.length() != 3) return false; - Map map = new HashMap<>(); - for (int i=0; i<3; i++){ - if ((49 > s.charAt(i) || s.charAt(i) > 57) || map.get(s.charAt(i)) != null) return false; - map.put(s.charAt(i), ""); - } - 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 handleInputNumberPhase() { - while(true) { - String userInput = _inputManager.GetInput(); - if (!IsProperInput((userInput))) { - _outputManager.PrintErrorMessage(ErrorEnum.userInputError); - continue; - } - _userNumber = userInput; - break; - } - _turnPhase = TurnPhase.judgeResult; - } - - private void handleJudgeResultPhase() { - JudgeResult result = _judgeManager.JudgeResult(_generatedNumber, _userNumber); - _outputManager.PrintJudgeResult(result); - if (result.strike() != BASEBALL_SIZE) { - _turnPhase = TurnPhase.inputNumber; - return; - } - _turnPhase = TurnPhase.idle; - } + 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(); - } - } + public void playGame() { + while (_turnPhase != TurnPhase.QUIT) { + _outputManager.printPhaseStartMessage(_turnPhase); + Runnable handler = _phaseHandler.get(_turnPhase); + handler.run(); + } + } } diff --git a/src/main/java/Model/JudgeManager.java b/src/main/java/Model/JudgeManager.java index 29b781b0..d7eb2324 100644 --- a/src/main/java/Model/JudgeManager.java +++ b/src/main/java/Model/JudgeManager.java @@ -1,24 +1,30 @@ -package Model; +package model; -import Constant.JudgeResult; -import java.util.Map; import java.util.HashMap; +import java.util.Map; + +import constant.JudgeResult; + public class JudgeManager { - public JudgeManager() {} - private static final int BASEBALL_SIZE = 3; - private static final int PLAYER_CNT = 2; - public JudgeResult JudgeResult(String number, String user){ - Map map = new HashMap<>(); - for (int i=0; i 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); + } } diff --git a/src/main/java/Model/NumberGenerator.java b/src/main/java/Model/NumberGenerator.java index 00741363..5fd4de8c 100644 --- a/src/main/java/Model/NumberGenerator.java +++ b/src/main/java/Model/NumberGenerator.java @@ -1,40 +1,48 @@ -package Model; +package model; import java.util.HashMap; import java.util.Map; import java.util.Random; public class NumberGenerator { - private static final int BASEBALL_SIZE = 3; - public NumberGenerator() {} - public String GenerateNumber() { - String result = ""; - Map map = new HashMap<>(); - Random random = new Random(); - while(result.length() < BASEBALL_SIZE) { - String randomNumber =random.nextInt(1, 9) + ""; - if (map.get(randomNumber) != null) continue; - map.put(randomNumber, ""); - result += randomNumber; - } - return result; - } + private static final int BASEBALL_SIZE = 3; - public String GenerateFixedNumber(String fixedNumber) { - if (!IsProperNumber(fixedNumber)) { - throw new IllegalArgumentException("Invalid fixed number"); - } - return fixedNumber; - } + public NumberGenerator() {} - private boolean IsProperNumber(String number) { - if (number == null || number.length() != BASEBALL_SIZE) return false; - Map map = new HashMap<>(); - for (int i = 0; i < BASEBALL_SIZE; i++) { - char c = number.charAt(i); - if (c < '1' || c > '9' || map.containsKey(c)) return false; - map.put(c, ""); - } - return true; - } + public String generateNumber() { + String result = ""; + Map map = new HashMap<>(); + Random random = new Random(); + while (result.length() < BASEBALL_SIZE) { + String randomNumber = random.nextInt(1, 9) + ""; + if (map.get(randomNumber) != null) { + continue; + } + map.put(randomNumber, ""); + result += randomNumber; + } + return result; + } + + public String generateFixedNumber(String fixedNumber) { + if (!isProperNumber(fixedNumber)) { + throw new IllegalArgumentException("Invalid fixed number"); + } + return fixedNumber; + } + + private boolean isProperNumber(String number) { + if (number == null || number.length() != BASEBALL_SIZE) { + return false; + } + Map map = new HashMap<>(); + for (int i = 0; i < BASEBALL_SIZE; i++) { + char c = number.charAt(i); + if (c < '1' || c > '9' || map.containsKey(c)) { + return false; + } + map.put(c, ""); + } + return true; + } } diff --git a/src/main/java/View/InputManager.java b/src/main/java/View/InputManager.java index d2883648..a24d2c28 100644 --- a/src/main/java/View/InputManager.java +++ b/src/main/java/View/InputManager.java @@ -1,13 +1,15 @@ -package View; +package view; import java.util.Scanner; public class InputManager { - Scanner scanner; - public InputManager() { - scanner = new Scanner(System.in); - } - public String GetInput() { - return scanner.next(); - } + private final Scanner scanner; + + public InputManager() { + scanner = new Scanner(System.in); + } + + public String getInput() { + return scanner.next(); + } } diff --git a/src/main/java/View/OutputManager.java b/src/main/java/View/OutputManager.java index e9c2f1e5..6f762242 100644 --- a/src/main/java/View/OutputManager.java +++ b/src/main/java/View/OutputManager.java @@ -1,39 +1,50 @@ -package View; +package view; import java.util.HashMap; import java.util.Map; -import Constant.ErrorEnum; -import Constant.TurnPhase; -import Constant.JudgeResult; + +import constant.ErrorEnum; +import constant.JudgeResult; +import constant.TurnPhase; public class OutputManager { - // errorEnumStringMap의 string에는 뒤에 \n을 넣어 출력 메서드는 println이 아닌 print를 사용 - private final Map _errorEnumStringMap; - private final Map _phaseStartMessageMap; - public OutputManager () { - _errorEnumStringMap = new HashMap<>(); - _errorEnumStringMap.put(ErrorEnum.idleInputError, "1 혹은 2를 입력해주세요.\n"); - _errorEnumStringMap.put(ErrorEnum.userInputError, "1 ~ 9 사이의 중복되지 않는 세 자리 숫자를 입력해주세요.\n숫자를 입력해주세요 : "); - - _phaseStartMessageMap = new HashMap<>(); - _phaseStartMessageMap.put(TurnPhase.idle, "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.\n"); - _phaseStartMessageMap.put(TurnPhase.inputNumber, "숫자를 입력해주세요 : "); - } - public void PrintErrorMessage(ErrorEnum errorEnum) { - if (_errorEnumStringMap.containsKey((errorEnum))) System.out.print(_errorEnumStringMap.get(errorEnum)); - } - - public void PrintPhaseStartMessage(TurnPhase turnPhase){ - if (_phaseStartMessageMap.containsKey(turnPhase)) System.out.print(_phaseStartMessageMap.get(turnPhase)); - } - - public void PrintJudgeResult(JudgeResult result){ - if (result.strike() == 3) { - System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝"); - return; - } - String resultString = result.strike() + result.ball() == 0 ? "낫씽" : result.strike() + "스트라이크 " + result.ball() + "볼"; - System.out.println(resultString); - } + // errorEnumStringMap의 string에는 뒤에 \n을 넣어 출력 메서드는 println이 아닌 print를 사용 + private final Map _errorEnumStringMap; + private final Map _phaseStartMessageMap; + + public OutputManager() { + _errorEnumStringMap = new HashMap<>(); + _errorEnumStringMap.put(ErrorEnum.IDLE_INPUT_ERROR, "1 혹은 2를 입력해주세요.\n"); + _errorEnumStringMap.put( + ErrorEnum.USER_INPUT_ERROR, + "1 ~ 9 사이의 중복되지 않는 세 자리 숫자를 입력해주세요.\n숫자를 입력해주세요 : " + ); + + _phaseStartMessageMap = new HashMap<>(); + _phaseStartMessageMap.put(TurnPhase.IDLE, "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.\n"); + _phaseStartMessageMap.put(TurnPhase.INPUT_NUMBER, "숫자를 입력해주세요 : "); + } + + public void printErrorMessage(ErrorEnum errorEnum) { + if (_errorEnumStringMap.containsKey(errorEnum)) { + System.out.print(_errorEnumStringMap.get(errorEnum)); + } + } + + public void printPhaseStartMessage(TurnPhase turnPhase) { + if (_phaseStartMessageMap.containsKey(turnPhase)) { + System.out.print(_phaseStartMessageMap.get(turnPhase)); + } + } + public void printJudgeResult(JudgeResult result) { + if (result.strike() == 3) { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝"); + return; + } + String resultString = result.strike() + result.ball() == 0 + ? "낫씽" + : result.strike() + "스트라이크 " + result.ball() + "볼"; + System.out.println(resultString); + } } diff --git a/src/test/java/AppTest.java b/src/test/java/AppTest.java index 183dec4e..728461a8 100644 --- a/src/test/java/AppTest.java +++ b/src/test/java/AppTest.java @@ -1,17 +1,17 @@ -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; class AppTest { - @Test - void mainMethodHasExpectedSignature() throws Exception { - Method main = App.class.getDeclaredMethod("main", String[].class); + @Test + void mainMethodHasExpectedSignature() throws Exception { + Method main = App.class.getDeclaredMethod("main", String[].class); - assertThat(main.getReturnType()).isEqualTo(void.class); - assertThat(Modifier.isPublic(main.getModifiers())).isTrue(); - assertThat(Modifier.isStatic(main.getModifiers())).isTrue(); - } + assertThat(main.getReturnType()).isEqualTo(void.class); + assertThat(Modifier.isPublic(main.getModifiers())).isTrue(); + assertThat(Modifier.isStatic(main.getModifiers())).isTrue(); + } } diff --git a/src/test/java/Model/JudgeManagerTest.java b/src/test/java/Model/JudgeManagerTest.java index 7e95f243..51627c1c 100644 --- a/src/test/java/Model/JudgeManagerTest.java +++ b/src/test/java/Model/JudgeManagerTest.java @@ -1,51 +1,52 @@ -package Model; +package model; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.Stream; -import Constant.JudgeResult; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.stream.Stream; - -import static org.assertj.core.api.Assertions.assertThat; +import constant.JudgeResult; class JudgeManagerTest { - private static Stream judgeCases() { - return Stream.of( - Arguments.of("456", 0, 0), - Arguments.of("415", 0, 1), - Arguments.of("314", 0, 2), - Arguments.of("312", 0, 3), - Arguments.of("145", 1, 0), - Arguments.of("134", 1, 1), - Arguments.of("132", 1, 2), - Arguments.of("124", 2, 0), - Arguments.of("123", 3, 0) - ); - } - - @ParameterizedTest - @MethodSource("judgeCases") - void judgeResultCoversValidStrikeBallCombinations(String userNumber, int strike, int ball) { - JudgeManager judgeManager = new JudgeManager(); - - JudgeResult result = judgeManager.JudgeResult("123", userNumber); - - assertThat(result.strike()).isEqualTo(strike); - assertThat(result.ball()).isEqualTo(ball); - } - - @Test - void twoStrikeOneBallIsNotReachableWithUniqueDigits() { - JudgeManager judgeManager = new JudgeManager(); - String[] permutations = {"123", "132", "213", "231", "312", "321"}; - - for (String userNumber : permutations) { - JudgeResult result = judgeManager.JudgeResult("123", userNumber); - assertThat(result.strike() == 2 && result.ball() == 1) - .as("2S1B should be unreachable for %s", userNumber) - .isFalse(); - } - } + private static Stream judgeCases() { + return Stream.of( + Arguments.of("456", 0, 0), + Arguments.of("415", 0, 1), + Arguments.of("314", 0, 2), + Arguments.of("312", 0, 3), + Arguments.of("145", 1, 0), + Arguments.of("134", 1, 1), + Arguments.of("132", 1, 2), + Arguments.of("124", 2, 0), + Arguments.of("123", 3, 0) + ); + } + + @ParameterizedTest + @MethodSource("judgeCases") + void judgeResultCoversValidStrikeBallCombinations(String userNumber, int strike, int ball) { + JudgeManager judgeManager = new JudgeManager(); + + JudgeResult result = judgeManager.judgeResult("123", userNumber); + + assertThat(result.strike()).isEqualTo(strike); + assertThat(result.ball()).isEqualTo(ball); + } + + @Test + void twoStrikeOneBallIsNotReachableWithUniqueDigits() { + JudgeManager judgeManager = new JudgeManager(); + String[] permutations = {"123", "132", "213", "231", "312", "321"}; + + for (String userNumber : permutations) { + JudgeResult result = judgeManager.judgeResult("123", userNumber); + assertThat(result.strike() == 2 && result.ball() == 1) + .as("2S1B should be unreachable for %s", userNumber) + .isFalse(); + } + } } diff --git a/src/test/java/Model/NumberGeneratorTest.java b/src/test/java/Model/NumberGeneratorTest.java index 48efa72a..930eafdf 100644 --- a/src/test/java/Model/NumberGeneratorTest.java +++ b/src/test/java/Model/NumberGeneratorTest.java @@ -1,34 +1,34 @@ -package Model; +package model; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - class NumberGeneratorTest { - @Test - void generateFixedNumberReturnsSameValueWhenValid() { - NumberGenerator generator = new NumberGenerator(); + @Test + void generateFixedNumberReturnsSameValueWhenValid() { + NumberGenerator generator = new NumberGenerator(); - assertThat(generator.GenerateFixedNumber("123")).isEqualTo("123"); - } + assertThat(generator.generateFixedNumber("123")).isEqualTo("123"); + } - @ParameterizedTest - @ValueSource(strings = {"12", "1234", "012", "11", "1a3", "9 1", "990"}) - void generateFixedNumberRejectsInvalidValues(String value) { - NumberGenerator generator = new NumberGenerator(); + @ParameterizedTest + @ValueSource(strings = {"12", "1234", "012", "11", "1a3", "9 1", "990"}) + void generateFixedNumberRejectsInvalidValues(String value) { + NumberGenerator generator = new NumberGenerator(); - assertThatThrownBy(() -> generator.GenerateFixedNumber(value)) - .isInstanceOf(IllegalArgumentException.class); - } + assertThatThrownBy(() -> generator.generateFixedNumber(value)) + .isInstanceOf(IllegalArgumentException.class); + } - @Test - void generateFixedNumberRejectsNull() { - NumberGenerator generator = new NumberGenerator(); + @Test + void generateFixedNumberRejectsNull() { + NumberGenerator generator = new NumberGenerator(); - assertThatThrownBy(() -> generator.GenerateFixedNumber(null)) - .isInstanceOf(IllegalArgumentException.class); - } + assertThatThrownBy(() -> generator.generateFixedNumber(null)) + .isInstanceOf(IllegalArgumentException.class); + } } From f1cda368847c216515d9f28e6559b51ca332b269 Mon Sep 17 00:00:00 2001 From: "theo.cha" Date: Tue, 3 Feb 2026 18:42:57 +0900 Subject: [PATCH 22/22] fix readme --- README.md | 122 +++++++++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index f6abe753..40881135 100644 --- a/README.md +++ b/README.md @@ -4,87 +4,74 @@ ## 📌 개요 -숫자야구 게임은 컴퓨터가 생성한 **서로 다른 3자리 숫자(1~9)**를 플레이어가 맞히는 게임입니다. +숫자야구 게임은 컴퓨터가 생성한 **서로 다른 3자리 숫자**를 플레이어가 맞히는 게임입니다. 플레이어의 입력에 대해 **스트라이크(Strike)** 와 **볼(Ball)** 개수를 판정하며, **3 스트라이크**가 되면 게임이 종료됩니다. --- -## 🧩 Manager 구성 +## 🧩 주요 클래스 구성 -### 1. Game Manager +### 1. `controller.GameManager` -* 게임 전체 흐름을 관리 -* 현재 Phase를 관리하고 다음 Phase로 전환 +* 게임 전체 흐름과 **Phase 전환**을 관리 +* 사용자 입력 검증 및 재입력 루프 처리 --- -### 2. Number Generator Manager (`numberGenerator`) +### 2. `model.NumberGenerator` **역할** -* 게임에서 사용할 숫자를 생성 +* 게임에서 사용할 숫자 생성 -**규칙** +**규칙(현재 구현 기준)** -* 숫자 범위: **1 ~ 9** +* 숫자 범위: **1 ~ 8** * 생성 개수: **3개** * 모든 숫자는 **서로 달라야 함** -* 이전에 생성된 숫자를 다시 생성하지 않음 --- -### 3. Input Manager (`inputManager`) +### 3. `model.JudgeManager` **역할** -* 사용자의 입력값이 올바른지 검증 +* 사용자 입력값과 생성된 숫자를 비교하여 결과 판정 -**검증 항목** - -* 입력 길이가 3인가? -* 모든 입력이 **1 ~ 9** 사이의 숫자인가? -* 모든 입력 값이 서로 다른가? - -**결과** +**판정 내용** -* 입력이 적절한 경우: `true` 반환 -* 입력이 부적절한 경우: `false` 반환 +* 스트라이크(Strike) 개수 +* 볼(Ball) 개수 +* 스트라이크 + 볼 = 0 인 경우 `낫씽` 출력 --- -### 4. Input Judge Manager (`inputJudge`) +### 4. `view.InputManager` **역할** -* 사용자의 입력값과 생성된 숫자를 비교하여 결과 판정 - -**판정 내용** - -* 스트라이크(Strike) 개수 -* 볼(Ball) 개수 -* 스트라이크 + 볼 = 0 인 경우 `Nothing` +* 콘솔에서 사용자 입력 수신 (`Scanner.next()` 사용) --- -## 🔄 Phase 구성 +### 5. `view.OutputManager` -### 1. `idle` +**역할** -**설명** +* Phase 시작 메시지, 에러 메시지, 판정 결과 출력 -* 게임을 시작할지 프로그램을 종료할지 선택하는 Phase +--- -**동작** +## 🔄 Phase 구성 및 흐름 -* 프로그램 최초 실행 시 기본적으로 `generateNumber` Phase로 이동 -* 사용자 입력에 따라 다음과 같이 분기 +### 1. 시작 단계 - * `1` 입력: `generateNumber` Phase로 이동 - * `2` 입력: 프로그램 종료 +* 프로그램은 **`GENERATE_NUMBER` Phase**에서 시작 +* 최초 실행 시 **시작 안내 메시지는 출력되지 않고** 바로 숫자 입력을 요청 --- -### 2. `generateNumber` +### 2. `GENERATE_NUMBER` **설명** @@ -92,61 +79,74 @@ **동작** -1. `numberGenerator`를 통해 숫자 생성 -2. 숫자 생성 완료 후 `inputNumber` Phase로 이동 +1. `NumberGenerator.generateNumber()`로 숫자 생성 +2. 생성 후 `INPUT_NUMBER` Phase로 이동 --- -### 3. `inputNumber` +### 3. `INPUT_NUMBER` **설명** * 사용자로부터 숫자를 입력받는 Phase -**동작** +**검증 조건** -1. 사용자 입력 수신 -2. `inputManager`를 통해 입력 검증 +* 입력 길이가 3인가? +* 모든 입력이 **1 ~ 9** 사이의 숫자인가? +* 모든 입력 값이 서로 다른가? **분기 처리** * 입력이 **적절한 경우** - * 입력값 저장 - * `printResult` Phase로 이동 - + * `JUDGE_RESULT` Phase로 이동 * 입력이 **부적절한 경우** - * 에러 메시지 출력 - * `inputNumber` Phase 유지 + * `INPUT_NUMBER` Phase 유지 --- -### 4. `judgeResult` +### 4. `JUDGE_RESULT` **설명** * 입력값을 판정하고 결과를 출력하는 Phase -**동작** +**분기 처리** + +* 결과가 **3 Strike**인 경우 + * 축하 메시지 출력 + * `IDLE` Phase로 이동 +* 그 외의 경우 + * 결과 출력 + * `INPUT_NUMBER` Phase로 이동 -1. `inputJudge`를 통해 스트라이크 / 볼 판정 +--- + +### 5. `IDLE` + +**설명** + +* 게임을 새로 시작하거나 종료를 선택하는 Phase **분기 처리** -* 결과가 **3 Strike**인 경우 +* `1` 입력: `GENERATE_NUMBER` Phase로 이동 (새 게임) +* `2` 입력: 프로그램 종료 +* 그 외 입력: 에러 메시지 출력 후 재입력 - * 게임 종료 +--- -* 그 외의 경우 +## 🧾 출력 메시지 - * 결과 출력 - * `inputNumber` Phase로 이동 +* 입력 요청: `숫자를 입력해주세요 : ` +* 잘못된 숫자 입력: `1 ~ 9 사이의 중복되지 않는 세 자리 숫자를 입력해주세요.` +* 게임 재시작/종료 선택: `게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.` +* 정답: `3개의 숫자를 모두 맞히셨습니다! 게임 끝` --- ## 🏁 게임 종료 조건 -* 스트라이크 개수가 **3개**가 되었을 때 게임 종료 - ---- \ No newline at end of file +* `IDLE` Phase에서 `2`를 입력하면 프로그램 종료