From 94073cec75922319b5b83e6716b871bedba5db98 Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 16:31:24 +0900 Subject: [PATCH 01/14] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d7e8aee..7282e598 100644 --- a/README.md +++ b/README.md @@ -1 +1,27 @@ -# java-baseball-precourse \ No newline at end of file +# java-baseball-precourse + +### 문제 +- 기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다. +- 같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 같은 수가 전혀 없으면 포볼 또는 낫싱이란 힌트를 +얻고, 그 힌트를 이용해서 먼저 상대방(컴퓨터)의 수를 맞추면 승리한다. + - [예] 상대방(컴퓨터)의 수가 425일 때, 123을 제시한 경우 : 1스트라이크, 456을 제시한 경우 : 1스트라이크 1볼, + 789를 제시한 경우 : 낫싱 +- 위 숫자 야구게임에서 상대방의 역할을 컴퓨터가 한다. 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게임 플레이어는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과를 출력한다. +- 이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다. +- 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다. +- 사용자가 잘못된 값을 입력할 경우 [ERROR]로 시작하는 에러 메시지를 출력하고 게임을 계속 진행할 수 있어야 + +### 구조 +- 입력기 (controller) +- 출력기 (view) +- baseball 판독기 (model) +- baseball 정답 생성기 (model) +- baseball 게임 진행 (model) +- 에러 핸들러 + +### 기능 요구사항 +- [ ] baseball 정답 생성 +- [ ] baseball 정답 판독 +- [ ] baseball 게임 판단 +- [ ] 입력기 +- [ ] 출력기 From cfcee2536c899104012709f3ffef4d22edd0487a Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 16:42:41 +0900 Subject: [PATCH 02/14] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EC=84=B8?= =?UTF-8?q?=EB=B6=80=EC=82=AC=ED=95=AD=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7282e598..95f977f8 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,15 @@ ### 기능 요구사항 - [ ] baseball 정답 생성 -- [ ] baseball 정답 판독 + - [ ] 1부터 9까지의 다른 수로 이루어진 3자리의 수를 생성합니다. +- [ ] baseball 정답 판독 + - [ ] 정답과 비교해서 자리와 숫자가 모두 같은 경우 strike의 카운트를 올립니다. + - [ ] 정답과 비교해서 숫자만 같고 자리만 같을 경우 ball 의 카운트를 올립니다. + - [ ] strike or ball의 카운트가 0이 아닌 경우 출력하고, 모두 0인 경우 `낫싱`을 출력합니다. - [ ] baseball 게임 판단 + - [ ] 정답 판독기에서 판독한 값이 3스트라이크일 경우 출력하고 `3개의 숫자를 모두 맞히셨습니다! 게임 끝` 멘트와 게임을 종료합니다. + - [ ] 게임이 시작된 상황이라면 숫자를 입력 받고 판독 결과를 반환합니다. + - [ ] 게임이 진행중이 아니라면 1의 입력의 경우 정답 생성을 요청하고, 숫자 입력을 요구합니다. + - [ ] 게임이 진행중이 아니라면 2의 입력의 경우 게임을 종료합니다. - [ ] 입력기 - [ ] 출력기 From 50b14c231e36d268dee941c5f414e51c9ad91468 Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 17:32:42 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feat:=20=EC=88=AB=EC=9E=90=EC=95=BC?= =?UTF-8?q?=EA=B5=AC=20=EC=A0=95=EB=8B=B5=20=EC=83=9D=EC=84=B1=EB=A1=9C?= =?UTF-8?q?=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +-- src/main/java/model/AnswerGenerator.java | 7 +++ .../java/model/BaseballAnswerGenerator.java | 24 ++++++++++ .../java/BaseballAnswerGeneratorTest.java | 46 +++++++++++++++++++ 4 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 src/main/java/model/AnswerGenerator.java create mode 100644 src/main/java/model/BaseballAnswerGenerator.java create mode 100644 src/test/java/BaseballAnswerGeneratorTest.java diff --git a/README.md b/README.md index 95f977f8..74493e8b 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,10 @@ - 에러 핸들러 ### 기능 요구사항 -- [ ] baseball 정답 생성 - - [ ] 1부터 9까지의 다른 수로 이루어진 3자리의 수를 생성합니다. -- [ ] baseball 정답 판독 +- [X] baseball 정답 생성 + - [X] 1부터 9까지의 다른 수로 이루어진 3자리의 수를 생성합니다. + - 제약 사항: 1부터 9까지만, 정답 길이 3 +- [ ] baseball 정답 판독 - [ ] 정답과 비교해서 자리와 숫자가 모두 같은 경우 strike의 카운트를 올립니다. - [ ] 정답과 비교해서 숫자만 같고 자리만 같을 경우 ball 의 카운트를 올립니다. - [ ] strike or ball의 카운트가 0이 아닌 경우 출력하고, 모두 0인 경우 `낫싱`을 출력합니다. diff --git a/src/main/java/model/AnswerGenerator.java b/src/main/java/model/AnswerGenerator.java new file mode 100644 index 00000000..23f1d3c7 --- /dev/null +++ b/src/main/java/model/AnswerGenerator.java @@ -0,0 +1,7 @@ +package model; + +public interface AnswerGenerator { + + public String generateAnswer(); + +} diff --git a/src/main/java/model/BaseballAnswerGenerator.java b/src/main/java/model/BaseballAnswerGenerator.java new file mode 100644 index 00000000..ae5ae9c0 --- /dev/null +++ b/src/main/java/model/BaseballAnswerGenerator.java @@ -0,0 +1,24 @@ +package model; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public class BaseballAnswerGenerator implements AnswerGenerator{ + + @Override + public String generateAnswer() { + Set numbers = new HashSet<>(); + + while (numbers.size() < 3) { + numbers.add(ThreadLocalRandom.current().nextInt(1, 10)); + } + + StringBuilder answer = new StringBuilder(); + for (int n : numbers) { + answer.append(n); + } + + return answer.toString(); + } +} diff --git a/src/test/java/BaseballAnswerGeneratorTest.java b/src/test/java/BaseballAnswerGeneratorTest.java new file mode 100644 index 00000000..330e8faa --- /dev/null +++ b/src/test/java/BaseballAnswerGeneratorTest.java @@ -0,0 +1,46 @@ +import model.AnswerGenerator; +import model.BaseballAnswerGenerator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BaseballAnswerGeneratorTest { + + private AnswerGenerator answerGenerator; + + @BeforeEach + void setup() { + answerGenerator = new BaseballAnswerGenerator(); + } + + @DisplayName("정답 길이 테스트") + @Test + void generatedLengthTest() { + String answer = answerGenerator.generateAnswer(); + assertThat(answer.length()).isSameAs(3); + } + + @DisplayName("정답 안에 0이 없는지 test") + @Test + void generatedAnswerZeroTest() { + String answer = answerGenerator.generateAnswer(); + assertThat(answer).doesNotContain("0"); + } + + @DisplayName("정답이 모두 숫자인지 test") + @Test + void generatedAnswerAsciiTest() { + String answer = answerGenerator.generateAnswer(); + assertThat(answer).matches("\\d+"); + } + + @DisplayName("정답이 숫자가 모두 다른지 test") + @Test + void generatedAnswerDiffTest() { + String answer = answerGenerator.generateAnswer(); + assertThat(answer.chars().distinct().count()).isEqualTo(answer.length()); + } + +} From cd798dc46fbb70d4fbcaa20dfac33fb26d95a0aa Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 18:01:36 +0900 Subject: [PATCH 04/14] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=A6=AC=ED=8E=99=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/BaseballAnswerGeneratorTest.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/test/java/BaseballAnswerGeneratorTest.java b/src/test/java/BaseballAnswerGeneratorTest.java index 330e8faa..f1fe8e33 100644 --- a/src/test/java/BaseballAnswerGeneratorTest.java +++ b/src/test/java/BaseballAnswerGeneratorTest.java @@ -15,32 +15,32 @@ void setup() { answerGenerator = new BaseballAnswerGenerator(); } - @DisplayName("정답 길이 테스트") + @DisplayName("정답은 3자리 숫자이다") @Test - void generatedLengthTest() { + void generateAnswer_returnsLengthThree() { String answer = answerGenerator.generateAnswer(); - assertThat(answer.length()).isSameAs(3); + assertThat(answer.length()).isEqualTo(3); } - @DisplayName("정답 안에 0이 없는지 test") + @DisplayName("정답은 0을 포함하지 않는다") @Test - void generatedAnswerZeroTest() { + void generateAnswer_doesNotContainZero() { String answer = answerGenerator.generateAnswer(); assertThat(answer).doesNotContain("0"); } - @DisplayName("정답이 모두 숫자인지 test") + @DisplayName("정답은 숫자로만 이루어져 있다") @Test - void generatedAnswerAsciiTest() { + void generateAnswer_containsOnlyDigits() { String answer = answerGenerator.generateAnswer(); assertThat(answer).matches("\\d+"); } - @DisplayName("정답이 숫자가 모두 다른지 test") + @DisplayName("정답의 모든 숫자는 서로 다르다") @Test - void generatedAnswerDiffTest() { + void generateAnswer_hasNoDuplicateDigits() { String answer = answerGenerator.generateAnswer(); - assertThat(answer.chars().distinct().count()).isEqualTo(answer.length()); + assertThat(answer.chars().distinct().count()) + .isEqualTo(answer.length()); } - } From 4986b5a635b5f16577853983b8a4dc134fb99267 Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 18:10:29 +0900 Subject: [PATCH 05/14] =?UTF-8?q?feat:=20=EC=8A=A4=ED=8A=B8=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=ED=81=AC=20=EA=B0=9C=EC=88=98=20=ED=8C=90=EB=B3=84=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/model/AnswerJudge.java | 7 ++++ src/main/java/model/BaseballAnswerJudge.java | 13 +++++++ src/test/java/BaseballAnswerJudgeTest.java | 38 ++++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/main/java/model/AnswerJudge.java create mode 100644 src/main/java/model/BaseballAnswerJudge.java create mode 100644 src/test/java/BaseballAnswerJudgeTest.java diff --git a/README.md b/README.md index 74493e8b..ce6af43e 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ - [X] 1부터 9까지의 다른 수로 이루어진 3자리의 수를 생성합니다. - 제약 사항: 1부터 9까지만, 정답 길이 3 - [ ] baseball 정답 판독 - - [ ] 정답과 비교해서 자리와 숫자가 모두 같은 경우 strike의 카운트를 올립니다. + - [X] 정답과 비교해서 자리와 숫자가 모두 같은 경우 strike의 카운트를 반환합니다. - [ ] 정답과 비교해서 숫자만 같고 자리만 같을 경우 ball 의 카운트를 올립니다. - [ ] strike or ball의 카운트가 0이 아닌 경우 출력하고, 모두 0인 경우 `낫싱`을 출력합니다. - [ ] baseball 게임 판단 diff --git a/src/main/java/model/AnswerJudge.java b/src/main/java/model/AnswerJudge.java new file mode 100644 index 00000000..c6919dee --- /dev/null +++ b/src/main/java/model/AnswerJudge.java @@ -0,0 +1,7 @@ +package model; + +public interface AnswerJudge { + + public Integer countStrikes(String input, String answer); + +} diff --git a/src/main/java/model/BaseballAnswerJudge.java b/src/main/java/model/BaseballAnswerJudge.java new file mode 100644 index 00000000..580ca608 --- /dev/null +++ b/src/main/java/model/BaseballAnswerJudge.java @@ -0,0 +1,13 @@ +package model; + +public class BaseballAnswerJudge implements AnswerJudge { + + @Override + public Integer countStrikes(String input, String answer) { + int result = 0; + for (int index = 0; index < 3; index++) { + if (input.charAt(index) == answer.charAt(index)) result++; + } + return result; + } +} diff --git a/src/test/java/BaseballAnswerJudgeTest.java b/src/test/java/BaseballAnswerJudgeTest.java new file mode 100644 index 00000000..147e0701 --- /dev/null +++ b/src/test/java/BaseballAnswerJudgeTest.java @@ -0,0 +1,38 @@ +import model.AnswerJudge; +import model.BaseballAnswerJudge; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BaseballAnswerJudgeTest { + + private AnswerJudge answerJudge; + + @BeforeEach + void setup() { + answerJudge = new BaseballAnswerJudge(); + } + + @DisplayName("같은 위치의 숫자는 스트라이크로 판정한다") + @Test + void countStrikes_returnsCorrectCount_when_positionsMatch() { + int strikes = answerJudge.countStrikes("123", "153"); + assertThat(strikes).isEqualTo(2); + } + + @DisplayName("같은 위치의 숫자가 없으면 스트라이크는 0이다") + @Test + void countStrikes_returnsZero_when_noPositionMatches() { + int strikes = answerJudge.countStrikes("456", "123"); + assertThat(strikes).isZero(); + } + + @DisplayName("모든 숫자와 위치가 같으면 스트라이크는 3이다") + @Test + void countStrikes_returnsThree_when_guessEqualsAnswer() { + int strikes = answerJudge.countStrikes("123", "123"); + assertThat(strikes).isEqualTo(3); + } +} From 64e1ac44edfe6c4bd98429b9c2d43524047faf53 Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 18:12:01 +0900 Subject: [PATCH 06/14] =?UTF-8?q?refactor:=20=EC=9D=B8=ED=84=B0=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=A0=91=EA=B7=BC=EC=9E=90=20=EC=83=9D?= =?UTF-8?q?=EB=9E=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/AnswerGenerator.java | 2 +- src/main/java/model/AnswerJudge.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/model/AnswerGenerator.java b/src/main/java/model/AnswerGenerator.java index 23f1d3c7..f48f03b0 100644 --- a/src/main/java/model/AnswerGenerator.java +++ b/src/main/java/model/AnswerGenerator.java @@ -2,6 +2,6 @@ public interface AnswerGenerator { - public String generateAnswer(); + String generateAnswer(); } diff --git a/src/main/java/model/AnswerJudge.java b/src/main/java/model/AnswerJudge.java index c6919dee..ba66d45d 100644 --- a/src/main/java/model/AnswerJudge.java +++ b/src/main/java/model/AnswerJudge.java @@ -2,6 +2,6 @@ public interface AnswerJudge { - public Integer countStrikes(String input, String answer); + Integer countStrikes(String input, String answer); } From 729baaacd36e4931165c96c3f6914921356f8d37 Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 18:34:40 +0900 Subject: [PATCH 07/14] =?UTF-8?q?feat:=20=EB=B3=BC=20=ED=8C=90=EC=A0=95=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=A9?= =?UTF-8?q?=EB=8B=88=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/model/AnswerJudge.java | 1 + src/main/java/model/BaseballAnswerJudge.java | 10 ++++++++++ src/test/java/BaseballAnswerJudgeTest.java | 21 ++++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ce6af43e..84f67a81 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ - 제약 사항: 1부터 9까지만, 정답 길이 3 - [ ] baseball 정답 판독 - [X] 정답과 비교해서 자리와 숫자가 모두 같은 경우 strike의 카운트를 반환합니다. - - [ ] 정답과 비교해서 숫자만 같고 자리만 같을 경우 ball 의 카운트를 올립니다. + - [X] 정답과 비교해서 숫자만 같고 자리만 같을 경우 ball 의 카운트를 올립니다. - [ ] strike or ball의 카운트가 0이 아닌 경우 출력하고, 모두 0인 경우 `낫싱`을 출력합니다. - [ ] baseball 게임 판단 - [ ] 정답 판독기에서 판독한 값이 3스트라이크일 경우 출력하고 `3개의 숫자를 모두 맞히셨습니다! 게임 끝` 멘트와 게임을 종료합니다. diff --git a/src/main/java/model/AnswerJudge.java b/src/main/java/model/AnswerJudge.java index ba66d45d..1cb4941d 100644 --- a/src/main/java/model/AnswerJudge.java +++ b/src/main/java/model/AnswerJudge.java @@ -4,4 +4,5 @@ public interface AnswerJudge { Integer countStrikes(String input, String answer); + Integer countBalls(String input, String answer); } diff --git a/src/main/java/model/BaseballAnswerJudge.java b/src/main/java/model/BaseballAnswerJudge.java index 580ca608..d0615bb1 100644 --- a/src/main/java/model/BaseballAnswerJudge.java +++ b/src/main/java/model/BaseballAnswerJudge.java @@ -10,4 +10,14 @@ public Integer countStrikes(String input, String answer) { } return result; } + + @Override + public Integer countBalls(String input, String answer) { + int result = 0; + for (int index = 0; index < 3; index++) { + char item = input.charAt(index); + if (item != answer.charAt(index) && answer.indexOf(item) != -1) result++; + } + return result; + } } diff --git a/src/test/java/BaseballAnswerJudgeTest.java b/src/test/java/BaseballAnswerJudgeTest.java index 147e0701..d5862401 100644 --- a/src/test/java/BaseballAnswerJudgeTest.java +++ b/src/test/java/BaseballAnswerJudgeTest.java @@ -35,4 +35,25 @@ void countStrikes_returnsThree_when_guessEqualsAnswer() { int strikes = answerJudge.countStrikes("123", "123"); assertThat(strikes).isEqualTo(3); } + + @DisplayName("같은 위치의 숫자는 볼로 판정하지 않는다.") + @Test + void countBalls_returnsCorrectCount_when_positionsMatch() { + int balls = answerJudge.countBalls("123", "153"); + assertThat(balls).isEqualTo(0); + } + + @DisplayName("같은 숫자가 위치가 다르면 볼이다.") + @Test + void countBalls_returnsOne_when_noPositionMatches_OneValueMatches() { + int balls = answerJudge.countBalls("456", "124"); + assertThat(balls).isEqualTo(1); + } + + @DisplayName("같은 숫자가 없으면 볼은 0이다.") + @Test + void countBalls_returnsZero_when_noPositionMatches() { + int balls = answerJudge.countBalls("123", "456"); + assertThat(balls).isZero(); + } } From 553c6bf297e37038e359a14e0d78c1324a6c4f17 Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 18:39:27 +0900 Subject: [PATCH 08/14] =?UTF-8?q?refactor:=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EA=B5=AC=ED=98=84=20=ED=8E=B8=EC=A7=91=20?= =?UTF-8?q?=EB=82=AB=EC=8B=B1=EC=9D=84=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8A=94=EA=B1=B4=20=EC=A0=95=EB=8B=B5=20=ED=8C=90=EB=8F=85?= =?UTF-8?q?=EA=B8=B0=EC=97=90=20=EB=93=A4=EC=96=B4=EA=B0=80=EB=8A=94?= =?UTF-8?q?=EA=B2=8C=20=EC=95=84=EB=8B=8C,=20=EC=9E=85=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=ED=8C=90=EB=8B=A8=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EA=B2=83=EC=9D=B4=EB=9D=BC=EA=B3=A0=20=EC=83=9D=EA=B0=81?= =?UTF-8?q?=ED=95=B4=20=ED=8E=B8=EC=A7=91=ED=95=98=EC=98=80=EC=8A=B5?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 84f67a81..2aaf5ed7 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ - [ ] baseball 정답 판독 - [X] 정답과 비교해서 자리와 숫자가 모두 같은 경우 strike의 카운트를 반환합니다. - [X] 정답과 비교해서 숫자만 같고 자리만 같을 경우 ball 의 카운트를 올립니다. - - [ ] strike or ball의 카운트가 0이 아닌 경우 출력하고, 모두 0인 경우 `낫싱`을 출력합니다. - [ ] baseball 게임 판단 - [ ] 정답 판독기에서 판독한 값이 3스트라이크일 경우 출력하고 `3개의 숫자를 모두 맞히셨습니다! 게임 끝` 멘트와 게임을 종료합니다. - [ ] 게임이 시작된 상황이라면 숫자를 입력 받고 판독 결과를 반환합니다. From aa0339cccdb0fd2bf5befc30547d9503853020ef Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 20:25:57 +0900 Subject: [PATCH 09/14] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=A7=84?= =?UTF-8?q?=ED=96=89=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +- src/main/java/model/BaseballGameManager.java | 46 ++++++++++++ src/main/java/model/GameManager.java | 13 ++++ src/test/java/BaseballGameManagerTest.java | 76 ++++++++++++++++++++ 4 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 src/main/java/model/BaseballGameManager.java create mode 100644 src/main/java/model/GameManager.java create mode 100644 src/test/java/BaseballGameManagerTest.java diff --git a/README.md b/README.md index 2aaf5ed7..92fc8481 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,11 @@ - [X] baseball 정답 생성 - [X] 1부터 9까지의 다른 수로 이루어진 3자리의 수를 생성합니다. - 제약 사항: 1부터 9까지만, 정답 길이 3 -- [ ] baseball 정답 판독 +- [X] baseball 정답 판독 - [X] 정답과 비교해서 자리와 숫자가 모두 같은 경우 strike의 카운트를 반환합니다. - [X] 정답과 비교해서 숫자만 같고 자리만 같을 경우 ball 의 카운트를 올립니다. -- [ ] baseball 게임 판단 - - [ ] 정답 판독기에서 판독한 값이 3스트라이크일 경우 출력하고 `3개의 숫자를 모두 맞히셨습니다! 게임 끝` 멘트와 게임을 종료합니다. - - [ ] 게임이 시작된 상황이라면 숫자를 입력 받고 판독 결과를 반환합니다. +- [X] baseball 게임 진행 + - [X] 게임이 시작된 상황이라면 숫자를 입력 받고 판독 결과를 반환합니다. - [ ] 게임이 진행중이 아니라면 1의 입력의 경우 정답 생성을 요청하고, 숫자 입력을 요구합니다. - [ ] 게임이 진행중이 아니라면 2의 입력의 경우 게임을 종료합니다. - [ ] 입력기 diff --git a/src/main/java/model/BaseballGameManager.java b/src/main/java/model/BaseballGameManager.java new file mode 100644 index 00000000..ffe4b8e8 --- /dev/null +++ b/src/main/java/model/BaseballGameManager.java @@ -0,0 +1,46 @@ +package model; + +public class BaseballGameManager implements GameManager { + private final AnswerGenerator answerGenerator; + private final AnswerJudge answerJudge; + private String answer; + private boolean playing; + private boolean gameWon; + + public BaseballGameManager(AnswerGenerator answerGenerator, AnswerJudge answerJudge) { + this.answerGenerator = answerGenerator; + this.answerJudge = answerJudge; + this.playing = false; + this.gameWon = false; + } + + @Override + public void startGame() { + this.answer = answerGenerator.generateAnswer(); + this.playing = true; + this.gameWon = false; + } + + @Override + public int[] guess(String input) { + int strikes = answerJudge.countStrikes(input, answer); + int balls = answerJudge.countBalls(input, answer); + + if (strikes == 3) { + this.playing = false; + this.gameWon = true; + } + + return new int[]{strikes, balls}; + } + + @Override + public boolean isPlaying() { + return playing; + } + + @Override + public boolean isGameWon() { + return gameWon; + } +} diff --git a/src/main/java/model/GameManager.java b/src/main/java/model/GameManager.java new file mode 100644 index 00000000..054db87f --- /dev/null +++ b/src/main/java/model/GameManager.java @@ -0,0 +1,13 @@ +package model; + +public interface GameManager { + + void startGame(); + + int[] guess(String input); + + boolean isPlaying(); + + boolean isGameWon(); + +} diff --git a/src/test/java/BaseballGameManagerTest.java b/src/test/java/BaseballGameManagerTest.java new file mode 100644 index 00000000..34c08dc4 --- /dev/null +++ b/src/test/java/BaseballGameManagerTest.java @@ -0,0 +1,76 @@ +import model.AnswerGenerator; +import model.AnswerJudge; +import model.BaseballAnswerJudge; +import model.BaseballGameManager; +import model.GameManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BaseballGameManagerTest { + + private GameManager gameManager; + private AnswerJudge answerJudge; + + @BeforeEach + void setup() { + AnswerGenerator fixedAnswerGenerator = () -> "123"; + answerJudge = new BaseballAnswerJudge(); + gameManager = new BaseballGameManager(fixedAnswerGenerator, answerJudge); + } + + @DisplayName("게임 시작 전에는 플레이 상태가 아니다") + @Test + void isPlaying_returnsFalse_beforeGameStart() { + assertThat(gameManager.isPlaying()).isFalse(); + } + + @DisplayName("게임 시작 후에는 플레이 상태이다") + @Test + void isPlaying_returnsTrue_afterGameStart() { + gameManager.startGame(); + assertThat(gameManager.isPlaying()).isTrue(); + } + + @DisplayName("추측 시 스트라이크와 볼 개수를 반환한다") + @Test + void guess_returnsStrikesAndBalls() { + gameManager.startGame(); + int[] result = gameManager.guess("145"); + assertThat(result[0]).isEqualTo(1); + assertThat(result[1]).isEqualTo(0); + } + + @DisplayName("3스트라이크 시 게임이 종료된다") + @Test + void guess_endsGame_whenThreeStrikes() { + gameManager.startGame(); + int[] result = gameManager.guess("123"); + assertThat(result[0]).isEqualTo(3); + assertThat(gameManager.isPlaying()).isFalse(); + assertThat(gameManager.isGameWon()).isTrue(); + } + + @DisplayName("3스트라이크가 아니면 게임이 계속된다") + @Test + void guess_continuesGame_whenNotThreeStrikes() { + gameManager.startGame(); + gameManager.guess("456"); + assertThat(gameManager.isPlaying()).isTrue(); + assertThat(gameManager.isGameWon()).isFalse(); + } + + @DisplayName("게임 재시작 시 상태가 초기화된다") + @Test + void startGame_resetsState_afterGameWon() { + gameManager.startGame(); + gameManager.guess("123"); + assertThat(gameManager.isGameWon()).isTrue(); + + gameManager.startGame(); + assertThat(gameManager.isPlaying()).isTrue(); + assertThat(gameManager.isGameWon()).isFalse(); + } +} From 42e050818761c287bc78b3da9a113113f528e779 Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 20:31:19 +0900 Subject: [PATCH 10/14] =?UTF-8?q?feat:=20=EC=9E=85=EB=A0=A5=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/model/BaseballInputValidator.java | 46 +++++++++++++++ src/main/java/model/InputValidator.java | 7 +++ src/test/java/BaseballInputValidatorTest.java | 57 +++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 src/main/java/model/BaseballInputValidator.java create mode 100644 src/main/java/model/InputValidator.java create mode 100644 src/test/java/BaseballInputValidatorTest.java diff --git a/src/main/java/model/BaseballInputValidator.java b/src/main/java/model/BaseballInputValidator.java new file mode 100644 index 00000000..a48c0a75 --- /dev/null +++ b/src/main/java/model/BaseballInputValidator.java @@ -0,0 +1,46 @@ +package model; + +import java.util.HashSet; +import java.util.Set; + +public class BaseballInputValidator implements InputValidator { + + @Override + public void validate(String input) { + validateLength(input); + validateDigitsOnly(input); + validateRange(input); + validateNoDuplicates(input); + } + + private void validateLength(String input) { + if (input.length() != 3) { + throw new IllegalArgumentException("[ERROR] 3자리 숫자를 입력해주세요."); + } + } + + private void validateDigitsOnly(String input) { + for (char c : input.toCharArray()) { + if (!Character.isDigit(c)) { + throw new IllegalArgumentException("[ERROR] 숫자만 입력해주세요."); + } + } + } + + private void validateRange(String input) { + for (char c : input.toCharArray()) { + if (c == '0') { + throw new IllegalArgumentException("[ERROR] 1부터 9까지의 숫자만 입력해주세요."); + } + } + } + + private void validateNoDuplicates(String input) { + Set seen = new HashSet<>(); + for (char c : input.toCharArray()) { + if (!seen.add(c)) { + throw new IllegalArgumentException("[ERROR] 중복되지 않는 숫자를 입력해주세요."); + } + } + } +} diff --git a/src/main/java/model/InputValidator.java b/src/main/java/model/InputValidator.java new file mode 100644 index 00000000..8715129d --- /dev/null +++ b/src/main/java/model/InputValidator.java @@ -0,0 +1,7 @@ +package model; + +public interface InputValidator { + + void validate(String input); + +} diff --git a/src/test/java/BaseballInputValidatorTest.java b/src/test/java/BaseballInputValidatorTest.java new file mode 100644 index 00000000..fb494d73 --- /dev/null +++ b/src/test/java/BaseballInputValidatorTest.java @@ -0,0 +1,57 @@ +import model.BaseballInputValidator; +import model.InputValidator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThatCode; + +public class BaseballInputValidatorTest { + + private InputValidator validator; + + @BeforeEach + void setup() { + validator = new BaseballInputValidator(); + } + + @DisplayName("올바른 입력은 예외가 발생하지 않는다") + @Test + void validate_doesNotThrow_whenValidInput() { + assertThatCode(() -> validator.validate("123")) + .doesNotThrowAnyException(); + } + + @DisplayName("3자리가 아니면 예외가 발생한다") + @Test + void validate_throwsException_whenLengthIsNotThree() { + assertThatThrownBy(() -> validator.validate("12")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR]"); + } + + @DisplayName("숫자가 아닌 문자가 포함되면 예외가 발생한다") + @Test + void validate_throwsException_whenContainsNonDigit() { + assertThatThrownBy(() -> validator.validate("12a")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR]"); + } + + @DisplayName("0이 포함되면 예외가 발생한다") + @Test + void validate_throwsException_whenContainsZero() { + assertThatThrownBy(() -> validator.validate("012")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR]"); + } + + @DisplayName("중복된 숫자가 있으면 예외가 발생한다") + @Test + void validate_throwsException_whenHasDuplicates() { + assertThatThrownBy(() -> validator.validate("112")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR]"); + } +} From 14f27c4cd351176ae191f1f2893cea1110c66681 Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 21:10:17 +0900 Subject: [PATCH 11/14] =?UTF-8?q?feat:=20controller=EC=99=80=20view,=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EA=B8=B0=20=EC=B6=9C=EB=A0=A5=EA=B8=B0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/GameController.java | 56 ++++++++++++++++++++ src/main/java/view/OutputView.java | 40 ++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/main/java/controller/GameController.java create mode 100644 src/main/java/view/OutputView.java diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java new file mode 100644 index 00000000..975aa978 --- /dev/null +++ b/src/main/java/controller/GameController.java @@ -0,0 +1,56 @@ +package controller; + +import model.GameManager; +import model.InputValidator; +import view.OutputView; + +import java.util.Scanner; + +public class GameController { + + private final GameManager gameManager; + private final InputValidator inputValidator; + private final OutputView outputView; + private final Scanner scanner; + + public GameController(GameManager gameManager, InputValidator inputValidator, OutputView outputView) { + this.gameManager = gameManager; + this.inputValidator = inputValidator; + this.outputView = outputView; + this.scanner = new Scanner(System.in); + } + + public void run() { + outputView.printGameStart(); + while (true) { + playGame(); + if (!askRestart()) break; + } + } + + private void playGame() { + gameManager.startGame(); + while (gameManager.isPlaying()) { + outputView.printInputPrompt(); + String input = scanner.nextLine(); + processGuess(input); + } + outputView.printGameWon(); + } + + private void processGuess(String input) { + try { + inputValidator.validate(input); + int[] result = gameManager.guess(input); + outputView.printResult(result[0], result[1]); + } catch (IllegalArgumentException e) { + outputView.printError(e.getMessage()); + } + } + + private boolean askRestart() { + outputView.printRestartPrompt(); + String input = scanner.nextLine(); + return input.equals("1"); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..00db7933 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,40 @@ +package view; + +public class OutputView { + + public void printGameStart() { + System.out.println("숫자 야구 게임을 시작합니다."); + } + + public void printInputPrompt() { + System.out.print("숫자를 입력해주세요 : "); + } + + public void printResult(int strikes, int balls) { + if (strikes == 0 && balls == 0) { + System.out.println("낫싱"); + return; + } + + StringBuilder result = new StringBuilder(); + if (balls > 0) { + result.append(balls).append("볼 "); + } + if (strikes > 0) { + result.append(strikes).append("스트라이크"); + } + System.out.println(result.toString().trim()); + } + + public void printGameWon() { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + } + + public void printRestartPrompt() { + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + } + + public void printError(String message) { + System.out.println(message); + } +} From 8872bdc90f45a7479fe3ee063c2ba6c8cd798c8c Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 21:18:16 +0900 Subject: [PATCH 12/14] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C=20=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 92fc8481..e2da9c64 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ - [X] 정답과 비교해서 숫자만 같고 자리만 같을 경우 ball 의 카운트를 올립니다. - [X] baseball 게임 진행 - [X] 게임이 시작된 상황이라면 숫자를 입력 받고 판독 결과를 반환합니다. - - [ ] 게임이 진행중이 아니라면 1의 입력의 경우 정답 생성을 요청하고, 숫자 입력을 요구합니다. - - [ ] 게임이 진행중이 아니라면 2의 입력의 경우 게임을 종료합니다. -- [ ] 입력기 -- [ ] 출력기 + - [X] 게임이 진행중이 아니라면 1의 입력의 경우 정답 생성을 요청하고, 숫자 입력을 요구합니다. + - [X] 게임이 진행중이 아니라면 2의 입력의 경우 게임을 종료합니다. +- [X] 입력기 +- [X] 출력기 From b5884b7c7ee22d776ee18edf04393e0698b4e50c Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Wed, 28 Jan 2026 21:25:57 +0900 Subject: [PATCH 13/14] =?UTF-8?q?feat:=20main=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EC=99=80=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Main.java | 10 ++++++++++ src/main/java/config/GameConfig.java | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/main/java/Main.java create mode 100644 src/main/java/config/GameConfig.java diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 00000000..35200557 --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,10 @@ +import config.GameConfig; +import controller.GameController; + +public class Main { + + public static void main(String[] args) { + GameController gameController = new GameConfig().gameController(); + gameController.run(); + } +} diff --git a/src/main/java/config/GameConfig.java b/src/main/java/config/GameConfig.java new file mode 100644 index 00000000..16a2feb8 --- /dev/null +++ b/src/main/java/config/GameConfig.java @@ -0,0 +1,27 @@ +package config; + +import controller.GameController; +import model.BaseballAnswerGenerator; +import model.BaseballAnswerJudge; +import model.BaseballGameManager; +import model.BaseballInputValidator; +import view.OutputView; + +public class GameConfig { + + public GameController gameController() { + return new GameController( + gameManager(), + new BaseballInputValidator(), + new OutputView() + ); + } + + private BaseballGameManager gameManager() { + return new BaseballGameManager( + new BaseballAnswerGenerator(), + new BaseballAnswerJudge() + ); + } + +} From a2c984c91af63803d2ad25f6c07c73ab49ba1e4d Mon Sep 17 00:00:00 2001 From: cheesecrust Date: Tue, 3 Feb 2026 20:41:55 +0900 Subject: [PATCH 14/14] =?UTF-8?q?refactor:=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EB=A1=9C=20=EB=B9=BC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/constant/GameConstants.java | 9 +++++++++ src/main/java/constant/GameMessages.java | 16 ++++++++++++++++ src/main/java/controller/GameController.java | 3 ++- src/main/java/model/BaseballAnswerGenerator.java | 11 ++++++++--- src/main/java/model/BaseballAnswerJudge.java | 14 ++++++++++---- src/main/java/model/BaseballGameManager.java | 4 +++- src/main/java/model/BaseballInputValidator.java | 15 +++++++++------ src/main/java/view/OutputView.java | 16 +++++++++------- 8 files changed, 66 insertions(+), 22 deletions(-) create mode 100644 src/main/java/constant/GameConstants.java create mode 100644 src/main/java/constant/GameMessages.java diff --git a/src/main/java/constant/GameConstants.java b/src/main/java/constant/GameConstants.java new file mode 100644 index 00000000..ec10db91 --- /dev/null +++ b/src/main/java/constant/GameConstants.java @@ -0,0 +1,9 @@ +package constant; + +public class GameConstants { + public static final int ANSWER_LENGTH = 3; + public static final int MIN_DIGIT = 1; + public static final int MAX_DIGIT = 9; + public static final char EXCLUDED_DIGIT = '0'; + public static final String RESTART_COMMAND = "1"; +} diff --git a/src/main/java/constant/GameMessages.java b/src/main/java/constant/GameMessages.java new file mode 100644 index 00000000..078df844 --- /dev/null +++ b/src/main/java/constant/GameMessages.java @@ -0,0 +1,16 @@ +package constant; + +public class GameMessages { + public static final String GAME_START = "숫자 야구 게임을 시작합니다."; + public static final String INPUT_PROMPT = "숫자를 입력해주세요 : "; + public static final String NOTHING = "낫싱"; + public static final String BALL = "볼"; + public static final String STRIKE = "스트라이크"; + public static final String GAME_WON = "3개의 숫자를 모두 맞히셨습니다! 게임 종료"; + public static final String RESTART_PROMPT = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."; + + public static final String ERROR_INVALID_LENGTH = "[ERROR] 3자리 숫자를 입력해주세요."; + public static final String ERROR_NOT_DIGIT = "[ERROR] 숫자만 입력해주세요."; + public static final String ERROR_INVALID_RANGE = "[ERROR] 1부터 9까지의 숫자만 입력해주세요."; + public static final String ERROR_DUPLICATE = "[ERROR] 중복되지 않는 숫자를 입력해주세요."; +} diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 975aa978..858ac58c 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -1,5 +1,6 @@ package controller; +import constant.GameConstants; import model.GameManager; import model.InputValidator; import view.OutputView; @@ -51,6 +52,6 @@ private void processGuess(String input) { private boolean askRestart() { outputView.printRestartPrompt(); String input = scanner.nextLine(); - return input.equals("1"); + return input.equals(GameConstants.RESTART_COMMAND); } } diff --git a/src/main/java/model/BaseballAnswerGenerator.java b/src/main/java/model/BaseballAnswerGenerator.java index ae5ae9c0..b56bce45 100644 --- a/src/main/java/model/BaseballAnswerGenerator.java +++ b/src/main/java/model/BaseballAnswerGenerator.java @@ -1,17 +1,22 @@ package model; +import constant.GameConstants; + import java.util.HashSet; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; -public class BaseballAnswerGenerator implements AnswerGenerator{ +public class BaseballAnswerGenerator implements AnswerGenerator { @Override public String generateAnswer() { Set numbers = new HashSet<>(); - while (numbers.size() < 3) { - numbers.add(ThreadLocalRandom.current().nextInt(1, 10)); + while (numbers.size() < GameConstants.ANSWER_LENGTH) { + numbers.add(ThreadLocalRandom.current().nextInt( + GameConstants.MIN_DIGIT, + GameConstants.MAX_DIGIT + 1 + )); } StringBuilder answer = new StringBuilder(); diff --git a/src/main/java/model/BaseballAnswerJudge.java b/src/main/java/model/BaseballAnswerJudge.java index d0615bb1..b280c985 100644 --- a/src/main/java/model/BaseballAnswerJudge.java +++ b/src/main/java/model/BaseballAnswerJudge.java @@ -1,12 +1,16 @@ package model; +import constant.GameConstants; + public class BaseballAnswerJudge implements AnswerJudge { @Override public Integer countStrikes(String input, String answer) { int result = 0; - for (int index = 0; index < 3; index++) { - if (input.charAt(index) == answer.charAt(index)) result++; + for (int index = 0; index < GameConstants.ANSWER_LENGTH; index++) { + if (input.charAt(index) == answer.charAt(index)) { + result++; + } } return result; } @@ -14,9 +18,11 @@ public Integer countStrikes(String input, String answer) { @Override public Integer countBalls(String input, String answer) { int result = 0; - for (int index = 0; index < 3; index++) { + for (int index = 0; index < GameConstants.ANSWER_LENGTH; index++) { char item = input.charAt(index); - if (item != answer.charAt(index) && answer.indexOf(item) != -1) result++; + if (item != answer.charAt(index) && answer.indexOf(item) != -1) { + result++; + } } return result; } diff --git a/src/main/java/model/BaseballGameManager.java b/src/main/java/model/BaseballGameManager.java index ffe4b8e8..06ac6a25 100644 --- a/src/main/java/model/BaseballGameManager.java +++ b/src/main/java/model/BaseballGameManager.java @@ -1,5 +1,7 @@ package model; +import constant.GameConstants; + public class BaseballGameManager implements GameManager { private final AnswerGenerator answerGenerator; private final AnswerJudge answerJudge; @@ -26,7 +28,7 @@ public int[] guess(String input) { int strikes = answerJudge.countStrikes(input, answer); int balls = answerJudge.countBalls(input, answer); - if (strikes == 3) { + if (strikes == GameConstants.ANSWER_LENGTH) { this.playing = false; this.gameWon = true; } diff --git a/src/main/java/model/BaseballInputValidator.java b/src/main/java/model/BaseballInputValidator.java index a48c0a75..4b1d3a1c 100644 --- a/src/main/java/model/BaseballInputValidator.java +++ b/src/main/java/model/BaseballInputValidator.java @@ -1,5 +1,8 @@ package model; +import constant.GameConstants; +import constant.GameMessages; + import java.util.HashSet; import java.util.Set; @@ -14,23 +17,23 @@ public void validate(String input) { } private void validateLength(String input) { - if (input.length() != 3) { - throw new IllegalArgumentException("[ERROR] 3자리 숫자를 입력해주세요."); + if (input.length() != GameConstants.ANSWER_LENGTH) { + throw new IllegalArgumentException(GameMessages.ERROR_INVALID_LENGTH); } } private void validateDigitsOnly(String input) { for (char c : input.toCharArray()) { if (!Character.isDigit(c)) { - throw new IllegalArgumentException("[ERROR] 숫자만 입력해주세요."); + throw new IllegalArgumentException(GameMessages.ERROR_NOT_DIGIT); } } } private void validateRange(String input) { for (char c : input.toCharArray()) { - if (c == '0') { - throw new IllegalArgumentException("[ERROR] 1부터 9까지의 숫자만 입력해주세요."); + if (c == GameConstants.EXCLUDED_DIGIT) { + throw new IllegalArgumentException(GameMessages.ERROR_INVALID_RANGE); } } } @@ -39,7 +42,7 @@ private void validateNoDuplicates(String input) { Set seen = new HashSet<>(); for (char c : input.toCharArray()) { if (!seen.add(c)) { - throw new IllegalArgumentException("[ERROR] 중복되지 않는 숫자를 입력해주세요."); + throw new IllegalArgumentException(GameMessages.ERROR_DUPLICATE); } } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 00db7933..4d48c225 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,37 +1,39 @@ package view; +import constant.GameMessages; + public class OutputView { public void printGameStart() { - System.out.println("숫자 야구 게임을 시작합니다."); + System.out.println(GameMessages.GAME_START); } public void printInputPrompt() { - System.out.print("숫자를 입력해주세요 : "); + System.out.print(GameMessages.INPUT_PROMPT); } public void printResult(int strikes, int balls) { if (strikes == 0 && balls == 0) { - System.out.println("낫싱"); + System.out.println(GameMessages.NOTHING); return; } StringBuilder result = new StringBuilder(); if (balls > 0) { - result.append(balls).append("볼 "); + result.append(balls).append(GameMessages.BALL).append(" "); } if (strikes > 0) { - result.append(strikes).append("스트라이크"); + result.append(strikes).append(GameMessages.STRIKE); } System.out.println(result.toString().trim()); } public void printGameWon() { - System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); + System.out.println(GameMessages.GAME_WON); } public void printRestartPrompt() { - System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + System.out.println(GameMessages.RESTART_PROMPT); } public void printError(String message) {