From e1bebd574ae2d264bbb9302a59ef6713c304f35c Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Wed, 28 Jan 2026 16:34:35 +0900 Subject: [PATCH 01/22] feat: add requirement --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d7e8aee..c4dddae8 100644 --- a/README.md +++ b/README.md @@ -1 +1,11 @@ -# java-baseball-precourse \ No newline at end of file +# java-baseball-precourse + +## 구현할 기능 목록 + +- [ ] 임의의 난수 3자리 생성하기 +- [ ] 사용자 응답 처리 +- [ ] 같은 수 & 같은 자리 (스트라이크) 분기 처리 +- [ ] 같은 수 & 다른 자리 (볼) 분기 처리 +- [ ] 같은 수 없는 경우 (포볼, 낫싱) 분기 처리 +- [ ] depth 최대 2가 되도록 리팩토링 +- [ ] 단위 테스트 코드 추가하기 From 2e4f30ac50017d15c6147f0577e2cea7cbeb1641 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Wed, 28 Jan 2026 16:43:02 +0900 Subject: [PATCH 02/22] feat(model): add basic baseballgameNumber model --- src/main/java/model/BaseballGameNumber.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/model/BaseballGameNumber.java diff --git a/src/main/java/model/BaseballGameNumber.java b/src/main/java/model/BaseballGameNumber.java new file mode 100644 index 00000000..2d9914d9 --- /dev/null +++ b/src/main/java/model/BaseballGameNumber.java @@ -0,0 +1,19 @@ +package model; + +public class BaseballGameNumber { + private int[] number; + + private boolean isContains(int num) { + for (int n : this.number) { + if (isSame(n, num)) { + return true; + } + } + return false; + } + + private boolean isSame(int num1, int num2) { + return num1 == num2; + } + +} From 5237c9dc50a427db310320ef3079d3734d8cdcf3 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Wed, 28 Jan 2026 16:49:36 +0900 Subject: [PATCH 03/22] feat(model): implement gameAnswerType --- src/main/java/model/GameAnswerType.java | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/java/model/GameAnswerType.java diff --git a/src/main/java/model/GameAnswerType.java b/src/main/java/model/GameAnswerType.java new file mode 100644 index 00000000..a09cc4b8 --- /dev/null +++ b/src/main/java/model/GameAnswerType.java @@ -0,0 +1,30 @@ +package model; + +public class GameAnswerType { + private int strikeCount; + private int ballCount; + + public GameAnswerType() { + this.strikeCount = 0; + this.ballCount = 0; + } + + public String getAnswer() { + if (strikeCount + ballCount == 0) { + return "낫싱"; + } + StringBuilder sb = new StringBuilder(); + + if (strikeCount > 0) { + sb.append(strikeCount); + sb.append("스트라이크 "); + } + + if (ballCount > 0) { + sb.append(ballCount); + sb.append("볼"); + } + + return sb.toString(); + } +} From 17d9bb948f411c105fb0318ae202caa1d7192bed Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Wed, 28 Jan 2026 16:55:52 +0900 Subject: [PATCH 04/22] feat(util): implement make random 3-digit logic --- README.md | 2 +- src/main/java/util/RandomNumberGenerator.java | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/main/java/util/RandomNumberGenerator.java diff --git a/README.md b/README.md index c4dddae8..88989af3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## 구현할 기능 목록 -- [ ] 임의의 난수 3자리 생성하기 +- [x] 임의의 난수 3자리 생성하기 - [ ] 사용자 응답 처리 - [ ] 같은 수 & 같은 자리 (스트라이크) 분기 처리 - [ ] 같은 수 & 다른 자리 (볼) 분기 처리 diff --git a/src/main/java/util/RandomNumberGenerator.java b/src/main/java/util/RandomNumberGenerator.java new file mode 100644 index 00000000..4f6f583d --- /dev/null +++ b/src/main/java/util/RandomNumberGenerator.java @@ -0,0 +1,22 @@ +package util; + +import java.util.Random; + +public class RandomNumberGenerator { + private Random random; + + public RandomNumberGenerator() { + this.random = new Random(); + } + + public int makeRand3digit() { + int answer = 0; + + for (int i = 0; i < 3; i++) { + answer *= 10; + answer += random.nextInt(9) + 1; + } + + return answer; + } +} From d4ff3149d5e239daaf15b19b72ff07dab0cc5a25 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Wed, 28 Jan 2026 17:08:03 +0900 Subject: [PATCH 05/22] feat(view): add basic GameView --- src/main/java/view/GameView.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/view/GameView.java diff --git a/src/main/java/view/GameView.java b/src/main/java/view/GameView.java new file mode 100644 index 00000000..3fb0cde9 --- /dev/null +++ b/src/main/java/view/GameView.java @@ -0,0 +1,21 @@ +package view; + +import java.io.*; + +public class GameView { + private static String turnMsg = "숫자를 입력해주세요 : "; + private static String gameEndMsg = "3개의 숫자를 모두 맞히셨습니다! 게임 끝\n 게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.\n"; + private BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); + + public void printTurnMsg() throws IOException { + bw.write(turnMsg); + } + + public void printGameEndMsg() throws IOException { + bw.write(gameEndMsg); + } + + public void releaseResource() throws IOException { + bw.close(); + } +} From 38396df4882632917e46333e9492282dee687b16 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Tue, 3 Feb 2026 08:31:42 +0900 Subject: [PATCH 06/22] feat(controller): implement basic gameController --- README.md | 6 +- src/main/java/controller/GameController.java | 117 +++++++++++++++++++ src/main/java/model/BaseballGameNumber.java | 26 ++++- src/main/java/model/GameAnswerType.java | 5 + src/main/java/view/GameView.java | 2 + 5 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 src/main/java/controller/GameController.java diff --git a/README.md b/README.md index 88989af3..90596518 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ ## 구현할 기능 목록 - [x] 임의의 난수 3자리 생성하기 -- [ ] 사용자 응답 처리 -- [ ] 같은 수 & 같은 자리 (스트라이크) 분기 처리 +- [x] 사용자 응답 처리 +- [x] 같은 수 & 같은 자리 (스트라이크) 분기 처리 - [ ] 같은 수 & 다른 자리 (볼) 분기 처리 -- [ ] 같은 수 없는 경우 (포볼, 낫싱) 분기 처리 +- [x] 같은 수 없는 경우 (포볼, 낫싱) 분기 처리 - [ ] depth 최대 2가 되도록 리팩토링 - [ ] 단위 테스트 코드 추가하기 diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java new file mode 100644 index 00000000..424c0a18 --- /dev/null +++ b/src/main/java/controller/GameController.java @@ -0,0 +1,117 @@ +package controller; + +import model.BaseballGameNumber; +import model.GameAnswerType; +import util.RandomNumberGenerator; +import view.GameView; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; + +public class GameController { + private static final int NUMBER_LENGTH = 3; + private static final String RESTART_COMMAND = "1"; + private static final String EXIT_COMMAND = "2"; + + private RandomNumberGenerator randomNumberGenerator; + private GameView gameView; + private BufferedReader br; + + public GameController() { + this.randomNumberGenerator = new RandomNumberGenerator(); + this.gameView = new GameView(); + br = new BufferedReader(new InputStreamReader(System.in)); + } + + public static void main(String[] args) { + try { + new GameController().run(); + } + catch (IOException e) { + System.out.println("[ERROR]: System IO Error"); + } + } + + public void run() throws IOException { + int resultCode; + + do { + resultCode = playSingleGame(); + } while(resultCode == 1); + + if (resultCode != 2) { + System.out.println("[ERROR]: Abnormal Exit"); + return; + } + + System.out.println("게임을 완전히 종료합니다."); + + br.close(); + } + + public int playSingleGame() throws IOException { + int answer = randomNumberGenerator.makeRand3digit(); + + int userInput = -1; + while (answer != userInput) { + gameView.printTurnMsg(); + userInput = getUserInput(); + BaseballGameNumber answerNumber = new BaseballGameNumber(toIntArray(answer)); + BaseballGameNumber userNumber = new BaseballGameNumber(toIntArray(userInput)); + + GameAnswerType answerType = answerNumber.compare(userNumber); + System.out.println(answerType.getAnswer()); + } + + gameView.printGameEndMsg(); + // 예외 처리 필요 + return Integer.parseInt(br.readLine()); + } + + private int getUserInput() throws IOException { + while (true) { + String rawInput = br.readLine(); + int parsedInput = parseUserInput(rawInput); + + if (parsedInput != -1) { + return parsedInput; + } + + gameView.printTurnMsg(); + } + } + + private int parseUserInput(String rawInput) { + int userInput; + + try { + userInput = Integer.parseInt(rawInput); + + if (isValid(NUMBER_LENGTH, rawInput)) { + return userInput; + } + } + catch (Exception e) { + System.out.println("[ERROR]: Invalid Input Number"); + return -1; + } + return -1; + } + + private boolean isValid(int numLength, String num) { + return num.length() == numLength; + } + + private ArrayList toIntArray(int number) { + ArrayList arr = new ArrayList<>(); + + while (number > 0) { + arr.add(number % 10); + number /= 10; + } + + return arr; + } +} diff --git a/src/main/java/model/BaseballGameNumber.java b/src/main/java/model/BaseballGameNumber.java index 2d9914d9..ee0d9709 100644 --- a/src/main/java/model/BaseballGameNumber.java +++ b/src/main/java/model/BaseballGameNumber.java @@ -1,7 +1,31 @@ package model; +import java.util.ArrayList; +import java.util.Objects; + public class BaseballGameNumber { - private int[] number; + private ArrayList number; + + public BaseballGameNumber(ArrayList arr) { + this.number = arr; + } + + + public GameAnswerType compare(BaseballGameNumber other) { + int strikes = 0; + int balls = 0; + + for (int i = 0; i < number.size(); i++) { + if (Objects.equals(number.get(i), other.number.get(i))) { + strikes += 1; + } + else if (isContains(other.number.get(i))){ + balls += 1; + } + } + + return new GameAnswerType(strikes, balls); + } private boolean isContains(int num) { for (int n : this.number) { diff --git a/src/main/java/model/GameAnswerType.java b/src/main/java/model/GameAnswerType.java index a09cc4b8..500c2b21 100644 --- a/src/main/java/model/GameAnswerType.java +++ b/src/main/java/model/GameAnswerType.java @@ -9,6 +9,11 @@ public GameAnswerType() { this.ballCount = 0; } + public GameAnswerType(int strikeCount, int ballCount){ + this.strikeCount = strikeCount; + this.ballCount = ballCount; + } + public String getAnswer() { if (strikeCount + ballCount == 0) { return "낫싱"; diff --git a/src/main/java/view/GameView.java b/src/main/java/view/GameView.java index 3fb0cde9..91e00332 100644 --- a/src/main/java/view/GameView.java +++ b/src/main/java/view/GameView.java @@ -9,10 +9,12 @@ public class GameView { public void printTurnMsg() throws IOException { bw.write(turnMsg); + bw.flush(); } public void printGameEndMsg() throws IOException { bw.write(gameEndMsg); + bw.flush(); } public void releaseResource() throws IOException { From 041bcd8f13edb7c9b8112640eb9cc776d0bce117 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sat, 7 Feb 2026 22:41:09 +0900 Subject: [PATCH 07/22] chore(util): remove duplicated number in random generator --- src/main/java/util/RandomNumberGenerator.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/util/RandomNumberGenerator.java b/src/main/java/util/RandomNumberGenerator.java index 4f6f583d..e9d0ba60 100644 --- a/src/main/java/util/RandomNumberGenerator.java +++ b/src/main/java/util/RandomNumberGenerator.java @@ -10,13 +10,25 @@ public RandomNumberGenerator() { } public int makeRand3digit() { + boolean[] isDuplicated = new boolean[10]; + int answer = 0; for (int i = 0; i < 3; i++) { answer *= 10; - answer += random.nextInt(9) + 1; + answer += getNonDuplicatedNumber(isDuplicated); } return answer; } + + private int getNonDuplicatedNumber(boolean[] isDuplicated) { + while(true) { + int randNum = random.nextInt(9) + 1; + if (!isDuplicated[randNum]) { + isDuplicated[randNum] = true; + return randNum; + } + } + } } From ea82c20ff2f708fab86186730f66819d6ba51588 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sat, 7 Feb 2026 23:03:16 +0900 Subject: [PATCH 08/22] chore(model): add ball duplicated check logic --- README.md | 2 +- src/main/java/controller/GameController.java | 2 +- src/main/java/model/BaseballGameNumber.java | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 90596518..1380118e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ - [x] 임의의 난수 3자리 생성하기 - [x] 사용자 응답 처리 - [x] 같은 수 & 같은 자리 (스트라이크) 분기 처리 -- [ ] 같은 수 & 다른 자리 (볼) 분기 처리 +- [x] 같은 수 & 다른 자리 (볼) 분기 처리 - [x] 같은 수 없는 경우 (포볼, 낫싱) 분기 처리 - [ ] depth 최대 2가 되도록 리팩토링 - [ ] 단위 테스트 코드 추가하기 diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 424c0a18..61543263 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -61,7 +61,7 @@ public int playSingleGame() throws IOException { BaseballGameNumber answerNumber = new BaseballGameNumber(toIntArray(answer)); BaseballGameNumber userNumber = new BaseballGameNumber(toIntArray(userInput)); - GameAnswerType answerType = answerNumber.compare(userNumber); + GameAnswerType answerType = userNumber.compare(answerNumber); System.out.println(answerType.getAnswer()); } diff --git a/src/main/java/model/BaseballGameNumber.java b/src/main/java/model/BaseballGameNumber.java index ee0d9709..c8399ba0 100644 --- a/src/main/java/model/BaseballGameNumber.java +++ b/src/main/java/model/BaseballGameNumber.java @@ -15,13 +15,21 @@ public GameAnswerType compare(BaseballGameNumber other) { int strikes = 0; int balls = 0; + boolean[] isDuplicated = new boolean[10]; + for (int i = 0; i < number.size(); i++) { + if (isDuplicated[number.get(i)]) { + continue; + } + if (Objects.equals(number.get(i), other.number.get(i))) { strikes += 1; } else if (isContains(other.number.get(i))){ balls += 1; } + + isDuplicated[number.get(i)] = true; } return new GameAnswerType(strikes, balls); From e6c2386c74d1ae2df74ae815cb8741e330d1c7e4 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 00:11:19 +0900 Subject: [PATCH 09/22] chore(model): refactor baseballGameNumber compare logic --- src/main/java/model/BaseballGameNumber.java | 64 +++++++++++++-------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/src/main/java/model/BaseballGameNumber.java b/src/main/java/model/BaseballGameNumber.java index c8399ba0..d45c6002 100644 --- a/src/main/java/model/BaseballGameNumber.java +++ b/src/main/java/model/BaseballGameNumber.java @@ -10,42 +10,60 @@ public BaseballGameNumber(ArrayList arr) { this.number = arr; } - public GameAnswerType compare(BaseballGameNumber other) { - int strikes = 0; - int balls = 0; + int strikes = calStrikes(other); + int balls = calBalls(strikes, other); - boolean[] isDuplicated = new boolean[10]; + return new GameAnswerType(strikes, balls); + } - for (int i = 0; i < number.size(); i++) { - if (isDuplicated[number.get(i)]) { - continue; + private int calStrikes(BaseballGameNumber other) { + int strike = 0; + for (int i = 0; i < this.number.size(); i++) { + if(isStrike(i, other)) { + strike += 1; } + } - if (Objects.equals(number.get(i), other.number.get(i))) { - strikes += 1; - } - else if (isContains(other.number.get(i))){ - balls += 1; - } + return strike; + } + + private int calBalls(int strikes, BaseballGameNumber other) { + return this.calMatchCount(other) - strikes; + } - isDuplicated[number.get(i)] = true; + private boolean isStrike(int index, BaseballGameNumber other) { + return Objects.equals(this.number.get(index), other.number.get(index)); + } + + private int calMatchCount(BaseballGameNumber other) { + boolean[] originFlags = this.getNumberFlags(); + boolean[] otherFlags = other.getNumberFlags(); + + int matchCount = 0; + + for (int i = 0; i < originFlags.length; i++) { + matchCount = getMatchCount(originFlags, i, otherFlags, matchCount); } - return new GameAnswerType(strikes, balls); + return matchCount; } - private boolean isContains(int num) { - for (int n : this.number) { - if (isSame(n, num)) { - return true; - } + private static int getMatchCount(boolean[] originFlags, int i, boolean[] otherFlags, int matchCount) { + if(originFlags[i] && otherFlags[i]) { + matchCount += 1; } - return false; + return matchCount; } - private boolean isSame(int num1, int num2) { - return num1 == num2; + private boolean[] getNumberFlags() { + boolean[] flags = new boolean[10]; + + for (int num : this.number) { + flags[num] = true; + } + + return flags; } } From 4c603651b6e85f47c6c63257e580a6a0548bec2e Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 00:29:26 +0900 Subject: [PATCH 10/22] chore(view): delegate print turn msg logic from controller to view --- src/main/java/controller/GameController.java | 7 +++--- src/main/java/view/GameView.java | 23 ++++++++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 61543263..115bda93 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -46,7 +46,7 @@ public void run() throws IOException { return; } - System.out.println("게임을 완전히 종료합니다."); + gameView.printGameEndMsg(); br.close(); } @@ -61,11 +61,10 @@ public int playSingleGame() throws IOException { BaseballGameNumber answerNumber = new BaseballGameNumber(toIntArray(answer)); BaseballGameNumber userNumber = new BaseballGameNumber(toIntArray(userInput)); - GameAnswerType answerType = userNumber.compare(answerNumber); - System.out.println(answerType.getAnswer()); + gameView.printResult(userNumber.compare(answerNumber)); } - gameView.printGameEndMsg(); + gameView.printSingleGameEndMsg(); // 예외 처리 필요 return Integer.parseInt(br.readLine()); } diff --git a/src/main/java/view/GameView.java b/src/main/java/view/GameView.java index 91e00332..2f12297e 100644 --- a/src/main/java/view/GameView.java +++ b/src/main/java/view/GameView.java @@ -1,19 +1,34 @@ package view; +import model.GameAnswerType; + import java.io.*; public class GameView { - private static String turnMsg = "숫자를 입력해주세요 : "; - private static String gameEndMsg = "3개의 숫자를 모두 맞히셨습니다! 게임 끝\n 게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.\n"; + private static String TURN_MSG = "숫자를 입력해주세요 : "; + private static String SINGLE_GAME_END_MSG = "3개의 숫자를 모두 맞히셨습니다! 게임 끝\n 게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.\n"; + private static String GAME_END_MSG = "게임을 완전히 종료합니다."; + private BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); public void printTurnMsg() throws IOException { - bw.write(turnMsg); + bw.write(TURN_MSG); + bw.flush(); + } + + public void printResult(GameAnswerType result) throws IOException { + bw.write(result.getAnswer()); + bw.newLine(); + bw.flush(); + } + + public void printSingleGameEndMsg() throws IOException { + bw.write(SINGLE_GAME_END_MSG); bw.flush(); } public void printGameEndMsg() throws IOException { - bw.write(gameEndMsg); + bw.write(GAME_END_MSG); bw.flush(); } From 4daedf0d018fc75ecdd1f099af29ac4661a85eab Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 00:39:06 +0900 Subject: [PATCH 11/22] chore(view): move errormsg print logic into view --- src/main/java/controller/GameController.java | 5 ++--- src/main/java/view/GameView.java | 11 +++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 115bda93..c09b4b30 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -42,7 +42,7 @@ public void run() throws IOException { } while(resultCode == 1); if (resultCode != 2) { - System.out.println("[ERROR]: Abnormal Exit"); + gameView.printErrorMsg("[ERROR]: Abnormal Exit"); return; } @@ -93,8 +93,7 @@ private int parseUserInput(String rawInput) { } } catch (Exception e) { - System.out.println("[ERROR]: Invalid Input Number"); - return -1; + gameView.printErrorMsg("[ERROR]: Invalid Input Number"); } return -1; } diff --git a/src/main/java/view/GameView.java b/src/main/java/view/GameView.java index 2f12297e..ad7d6593 100644 --- a/src/main/java/view/GameView.java +++ b/src/main/java/view/GameView.java @@ -32,6 +32,17 @@ public void printGameEndMsg() throws IOException { bw.flush(); } + public void printErrorMsg(String message) { + try { + bw.write(message); + bw.newLine(); + bw.flush(); + } + catch (IOException e) { + System.out.println(message); + } + } + public void releaseResource() throws IOException { bw.close(); } From 0f282cfdc8c01cb6e5b773e1b27caf03f7dcb1c6 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 00:51:07 +0900 Subject: [PATCH 12/22] feat(view): implement Enum ErrorMessage --- src/main/java/controller/GameController.java | 7 ++++--- src/main/java/view/ErrorMessage.java | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 src/main/java/view/ErrorMessage.java diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index c09b4b30..84b39302 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -3,6 +3,7 @@ import model.BaseballGameNumber; import model.GameAnswerType; import util.RandomNumberGenerator; +import view.ErrorMessage; import view.GameView; import java.io.BufferedReader; @@ -30,7 +31,7 @@ public static void main(String[] args) { new GameController().run(); } catch (IOException e) { - System.out.println("[ERROR]: System IO Error"); + System.out.println(ErrorMessage.SYSTEM_IO_ERROR.getMsg()); } } @@ -42,7 +43,7 @@ public void run() throws IOException { } while(resultCode == 1); if (resultCode != 2) { - gameView.printErrorMsg("[ERROR]: Abnormal Exit"); + gameView.printErrorMsg(ErrorMessage.ABNORMAL_EXIT.getMsg()); return; } @@ -93,7 +94,7 @@ private int parseUserInput(String rawInput) { } } catch (Exception e) { - gameView.printErrorMsg("[ERROR]: Invalid Input Number"); + gameView.printErrorMsg(ErrorMessage.INVALID_INPUT_NUMBER.getMsg()); } return -1; } diff --git a/src/main/java/view/ErrorMessage.java b/src/main/java/view/ErrorMessage.java new file mode 100644 index 00000000..cbf66ea4 --- /dev/null +++ b/src/main/java/view/ErrorMessage.java @@ -0,0 +1,18 @@ +package view; + +public enum ErrorMessage { + SYSTEM_IO_ERROR("System IO Error"), + ABNORMAL_EXIT("Abnormal Exit"), + INVALID_INPUT_NUMBER("Invalid Input Number"); + + private static final String ERROR_PREFIX_MSG = "[ERROR]: "; + private final String msg; + + ErrorMessage(String msg) { + this.msg = msg; + } + + public String getMsg() { + return ERROR_PREFIX_MSG + msg; + } +} From 6b238b9873f8456c878d7ee659f2d4db7d4a67dd Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 01:35:13 +0900 Subject: [PATCH 13/22] chore(controller): refactor game turn logic --- src/main/java/controller/GameController.java | 57 ++++++++++++-------- src/main/java/view/ErrorMessage.java | 3 +- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 84b39302..7a45a258 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -10,6 +10,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.Collections; +import java.util.Objects; public class GameController { private static final int NUMBER_LENGTH = 3; @@ -36,13 +38,13 @@ public static void main(String[] args) { } public void run() throws IOException { - int resultCode; + String gameEndUserResponse; do { - resultCode = playSingleGame(); - } while(resultCode == 1); + gameEndUserResponse = playSingleGame(); + } while(Objects.equals(gameEndUserResponse, RESTART_COMMAND)); - if (resultCode != 2) { + if (!Objects.equals(gameEndUserResponse, EXIT_COMMAND)) { gameView.printErrorMsg(ErrorMessage.ABNORMAL_EXIT.getMsg()); return; } @@ -50,24 +52,31 @@ public void run() throws IOException { gameView.printGameEndMsg(); br.close(); + gameView.releaseResource(); } - public int playSingleGame() throws IOException { + public String playSingleGame() throws IOException { int answer = randomNumberGenerator.makeRand3digit(); + BaseballGameNumber answerNumber = new BaseballGameNumber(toIntArray(answer)); int userInput = -1; while (answer != userInput) { - gameView.printTurnMsg(); - userInput = getUserInput(); - BaseballGameNumber answerNumber = new BaseballGameNumber(toIntArray(answer)); - BaseballGameNumber userNumber = new BaseballGameNumber(toIntArray(userInput)); - - gameView.printResult(userNumber.compare(answerNumber)); + userInput = playTurn(answerNumber); } gameView.printSingleGameEndMsg(); - // 예외 처리 필요 - return Integer.parseInt(br.readLine()); + return br.readLine(); + } + + private int playTurn(BaseballGameNumber answerNumber) throws IOException { + int userInput; + gameView.printTurnMsg(); + userInput = getUserInput(); + + BaseballGameNumber userNumber = new BaseballGameNumber(toIntArray(userInput)); + + gameView.printResult(userNumber.compare(answerNumber)); + return userInput; } private int getUserInput() throws IOException { @@ -84,25 +93,30 @@ private int getUserInput() throws IOException { } private int parseUserInput(String rawInput) { - int userInput; + int userInput = -1; + + if (!isValidLength(rawInput)) { + return userInput; + } try { userInput = Integer.parseInt(rawInput); - - if (isValid(NUMBER_LENGTH, rawInput)) { - return userInput; - } } catch (Exception e) { gameView.printErrorMsg(ErrorMessage.INVALID_INPUT_NUMBER.getMsg()); } - return -1; + return userInput; } - private boolean isValid(int numLength, String num) { - return num.length() == numLength; + private boolean isValidLength(String input) { + if (input.length() != NUMBER_LENGTH) { + gameView.printErrorMsg(ErrorMessage.INVALID_INPUT_LENGTH.getMsg()); + return false; + } + return true; } + private ArrayList toIntArray(int number) { ArrayList arr = new ArrayList<>(); @@ -110,6 +124,7 @@ private ArrayList toIntArray(int number) { arr.add(number % 10); number /= 10; } + Collections.reverse(arr); return arr; } diff --git a/src/main/java/view/ErrorMessage.java b/src/main/java/view/ErrorMessage.java index cbf66ea4..757c885d 100644 --- a/src/main/java/view/ErrorMessage.java +++ b/src/main/java/view/ErrorMessage.java @@ -3,7 +3,8 @@ public enum ErrorMessage { SYSTEM_IO_ERROR("System IO Error"), ABNORMAL_EXIT("Abnormal Exit"), - INVALID_INPUT_NUMBER("Invalid Input Number"); + INVALID_INPUT_NUMBER("숫자만 입력해주세요."), + INVALID_INPUT_LENGTH("3자리의 숫자를 입력해주세요."); private static final String ERROR_PREFIX_MSG = "[ERROR]: "; private final String msg; From ffae489ab5191a429c4a23e913a7777d1b794656 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 01:40:15 +0900 Subject: [PATCH 14/22] feat(controller): add exception handling for positive number check & zero check --- src/main/java/controller/GameController.java | 10 ++++++++++ src/main/java/view/ErrorMessage.java | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 7a45a258..449caf75 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -99,8 +99,18 @@ private int parseUserInput(String rawInput) { return userInput; } + if (rawInput.contains("0")) { + gameView.printErrorMsg(ErrorMessage.CONTAINS_ZERO.getMsg()); + return userInput; + } + try { userInput = Integer.parseInt(rawInput); + + if (userInput <= 0) { + gameView.printErrorMsg(ErrorMessage.NOT_POSITIVE.getMsg()); + return -1; + } } catch (Exception e) { gameView.printErrorMsg(ErrorMessage.INVALID_INPUT_NUMBER.getMsg()); diff --git a/src/main/java/view/ErrorMessage.java b/src/main/java/view/ErrorMessage.java index 757c885d..117a3ac2 100644 --- a/src/main/java/view/ErrorMessage.java +++ b/src/main/java/view/ErrorMessage.java @@ -4,7 +4,9 @@ public enum ErrorMessage { SYSTEM_IO_ERROR("System IO Error"), ABNORMAL_EXIT("Abnormal Exit"), INVALID_INPUT_NUMBER("숫자만 입력해주세요."), - INVALID_INPUT_LENGTH("3자리의 숫자를 입력해주세요."); + INVALID_INPUT_LENGTH("3자리의 숫자를 입력해주세요."), + CONTAINS_ZERO("0이 포함된 숫자는 입력할 수 없습니다."), + NOT_POSITIVE("양수로 입력해주세요."); private static final String ERROR_PREFIX_MSG = "[ERROR]: "; private final String msg; From 5c3c0196cb3c6db26ccc7a5c3d15e5418ba741bf Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 11:40:48 +0900 Subject: [PATCH 15/22] feat(view): introduce inputView --- src/main/java/controller/GameController.java | 71 ++------------------ src/main/java/util/IntegerParser.java | 18 +++++ src/main/java/view/InputView.java | 63 +++++++++++++++++ 3 files changed, 88 insertions(+), 64 deletions(-) create mode 100644 src/main/java/util/IntegerParser.java create mode 100644 src/main/java/view/InputView.java diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 449caf75..bd6b7a0f 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -2,9 +2,11 @@ import model.BaseballGameNumber; import model.GameAnswerType; +import util.IntegerParser; import util.RandomNumberGenerator; import view.ErrorMessage; import view.GameView; +import view.InputView; import java.io.BufferedReader; import java.io.IOException; @@ -14,17 +16,18 @@ import java.util.Objects; public class GameController { - private static final int NUMBER_LENGTH = 3; private static final String RESTART_COMMAND = "1"; private static final String EXIT_COMMAND = "2"; private RandomNumberGenerator randomNumberGenerator; private GameView gameView; + private InputView inputView; private BufferedReader br; public GameController() { this.randomNumberGenerator = new RandomNumberGenerator(); this.gameView = new GameView(); + this.inputView = new InputView(gameView); br = new BufferedReader(new InputStreamReader(System.in)); } @@ -57,7 +60,7 @@ public void run() throws IOException { public String playSingleGame() throws IOException { int answer = randomNumberGenerator.makeRand3digit(); - BaseballGameNumber answerNumber = new BaseballGameNumber(toIntArray(answer)); + BaseballGameNumber answerNumber = new BaseballGameNumber(IntegerParser.toIntArray(answer)); int userInput = -1; while (answer != userInput) { @@ -71,71 +74,11 @@ public String playSingleGame() throws IOException { private int playTurn(BaseballGameNumber answerNumber) throws IOException { int userInput; gameView.printTurnMsg(); - userInput = getUserInput(); + userInput = inputView.getUserInput(); - BaseballGameNumber userNumber = new BaseballGameNumber(toIntArray(userInput)); + BaseballGameNumber userNumber = new BaseballGameNumber(IntegerParser.toIntArray(userInput)); gameView.printResult(userNumber.compare(answerNumber)); return userInput; } - - private int getUserInput() throws IOException { - while (true) { - String rawInput = br.readLine(); - int parsedInput = parseUserInput(rawInput); - - if (parsedInput != -1) { - return parsedInput; - } - - gameView.printTurnMsg(); - } - } - - private int parseUserInput(String rawInput) { - int userInput = -1; - - if (!isValidLength(rawInput)) { - return userInput; - } - - if (rawInput.contains("0")) { - gameView.printErrorMsg(ErrorMessage.CONTAINS_ZERO.getMsg()); - return userInput; - } - - try { - userInput = Integer.parseInt(rawInput); - - if (userInput <= 0) { - gameView.printErrorMsg(ErrorMessage.NOT_POSITIVE.getMsg()); - return -1; - } - } - catch (Exception e) { - gameView.printErrorMsg(ErrorMessage.INVALID_INPUT_NUMBER.getMsg()); - } - return userInput; - } - - private boolean isValidLength(String input) { - if (input.length() != NUMBER_LENGTH) { - gameView.printErrorMsg(ErrorMessage.INVALID_INPUT_LENGTH.getMsg()); - return false; - } - return true; - } - - - private ArrayList toIntArray(int number) { - ArrayList arr = new ArrayList<>(); - - while (number > 0) { - arr.add(number % 10); - number /= 10; - } - Collections.reverse(arr); - - return arr; - } } diff --git a/src/main/java/util/IntegerParser.java b/src/main/java/util/IntegerParser.java new file mode 100644 index 00000000..18bef16d --- /dev/null +++ b/src/main/java/util/IntegerParser.java @@ -0,0 +1,18 @@ +package util; + +import java.util.ArrayList; +import java.util.Collections; + +public class IntegerParser { + public static ArrayList toIntArray(int number) { + ArrayList arr = new ArrayList<>(); + + while (number > 0) { + arr.add(number % 10); + number /= 10; + } + Collections.reverse(arr); + + return arr; + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..6dc18e8f --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,63 @@ +package view; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class InputView { + private static final int NUMBER_LENGTH = 3; + private final GameView gameView; + private final BufferedReader br; + + public InputView(GameView gameView) { + this.br = new BufferedReader(new InputStreamReader(System.in)); + this.gameView = gameView; + } + + public int getUserInput() throws IOException { + while (true) { + String rawInput = br.readLine(); + int parsedInput = parseUserInput(rawInput); + + if (parsedInput != -1) { + return parsedInput; + } + + gameView.printTurnMsg(); + } + } + + private int parseUserInput(String rawInput) { + int userInput = -1; + + if (!isValidLength(rawInput)) { + return userInput; + } + + if (rawInput.contains("0")) { + gameView.printErrorMsg(ErrorMessage.CONTAINS_ZERO.getMsg()); + return userInput; + } + + try { + userInput = Integer.parseInt(rawInput); + + if (userInput <= 0) { + gameView.printErrorMsg(ErrorMessage.NOT_POSITIVE.getMsg()); + return -1; + } + } + catch (Exception e) { + gameView.printErrorMsg(ErrorMessage.INVALID_INPUT_NUMBER.getMsg()); + } + return userInput; + } + + private boolean isValidLength(String input) { + if (input.length() != NUMBER_LENGTH) { + gameView.printErrorMsg(ErrorMessage.INVALID_INPUT_LENGTH.getMsg()); + return false; + } + return true; + } +} From ba269d74608ec4f14a9c5f0317095d4cb826c773 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 11:42:16 +0900 Subject: [PATCH 16/22] chore: add final --- src/main/java/controller/GameController.java | 6 +++--- src/main/java/model/BaseballGameNumber.java | 2 +- src/main/java/model/GameAnswerType.java | 4 ++-- src/main/java/util/RandomNumberGenerator.java | 2 +- src/main/java/view/GameView.java | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index bd6b7a0f..61afb1a4 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -20,9 +20,9 @@ public class GameController { private static final String EXIT_COMMAND = "2"; private RandomNumberGenerator randomNumberGenerator; - private GameView gameView; - private InputView inputView; - private BufferedReader br; + private final GameView gameView; + private final InputView inputView; + private final BufferedReader br; public GameController() { this.randomNumberGenerator = new RandomNumberGenerator(); diff --git a/src/main/java/model/BaseballGameNumber.java b/src/main/java/model/BaseballGameNumber.java index d45c6002..8510e18a 100644 --- a/src/main/java/model/BaseballGameNumber.java +++ b/src/main/java/model/BaseballGameNumber.java @@ -4,7 +4,7 @@ import java.util.Objects; public class BaseballGameNumber { - private ArrayList number; + private final ArrayList number; public BaseballGameNumber(ArrayList arr) { this.number = arr; diff --git a/src/main/java/model/GameAnswerType.java b/src/main/java/model/GameAnswerType.java index 500c2b21..edd81107 100644 --- a/src/main/java/model/GameAnswerType.java +++ b/src/main/java/model/GameAnswerType.java @@ -1,8 +1,8 @@ package model; public class GameAnswerType { - private int strikeCount; - private int ballCount; + private final int strikeCount; + private final int ballCount; public GameAnswerType() { this.strikeCount = 0; diff --git a/src/main/java/util/RandomNumberGenerator.java b/src/main/java/util/RandomNumberGenerator.java index e9d0ba60..3d68b1fa 100644 --- a/src/main/java/util/RandomNumberGenerator.java +++ b/src/main/java/util/RandomNumberGenerator.java @@ -3,7 +3,7 @@ import java.util.Random; public class RandomNumberGenerator { - private Random random; + private final Random random; public RandomNumberGenerator() { this.random = new Random(); diff --git a/src/main/java/view/GameView.java b/src/main/java/view/GameView.java index ad7d6593..a681b015 100644 --- a/src/main/java/view/GameView.java +++ b/src/main/java/view/GameView.java @@ -5,11 +5,11 @@ import java.io.*; public class GameView { - private static String TURN_MSG = "숫자를 입력해주세요 : "; - private static String SINGLE_GAME_END_MSG = "3개의 숫자를 모두 맞히셨습니다! 게임 끝\n 게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.\n"; - private static String GAME_END_MSG = "게임을 완전히 종료합니다."; + private static final String TURN_MSG = "숫자를 입력해주세요 : "; + private static final String SINGLE_GAME_END_MSG = "3개의 숫자를 모두 맞히셨습니다! 게임 끝\n 게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.\n"; + private static final String GAME_END_MSG = "게임을 완전히 종료합니다."; - private BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); + private final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); public void printTurnMsg() throws IOException { bw.write(TURN_MSG); From 0a8aa8944ee7690cc8c13e6edbe1caccecfc988e Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 11:56:34 +0900 Subject: [PATCH 17/22] feat(view): refactor parseUserInput logic --- src/main/java/view/InputView.java | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 6dc18e8f..1baf16d8 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -6,6 +6,7 @@ public class InputView { private static final int NUMBER_LENGTH = 3; + private static final int INVALID_INPUT = -1; private final GameView gameView; private final BufferedReader br; @@ -19,7 +20,7 @@ public int getUserInput() throws IOException { String rawInput = br.readLine(); int parsedInput = parseUserInput(rawInput); - if (parsedInput != -1) { + if (parsedInput != INVALID_INPUT) { return parsedInput; } @@ -28,29 +29,40 @@ public int getUserInput() throws IOException { } private int parseUserInput(String rawInput) { - int userInput = -1; + if (!checkInputFormat(rawInput)) { + return INVALID_INPUT; + } + + return parseToPositiveInt(rawInput); + } + private boolean checkInputFormat(String rawInput) { if (!isValidLength(rawInput)) { - return userInput; + return false; } if (rawInput.contains("0")) { gameView.printErrorMsg(ErrorMessage.CONTAINS_ZERO.getMsg()); - return userInput; + return false; } - try { - userInput = Integer.parseInt(rawInput); + return true; + } + private int parseToPositiveInt(String rawInput) { + try { + int userInput = Integer.parseInt(rawInput); if (userInput <= 0) { gameView.printErrorMsg(ErrorMessage.NOT_POSITIVE.getMsg()); - return -1; + return INVALID_INPUT; } + return userInput; } - catch (Exception e) { + catch (NumberFormatException e) { gameView.printErrorMsg(ErrorMessage.INVALID_INPUT_NUMBER.getMsg()); + return INVALID_INPUT; } - return userInput; + } private boolean isValidLength(String input) { From d90620997b722b6b014c1f563f0929572b024dfd Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 12:08:17 +0900 Subject: [PATCH 18/22] feat(model): add baseballGameNumber model test code --- README.md | 2 +- src/main/java/model/GameAnswerType.java | 8 +++ .../java/model/BaseBallGameNumberTest.java | 68 +++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/test/java/model/BaseBallGameNumberTest.java diff --git a/README.md b/README.md index 1380118e..89cf23cf 100644 --- a/README.md +++ b/README.md @@ -7,5 +7,5 @@ - [x] 같은 수 & 같은 자리 (스트라이크) 분기 처리 - [x] 같은 수 & 다른 자리 (볼) 분기 처리 - [x] 같은 수 없는 경우 (포볼, 낫싱) 분기 처리 -- [ ] depth 최대 2가 되도록 리팩토링 +- [x] depth 최대 2가 되도록 리팩토링 - [ ] 단위 테스트 코드 추가하기 diff --git a/src/main/java/model/GameAnswerType.java b/src/main/java/model/GameAnswerType.java index edd81107..8c7fd3a9 100644 --- a/src/main/java/model/GameAnswerType.java +++ b/src/main/java/model/GameAnswerType.java @@ -14,6 +14,14 @@ public GameAnswerType(int strikeCount, int ballCount){ this.ballCount = ballCount; } + public int getStrikeCount() { + return strikeCount; + } + + public int getBallCount() { + return ballCount; + } + public String getAnswer() { if (strikeCount + ballCount == 0) { return "낫싱"; diff --git a/src/test/java/model/BaseBallGameNumberTest.java b/src/test/java/model/BaseBallGameNumberTest.java new file mode 100644 index 00000000..c39afd3b --- /dev/null +++ b/src/test/java/model/BaseBallGameNumberTest.java @@ -0,0 +1,68 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BaseBallGameNumberTest { + + @Test + @DisplayName("3 스트라이크 체크") + void strike3() { + // given + BaseballGameNumber computer = new BaseballGameNumber(new ArrayList<>(List.of(1, 2, 3))); + BaseballGameNumber user = new BaseballGameNumber(new ArrayList<>(List.of(1, 2, 3))); + // when + GameAnswerType result = user.compare(computer); + // then + assertThat(result.getStrikeCount()).isEqualTo(3); + assertThat(result.getBallCount()).isEqualTo(0); + assertThat(result.getAnswer()).isEqualTo("3스트라이크"); + } + + @Test + @DisplayName("3볼 체크") + void ball3() { + // given + BaseballGameNumber computer = new BaseballGameNumber(new ArrayList<>(List.of(2, 3, 1))); + BaseballGameNumber user = new BaseballGameNumber(new ArrayList<>(List.of(1, 2, 3))); + // when + GameAnswerType result = user.compare(computer); + // then + assertThat(result.getStrikeCount()).isEqualTo(0); + assertThat(result.getBallCount()).isEqualTo(3); + assertThat(result.getAnswer()).isEqualTo("3볼"); + } + + @Test + @DisplayName("낫싱 체크") + void nothing() { + // given + BaseballGameNumber computer = new BaseballGameNumber(new ArrayList<>(List.of(1, 2, 3))); + BaseballGameNumber user = new BaseballGameNumber(new ArrayList<>(List.of(4, 5, 6))); + // when + GameAnswerType result = user.compare(computer); + // then + assertThat(result.getStrikeCount()).isEqualTo(0); + assertThat(result.getBallCount()).isEqualTo(0); + assertThat(result.getAnswer()).isEqualTo("낫싱"); + } + + @Test + @DisplayName("1스트라이크 1볼") + void strike1ball1() { + // given + BaseballGameNumber computer = new BaseballGameNumber(new ArrayList<>(List.of(1, 2, 3))); + BaseballGameNumber user = new BaseballGameNumber(new ArrayList<>(List.of(1, 3, 7))); + // when + GameAnswerType result = user.compare(computer); + // then + assertThat(result.getStrikeCount()).isEqualTo(1); + assertThat(result.getBallCount()).isEqualTo(1); + assertThat(result.getAnswer()).isEqualTo("1스트라이크 1볼"); + } +} From c4ad49ee0bc17a3c36c80066caa2dca3bec26e4c Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 12:14:34 +0900 Subject: [PATCH 19/22] feat(model): fix space trim --- src/main/java/model/GameAnswerType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/model/GameAnswerType.java b/src/main/java/model/GameAnswerType.java index 8c7fd3a9..dee87655 100644 --- a/src/main/java/model/GameAnswerType.java +++ b/src/main/java/model/GameAnswerType.java @@ -35,9 +35,9 @@ public String getAnswer() { if (ballCount > 0) { sb.append(ballCount); - sb.append("볼"); + sb.append("볼 "); } - return sb.toString(); + return sb.toString().trim(); } } From ac18f725a07539d7de4b586a2d1bc6b45d3a313e Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 12:47:40 +0900 Subject: [PATCH 20/22] fix: test class name --- ...{BaseBallGameNumberTest.java => BaseballGameNumberTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/java/model/{BaseBallGameNumberTest.java => BaseballGameNumberTest.java} (98%) diff --git a/src/test/java/model/BaseBallGameNumberTest.java b/src/test/java/model/BaseballGameNumberTest.java similarity index 98% rename from src/test/java/model/BaseBallGameNumberTest.java rename to src/test/java/model/BaseballGameNumberTest.java index c39afd3b..fb2cffca 100644 --- a/src/test/java/model/BaseBallGameNumberTest.java +++ b/src/test/java/model/BaseballGameNumberTest.java @@ -8,7 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; -public class BaseBallGameNumberTest { +public class BaseballGameNumberTest { @Test @DisplayName("3 스트라이크 체크") From 64d8b53e871d0f7230677586044e1439eb01bca8 Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 12:58:21 +0900 Subject: [PATCH 21/22] feat: add GameAnswerTypeTest, IntegerParserTest --- README.md | 2 +- src/test/java/model/GameAnswerTypeTest.java | 40 +++++++++++++++++++++ src/test/java/util/IntegerParserTest.java | 23 ++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/test/java/model/GameAnswerTypeTest.java create mode 100644 src/test/java/util/IntegerParserTest.java diff --git a/README.md b/README.md index 89cf23cf..e97f8cc8 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,4 @@ - [x] 같은 수 & 다른 자리 (볼) 분기 처리 - [x] 같은 수 없는 경우 (포볼, 낫싱) 분기 처리 - [x] depth 최대 2가 되도록 리팩토링 -- [ ] 단위 테스트 코드 추가하기 +- [x] 단위 테스트 코드 추가하기 diff --git a/src/test/java/model/GameAnswerTypeTest.java b/src/test/java/model/GameAnswerTypeTest.java new file mode 100644 index 00000000..9bbf1067 --- /dev/null +++ b/src/test/java/model/GameAnswerTypeTest.java @@ -0,0 +1,40 @@ +package model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GameAnswerTypeTest { + + @Test + @DisplayName("메시지 - 낫싱") + void nothingMessage() { + GameAnswerType result = new GameAnswerType(0, 0); + assertThat(result.getAnswer()).isEqualTo("낫싱"); + } + + @Test + @DisplayName("메시지 - 스트라이크") + void strikeMessage() { + GameAnswerType result = new GameAnswerType(2, 0); + assertThat(result.getAnswer()).isEqualTo("2스트라이크"); + } + + @Test + @DisplayName("메시지 - 볼") + void ballMessage() { + GameAnswerType result = new GameAnswerType(0, 2); + assertThat(result.getAnswer()).isEqualTo("2볼"); + } + + @Test + @DisplayName("메시지 - 스트라이크 & 볼") + void strikeBallMessage() { + GameAnswerType result = new GameAnswerType(2, 1); + assertThat(result.getAnswer()).isEqualTo("2스트라이크 1볼"); + } + + + +} diff --git a/src/test/java/util/IntegerParserTest.java b/src/test/java/util/IntegerParserTest.java new file mode 100644 index 00000000..7d03e253 --- /dev/null +++ b/src/test/java/util/IntegerParserTest.java @@ -0,0 +1,23 @@ +package util; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class IntegerParserTest { + @Test + @DisplayName("정수 리스트 변환") + void toIntArray() { + // given + int input = 456; + // when + List result = IntegerParser.toIntArray(input); + // then + assertThat(result) + .hasSize(3) + .containsExactly(4, 5, 6); + } +} From a9bb0fa66cead35eb5b4015cd125170a352f62dd Mon Sep 17 00:00:00 2001 From: sinsehwan Date: Sun, 8 Feb 2026 13:04:45 +0900 Subject: [PATCH 22/22] feat(util): implement randomNumberGeneratorTest --- .../java/util/RandomNumberGeneratorTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/test/java/util/RandomNumberGeneratorTest.java diff --git a/src/test/java/util/RandomNumberGeneratorTest.java b/src/test/java/util/RandomNumberGeneratorTest.java new file mode 100644 index 00000000..87507524 --- /dev/null +++ b/src/test/java/util/RandomNumberGeneratorTest.java @@ -0,0 +1,32 @@ +package util; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.RepeatedTest; + +import java.util.HashSet; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RandomNumberGeneratorTest { + + @RepeatedTest(50) + @DisplayName("난수 생성 시 3자리, 범위, 중복없음 체크") + void makeRand3digit() { + // given + RandomNumberGenerator generator = new RandomNumberGenerator(); + // when + int number = generator.makeRand3digit(); + String numStr = String.valueOf(number); + // then + assertThat(number).isBetween(123, 999); + assertThat(numStr).doesNotContain("0"); + + Set digitSet = new HashSet<>(); + + for (char c : numStr.toCharArray()) { + digitSet.add(c); + } + assertThat(digitSet).hasSize(3); + } +}