From a29f54b4827af3bc4e46d3bcb57f12038bc6ba64 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Wed, 28 Jan 2026 16:56:44 +0900 Subject: [PATCH 01/29] =?UTF-8?q?docs(README):=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=9A=94=EA=B5=AC=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 | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d7e8aee..d1158529 100644 --- a/README.md +++ b/README.md @@ -1 +1,22 @@ -# java-baseball-precourse \ No newline at end of file +# java-baseball-precourse + + +## Domain +- [ ] 컴퓨터의 3자리의 수를 맞춰야 한다. + - [ ] 3자리의 수는 1~9까지 서로 다른 수로 랜덤하게 이루어진다. + - [ ] 같은 수가 같은 자리에 있으면 '스트라이크' + - [ ] 같은 수가 다른 자리에 있으면 '볼' + - [ ] 같은 수가 없으면 '낫싱' + +## Input +- [ ] 사용자는 컴퓨터가 생각하고 있는 3개의 숫자를 입력한다. +- [ ] 게임 종료 시 재시작 또는 종료 여부를 입력한다. + - [ ] '1' 입력 시 재시작 + - [ ] '2' 입력 시 종료 + + +## Output +- [ ] 컴퓨터는 플레이어가 입력한 숫자에 대한 결과를 출력한다. +- [ ] 게임 종료 시 문구를 출력한다. + - [ ] 게임 끝 문구 출력 + - [ ] 종료 또는 재시작을 선택할 수 있는 문구 출력 \ No newline at end of file From b03097ef2f7bc47f86afa1255aacbddc7118a08d Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Wed, 28 Jan 2026 17:03:35 +0900 Subject: [PATCH 02/29] =?UTF-8?q?docs(README):=20=EC=9E=98=EB=AA=BB?= =?UTF-8?q?=EB=90=9C=20=EC=9E=85=EB=A0=A5=20=EA=B0=92=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=B6=94=EA=B0=80=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d1158529..4873ce11 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,10 @@ - [ ] 같은 수가 같은 자리에 있으면 '스트라이크' - [ ] 같은 수가 다른 자리에 있으면 '볼' - [ ] 같은 수가 없으면 '낫싱' +- [ ] 사용자가 잘못된 값을 입력해도 게임을 계속 진행할 수 있어야 한다. + - [ ] 에러 메시지를 띄운다. + - [ ] 다시 입력을 받는다. + ## Input - [ ] 사용자는 컴퓨터가 생각하고 있는 3개의 숫자를 입력한다. @@ -17,6 +21,8 @@ ## Output - [ ] 컴퓨터는 플레이어가 입력한 숫자에 대한 결과를 출력한다. +- [ ] 사용자가 잘못된 값을 입력할 경우 에러 메시지를 출력한다. + - [ ] 에러 메시지는 [ERROR]로 시작한다. - [ ] 게임 종료 시 문구를 출력한다. - [ ] 게임 끝 문구 출력 - [ ] 종료 또는 재시작을 선택할 수 있는 문구 출력 \ No newline at end of file From fbb2be317795a67c4c8bbf7dddfbbf03486d4fc1 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Wed, 28 Jan 2026 17:15:42 +0900 Subject: [PATCH 03/29] =?UTF-8?q?chore:=20editorconfig=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..1a424d53 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = false +max_line_length = 120 +tab_width = 4 From 7998aecd668f6d0385840a8199f1ea1fb12eedf4 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Wed, 28 Jan 2026 17:47:40 +0900 Subject: [PATCH 04/29] =?UTF-8?q?build:=20=EC=9D=B8=EC=BD=94=EB=94=A9=20?= =?UTF-8?q?=EC=86=8D=EC=84=B1=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index 20a92c9e..8b5ed857 100644 --- a/build.gradle +++ b/build.gradle @@ -23,3 +23,6 @@ dependencies { test { useJUnitPlatform() } + +compileJava.options.encoding = 'UTF-8' +compileTestJava.options.encoding = 'UTF-8' \ No newline at end of file From 697403ad8ad3da2c646bae018fb6c138a456cc71 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Wed, 28 Jan 2026 17:54:55 +0900 Subject: [PATCH 05/29] =?UTF-8?q?chore:=20editorconfig=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 1a424d53..00000000 --- a/.editorconfig +++ /dev/null @@ -1,10 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_size = 4 -indent_style = space -insert_final_newline = false -max_line_length = 120 -tab_width = 4 From a437454d2d7c2b0aeacd130b92c0b2abba2996c4 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 14:32:28 +0900 Subject: [PATCH 06/29] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EC=9D=98=20=EC=9E=85=EB=A0=A5=20=EA=B0=92=EC=9D=84=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/main/java/.gitkeep | 0 src/main/java/model/Player.java | 53 +++++++++++++++++++++++++++++++++ src/test/java/.gitkeep | 0 4 files changed, 54 insertions(+), 1 deletion(-) delete mode 100644 src/main/java/.gitkeep create mode 100644 src/main/java/model/Player.java delete mode 100644 src/test/java/.gitkeep diff --git a/README.md b/README.md index 4873ce11..9c462d01 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,4 @@ - [ ] 에러 메시지는 [ERROR]로 시작한다. - [ ] 게임 종료 시 문구를 출력한다. - [ ] 게임 끝 문구 출력 - - [ ] 종료 또는 재시작을 선택할 수 있는 문구 출력 \ No newline at end of file + - [ ] 종료 또는 재시작을 선택할 수 있는 문구 출력 diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/java/model/Player.java b/src/main/java/model/Player.java new file mode 100644 index 00000000..f9e3987f --- /dev/null +++ b/src/main/java/model/Player.java @@ -0,0 +1,53 @@ +package model; + +import java.util.HashSet; +import java.util.Set; + +public class Player { + private static final int NUMBER_LENGTH = 3; + private static final int MIN_NUMBER = 1; + private static final int MAX_NUMBER = 9; + + private static final String ERROR_INVALID_LENGTH = "[ERROR] 숫자는 3자리여야 합니다."; + private static final String ERROR_NOT_A_DIGIT = "[ERROR] 숫자만 입력해야 합니다."; + private static final String ERROR_INVALID_RANGE = "[ERROR] 숫자는 1부터 9까지만 가능합니다."; + private static final String ERROR_DUPLICATED_DIGIT = "[ERROR] 숫자는 서로 중복될 수 없습니다."; + + public void validateNumber(String number) { + validateLength(number); + + Set uniqueNumbers = new HashSet<>(); + for (char num : number.toCharArray()) { + validateIsNumber(num); + validateNumRange(num); + uniqueNumbers.add(num); + } + + validateDuplication(uniqueNumbers); + } + + private static void validateLength(String number) { + if (number == null || number.length() != NUMBER_LENGTH) { + throw new IllegalArgumentException(ERROR_INVALID_LENGTH); + } + } + + private static void validateIsNumber(char num) { + if (!Character.isDigit(num)) { + throw new IllegalArgumentException(ERROR_NOT_A_DIGIT); + } + } + + private static void validateNumRange(char num) { + int digit = num - '0'; + if (digit < MIN_NUMBER || digit > MAX_NUMBER) { + throw new IllegalArgumentException(ERROR_INVALID_RANGE); + } + } + + private static void validateDuplication(Set uniqueNumbers) { + if (uniqueNumbers.size() != NUMBER_LENGTH) { + throw new IllegalArgumentException(ERROR_DUPLICATED_DIGIT); + } + } +} diff --git a/src/test/java/.gitkeep b/src/test/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 From 28e97acf5ed35d6e88ca942b6a093a9a0ba2d0cb Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 15:08:55 +0900 Subject: [PATCH 07/29] =?UTF-8?q?feat:=20=EB=9E=9C=EB=8D=A4=20=EC=88=98=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 26 +++++++++---------- src/main/java/model/Computer.java | 12 +++++++++ src/main/java/model/NumberGenerator.java | 7 +++++ .../java/model/RandomNumberGenerator.java | 26 +++++++++++++++++++ 4 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 src/main/java/model/Computer.java create mode 100644 src/main/java/model/NumberGenerator.java create mode 100644 src/main/java/model/RandomNumberGenerator.java diff --git a/README.md b/README.md index 9c462d01..460297c5 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,28 @@ # java-baseball-precourse - ## Domain -- [ ] 컴퓨터의 3자리의 수를 맞춰야 한다. - - [ ] 3자리의 수는 1~9까지 서로 다른 수로 랜덤하게 이루어진다. - - [ ] 같은 수가 같은 자리에 있으면 '스트라이크' - - [ ] 같은 수가 다른 자리에 있으면 '볼' - - [ ] 같은 수가 없으면 '낫싱' -- [ ] 사용자가 잘못된 값을 입력해도 게임을 계속 진행할 수 있어야 한다. - - [ ] 에러 메시지를 띄운다. - - [ ] 다시 입력을 받는다. +- [ ] 컴퓨터의 3자리의 수를 맞춰야 한다. + - [x] 3자리의 수는 1~9까지 서로 다른 수로 랜덤하게 이루어진다. + - [ ] 같은 수가 같은 자리에 있으면 '스트라이크' + - [ ] 같은 수가 다른 자리에 있으면 '볼' + - [ ] 같은 수가 없으면 '낫싱' +- [ ] 사용자가 잘못된 값을 입력해도 게임을 계속 진행할 수 있어야 한다. + - [ ] 에러 메시지를 띄운다. + - [ ] 다시 입력을 받는다. ## Input + - [ ] 사용자는 컴퓨터가 생각하고 있는 3개의 숫자를 입력한다. - [ ] 게임 종료 시 재시작 또는 종료 여부를 입력한다. - [ ] '1' 입력 시 재시작 - [ ] '2' 입력 시 종료 - ## Output + - [ ] 컴퓨터는 플레이어가 입력한 숫자에 대한 결과를 출력한다. - [ ] 사용자가 잘못된 값을 입력할 경우 에러 메시지를 출력한다. - - [ ] 에러 메시지는 [ERROR]로 시작한다. + - [ ] 에러 메시지는 [ERROR]로 시작한다. - [ ] 게임 종료 시 문구를 출력한다. - - [ ] 게임 끝 문구 출력 - - [ ] 종료 또는 재시작을 선택할 수 있는 문구 출력 + - [ ] 게임 끝 문구 출력 + - [ ] 종료 또는 재시작을 선택할 수 있는 문구 출력 diff --git a/src/main/java/model/Computer.java b/src/main/java/model/Computer.java new file mode 100644 index 00000000..e93027c9 --- /dev/null +++ b/src/main/java/model/Computer.java @@ -0,0 +1,12 @@ +package model; + +import java.util.List; + +public class Computer { + private static final int NUMBER_LENGTH = 3; + private final List number; + + public Computer(NumberGenerator numberGenerator) { + this.number = numberGenerator.generate(); + } +} diff --git a/src/main/java/model/NumberGenerator.java b/src/main/java/model/NumberGenerator.java new file mode 100644 index 00000000..79949d71 --- /dev/null +++ b/src/main/java/model/NumberGenerator.java @@ -0,0 +1,7 @@ +package model; + +import java.util.List; + +public interface NumberGenerator { + List generate(); +} diff --git a/src/main/java/model/RandomNumberGenerator.java b/src/main/java/model/RandomNumberGenerator.java new file mode 100644 index 00000000..30c5316f --- /dev/null +++ b/src/main/java/model/RandomNumberGenerator.java @@ -0,0 +1,26 @@ +package model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +public class RandomNumberGenerator implements NumberGenerator { + + private static final int NUMBER_LENGTH = 3; + private static final int MIN_DIGIT = 1; + private static final int MAX_DIGIT = 9; + + private final Random random = new Random(); + + @Override + public List generate() { + List pool = new ArrayList<>(); + for (int i = MIN_DIGIT; i <= MAX_DIGIT; i++) { + pool.add(i); + } + + Collections.shuffle(pool, random); + return new ArrayList<>(pool.subList(0, NUMBER_LENGTH)); + } +} From 7ea8b1529075b71c07a54ede748bd9872dbfac0b Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 15:09:54 +0900 Subject: [PATCH 08/29] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++---- src/main/java/model/Computer.java | 38 +++++++++++++++++++++++++++++++ src/main/java/model/Result.java | 4 ++++ 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 src/main/java/model/Result.java diff --git a/README.md b/README.md index 460297c5..95db6bf5 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ ## Domain -- [ ] 컴퓨터의 3자리의 수를 맞춰야 한다. +- [x] 컴퓨터의 3자리의 수를 맞춰야 한다. - [x] 3자리의 수는 1~9까지 서로 다른 수로 랜덤하게 이루어진다. - - [ ] 같은 수가 같은 자리에 있으면 '스트라이크' - - [ ] 같은 수가 다른 자리에 있으면 '볼' - - [ ] 같은 수가 없으면 '낫싱' + - [x] 같은 수가 같은 자리에 있으면 '스트라이크' + - [x] 같은 수가 다른 자리에 있으면 '볼' + - [x] 같은 수가 없으면 '낫싱' - [ ] 사용자가 잘못된 값을 입력해도 게임을 계속 진행할 수 있어야 한다. - [ ] 에러 메시지를 띄운다. - [ ] 다시 입력을 받는다. diff --git a/src/main/java/model/Computer.java b/src/main/java/model/Computer.java index e93027c9..a5447575 100644 --- a/src/main/java/model/Computer.java +++ b/src/main/java/model/Computer.java @@ -1,5 +1,6 @@ package model; +import java.util.ArrayList; import java.util.List; public class Computer { @@ -9,4 +10,41 @@ public class Computer { public Computer(NumberGenerator numberGenerator) { this.number = numberGenerator.generate(); } + + public Result calculate(String playerNumber) { + List playerNumbers = toDigits(playerNumber); + + int strikes = countStrikes(playerNumbers); + int balls = countBalls(playerNumbers) - strikes; + + return new Result(strikes, balls); + } + + private List toDigits(String number) { + List digits = new ArrayList<>(NUMBER_LENGTH); + for (char num : number.toCharArray()) { + digits.add(num - '0'); + } + return digits; + } + + private int countStrikes(List playerNumbers) { + int strikes = 0; + for (int i = 0; i < NUMBER_LENGTH; i++) { + if (number.get(i).equals(playerNumbers.get(i))) { + strikes++; + } + } + return strikes; + } + + private int countBalls(List playerNumbers) { + int balls = 0; + for (int num : playerNumbers) { + if (number.contains(num)) { + balls++; + } + } + return balls; + } } diff --git a/src/main/java/model/Result.java b/src/main/java/model/Result.java new file mode 100644 index 00000000..99997734 --- /dev/null +++ b/src/main/java/model/Result.java @@ -0,0 +1,4 @@ +package model; + +public record Result(int strikes, int balls) { +} From b939d4facc8c05e61787feec77dbaba089ecece8 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 15:29:54 +0900 Subject: [PATCH 09/29] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EC=88=AB=EC=9E=90=EB=A5=BC=20PlayerNumber?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/Computer.java | 17 ++---- src/main/java/model/Player.java | 50 +++--------------- src/main/java/model/PlayerNumber.java | 75 +++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 58 deletions(-) create mode 100644 src/main/java/model/PlayerNumber.java diff --git a/src/main/java/model/Computer.java b/src/main/java/model/Computer.java index a5447575..29fe0375 100644 --- a/src/main/java/model/Computer.java +++ b/src/main/java/model/Computer.java @@ -1,6 +1,5 @@ package model; -import java.util.ArrayList; import java.util.List; public class Computer { @@ -11,23 +10,13 @@ public Computer(NumberGenerator numberGenerator) { this.number = numberGenerator.generate(); } - public Result calculate(String playerNumber) { - List playerNumbers = toDigits(playerNumber); - - int strikes = countStrikes(playerNumbers); - int balls = countBalls(playerNumbers) - strikes; + public Result calculate(List playerNumber) { + int strikes = countStrikes(playerNumber); + int balls = countBalls(playerNumber) - strikes; return new Result(strikes, balls); } - private List toDigits(String number) { - List digits = new ArrayList<>(NUMBER_LENGTH); - for (char num : number.toCharArray()) { - digits.add(num - '0'); - } - return digits; - } - private int countStrikes(List playerNumbers) { int strikes = 0; for (int i = 0; i < NUMBER_LENGTH; i++) { diff --git a/src/main/java/model/Player.java b/src/main/java/model/Player.java index f9e3987f..e6275c11 100644 --- a/src/main/java/model/Player.java +++ b/src/main/java/model/Player.java @@ -1,53 +1,15 @@ package model; -import java.util.HashSet; -import java.util.Set; +import java.util.List; public class Player { - private static final int NUMBER_LENGTH = 3; - private static final int MIN_NUMBER = 1; - private static final int MAX_NUMBER = 9; + private final PlayerNumber playerNumber; - private static final String ERROR_INVALID_LENGTH = "[ERROR] 숫자는 3자리여야 합니다."; - private static final String ERROR_NOT_A_DIGIT = "[ERROR] 숫자만 입력해야 합니다."; - private static final String ERROR_INVALID_RANGE = "[ERROR] 숫자는 1부터 9까지만 가능합니다."; - private static final String ERROR_DUPLICATED_DIGIT = "[ERROR] 숫자는 서로 중복될 수 없습니다."; - - public void validateNumber(String number) { - validateLength(number); - - Set uniqueNumbers = new HashSet<>(); - for (char num : number.toCharArray()) { - validateIsNumber(num); - validateNumRange(num); - uniqueNumbers.add(num); - } - - validateDuplication(uniqueNumbers); - } - - private static void validateLength(String number) { - if (number == null || number.length() != NUMBER_LENGTH) { - throw new IllegalArgumentException(ERROR_INVALID_LENGTH); - } - } - - private static void validateIsNumber(char num) { - if (!Character.isDigit(num)) { - throw new IllegalArgumentException(ERROR_NOT_A_DIGIT); - } - } - - private static void validateNumRange(char num) { - int digit = num - '0'; - if (digit < MIN_NUMBER || digit > MAX_NUMBER) { - throw new IllegalArgumentException(ERROR_INVALID_RANGE); - } + public Player(String number) { + this.playerNumber = new PlayerNumber(number); } - private static void validateDuplication(Set uniqueNumbers) { - if (uniqueNumbers.size() != NUMBER_LENGTH) { - throw new IllegalArgumentException(ERROR_DUPLICATED_DIGIT); - } + public List getNumber() { + return playerNumber.getNumber(); } } diff --git a/src/main/java/model/PlayerNumber.java b/src/main/java/model/PlayerNumber.java new file mode 100644 index 00000000..f6b89eec --- /dev/null +++ b/src/main/java/model/PlayerNumber.java @@ -0,0 +1,75 @@ +package model; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class PlayerNumber { + private static final int NUMBER_LENGTH = 3; + private static final int MIN_NUMBER = 1; + private static final int MAX_NUMBER = 9; + + private static final String ERROR_INVALID_LENGTH = "[ERROR] 숫자는 3자리여야 합니다."; + private static final String ERROR_NOT_A_DIGIT = "[ERROR] 숫자만 입력해야 합니다."; + private static final String ERROR_INVALID_RANGE = "[ERROR] 숫자는 1부터 9까지만 가능합니다."; + private static final String ERROR_DUPLICATED_DIGIT = "[ERROR] 숫자는 서로 중복될 수 없습니다."; + + private final List number; + + public PlayerNumber(String number) { + validateNumber(number); + + this.number = toDigits(number); + } + + public List getNumber() { + return number; + } + + private List toDigits(String number) { + List digits = new ArrayList<>(NUMBER_LENGTH); + for (char num : number.toCharArray()) { + digits.add(num - '0'); + } + return digits; + } + + private static void validateNumber(String number) { + validateLength(number); + + Set uniqueNumbers = new HashSet<>(); + for (char num : number.toCharArray()) { + validateIsNumber(num); + validateNumRange(num); + uniqueNumbers.add(num); + } + + validateDuplication(uniqueNumbers); + } + + private static void validateLength(String number) { + if (number == null || number.length() != NUMBER_LENGTH) { + throw new IllegalArgumentException(ERROR_INVALID_LENGTH); + } + } + + private static void validateIsNumber(char num) { + if (!Character.isDigit(num)) { + throw new IllegalArgumentException(ERROR_NOT_A_DIGIT); + } + } + + private static void validateNumRange(char num) { + int digit = num - '0'; + if (digit < MIN_NUMBER || digit > MAX_NUMBER) { + throw new IllegalArgumentException(ERROR_INVALID_RANGE); + } + } + + private static void validateDuplication(Set uniqueNumbers) { + if (uniqueNumbers.size() != NUMBER_LENGTH) { + throw new IllegalArgumentException(ERROR_DUPLICATED_DIGIT); + } + } +} From 63dd54a79e091379aa4bb94d318cbc7539c9915e Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 15:48:31 +0900 Subject: [PATCH 10/29] =?UTF-8?q?feat:=20Result=20=EC=B6=9C=EB=A0=A5=20?= =?UTF-8?q?=ED=8F=AC=EB=A7=B7=EC=9D=84=20toString=EC=9C=BC=EB=A1=9C=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/model/Result.java | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/model/Result.java b/src/main/java/model/Result.java index 99997734..7c0d88d8 100644 --- a/src/main/java/model/Result.java +++ b/src/main/java/model/Result.java @@ -1,4 +1,33 @@ package model; public record Result(int strikes, int balls) { + + private static final String NOTHING_MESSAGE = "낫싱"; + private static final String STRIKE_SUFFIX = "스트라이크"; + private static final String BALL_SUFFIX = "볼"; + + @Override + public String toString() { + if (isNothing()) { + return NOTHING_MESSAGE; + } + + StringBuilder sb = new StringBuilder(); + if (strikes > 0) { + sb.append(strikes).append(STRIKE_SUFFIX); + } + + if (balls > 0) { + if (!sb.isEmpty()) { + sb.append(" "); + } + sb.append(balls).append(BALL_SUFFIX); + } + + return sb.toString(); + } + + public boolean isNothing() { + return strikes == 0 && balls == 0; + } } From e8473ce36ffdadcec60c90c980c21f9575d53ddd Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 15:48:42 +0900 Subject: [PATCH 11/29] =?UTF-8?q?feat:=20InputView=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/view/InputView.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/view/InputView.java diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..5b31b1b2 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,19 @@ +package view; + +import java.util.Scanner; + +public class InputView { + private static final String INPUT_NUMBER_MESSAGE = "숫자를 입력해주세요: "; + private static final String RESTART_OR_QUIT_MESSAGE = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."; + private static final Scanner SCANNER = new Scanner(System.in); + + public String readPlayerNumber() { + System.out.print(INPUT_NUMBER_MESSAGE); + return SCANNER.nextLine(); + } + + public String readRestartOrQuit() { + System.out.println(RESTART_OR_QUIT_MESSAGE); + return SCANNER.nextLine(); + } +} From 362b0f3395a099edb2c40be24d0d4871d2ed1916 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 15:48:50 +0900 Subject: [PATCH 12/29] =?UTF-8?q?feat:=20OutputView=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/view/OutputView.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/view/OutputView.java diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..304b6cdf --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,15 @@ +package view; + +import model.Result; + +public class OutputView { + private static final String GAME_CLEAR_MESSAGE = "3개의 숫자를 모두 맞히셨습니다! 게임 끝"; + + public void printResult(Result result) { + System.out.println(result); + } + + public void printGameClearMessage() { + System.out.println(GAME_CLEAR_MESSAGE); + } +} From 1f764544acd57e5c2ae69f3ef59fdb9ea2aa769b Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 15:49:49 +0900 Subject: [PATCH 13/29] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=ED=95=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 95db6bf5..94143353 100644 --- a/README.md +++ b/README.md @@ -13,16 +13,16 @@ ## Input -- [ ] 사용자는 컴퓨터가 생각하고 있는 3개의 숫자를 입력한다. -- [ ] 게임 종료 시 재시작 또는 종료 여부를 입력한다. - - [ ] '1' 입력 시 재시작 - - [ ] '2' 입력 시 종료 +- [x] 사용자는 컴퓨터가 생각하고 있는 3개의 숫자를 입력한다. +- [x] 게임 종료 시 재시작 또는 종료 여부를 입력한다. + - [x] '1' 입력 시 재시작 + - [x] '2' 입력 시 종료 ## Output -- [ ] 컴퓨터는 플레이어가 입력한 숫자에 대한 결과를 출력한다. +- [x] 컴퓨터는 플레이어가 입력한 숫자에 대한 결과를 출력한다. - [ ] 사용자가 잘못된 값을 입력할 경우 에러 메시지를 출력한다. - [ ] 에러 메시지는 [ERROR]로 시작한다. -- [ ] 게임 종료 시 문구를 출력한다. - - [ ] 게임 끝 문구 출력 - - [ ] 종료 또는 재시작을 선택할 수 있는 문구 출력 +- [x] 게임 종료 시 문구를 출력한다. + - [x] 게임 끝 문구 출력 + - [x] 종료 또는 재시작을 선택할 수 있는 문구 출력 From f095e3831079dc1f82c8e5cd9580e6cbfe1ab36d Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 16:32:30 +0900 Subject: [PATCH 14/29] =?UTF-8?q?feat:=20=EC=97=90=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=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/view/OutputView.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 304b6cdf..b2c1a407 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -3,6 +3,7 @@ import model.Result; public class OutputView { + private static final String ERROR_PREFIX = "[ERROR]"; private static final String GAME_CLEAR_MESSAGE = "3개의 숫자를 모두 맞히셨습니다! 게임 끝"; public void printResult(Result result) { @@ -12,4 +13,12 @@ public void printResult(Result result) { public void printGameClearMessage() { System.out.println(GAME_CLEAR_MESSAGE); } + + public void printErrorMessage(String message) { + if (message != null && message.startsWith(ERROR_PREFIX)) { + System.out.println(message); + return; + } + System.out.println(ERROR_PREFIX + " " + (message == null ? "잘못된 입력입니다." : message)); + } } From 503745e1e346ab6319b77b947a32f7e37fae6f0b Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 16:33:27 +0900 Subject: [PATCH 15/29] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20=EC=9E=AC?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=20=EC=97=AC=EB=B6=80=20=ED=8C=90=EB=8B=A8?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/GameCommand.java | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/model/GameCommand.java diff --git a/src/main/java/model/GameCommand.java b/src/main/java/model/GameCommand.java new file mode 100644 index 00000000..32a7b1bd --- /dev/null +++ b/src/main/java/model/GameCommand.java @@ -0,0 +1,27 @@ +package model; + +public enum GameCommand { + RESTART("1"), + QUIT("2"); + + private static final String ERROR_INVALID_COMMAND = "1 또는 2를 입력해야 합니다."; + + private final String command; + + GameCommand(String command) { + this.command = command; + } + + public static GameCommand from(String input) { + for (GameCommand command : values()) { + if (command.command.equals(input)) { + return command; + } + } + throw new IllegalArgumentException(ERROR_INVALID_COMMAND); + } + + public boolean isRestart() { + return this == RESTART; + } +} From 22cb6a7f509865dc43ec63c357a7c93b3fe49944 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 16:33:37 +0900 Subject: [PATCH 16/29] =?UTF-8?q?feat:=20BaseballGameController=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 --- .../controller/BaseballGameController.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/main/java/controller/BaseballGameController.java diff --git a/src/main/java/controller/BaseballGameController.java b/src/main/java/controller/BaseballGameController.java new file mode 100644 index 00000000..c2679dd3 --- /dev/null +++ b/src/main/java/controller/BaseballGameController.java @@ -0,0 +1,62 @@ +package controller; + +import model.Computer; +import model.GameCommand; +import model.NumberGenerator; +import model.PlayerNumber; +import model.Result; +import view.InputView; +import view.OutputView; + +public class BaseballGameController { + private final InputView inputView; + private final OutputView outputView; + private final NumberGenerator numberGenerator; + + public BaseballGameController(InputView inputView, OutputView outputView, NumberGenerator numberGenerator) { + this.inputView = inputView; + this.outputView = outputView; + this.numberGenerator = numberGenerator; + } + + public void run() { + do { + start(); + } while (shouldRestart()); + } + + private void start() { + Computer computer = new Computer(numberGenerator); + Result result; + + do { + PlayerNumber playerNumber = getPlayerNumber(); + result = computer.calculate(playerNumber.getNumber()); + outputView.printResult(result); + } while (result.strikes() != 3); + + outputView.printGameClearMessage(); + } + + private boolean shouldRestart() { + while (true) { + try { + String input = inputView.readRestartOrQuit(); + return GameCommand.from(input).isRestart(); + } catch (IllegalArgumentException e) { + outputView.printErrorMessage(e.getMessage()); + } + } + } + + private PlayerNumber getPlayerNumber() { + while (true) { + try { + String input = inputView.readPlayerNumber(); + return new PlayerNumber(input); + } catch (IllegalArgumentException e) { + outputView.printErrorMessage(e.getMessage()); + } + } + } +} From 1e7b45c79916aad23c67d38f4f0c18a32f1bc9aa Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 16:33:46 +0900 Subject: [PATCH 17/29] =?UTF-8?q?feat:=20BaseballGame=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++----- src/main/java/Application.java | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 src/main/java/Application.java diff --git a/README.md b/README.md index 94143353..391c720d 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ - [x] 같은 수가 같은 자리에 있으면 '스트라이크' - [x] 같은 수가 다른 자리에 있으면 '볼' - [x] 같은 수가 없으면 '낫싱' -- [ ] 사용자가 잘못된 값을 입력해도 게임을 계속 진행할 수 있어야 한다. - - [ ] 에러 메시지를 띄운다. - - [ ] 다시 입력을 받는다. +- [x] 사용자가 잘못된 값을 입력해도 게임을 계속 진행할 수 있어야 한다. + - [x] 에러 메시지를 띄운다. + - [x] 다시 입력을 받는다. ## Input @@ -21,8 +21,8 @@ ## Output - [x] 컴퓨터는 플레이어가 입력한 숫자에 대한 결과를 출력한다. -- [ ] 사용자가 잘못된 값을 입력할 경우 에러 메시지를 출력한다. - - [ ] 에러 메시지는 [ERROR]로 시작한다. +- [x] 사용자가 잘못된 값을 입력할 경우 에러 메시지를 출력한다. + - [x] 에러 메시지는 [ERROR]로 시작한다. - [x] 게임 종료 시 문구를 출력한다. - [x] 게임 끝 문구 출력 - [x] 종료 또는 재시작을 선택할 수 있는 문구 출력 diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..41d9b52d --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,16 @@ +import controller.BaseballGameController; +import model.NumberGenerator; +import model.RandomNumberGenerator; +import view.InputView; +import view.OutputView; + +public class Application { + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + NumberGenerator numberGenerator = new RandomNumberGenerator(); + + BaseballGameController gameController = new BaseballGameController(inputView, outputView, numberGenerator); + gameController.run(); + } +} From 9481aebb32242df4f86e7f72ddbba59ecedcdb5e Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 16:37:15 +0900 Subject: [PATCH 18/29] =?UTF-8?q?refactor:=20model=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 4 ++-- src/main/java/controller/BaseballGameController.java | 10 +++++----- src/main/java/model/{ => computer}/Computer.java | 5 ++++- src/main/java/model/{ => game}/GameCommand.java | 2 +- src/main/java/model/{ => game}/Result.java | 2 +- .../java/model/{ => generator}/NumberGenerator.java | 2 +- .../model/{ => generator}/RandomNumberGenerator.java | 2 +- src/main/java/model/{ => player}/Player.java | 2 +- src/main/java/model/{ => player}/PlayerNumber.java | 2 +- src/main/java/view/OutputView.java | 2 +- 10 files changed, 18 insertions(+), 15 deletions(-) rename src/main/java/model/{ => computer}/Computer.java (90%) rename src/main/java/model/{ => game}/GameCommand.java (96%) rename src/main/java/model/{ => game}/Result.java (96%) rename src/main/java/model/{ => generator}/NumberGenerator.java (78%) rename src/main/java/model/{ => generator}/RandomNumberGenerator.java (96%) rename src/main/java/model/{ => player}/Player.java (91%) rename src/main/java/model/{ => player}/PlayerNumber.java (98%) diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 41d9b52d..848cbc0b 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,6 +1,6 @@ import controller.BaseballGameController; -import model.NumberGenerator; -import model.RandomNumberGenerator; +import model.generator.NumberGenerator; +import model.generator.RandomNumberGenerator; import view.InputView; import view.OutputView; diff --git a/src/main/java/controller/BaseballGameController.java b/src/main/java/controller/BaseballGameController.java index c2679dd3..ac9c045a 100644 --- a/src/main/java/controller/BaseballGameController.java +++ b/src/main/java/controller/BaseballGameController.java @@ -1,10 +1,10 @@ package controller; -import model.Computer; -import model.GameCommand; -import model.NumberGenerator; -import model.PlayerNumber; -import model.Result; +import model.computer.Computer; +import model.game.GameCommand; +import model.game.Result; +import model.generator.NumberGenerator; +import model.player.PlayerNumber; import view.InputView; import view.OutputView; diff --git a/src/main/java/model/Computer.java b/src/main/java/model/computer/Computer.java similarity index 90% rename from src/main/java/model/Computer.java rename to src/main/java/model/computer/Computer.java index 29fe0375..460fe397 100644 --- a/src/main/java/model/Computer.java +++ b/src/main/java/model/computer/Computer.java @@ -1,7 +1,10 @@ -package model; +package model.computer; import java.util.List; +import model.game.Result; +import model.generator.NumberGenerator; + public class Computer { private static final int NUMBER_LENGTH = 3; private final List number; diff --git a/src/main/java/model/GameCommand.java b/src/main/java/model/game/GameCommand.java similarity index 96% rename from src/main/java/model/GameCommand.java rename to src/main/java/model/game/GameCommand.java index 32a7b1bd..71acd9e7 100644 --- a/src/main/java/model/GameCommand.java +++ b/src/main/java/model/game/GameCommand.java @@ -1,4 +1,4 @@ -package model; +package model.game; public enum GameCommand { RESTART("1"), diff --git a/src/main/java/model/Result.java b/src/main/java/model/game/Result.java similarity index 96% rename from src/main/java/model/Result.java rename to src/main/java/model/game/Result.java index 7c0d88d8..132c1e5a 100644 --- a/src/main/java/model/Result.java +++ b/src/main/java/model/game/Result.java @@ -1,4 +1,4 @@ -package model; +package model.game; public record Result(int strikes, int balls) { diff --git a/src/main/java/model/NumberGenerator.java b/src/main/java/model/generator/NumberGenerator.java similarity index 78% rename from src/main/java/model/NumberGenerator.java rename to src/main/java/model/generator/NumberGenerator.java index 79949d71..e15e89ad 100644 --- a/src/main/java/model/NumberGenerator.java +++ b/src/main/java/model/generator/NumberGenerator.java @@ -1,4 +1,4 @@ -package model; +package model.generator; import java.util.List; diff --git a/src/main/java/model/RandomNumberGenerator.java b/src/main/java/model/generator/RandomNumberGenerator.java similarity index 96% rename from src/main/java/model/RandomNumberGenerator.java rename to src/main/java/model/generator/RandomNumberGenerator.java index 30c5316f..cd64c274 100644 --- a/src/main/java/model/RandomNumberGenerator.java +++ b/src/main/java/model/generator/RandomNumberGenerator.java @@ -1,4 +1,4 @@ -package model; +package model.generator; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/model/Player.java b/src/main/java/model/player/Player.java similarity index 91% rename from src/main/java/model/Player.java rename to src/main/java/model/player/Player.java index e6275c11..216671c6 100644 --- a/src/main/java/model/Player.java +++ b/src/main/java/model/player/Player.java @@ -1,4 +1,4 @@ -package model; +package model.player; import java.util.List; diff --git a/src/main/java/model/PlayerNumber.java b/src/main/java/model/player/PlayerNumber.java similarity index 98% rename from src/main/java/model/PlayerNumber.java rename to src/main/java/model/player/PlayerNumber.java index f6b89eec..abe59f8c 100644 --- a/src/main/java/model/PlayerNumber.java +++ b/src/main/java/model/player/PlayerNumber.java @@ -1,4 +1,4 @@ -package model; +package model.player; import java.util.ArrayList; import java.util.HashSet; diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index b2c1a407..7e98f831 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,6 +1,6 @@ package view; -import model.Result; +import model.game.Result; public class OutputView { private static final String ERROR_PREFIX = "[ERROR]"; From c7bddee61ef7f3dabdeb8ded3f1e8094480cee37 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 16:47:56 +0900 Subject: [PATCH 19/29] =?UTF-8?q?rename:=20PlayerNumber=EB=A5=BC=20GameNum?= =?UTF-8?q?ber=EB=A1=9C=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BaseballGameController.java | 10 +++++----- .../{player/PlayerNumber.java => game/GameNumber.java} | 6 +++--- src/main/java/model/player/Player.java | 8 +++++--- 3 files changed, 13 insertions(+), 11 deletions(-) rename src/main/java/model/{player/PlayerNumber.java => game/GameNumber.java} (95%) diff --git a/src/main/java/controller/BaseballGameController.java b/src/main/java/controller/BaseballGameController.java index ac9c045a..bb95cb04 100644 --- a/src/main/java/controller/BaseballGameController.java +++ b/src/main/java/controller/BaseballGameController.java @@ -2,9 +2,9 @@ import model.computer.Computer; import model.game.GameCommand; +import model.game.GameNumber; import model.game.Result; import model.generator.NumberGenerator; -import model.player.PlayerNumber; import view.InputView; import view.OutputView; @@ -30,8 +30,8 @@ private void start() { Result result; do { - PlayerNumber playerNumber = getPlayerNumber(); - result = computer.calculate(playerNumber.getNumber()); + GameNumber gameNumber = getPlayerNumber(); + result = computer.calculate(gameNumber.getNumber()); outputView.printResult(result); } while (result.strikes() != 3); @@ -49,11 +49,11 @@ private boolean shouldRestart() { } } - private PlayerNumber getPlayerNumber() { + private GameNumber getPlayerNumber() { while (true) { try { String input = inputView.readPlayerNumber(); - return new PlayerNumber(input); + return new GameNumber(input); } catch (IllegalArgumentException e) { outputView.printErrorMessage(e.getMessage()); } diff --git a/src/main/java/model/player/PlayerNumber.java b/src/main/java/model/game/GameNumber.java similarity index 95% rename from src/main/java/model/player/PlayerNumber.java rename to src/main/java/model/game/GameNumber.java index abe59f8c..20c54105 100644 --- a/src/main/java/model/player/PlayerNumber.java +++ b/src/main/java/model/game/GameNumber.java @@ -1,11 +1,11 @@ -package model.player; +package model.game; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -public class PlayerNumber { +public class GameNumber { private static final int NUMBER_LENGTH = 3; private static final int MIN_NUMBER = 1; private static final int MAX_NUMBER = 9; @@ -17,7 +17,7 @@ public class PlayerNumber { private final List number; - public PlayerNumber(String number) { + public GameNumber(String number) { validateNumber(number); this.number = toDigits(number); diff --git a/src/main/java/model/player/Player.java b/src/main/java/model/player/Player.java index 216671c6..1b83f5bb 100644 --- a/src/main/java/model/player/Player.java +++ b/src/main/java/model/player/Player.java @@ -2,14 +2,16 @@ import java.util.List; +import model.game.GameNumber; + public class Player { - private final PlayerNumber playerNumber; + private final GameNumber gameNumber; public Player(String number) { - this.playerNumber = new PlayerNumber(number); + this.gameNumber = new GameNumber(number); } public List getNumber() { - return playerNumber.getNumber(); + return gameNumber.getNumber(); } } From d664960ee884061cbbf497a599ed7870e7b92527 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:02:30 +0900 Subject: [PATCH 20/29] =?UTF-8?q?refactor:=20Computer=EA=B0=80=20GameNumbe?= =?UTF-8?q?r=EB=A1=9C=20=EC=88=AB=EC=9E=90=EB=A5=BC=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/computer/Computer.java | 9 +++--- src/main/java/model/game/GameNumber.java | 34 ++++++++++++++-------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/main/java/model/computer/Computer.java b/src/main/java/model/computer/Computer.java index 460fe397..5cc606d7 100644 --- a/src/main/java/model/computer/Computer.java +++ b/src/main/java/model/computer/Computer.java @@ -2,15 +2,16 @@ import java.util.List; +import model.game.GameNumber; import model.game.Result; import model.generator.NumberGenerator; public class Computer { private static final int NUMBER_LENGTH = 3; - private final List number; + private final GameNumber gameNumber; public Computer(NumberGenerator numberGenerator) { - this.number = numberGenerator.generate(); + this.gameNumber = new GameNumber(numberGenerator.generate()); } public Result calculate(List playerNumber) { @@ -23,7 +24,7 @@ public Result calculate(List playerNumber) { private int countStrikes(List playerNumbers) { int strikes = 0; for (int i = 0; i < NUMBER_LENGTH; i++) { - if (number.get(i).equals(playerNumbers.get(i))) { + if (gameNumber.getNumber().get(i).equals(playerNumbers.get(i))) { strikes++; } } @@ -33,7 +34,7 @@ private int countStrikes(List playerNumbers) { private int countBalls(List playerNumbers) { int balls = 0; for (int num : playerNumbers) { - if (number.contains(num)) { + if (gameNumber.getNumber().contains(num)) { balls++; } } diff --git a/src/main/java/model/game/GameNumber.java b/src/main/java/model/game/GameNumber.java index 20c54105..3f20fe46 100644 --- a/src/main/java/model/game/GameNumber.java +++ b/src/main/java/model/game/GameNumber.java @@ -17,10 +17,17 @@ public class GameNumber { private final List number; - public GameNumber(String number) { + public GameNumber(List number) { validateNumber(number); - this.number = toDigits(number); + this.number = List.copyOf(number); + } + + public GameNumber(String number) { + List parsedNumber = toDigits(number); + // 유효성 검증 + validateNumber(parsedNumber); + this.number = parsedNumber; } public List getNumber() { @@ -28,19 +35,23 @@ public List getNumber() { } private List toDigits(String number) { + if (number == null) { + throw new IllegalArgumentException(ERROR_INVALID_LENGTH); + } + List digits = new ArrayList<>(NUMBER_LENGTH); for (char num : number.toCharArray()) { + validateIsNumber(num); digits.add(num - '0'); } return digits; } - private static void validateNumber(String number) { + private static void validateNumber(List number) { validateLength(number); - Set uniqueNumbers = new HashSet<>(); - for (char num : number.toCharArray()) { - validateIsNumber(num); + Set uniqueNumbers = new HashSet<>(); + for (Integer num : number) { validateNumRange(num); uniqueNumbers.add(num); } @@ -48,8 +59,8 @@ private static void validateNumber(String number) { validateDuplication(uniqueNumbers); } - private static void validateLength(String number) { - if (number == null || number.length() != NUMBER_LENGTH) { + private static void validateLength(List number) { + if (number.size() != NUMBER_LENGTH) { throw new IllegalArgumentException(ERROR_INVALID_LENGTH); } } @@ -60,14 +71,13 @@ private static void validateIsNumber(char num) { } } - private static void validateNumRange(char num) { - int digit = num - '0'; - if (digit < MIN_NUMBER || digit > MAX_NUMBER) { + private static void validateNumRange(Integer num) { + if (num < MIN_NUMBER || num > MAX_NUMBER) { throw new IllegalArgumentException(ERROR_INVALID_RANGE); } } - private static void validateDuplication(Set uniqueNumbers) { + private static void validateDuplication(Set uniqueNumbers) { if (uniqueNumbers.size() != NUMBER_LENGTH) { throw new IllegalArgumentException(ERROR_DUPLICATED_DIGIT); } From e4ec5a3dc861daf94abb1920a78d1a010be965bc Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:11:23 +0900 Subject: [PATCH 21/29] =?UTF-8?q?test:=20ComputerTest=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/model/computer/ComputerTest.java | 57 +++++++++++++++++++ .../model/generator/TestNumberGenerator.java | 16 ++++++ 2 files changed, 73 insertions(+) create mode 100644 src/test/java/model/computer/ComputerTest.java create mode 100644 src/test/java/model/generator/TestNumberGenerator.java diff --git a/src/test/java/model/computer/ComputerTest.java b/src/test/java/model/computer/ComputerTest.java new file mode 100644 index 00000000..644c79eb --- /dev/null +++ b/src/test/java/model/computer/ComputerTest.java @@ -0,0 +1,57 @@ +package model.computer; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import model.game.Result; +import model.generator.TestNumberGenerator; + +public class ComputerTest { + @Test + @DisplayName("정답 123, 입력 123이면 3스트라이크 0볼") + void calculateAllStrike() { + Computer computer = new Computer(new TestNumberGenerator(List.of(1, 2, 3))); + + Result result = computer.calculate(List.of(1, 2, 3)); + + assertEquals(3, result.strikes()); + assertEquals(0, result.balls()); + } + + @Test + @DisplayName("정답 123, 입력 145이면 1볼") + void calculateOneBall() { + Computer computer = new Computer(new TestNumberGenerator(List.of(1, 2, 3))); + + Result result = computer.calculate(List.of(1, 4, 5)); + + assertEquals(1, result.balls()); + assertEquals(0, result.strikes()); + } + + @Test + @DisplayName("정답 123, 입력 132이면 1스트라이크 2볼") + void calculateStrikeAndBalls() { + Computer computer = new Computer(new TestNumberGenerator(List.of(1, 2, 3))); + + Result result = computer.calculate(List.of(1, 3, 2)); + + assertEquals(1, result.strikes()); + assertEquals(2, result.balls()); + } + + @Test + @DisplayName("정답 123, 입력 456이면 0스트라이크 0볼") + void calculateNothing() { + Computer computer = new Computer(new TestNumberGenerator(List.of(1, 2, 3))); + + Result result = computer.calculate(List.of(4, 5, 6)); + + assertEquals(0, result.strikes()); + assertEquals(0, result.balls()); + } +} diff --git a/src/test/java/model/generator/TestNumberGenerator.java b/src/test/java/model/generator/TestNumberGenerator.java new file mode 100644 index 00000000..01321f31 --- /dev/null +++ b/src/test/java/model/generator/TestNumberGenerator.java @@ -0,0 +1,16 @@ +package model.generator; + +import java.util.List; + +public class TestNumberGenerator implements NumberGenerator { + private final List fixed; + + public TestNumberGenerator(List fixed) { + this.fixed = fixed; + } + + @Override + public List generate() { + return fixed; + } +} From e082359d5b04a8c39302d32aadd39e748b7a3a4f Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:20:48 +0900 Subject: [PATCH 22/29] =?UTF-8?q?test:=20GameNumberTest=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/game/GameNumber.java | 1 - .../java/model/computer/ComputerTest.java | 4 +- src/test/java/model/game/GameNumberTest.java | 97 +++++++++++++++++++ 3 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 src/test/java/model/game/GameNumberTest.java diff --git a/src/main/java/model/game/GameNumber.java b/src/main/java/model/game/GameNumber.java index 3f20fe46..7e62c0c9 100644 --- a/src/main/java/model/game/GameNumber.java +++ b/src/main/java/model/game/GameNumber.java @@ -25,7 +25,6 @@ public GameNumber(List number) { public GameNumber(String number) { List parsedNumber = toDigits(number); - // 유효성 검증 validateNumber(parsedNumber); this.number = parsedNumber; } diff --git a/src/test/java/model/computer/ComputerTest.java b/src/test/java/model/computer/ComputerTest.java index 644c79eb..0a358dc8 100644 --- a/src/test/java/model/computer/ComputerTest.java +++ b/src/test/java/model/computer/ComputerTest.java @@ -23,11 +23,11 @@ void calculateAllStrike() { } @Test - @DisplayName("정답 123, 입력 145이면 1볼") + @DisplayName("정답 123, 입력 415이면 1볼") void calculateOneBall() { Computer computer = new Computer(new TestNumberGenerator(List.of(1, 2, 3))); - Result result = computer.calculate(List.of(1, 4, 5)); + Result result = computer.calculate(List.of(4, 1, 5)); assertEquals(1, result.balls()); assertEquals(0, result.strikes()); diff --git a/src/test/java/model/game/GameNumberTest.java b/src/test/java/model/game/GameNumberTest.java new file mode 100644 index 00000000..893c0e75 --- /dev/null +++ b/src/test/java/model/game/GameNumberTest.java @@ -0,0 +1,97 @@ +package model.game; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class GameNumberTest { + @Test + @DisplayName("문자열 생성: 정상 입력이면 3자리 숫자로 생성된다") + void createFromString_success() { + GameNumber gameNumber = new GameNumber("123"); + + assertEquals(List.of(1, 2, 3), gameNumber.getNumber()); + } + + @Test + @DisplayName("리스트 생성: 정상 입력이면 3자리 숫자로 생성된다") + void createFromList_success() { + GameNumber gameNumber = new GameNumber(List.of(4, 5, 6)); + + assertEquals(List.of(4, 5, 6), gameNumber.getNumber()); + } + + @Test + @DisplayName("문자열 생성: null이면 예외가 발생한다") + void createFromString_null_throws() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> new GameNumber((String)null)); + + assertEquals("[ERROR] 숫자는 3자리여야 합니다.", exception.getMessage()); + } + + @Test + @DisplayName("문자열 생성: 길이가 3이 아니면 예외가 발생한다") + void createFromString_invalidLength_throws() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new GameNumber("12")); + + assertEquals("[ERROR] 숫자는 3자리여야 합니다.", exception.getMessage()); + } + + @Test + @DisplayName("리스트 생성: 길이가 3이 아니면 예외가 발생한다") + void createFromList_invalidLength_throws() { + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, () -> new GameNumber(List.of(1, 2))); + + assertEquals("[ERROR] 숫자는 3자리여야 합니다.", exception.getMessage()); + } + + @Test + @DisplayName("문자열 생성: 숫자가 아니면 예외가 발생한다") + void createFromString_notDigit_throws() { + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, () -> new GameNumber("12a")); + + assertEquals("[ERROR] 숫자만 입력해야 합니다.", exception.getMessage()); + } + + @Test + @DisplayName("문자열 생성: 0이 포함되면 예외가 발생한다") + void createFromString_outOfRange_throws() { + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, () -> new GameNumber("102")); + + assertEquals("[ERROR] 숫자는 1부터 9까지만 가능합니다.", exception.getMessage()); + } + + @Test + @DisplayName("리스트 생성: 10이 포함되면 예외가 발생한다") + void createFromList_outOfRange_throws() { + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, () -> new GameNumber(List.of(1, 2, 10))); + + assertEquals("[ERROR] 숫자는 1부터 9까지만 가능합니다.", exception.getMessage()); + } + + @Test + @DisplayName("문자열 생성: 중복이 있으면 예외가 발생한다") + void createFromString_duplicated_throws() { + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, () -> new GameNumber("112")); + + assertEquals("[ERROR] 숫자는 서로 중복될 수 없습니다.", exception.getMessage()); + } + + @Test + @DisplayName("리스트 생성: 중복이 있으면 예외가 발생한다") + void createFromList_duplicated_throws() { + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, () -> new GameNumber(List.of(7, 7, 1))); + + assertEquals("[ERROR] 숫자는 서로 중복될 수 없습니다.", exception.getMessage()); + } +} From 3fd401606396699c211bb8915b9339d60a7e88ad Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:23:21 +0900 Subject: [PATCH 23/29] =?UTF-8?q?test:=20GameCommandTest=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/model/game/GameCommandTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/test/java/model/game/GameCommandTest.java diff --git a/src/test/java/model/game/GameCommandTest.java b/src/test/java/model/game/GameCommandTest.java new file mode 100644 index 00000000..8f09cff8 --- /dev/null +++ b/src/test/java/model/game/GameCommandTest.java @@ -0,0 +1,32 @@ +package model.game; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class GameCommandTest { + @Test + @DisplayName("입력이 1이면 RESTART를 반환한다") + void from_restart() { + GameCommand command = GameCommand.from("1"); + + assertEquals(GameCommand.RESTART, command); + } + + @Test + @DisplayName("입력이 2이면 QUIT를 반환한다") + void from_quit() { + GameCommand command = GameCommand.from("2"); + + assertEquals(GameCommand.QUIT, command); + } + + @Test + @DisplayName("1, 2가 아닌 입력이면 예외를 던진다") + void from_invalidInput_throws() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> GameCommand.from("3")); + + assertEquals("1 또는 2를 입력해야 합니다.", exception.getMessage()); + } +} From cae80277717205425f87574043f5e8881e50ed12 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:26:42 +0900 Subject: [PATCH 24/29] =?UTF-8?q?test:=20ResultTest=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/model/game/ResultTest.java | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/test/java/model/game/ResultTest.java diff --git a/src/test/java/model/game/ResultTest.java b/src/test/java/model/game/ResultTest.java new file mode 100644 index 00000000..87a76a85 --- /dev/null +++ b/src/test/java/model/game/ResultTest.java @@ -0,0 +1,44 @@ +package model.game; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class ResultTest { + @Test + @DisplayName("스트라이크와 볼이 모두 0이면 낫싱이다") + void nothing() { + Result result = new Result(0, 0); + + assertTrue(result.isNothing()); + assertEquals("낫싱", result.toString()); + } + + @Test + @DisplayName("스트라이크만 있으면 스트라이크만 출력한다") + void onlyStrike() { + Result result = new Result(2, 0); + + assertFalse(result.isNothing()); + assertEquals("2스트라이크", result.toString()); + } + + @Test + @DisplayName("볼만 있으면 볼만 출력한다") + void onlyBall() { + Result result = new Result(0, 1); + + assertFalse(result.isNothing()); + assertEquals("1볼", result.toString()); + } + + @Test + @DisplayName("스트라이크와 볼이 모두 있으면 공백으로 구분해서 출력한다") + void strikeAndBall() { + Result result = new Result(1, 2); + + assertFalse(result.isNothing()); + assertEquals("1스트라이크 2볼", result.toString()); + } +} From c15b6417396e4c9c9dde4541b4da1d4edfd9625b Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:32:47 +0900 Subject: [PATCH 25/29] =?UTF-8?q?test:=20RandomNumberGeneratorTest=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generator/RandomNumberGeneratorTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/test/java/model/generator/RandomNumberGeneratorTest.java diff --git a/src/test/java/model/generator/RandomNumberGeneratorTest.java b/src/test/java/model/generator/RandomNumberGeneratorTest.java new file mode 100644 index 00000000..589e3a5b --- /dev/null +++ b/src/test/java/model/generator/RandomNumberGeneratorTest.java @@ -0,0 +1,39 @@ +package model.generator; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class RandomNumberGeneratorTest { + private static final int TEST_COUNT = 100; + private static final int NUMBER_LENGTH = 3; + private static final int MIN_DIGIT = 1; + private static final int MAX_DIGIT = 9; + + @Test + @DisplayName("랜덤 숫자 생성은 항상 3자리, 1~9 범위, 중복 없는 숫자를 생성한다") + void generateValidRandomNumbers() { + RandomNumberGenerator generator = new RandomNumberGenerator(); + + for (int i = 0; i < TEST_COUNT; i++) { + List numbers = generator.generate(); + + // 길이 검증 + assertEquals(NUMBER_LENGTH, numbers.size()); + + // 범위 검증 + for (int num : numbers) { + assertTrue(num >= MIN_DIGIT && num <= MAX_DIGIT); + } + + // 중복 검증 + Set uniqueNumbers = new HashSet<>(numbers); + assertEquals(NUMBER_LENGTH, uniqueNumbers.size()); + } + } +} From 8f99a9f9b9be35d3a0daeb7de6f84ba697580758 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:37:55 +0900 Subject: [PATCH 26/29] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/model/game/GameCommandTest.java | 6 +++--- src/test/java/model/game/GameNumberTest.java | 20 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/test/java/model/game/GameCommandTest.java b/src/test/java/model/game/GameCommandTest.java index 8f09cff8..ea230c68 100644 --- a/src/test/java/model/game/GameCommandTest.java +++ b/src/test/java/model/game/GameCommandTest.java @@ -8,7 +8,7 @@ public class GameCommandTest { @Test @DisplayName("입력이 1이면 RESTART를 반환한다") - void from_restart() { + void fromRestart() { GameCommand command = GameCommand.from("1"); assertEquals(GameCommand.RESTART, command); @@ -16,7 +16,7 @@ void from_restart() { @Test @DisplayName("입력이 2이면 QUIT를 반환한다") - void from_quit() { + void fromQuit() { GameCommand command = GameCommand.from("2"); assertEquals(GameCommand.QUIT, command); @@ -24,7 +24,7 @@ void from_quit() { @Test @DisplayName("1, 2가 아닌 입력이면 예외를 던진다") - void from_invalidInput_throws() { + void fromInvalidInput() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> GameCommand.from("3")); assertEquals("1 또는 2를 입력해야 합니다.", exception.getMessage()); diff --git a/src/test/java/model/game/GameNumberTest.java b/src/test/java/model/game/GameNumberTest.java index 893c0e75..4122e24b 100644 --- a/src/test/java/model/game/GameNumberTest.java +++ b/src/test/java/model/game/GameNumberTest.java @@ -10,7 +10,7 @@ public class GameNumberTest { @Test @DisplayName("문자열 생성: 정상 입력이면 3자리 숫자로 생성된다") - void createFromString_success() { + void createFromStringSuccess() { GameNumber gameNumber = new GameNumber("123"); assertEquals(List.of(1, 2, 3), gameNumber.getNumber()); @@ -18,7 +18,7 @@ void createFromString_success() { @Test @DisplayName("리스트 생성: 정상 입력이면 3자리 숫자로 생성된다") - void createFromList_success() { + void createFromListSuccess() { GameNumber gameNumber = new GameNumber(List.of(4, 5, 6)); assertEquals(List.of(4, 5, 6), gameNumber.getNumber()); @@ -26,7 +26,7 @@ void createFromList_success() { @Test @DisplayName("문자열 생성: null이면 예외가 발생한다") - void createFromString_null_throws() { + void createFromNull() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new GameNumber((String)null)); @@ -35,7 +35,7 @@ void createFromString_null_throws() { @Test @DisplayName("문자열 생성: 길이가 3이 아니면 예외가 발생한다") - void createFromString_invalidLength_throws() { + void createFromStringWithInvalidLength() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new GameNumber("12")); assertEquals("[ERROR] 숫자는 3자리여야 합니다.", exception.getMessage()); @@ -43,7 +43,7 @@ void createFromString_invalidLength_throws() { @Test @DisplayName("리스트 생성: 길이가 3이 아니면 예외가 발생한다") - void createFromList_invalidLength_throws() { + void createFromListWithInvalidLength() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new GameNumber(List.of(1, 2))); @@ -52,7 +52,7 @@ void createFromList_invalidLength_throws() { @Test @DisplayName("문자열 생성: 숫자가 아니면 예외가 발생한다") - void createFromString_notDigit_throws() { + void createFromStringWithNotDigit() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new GameNumber("12a")); @@ -61,7 +61,7 @@ void createFromString_notDigit_throws() { @Test @DisplayName("문자열 생성: 0이 포함되면 예외가 발생한다") - void createFromString_outOfRange_throws() { + void createFromStringWithOutOfRange() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new GameNumber("102")); @@ -70,7 +70,7 @@ void createFromString_outOfRange_throws() { @Test @DisplayName("리스트 생성: 10이 포함되면 예외가 발생한다") - void createFromList_outOfRange_throws() { + void createFromListWithOutOfRange() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new GameNumber(List.of(1, 2, 10))); @@ -79,7 +79,7 @@ void createFromList_outOfRange_throws() { @Test @DisplayName("문자열 생성: 중복이 있으면 예외가 발생한다") - void createFromString_duplicated_throws() { + void createFromStringWithDuplicated() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new GameNumber("112")); @@ -88,7 +88,7 @@ void createFromString_duplicated_throws() { @Test @DisplayName("리스트 생성: 중복이 있으면 예외가 발생한다") - void createFromList_duplicated_throws() { + void createFromListWithDuplicated() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new GameNumber(List.of(7, 7, 1))); From 0c0c4f278a2263ad0a416f9c54ba8bdcfda6edfd Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:43:43 +0900 Subject: [PATCH 27/29] =?UTF-8?q?refactor:=20BaseballGameController=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BaseballGameController.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/controller/BaseballGameController.java b/src/main/java/controller/BaseballGameController.java index bb95cb04..651542db 100644 --- a/src/main/java/controller/BaseballGameController.java +++ b/src/main/java/controller/BaseballGameController.java @@ -1,10 +1,12 @@ package controller; +import java.util.List; + import model.computer.Computer; import model.game.GameCommand; -import model.game.GameNumber; import model.game.Result; import model.generator.NumberGenerator; +import model.player.Player; import view.InputView; import view.OutputView; @@ -30,8 +32,8 @@ private void start() { Result result; do { - GameNumber gameNumber = getPlayerNumber(); - result = computer.calculate(gameNumber.getNumber()); + List playerNumber = getPlayer().getNumber(); + result = computer.calculate(playerNumber); outputView.printResult(result); } while (result.strikes() != 3); @@ -49,11 +51,11 @@ private boolean shouldRestart() { } } - private GameNumber getPlayerNumber() { + private Player getPlayer() { while (true) { try { String input = inputView.readPlayerNumber(); - return new GameNumber(input); + return new Player(input); } catch (IllegalArgumentException e) { outputView.printErrorMessage(e.getMessage()); } From 84a8240d0fe5c841d356279ddbb0e89718afff3c Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:44:16 +0900 Subject: [PATCH 28/29] =?UTF-8?q?rename:=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/model/generator/RandomNumberGenerator.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/model/generator/RandomNumberGenerator.java b/src/main/java/model/generator/RandomNumberGenerator.java index cd64c274..072df9d9 100644 --- a/src/main/java/model/generator/RandomNumberGenerator.java +++ b/src/main/java/model/generator/RandomNumberGenerator.java @@ -15,12 +15,12 @@ public class RandomNumberGenerator implements NumberGenerator { @Override public List generate() { - List pool = new ArrayList<>(); - for (int i = MIN_DIGIT; i <= MAX_DIGIT; i++) { - pool.add(i); + List availableDigits = new ArrayList<>(); + for (int num = MIN_DIGIT; num <= MAX_DIGIT; num++) { + availableDigits.add(num); } - Collections.shuffle(pool, random); - return new ArrayList<>(pool.subList(0, NUMBER_LENGTH)); + Collections.shuffle(availableDigits, random); + return new ArrayList<>(availableDigits.subList(0, NUMBER_LENGTH)); } } From a9f2da15d5dfee7ef0efb9d5d07bb7b878984151 Mon Sep 17 00:00:00 2001 From: "seogi.nam" Date: Sun, 1 Feb 2026 17:46:05 +0900 Subject: [PATCH 29/29] =?UTF-8?q?refactor:=20=EC=83=81=EC=88=98=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/BaseballGameController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/controller/BaseballGameController.java b/src/main/java/controller/BaseballGameController.java index 651542db..592ffb81 100644 --- a/src/main/java/controller/BaseballGameController.java +++ b/src/main/java/controller/BaseballGameController.java @@ -11,6 +11,7 @@ import view.OutputView; public class BaseballGameController { + private static final int GAME_CLEAR_STRIKES = 3; private final InputView inputView; private final OutputView outputView; private final NumberGenerator numberGenerator; @@ -35,7 +36,7 @@ private void start() { List playerNumber = getPlayer().getNumber(); result = computer.calculate(playerNumber); outputView.printResult(result); - } while (result.strikes() != 3); + } while (result.strikes() != GAME_CLEAR_STRIKES); outputView.printGameClearMessage(); }