From d146768578506aada28f8ef22809707f33ff4bf0 Mon Sep 17 00:00:00 2001 From: "dodo.100" Date: Wed, 28 Jan 2026 16:19:36 +0900 Subject: [PATCH 01/10] =?UTF-8?q?docs:=20Readme.md=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=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 | 12 +++++++++++- src/main/java/Application.java | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/main/java/Application.java diff --git a/README.md b/README.md index 8d7e8aee..0157fb14 100644 --- a/README.md +++ b/README.md @@ -1 +1,11 @@ -# java-baseball-precourse \ No newline at end of file +# java-baseball-precourse + +## 구현할 기능 목록 + +- 컴퓨터 플레이어 클래스 구현 +- 플레이어 클래스 구현 +- 결과를 판단해줄 심판 클래스 구현 +- 입력을 담당하는 인풋 뷰 클래스 구현 +- 출력을 담당하는 아웃풋 뷰 클래스 구현 +- 입력과 출력을 담당하는 컨트롤러 클래스 구현 +- 게임을 전체 진행해줄 게임 컨트롤러 클래스 구현 \ No newline at end of file diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..39bd1d73 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,7 @@ +public class Application { + + public static void main(String[] args) { + + } + +} From c09f45357bbafe4ad7942c2da32d1deaec8aed29 Mon Sep 17 00:00:00 2001 From: dh1010a Date: Wed, 28 Jan 2026 16:39:13 +0900 Subject: [PATCH 02/10] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EB=8B=A8=EC=9C=84=EB=A1=9C=20=EC=9E=AC=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 | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0157fb14..1046b8a0 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@ ## 구현할 기능 목록 -- 컴퓨터 플레이어 클래스 구현 -- 플레이어 클래스 구현 -- 결과를 판단해줄 심판 클래스 구현 -- 입력을 담당하는 인풋 뷰 클래스 구현 -- 출력을 담당하는 아웃풋 뷰 클래스 구현 -- 입력과 출력을 담당하는 컨트롤러 클래스 구현 -- 게임을 전체 진행해줄 게임 컨트롤러 클래스 구현 \ No newline at end of file +- 게임이 실행되고, 컴퓨터가 생각한 수를 사전에 미리 설정할 수 있는 기능 구현 +- 사용자에게 안내 문구를 출력한 뒤 입력을 받아오는 기능 구현 +- 사용자의 입력값이 잘못 되었을 경우 에러를 출력하는 기능 구현 +- 입력값을 토대로 결과를 판단하는 심판 기능 구현 +- 결과를 출력하는 기능 구현 +- 게임 진행 흐름을 컨트롤 하는 기능 구현 \ No newline at end of file From 0995210efb7ba7592a0d4be95f8bd9302e638836 Mon Sep 17 00:00:00 2001 From: dh1010a Date: Wed, 28 Jan 2026 17:10:00 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=EC=9D=B4=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=EB=90=98=EA=B3=A0,=20=EC=BB=B4=ED=93=A8?= =?UTF-8?q?=ED=84=B0=EA=B0=80=20=EC=83=9D=EA=B0=81=ED=95=9C=20=EC=88=98?= =?UTF-8?q?=EB=A5=BC=20=EC=82=AC=EC=A0=84=EC=97=90=20=EB=AF=B8=EB=A6=AC=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=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 --- src/main/java/Application.java | 5 +- src/main/java/controller/GameController.java | 20 ++++++++ .../java/domain/player/ComputerPlayer.java | 39 ++++++++++++++++ src/main/java/domain/player/NormalPlayer.java | 20 ++++++++ .../domain/player/ComputerPlayerTest.java | 46 +++++++++++++++++++ 5 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/main/java/controller/GameController.java create mode 100644 src/main/java/domain/player/ComputerPlayer.java create mode 100644 src/main/java/domain/player/NormalPlayer.java create mode 100644 src/test/java/domain/player/ComputerPlayerTest.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 39bd1d73..4dacf46f 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,7 +1,10 @@ +import controller.GameController; + public class Application { public static void main(String[] args) { - + GameController gameController = new GameController(); + gameController.start(); } } diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java new file mode 100644 index 00000000..96708bb2 --- /dev/null +++ b/src/main/java/controller/GameController.java @@ -0,0 +1,20 @@ +package controller; + +import domain.player.ComputerPlayer; +import domain.player.NormalPlayer; + +public class GameController { + + public void start() { + boolean resume = true; + while (resume) { + NormalPlayer player = new NormalPlayer(); + ComputerPlayer computerPlayer = new ComputerPlayer(); + play(player, computerPlayer); + } + } + + private void play(NormalPlayer player, ComputerPlayer computerPlayer) { + computerPlayer.setRandomNumbers(); + } +} diff --git a/src/main/java/domain/player/ComputerPlayer.java b/src/main/java/domain/player/ComputerPlayer.java new file mode 100644 index 00000000..cb659a94 --- /dev/null +++ b/src/main/java/domain/player/ComputerPlayer.java @@ -0,0 +1,39 @@ +package domain.player; + +import java.util.Random; + +public class ComputerPlayer { + + private final int[] numbers; + + public ComputerPlayer() { + this.numbers = new int[3]; + } + + public int[] getNumbers() { + return numbers; + } + + public void setRandomNumbers() { + Random random = new Random(); + int idx = 0; + + while (idx < 3) { + int randomNumber = random.nextInt(9) + 1; + + if (!isDuplicate(numbers, randomNumber, idx)) { + numbers[idx] = randomNumber; + idx++; + } + } + } + + private boolean isDuplicate(int[] arr, int num, int idx) { + for (int i = 0; i < idx; i++) { + if (arr[i] == num) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/domain/player/NormalPlayer.java b/src/main/java/domain/player/NormalPlayer.java new file mode 100644 index 00000000..5b518c7c --- /dev/null +++ b/src/main/java/domain/player/NormalPlayer.java @@ -0,0 +1,20 @@ +package domain.player; + +public class NormalPlayer { + + private final int[] numbers; + + public NormalPlayer() { + this.numbers = new int[3]; + } + + public int[] getNumbers() { + return numbers; + } + + public void updateNumbers(int n1, int n2, int n3) { + this.numbers[0] = n1; + this.numbers[1] = n2; + this.numbers[2] = n3; + } +} diff --git a/src/test/java/domain/player/ComputerPlayerTest.java b/src/test/java/domain/player/ComputerPlayerTest.java new file mode 100644 index 00000000..c414612d --- /dev/null +++ b/src/test/java/domain/player/ComputerPlayerTest.java @@ -0,0 +1,46 @@ +package domain.player; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; + +class ComputerPlayerTest { + + @Test + @DisplayName("생성된 모든 숫자는 1 이상 9 이하의 정수여야 한다") + void testNumbersWithinRange() { + ComputerPlayer player = new ComputerPlayer(); + + for (int i = 0; i < 100; i++) { + player.setRandomNumbers(); + int[] numbers = player.getNumbers(); + + for (int num : numbers) { + assertTrue(num >= 1 && num <= 9, + "1~9의 범위를 벗어난 숫자가 존재합니다: " + num); + } + } + } + + @Test + @DisplayName("생성된 3개의 숫자는 서로 중복되지 않아야 한다") + void testNoDuplicateNumbers() { + ComputerPlayer player = new ComputerPlayer(); + + for (int i = 0; i < 100; i++) { + player.setRandomNumbers(); + int[] result = player.getNumbers(); + + Set numberSet = new HashSet<>(); + for (int num : result) { + numberSet.add(num); + } + + assertEquals(3, numberSet.size(), "생성된 숫자 3개 중 중복된 숫자가 존재합니다."); + } + } +} \ No newline at end of file From e942c83cb7ec31cbc0b011cf9841eba5fa781139 Mon Sep 17 00:00:00 2001 From: dh1010a Date: Wed, 28 Jan 2026 17:15:00 +0900 Subject: [PATCH 04/10] =?UTF-8?q?chore:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/GameController.java | 4 ++-- src/main/java/{domain => model}/player/ComputerPlayer.java | 2 +- src/main/java/{domain => model}/player/NormalPlayer.java | 2 +- .../java/{domain => model}/player/ComputerPlayerTest.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/main/java/{domain => model}/player/ComputerPlayer.java (97%) rename src/main/java/{domain => model}/player/NormalPlayer.java (93%) rename src/test/java/{domain => model}/player/ComputerPlayerTest.java (98%) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 96708bb2..064ecde8 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -1,7 +1,7 @@ package controller; -import domain.player.ComputerPlayer; -import domain.player.NormalPlayer; +import model.player.ComputerPlayer; +import model.player.NormalPlayer; public class GameController { diff --git a/src/main/java/domain/player/ComputerPlayer.java b/src/main/java/model/player/ComputerPlayer.java similarity index 97% rename from src/main/java/domain/player/ComputerPlayer.java rename to src/main/java/model/player/ComputerPlayer.java index cb659a94..9ace0fc4 100644 --- a/src/main/java/domain/player/ComputerPlayer.java +++ b/src/main/java/model/player/ComputerPlayer.java @@ -1,4 +1,4 @@ -package domain.player; +package model.player; import java.util.Random; diff --git a/src/main/java/domain/player/NormalPlayer.java b/src/main/java/model/player/NormalPlayer.java similarity index 93% rename from src/main/java/domain/player/NormalPlayer.java rename to src/main/java/model/player/NormalPlayer.java index 5b518c7c..c5103486 100644 --- a/src/main/java/domain/player/NormalPlayer.java +++ b/src/main/java/model/player/NormalPlayer.java @@ -1,4 +1,4 @@ -package domain.player; +package model.player; public class NormalPlayer { diff --git a/src/test/java/domain/player/ComputerPlayerTest.java b/src/test/java/model/player/ComputerPlayerTest.java similarity index 98% rename from src/test/java/domain/player/ComputerPlayerTest.java rename to src/test/java/model/player/ComputerPlayerTest.java index c414612d..2bde18fc 100644 --- a/src/test/java/domain/player/ComputerPlayerTest.java +++ b/src/test/java/model/player/ComputerPlayerTest.java @@ -1,4 +1,4 @@ -package domain.player; +package model.player; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From 81f2fdc92ed56b4154ee70a75e4b241e0a3eaecb Mon Sep 17 00:00:00 2001 From: dh1010a Date: Wed, 28 Jan 2026 17:41:01 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EC=97=90=EA=B2=8C=20=EC=95=88=EB=82=B4=20=EB=AC=B8=EA=B5=AC?= =?UTF-8?q?=EB=A5=BC=20=EC=B6=9C=EB=A0=A5=ED=95=9C=20=EB=92=A4=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EC=9D=84=20=EB=B0=9B=EC=95=84=EC=98=A4=EB=8A=94=20?= =?UTF-8?q?=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 --- src/main/java/controller/GameController.java | 18 +++++++++++++ src/main/java/model/player/NormalPlayer.java | 8 +++--- src/main/java/util/StringUtils.java | 13 ++++++++++ src/main/java/view/InputView.java | 27 ++++++++++++++++++++ src/main/java/view/OutputView.java | 20 +++++++++++++++ 5 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 src/main/java/util/StringUtils.java create mode 100644 src/main/java/view/InputView.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 index 064ecde8..4499af13 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -2,9 +2,19 @@ import model.player.ComputerPlayer; import model.player.NormalPlayer; +import view.InputView; +import view.OutputView; public class GameController { + private final InputView inputView; + private final OutputView outputView; + + public GameController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + public void start() { boolean resume = true; while (resume) { @@ -16,5 +26,13 @@ public void start() { private void play(NormalPlayer player, ComputerPlayer computerPlayer) { computerPlayer.setRandomNumbers(); + try { + outputView.printInputMessage(); + int[] userNumbers = inputView.getUserNumbers(); + player.updateNumbers(userNumbers); + } catch (Exception e) { + outputView.printlnMessage(e.getMessage()); + } + } } diff --git a/src/main/java/model/player/NormalPlayer.java b/src/main/java/model/player/NormalPlayer.java index c5103486..26ad4ac9 100644 --- a/src/main/java/model/player/NormalPlayer.java +++ b/src/main/java/model/player/NormalPlayer.java @@ -12,9 +12,9 @@ public int[] getNumbers() { return numbers; } - public void updateNumbers(int n1, int n2, int n3) { - this.numbers[0] = n1; - this.numbers[1] = n2; - this.numbers[2] = n3; + public void updateNumbers(int[] inputNumbers) { + this.numbers[0] = inputNumbers[0]; + this.numbers[1] = inputNumbers[1]; + this.numbers[2] = inputNumbers[2]; } } diff --git a/src/main/java/util/StringUtils.java b/src/main/java/util/StringUtils.java new file mode 100644 index 00000000..57f213c9 --- /dev/null +++ b/src/main/java/util/StringUtils.java @@ -0,0 +1,13 @@ +package util; + +public class StringUtils { + + public static int[] parseStringToIntArray(String inputString) { + String[] array = inputString.split(""); + int[] numberArray = new int[3]; + for (int i = 0; i < 3; i++) { + numberArray[i] = Integer.parseInt(array[i]); + } + return numberArray; + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..7a8c0b14 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,27 @@ +package view; + +import util.StringUtils; + +import java.io.BufferedReader; + +import java.io.InputStreamReader; + +public class InputView { + + private final BufferedReader reader; + + public InputView() { + this.reader = new BufferedReader(new InputStreamReader(System.in)); + } + + public int[] getUserNumbers() throws Exception { + String inputString = reader.readLine(); + return StringUtils.parseStringToIntArray(inputString); + } + + public int getResumeOption() throws Exception { + String inputString = reader.readLine(); + return Integer.parseInt(inputString); + } + +} \ No newline at end of file diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..a51542be --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,20 @@ +package view; + +public class OutputView { + + private static final String inputMessage = "숫자를 입력해주세요 : "; + + + public void printlnMessage(String message) { + System.out.println(message); + } + + public void printMessage(String message) { + System.out.print(message); + } + + public void printInputMessage() { + printMessage(inputMessage); + } + +} From d4b24ab61a1ecec77c4ad9d2d868e8c175f2f585 Mon Sep 17 00:00:00 2001 From: dh1010a Date: Wed, 28 Jan 2026 17:41:46 +0900 Subject: [PATCH 06/10] =?UTF-8?q?fix:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EB=B7=B0=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EB=AF=B8?= =?UTF-8?q?=EC=82=BD=EC=9E=85=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 4dacf46f..6f9cdc67 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,9 +1,13 @@ import controller.GameController; +import view.InputView; +import view.OutputView; public class Application { public static void main(String[] args) { - GameController gameController = new GameController(); + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + GameController gameController = new GameController(inputView, outputView); gameController.start(); } From e3e7533224856faff59feffa0200095afd057b58 Mon Sep 17 00:00:00 2001 From: dh1010a Date: Wed, 28 Jan 2026 17:58:28 +0900 Subject: [PATCH 07/10] =?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=EA=B0=92=EC=9D=B4=20=EC=9E=98?= =?UTF-8?q?=EB=AA=BB=20=EB=90=98=EC=97=88=EC=9D=84=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EB=A5=BC=20=EC=B6=9C=EB=A0=A5=ED=95=98?= =?UTF-8?q?=EB=8A=94=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 --- src/main/java/controller/GameController.java | 22 ++++-- src/main/java/view/InputView.java | 64 ++++++++++++++++++ src/test/java/view/InputViewTest.java | 70 ++++++++++++++++++++ 3 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 src/test/java/view/InputViewTest.java diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 4499af13..f9a6b00a 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -26,13 +26,23 @@ public void start() { private void play(NormalPlayer player, ComputerPlayer computerPlayer) { computerPlayer.setRandomNumbers(); - try { - outputView.printInputMessage(); - int[] userNumbers = inputView.getUserNumbers(); - player.updateNumbers(userNumbers); - } catch (Exception e) { - outputView.printlnMessage(e.getMessage()); + boolean isValidInput = false; + + while (!isValidInput) { + int[] userNumbers = receiveValidUserNumbers(); + isValidInput = true; } } + + private int[] receiveValidUserNumbers() { + while (true) { + try { + outputView.printInputMessage(); + return inputView.getUserNumbers(); + } catch (Exception e) { + outputView.printlnMessage(e.getMessage()); + } + } + } } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 7a8c0b14..67d61c0d 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -4,7 +4,11 @@ import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; public class InputView { @@ -16,12 +20,72 @@ public InputView() { public int[] getUserNumbers() throws Exception { String inputString = reader.readLine(); + checkInputFormat(inputString); return StringUtils.parseStringToIntArray(inputString); } public int getResumeOption() throws Exception { String inputString = reader.readLine(); + checkResumeInputFormat(inputString); return Integer.parseInt(inputString); } + private void checkInputFormat(String inputString) throws Exception { + validateIntegerInput(inputString); + validateIntegerLength(inputString, 3); + validateNotZero(inputString); + validateDuplicatedNumber(inputString); + } + + public void checkResumeInputFormat(String inputString) throws Exception{ + validateIntegerInput(inputString); + validateIntegerLength(inputString, 1); + validateResumeFormat(inputString); + } + + private void validateIntegerInput(String inputString) throws Exception{ + if (!isInteger(inputString)) { + throw new IllegalArgumentException("[ERROR] 숫자만 입력 가능합니다."); + } + } + + private boolean isInteger(String inputString) throws Exception { + try { + Integer.parseInt(inputString); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + private void validateIntegerLength(String inputString, int N) throws Exception { + if (inputString.length() != N) { + throw new IllegalArgumentException("[ERROR] " + N + "자리의 숫자여야 합니다."); + } + } + + private void validateNotZero(String inputString) throws Exception { + if (inputString.contains("0")) { + throw new IllegalArgumentException("[ERROR] 0은 포함될 수 없습니다."); + } + } + + private void validateDuplicatedNumber(String inputString) throws Exception { + String[] array = inputString.split(""); + Set set = new HashSet<>(Arrays.asList(array)); + if (set.size() != array.length) { + throw new IllegalArgumentException("[ERROR] 중복된 숫자가 있습니다."); + } + } + + private void validateResumeFormat(String inputString) throws Exception { + if (!inputString.equals("1") && !inputString.equals("2")) { + throw new IllegalArgumentException("[ERROR] 1 또는 2만 입력 가능합니다."); + } + } + + public void close() throws IOException { + reader.close(); + } + } \ No newline at end of file diff --git a/src/test/java/view/InputViewTest.java b/src/test/java/view/InputViewTest.java new file mode 100644 index 00000000..97e98c0e --- /dev/null +++ b/src/test/java/view/InputViewTest.java @@ -0,0 +1,70 @@ +package view; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import static org.junit.jupiter.api.Assertions.*; + +class InputViewTest { + + private InputView inputView; + private final InputStream standardIn = System.in; + + @AfterEach + void tearDown() { + System.setIn(standardIn); + } + + private void provideInput(String input) { + System.setIn(new ByteArrayInputStream(input.getBytes())); + inputView = new InputView(); + } + + @Test + @DisplayName("정상적인 3자리 숫자를 입력하면 int 배열을 반환한다") + void success_getUserNumbers() throws Exception { + provideInput("123"); + + int[] result = inputView.getUserNumbers(); + + assertArrayEquals(new int[]{1, 2, 3}, result); + } + + @ParameterizedTest + @ValueSource(strings = {"12", "1234", "abc", "102", "112", ""}) + @DisplayName("잘못된 형식의 숫자를 입력하면 예외가 발생한다") + void fail_getUserNumbers(String input) { + provideInput(input); + + assertThrows(IllegalArgumentException.class, () -> { + inputView.getUserNumbers(); + }); + } + + @Test + @DisplayName("재시작 옵션으로 1을 입력하면 정수 1을 반환한다") + void success_getResumeOption() throws Exception { + provideInput("1"); + + int result = inputView.getResumeOption(); + + assertEquals(1, result); + } + + @ParameterizedTest + @ValueSource(strings = {"3", "0", "a", "11"}) + @DisplayName("재시작 옵션으로 1 또는 2가 아닌 값을 입력하면 예외가 발생한다") + void fail_getResumeOption(String input) { + provideInput(input); + + assertThrows(IllegalArgumentException.class, () -> { + inputView.getResumeOption(); + }); + } +} \ No newline at end of file From b5659050ad2c6b26a4b2a48f2b217ff85afb92e0 Mon Sep 17 00:00:00 2001 From: dh1010a Date: Wed, 28 Jan 2026 18:05:39 +0900 Subject: [PATCH 08/10] =?UTF-8?q?feat:=20=EC=9E=85=EB=A0=A5=EA=B0=92?= =?UTF-8?q?=EC=9D=84=20=ED=86=A0=EB=8C=80=EB=A1=9C=20=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=EB=A5=BC=20=ED=8C=90=EB=8B=A8=ED=95=98=EB=8A=94=20=EC=8B=AC?= =?UTF-8?q?=ED=8C=90=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 --- src/main/java/controller/GameController.java | 11 ++-- src/main/java/model/Referee.java | 41 ++++++++++++++ src/test/java/model/RefereeTest.java | 57 ++++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 src/main/java/model/Referee.java create mode 100644 src/test/java/model/RefereeTest.java diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index f9a6b00a..70448b16 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -1,5 +1,6 @@ package controller; +import model.Referee; import model.player.ComputerPlayer; import model.player.NormalPlayer; import view.InputView; @@ -26,13 +27,17 @@ public void start() { private void play(NormalPlayer player, ComputerPlayer computerPlayer) { computerPlayer.setRandomNumbers(); - boolean isValidInput = false; + Referee referee = new Referee(); - while (!isValidInput) { + boolean gameOver = false; + + while (!gameOver) { int[] userNumbers = receiveValidUserNumbers(); - isValidInput = true; + int[] score = referee.judgeGameScore(player.getNumbers(), computerPlayer.getNumbers()); + gameOver = referee.judgeGameOver(score); } + } private int[] receiveValidUserNumbers() { diff --git a/src/main/java/model/Referee.java b/src/main/java/model/Referee.java new file mode 100644 index 00000000..d2187b60 --- /dev/null +++ b/src/main/java/model/Referee.java @@ -0,0 +1,41 @@ +package model; + +public class Referee { + private static int OFFSET = 3; + + public int[] judgeGameScore(int[] userNumberArray, int[] computerNumberArray) { + int[] score = {0, 0}; // ball, strike + score[0] = countBall(userNumberArray, computerNumberArray); + score[1] = countStrike(userNumberArray, computerNumberArray); + return score; + } + + public boolean judgeGameOver(int[] score) { + return score[1] == OFFSET; + } + + private int countStrike(int[] userNumberArray, int[] computerNumberArray) { + int cnt = 0; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (userNumberArray[i] == computerNumberArray[j] && i == j) { + cnt++; + + } + } + } + return cnt; + } + + private int countBall(int[] userNumberArray, int[] computerNumberArray) { + int cnt = 0; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (userNumberArray[i] == computerNumberArray[j] && i != j) { + cnt++; + } + } + } + return cnt; + } +} \ No newline at end of file diff --git a/src/test/java/model/RefereeTest.java b/src/test/java/model/RefereeTest.java new file mode 100644 index 00000000..193057d4 --- /dev/null +++ b/src/test/java/model/RefereeTest.java @@ -0,0 +1,57 @@ +package model; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class RefereeTest { + + private Referee referee; + private final int[] computerNumbers = {1, 2, 3}; + + @BeforeEach + void setUp() { + referee = new Referee(); + } + + @ParameterizedTest + @CsvSource({ + "1, 2, 3, 0, 3", + "3, 1, 2, 3, 0", + "1, 3, 2, 2, 1", + "1, 4, 5, 0, 1", + "4, 5, 6, 0, 0", + "2, 3, 1, 3, 0" + }) + @DisplayName("사용자 입력에 따른 볼과 스트라이크 개수를 정확히 계산해야 한다") + void testJudgeGameScore(int n1, int n2, int n3, int expectedBall, int expectedStrike) { + int[] userNumbers = {n1, n2, n3}; + + int[] score = referee.judgeGameScore(userNumbers, computerNumbers); + + assertAll( + () -> assertEquals(expectedBall, score[0], "볼 개수가 일치하지 않습니다."), + () -> assertEquals(expectedStrike, score[1], "스트라이크 개수가 일치하지 않습니다.") + ); + } + + @Test + @DisplayName("3스트라이크일 경우 게임 종료 판정(true)을 내려야 한다") + void testJudgeGameOver_True() { + int[] score = {0, 3}; + + assertTrue(referee.judgeGameOver(score)); + } + + @Test + @DisplayName("3스트라이크가 아닐 경우 게임 종료 판정(false)을 내려야 한다") + void testJudgeGameOver_False() { + int[] score = {2, 1}; + + assertFalse(referee.judgeGameOver(score)); + } +} \ No newline at end of file From 6b94b089566c1b3d10f4d09904928ba2f9fabc5c Mon Sep 17 00:00:00 2001 From: dh1010a Date: Wed, 28 Jan 2026 18:21:24 +0900 Subject: [PATCH 09/10] =?UTF-8?q?feat:=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8A=94=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/controller/GameController.java | 24 +++++++++++++---- src/main/java/view/OutputView.java | 27 ++++++++++++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 70448b16..86a298c3 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -17,11 +17,15 @@ public GameController(InputView inputView, OutputView outputView) { } public void start() { - boolean resume = true; - while (resume) { + while (true) { NormalPlayer player = new NormalPlayer(); ComputerPlayer computerPlayer = new ComputerPlayer(); play(player, computerPlayer); + outputView.printFinishMessage(); + int validResume = getValidResume(); + if (validResume != 1) { + return; + } } } @@ -32,15 +36,14 @@ private void play(NormalPlayer player, ComputerPlayer computerPlayer) { boolean gameOver = false; while (!gameOver) { - int[] userNumbers = receiveValidUserNumbers(); + int[] userNumbers = getValidUserNumbers(); int[] score = referee.judgeGameScore(player.getNumbers(), computerPlayer.getNumbers()); gameOver = referee.judgeGameOver(score); } - } - private int[] receiveValidUserNumbers() { + private int[] getValidUserNumbers() { while (true) { try { outputView.printInputMessage(); @@ -50,4 +53,15 @@ private int[] receiveValidUserNumbers() { } } } + + private int getValidResume() { + while (true) { + try { + outputView.printResumeMessage(); + return inputView.getResumeOption(); + } catch (Exception e) { + outputView.printlnMessage(e.getMessage()); + } + } + } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index a51542be..22a67f5d 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -3,6 +3,11 @@ public class OutputView { private static final String inputMessage = "숫자를 입력해주세요 : "; + private static final String ballMessage = "볼 "; + private static final String strikeMessage = "스트라이크"; + private static final String nothingMessage = "낫싱"; + private static final String endMessage = "3개의 숫자를 모두 맞히셨습니다! 게임 끝"; + private static final String resumeMessage = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."; public void printlnMessage(String message) { @@ -17,4 +22,26 @@ public void printInputMessage() { printMessage(inputMessage); } + public void printFinishMessage() { + printlnMessage(endMessage); + } + + public void printResumeMessage() { + printlnMessage(resumeMessage); + } + + public void printResultMessage(int ball, int strike) { + String message = ""; + if (strike == 0 && ball == 0) { + message += nothingMessage; + } + if (ball > 0) { + message += ball + ballMessage; + } + if (strike > 0) { + message += strike + strikeMessage; + } + printlnMessage(message); + } + } From e142d0cef805de5a5cb97d12d7255fbe8b56f706 Mon Sep 17 00:00:00 2001 From: dh1010a Date: Wed, 28 Jan 2026 18:28:26 +0900 Subject: [PATCH 10/10] =?UTF-8?q?fix:=20=EC=9E=85=EB=A0=A5=EC=9D=84=20?= =?UTF-8?q?=EB=B0=9B=EC=95=84=EC=98=A8=20=EB=92=A4=20=EC=9C=A0=EC=A0=80=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EC=97=90=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/GameController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index 86a298c3..d7838de2 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -36,8 +36,9 @@ private void play(NormalPlayer player, ComputerPlayer computerPlayer) { boolean gameOver = false; while (!gameOver) { - int[] userNumbers = getValidUserNumbers(); + player.updateNumbers(getValidUserNumbers()); int[] score = referee.judgeGameScore(player.getNumbers(), computerPlayer.getNumbers()); + outputView.printResultMessage(score[0], score[1]); gameOver = referee.judgeGameOver(score); }