From ac6e1ab756dc12f27f61ecf30a3b113388689f86 Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Wed, 28 Jan 2026 16:12:25 +0900 Subject: [PATCH 01/12] =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danny.197 --- README.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d7e8aee..3ac79b54 100644 --- a/README.md +++ b/README.md @@ -1 +1,73 @@ -# java-baseball-precourse \ No newline at end of file +# java-baseball-precourse + + + +## 숫자 야구 게임 기능 목록 + +--- +### 1. 게임 프로세스 관리 + + +**게임 시작**: 프로그램 실행 시 게임을 시작함. + + +**게임 재시작/종료 선택**: 3스트라이크로 게임 종료 후, '1'(재시작) 또는 '2'(종료)를 입력받아 처리함. + + + +**전체 게임 루프**: 사용자가 종료를 선택할 때까지 게임 프로세스를 반복함. + +--- + +### 2. 컴퓨터 (상대방) 기능 + +**정답 숫자 생성**: 1에서 9까지 서로 다른 임의의 수 3개를 선택함. + +--- + +### 3. 사용자 입력 및 유효성 검사 + +**숫자 입력 받기**: 사용자로부터 3자리의 숫자를 입력받음. + + +**예외 처리**: 사용자가 잘못된 값을 입력할 경우 `[ERROR]`로 시작하는 에러 메시지를 출력하고 게임을 계속 진행함. + + +* *예: 숫자가 아닌 경우, 3자리가 아닌 경우, 중복된 숫자가 있는 경우 등* + +--- + +### 4. 게임 판정 로직 (핵심 도메인) + +**숫자 비교**: 컴퓨터의 수와 사용자의 수를 비교하여 힌트(스트라이크, 볼)를 계산함. + + +**스트라이크**: 같은 수가 같은 자리에 있는 경우. + + +**볼**: 같은 수가 다른 자리에 있는 경우. + + +**낫싱(포볼)**: 같은 수가 전혀 없는 경우. + + +--- + + +### 5. 출력 기능 (UI) + +**입력 안내 메시지**: `숫자를 입력해주세요 : ` 메시지 출력. + + +**힌트 결과 출력**: 계산된 스트라이크와 볼의 개수를 출력 (예: `1스트라이크 1볼`, `낫싱`). + + +**게임 종료 메시지**: `3개의 숫자를 모두 맞히셨습니다! [cite_start]게임 끝` 출력. + + + +**재시작 안내 메시지**: `게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.` 출력. + + + +--- From c54ddbe4926b9ade7b4d34acacdbf7fbd64cff99 Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 11:20:49 +0900 Subject: [PATCH 02/12] =?UTF-8?q?git=20keep=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danny.197 --- src/main/java/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/java/.gitkeep diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 From 036f89f8870be02dc99b3f4fee54e74c4a99e50b Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 15:12:50 +0900 Subject: [PATCH 03/12] =?UTF-8?q?Computer=20=EB=8F=84=EB=A9=94=EC=9D=B8=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 Signed-off-by: danny.197 --- src/main/java/baseball/domain/Computer.java | 16 ++++++++++++ .../baseball/utils/RandomNumberGenerator.java | 25 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 src/main/java/baseball/domain/Computer.java create mode 100644 src/main/java/baseball/utils/RandomNumberGenerator.java diff --git a/src/main/java/baseball/domain/Computer.java b/src/main/java/baseball/domain/Computer.java new file mode 100644 index 00000000..224694cd --- /dev/null +++ b/src/main/java/baseball/domain/Computer.java @@ -0,0 +1,16 @@ +package baseball.domain; + +import java.util.List; +import baseball.utils.RandomNumberGenerator; + +public class Computer { + private final List numbers; + + public Computer() { + this.numbers = RandomNumberGenerator.generate(); + } + + public List getNumbers() { + return numbers; + } +} \ No newline at end of file diff --git a/src/main/java/baseball/utils/RandomNumberGenerator.java b/src/main/java/baseball/utils/RandomNumberGenerator.java new file mode 100644 index 00000000..b9f23f7d --- /dev/null +++ b/src/main/java/baseball/utils/RandomNumberGenerator.java @@ -0,0 +1,25 @@ +package baseball.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class RandomNumberGenerator { + + public static List generate() { + List numbers = new ArrayList<>(); + Random random = new Random(); + + while (numbers.size() < 3) { + int randomNumber = random.nextInt(9) + 1; + addIfUnique(numbers, randomNumber); + } + return numbers; + } + + private static void addIfUnique(List list, int number) { + if (!list.contains(number)) { + list.add(number); + } + } +} \ No newline at end of file From e15106f3f6a11962dca2d336e85a48d7033ebd17 Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 15:13:14 +0900 Subject: [PATCH 04/12] =?UTF-8?q?Player=20=EB=8F=84=EB=A9=94=EC=9D=B8=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 Signed-off-by: danny.197 --- src/main/java/baseball/domain/Player.java | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/baseball/domain/Player.java diff --git a/src/main/java/baseball/domain/Player.java b/src/main/java/baseball/domain/Player.java new file mode 100644 index 00000000..cdc1d44a --- /dev/null +++ b/src/main/java/baseball/domain/Player.java @@ -0,0 +1,38 @@ +package baseball.domain; + +import java.util.ArrayList; +import java.util.List; + +public class Player { + private final List numbers; + + public Player(String input) { + validate(input); + this.numbers = parse(input); + } + + private void validate(String input) { + if (!input.matches("^[1-9]{3}$")) { + throw new IllegalArgumentException("[ERROR] 1-9 사이의 숫자 3개를 입력해야 합니다."); + } + if (hasDuplicate(input)) { + throw new IllegalArgumentException("[ERROR] 중복된 숫자가 있습니다."); + } + } + + private boolean hasDuplicate(String input) { + return input.chars().distinct().count() != input.length(); + } + + private List parse(String input) { + List list = new ArrayList<>(); + for (char c : input.toCharArray()) { + list.add(Character.getNumericValue(c)); + } + return list; + } + + public List getNumbers() { + return numbers; + } +} \ No newline at end of file From f75721838b9e3ebd1daf6299f744fe004eb3acd7 Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 15:13:49 +0900 Subject: [PATCH 05/12] =?UTF-8?q?Score=20=EB=8F=84=EB=A9=94=EC=9D=B8=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 Signed-off-by: danny.197 --- src/main/java/baseball/domain/Score.java | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/baseball/domain/Score.java diff --git a/src/main/java/baseball/domain/Score.java b/src/main/java/baseball/domain/Score.java new file mode 100644 index 00000000..ec573a50 --- /dev/null +++ b/src/main/java/baseball/domain/Score.java @@ -0,0 +1,27 @@ +package baseball.domain; + +public class Score { + private final int strike; + private final int ball; + + public Score(int strike, int ball) { + this.strike = strike; + this.ball = ball; + } + + public int getStrike() { + return strike; + } + + public boolean isFinished() { + return strike == 3; + } + + @Override + public String toString() { + if (strike == 0 && ball == 0) return "낫싱"; + if (strike == 0) return ball + "볼"; + if (ball == 0) return strike + "스트라이크"; + return ball + "볼 " + strike + "스트라이크"; + } +} \ No newline at end of file From 5a6cafc8ba4c02fc6d761ffab2a96a65617e9933 Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 15:13:54 +0900 Subject: [PATCH 06/12] =?UTF-8?q?Referee=20=EB=8F=84=EB=A9=94=EC=9D=B8=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 Signed-off-by: danny.197 --- src/main/java/baseball/domain/Referee.java | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/main/java/baseball/domain/Referee.java diff --git a/src/main/java/baseball/domain/Referee.java b/src/main/java/baseball/domain/Referee.java new file mode 100644 index 00000000..070d4303 --- /dev/null +++ b/src/main/java/baseball/domain/Referee.java @@ -0,0 +1,29 @@ +package baseball.domain; + +import java.util.List; +import java.util.Objects; + +public class Referee { + public static Score compare(List computer, List player) { + int strike = 0; + int ball = 0; + + for (int i = 0; i < 3; i++) { + strike += countStrike(computer.get(i), player.get(i)); + ball += countBall(computer, player, i); + } + return new Score(strike, ball); + } + + private static int countStrike(int computerNum, int playerNum) { + if (computerNum == playerNum) return 1; + return 0; + } + + private static int countBall(List computer, List player, int index) { + if (computer.contains(player.get(index)) && !Objects.equals(computer.get(index), player.get(index))) { + return 1; + } + return 0; + } +} \ No newline at end of file From 63c2bb62c872bc504a4e3c4c98ddc0d31e3b89f7 Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 15:14:07 +0900 Subject: [PATCH 07/12] =?UTF-8?q?README=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danny.197 --- README.md | 88 ++++++++++++++++++------------------------------------- 1 file changed, 29 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 3ac79b54..492f39a3 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,43 @@ # java-baseball-precourse +## 기능 목록 +역할과 책임에 따라 **Controller, View, Domain** 세 개의 계층으로 분리되어 있습니다. -## 숫자 야구 게임 기능 목록 +- **Controller (`BaseballController`)** + - 게임의 전체적인 흐름(시작, 재시작, 종료)을 관리합니다. + - 사용자 입력에 따라 View와 Domain 객체 간의 상호작용을 조율합니다. ---- -### 1. 게임 프로세스 관리 +- **View (`InputView`, `OutputView`)** + - 사용자와의 모든 상호작용(콘솔 입출력)을 담당합니다. + - `InputView`: 사용자로부터 입력을 받습니다. + - `OutputView`: 게임 진행 상황, 결과, 오류 메시지 등을 출력합니다. -**게임 시작**: 프로그램 실행 시 게임을 시작함. +- **Domain (`baseball.domain.*`)** -**게임 재시작/종료 선택**: 3스트라이크로 게임 종료 후, '1'(재시작) 또는 '2'(종료)를 입력받아 처리함. + - **`BaseballGame`** + - 한 판의 게임 세션을 관리하며, 게임의 핵심 진행을 책임집니다. + - `Computer`를 내부적으로 생성하여 정답 번호를 가집니다. + - `playRound(Player)`: 플레이어의 추측을 받아 결과를 `Score`로 반환합니다. + + - **`Computer`** + - 서로 다른 1~9 사이의 임의의 수 3개(정답 번호)를 생성합니다. + + - **`Player`** + - 사용자가 입력한 세 자리 숫자를 보유합니다. + - **입력값 검증**: 생성 시점에서 입력값이 3자리의 숫자인지, 중복된 숫자가 없는지 등을 검증하고, 유효하지 않으면 `IllegalArgumentException`을 발생시킵니다. + - **`Referee`** + - `Computer`의 숫자와 `Player`의 숫자를 비교하여 스트라이크와 볼의 개수를 계산하는 정적(static) 유틸리티 메소드를 제공합니다. + - **`Score`** + - 한 라운드의 결과(스트라이크, 볼의 개수)를 저장합니다. + - `isFinished()`: 3스트라이크인지 여부를 판단하여 게임 종료 조건을 캡슐화합니다. + - `toString()`: "1볼 1스트라이크", "낫싱" 등 출력용 문자열로 변환하는 기능을 제공합니다. -**전체 게임 루프**: 사용자가 종료를 선택할 때까지 게임 프로세스를 반복함. + - **`GameStatus`** + - 게임 종료 후 사용자의 선택(재시작/완전 종료) 상태를 관리하는 열거형(Enum)입니다. ---- -### 2. 컴퓨터 (상대방) 기능 - -**정답 숫자 생성**: 1에서 9까지 서로 다른 임의의 수 3개를 선택함. - ---- - -### 3. 사용자 입력 및 유효성 검사 - -**숫자 입력 받기**: 사용자로부터 3자리의 숫자를 입력받음. - - -**예외 처리**: 사용자가 잘못된 값을 입력할 경우 `[ERROR]`로 시작하는 에러 메시지를 출력하고 게임을 계속 진행함. - - -* *예: 숫자가 아닌 경우, 3자리가 아닌 경우, 중복된 숫자가 있는 경우 등* - ---- - -### 4. 게임 판정 로직 (핵심 도메인) - -**숫자 비교**: 컴퓨터의 수와 사용자의 수를 비교하여 힌트(스트라이크, 볼)를 계산함. - - -**스트라이크**: 같은 수가 같은 자리에 있는 경우. - - -**볼**: 같은 수가 다른 자리에 있는 경우. - - -**낫싱(포볼)**: 같은 수가 전혀 없는 경우. - - ---- - - -### 5. 출력 기능 (UI) - -**입력 안내 메시지**: `숫자를 입력해주세요 : ` 메시지 출력. - - -**힌트 결과 출력**: 계산된 스트라이크와 볼의 개수를 출력 (예: `1스트라이크 1볼`, `낫싱`). - - -**게임 종료 메시지**: `3개의 숫자를 모두 맞히셨습니다! [cite_start]게임 끝` 출력. - - - -**재시작 안내 메시지**: `게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.` 출력. - - - ---- From 15435f0a1630f76e5354c8d55b0b28e1370fe127 Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 15:17:15 +0900 Subject: [PATCH 08/12] =?UTF-8?q?BaseballGame=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danny.197 --- src/main/java/baseball/domain/BaseballGame.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/baseball/domain/BaseballGame.java diff --git a/src/main/java/baseball/domain/BaseballGame.java b/src/main/java/baseball/domain/BaseballGame.java new file mode 100644 index 00000000..8d398d56 --- /dev/null +++ b/src/main/java/baseball/domain/BaseballGame.java @@ -0,0 +1,17 @@ +package baseball.domain; + +import java.util.List; + +public class BaseballGame { + private final Computer computer; + + public BaseballGame() { + this.computer = new Computer(); + } + + public Score playRound(Player player) { + List computerNumbers = computer.getNumbers(); + List playerNumbers = player.getNumbers(); + return Referee.compare(computerNumbers, playerNumbers); + } +} From ff9ea5932397ed44cee6f1cf16d710e2bcb591d8 Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 15:17:28 +0900 Subject: [PATCH 09/12] =?UTF-8?q?GameStatus=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danny.197 --- src/main/java/baseball/domain/GameStatus.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/main/java/baseball/domain/GameStatus.java diff --git a/src/main/java/baseball/domain/GameStatus.java b/src/main/java/baseball/domain/GameStatus.java new file mode 100644 index 00000000..47de9d9e --- /dev/null +++ b/src/main/java/baseball/domain/GameStatus.java @@ -0,0 +1,25 @@ +package baseball.domain; + +public enum GameStatus { + RESTART("1"), + EXIT("2"); + + private final String command; + + GameStatus(String command) { + this.command = command; + } + + public static GameStatus from(String input) { + for (GameStatus status : values()) { + if (status.command.equals(input)) { + return status; + } + } + throw new IllegalArgumentException("[ERROR] 1 또는 2만 입력 가능합니다."); + } + + public boolean isRestart() { + return this == RESTART; + } +} \ No newline at end of file From 1574b3606a1c1e7ac869bb29e328d85240b970bd Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 15:17:36 +0900 Subject: [PATCH 10/12] =?UTF-8?q?View=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danny.197 --- src/main/java/baseball/view/InputView.java | 13 +++++++++++++ src/main/java/baseball/view/OutputView.java | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/main/java/baseball/view/InputView.java create mode 100644 src/main/java/baseball/view/OutputView.java diff --git a/src/main/java/baseball/view/InputView.java b/src/main/java/baseball/view/InputView.java new file mode 100644 index 00000000..27c3e64b --- /dev/null +++ b/src/main/java/baseball/view/InputView.java @@ -0,0 +1,13 @@ +package baseball.view; + +import java.util.Scanner; + +public class InputView { + + Scanner scanner = new Scanner(System.in); + + public String readNumbers() { + + return scanner.nextLine(); + } +} diff --git a/src/main/java/baseball/view/OutputView.java b/src/main/java/baseball/view/OutputView.java new file mode 100644 index 00000000..c987f8fa --- /dev/null +++ b/src/main/java/baseball/view/OutputView.java @@ -0,0 +1,21 @@ +package baseball.view; + +public class OutputView { + public void printError(String message) { + System.out.println(message); + } + + public void printInputRequest() { + System.out.print("숫자를 입력해 주세요 : "); + } + + public void printScore(String string) { + System.out.println(string); + } + + public void printGameEnd() { + System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 끝\n" + + "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + + } +} From b7164000e39fae60bb89118cbd611e390cbfadfb Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Thu, 29 Jan 2026 15:17:44 +0900 Subject: [PATCH 11/12] =?UTF-8?q?Controller=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danny.197 --- src/main/java/baseball/Application.java | 12 +++++ .../controller/BaseballController.java | 49 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/main/java/baseball/Application.java create mode 100644 src/main/java/baseball/controller/BaseballController.java diff --git a/src/main/java/baseball/Application.java b/src/main/java/baseball/Application.java new file mode 100644 index 00000000..477ef655 --- /dev/null +++ b/src/main/java/baseball/Application.java @@ -0,0 +1,12 @@ +package baseball; + +import baseball.controller.BaseballController; + +public class Application { + + public static void main(String[] args) { + BaseballController controller = new BaseballController(); + controller.play(); + } + +} diff --git a/src/main/java/baseball/controller/BaseballController.java b/src/main/java/baseball/controller/BaseballController.java new file mode 100644 index 00000000..4b2f51aa --- /dev/null +++ b/src/main/java/baseball/controller/BaseballController.java @@ -0,0 +1,49 @@ +package baseball.controller; + +import baseball.domain.*; +import baseball.view.*; +import baseball.domain.BaseballGame; + +public class BaseballController { + private final InputView inputView = new InputView(); + private final OutputView outputView = new OutputView(); + + public void play() { + do { + runGame(); + } while (isRestartRequested()); + } + + private void runGame() { + BaseballGame game = new BaseballGame(); + Score score; + do { + Player player = enrollPlayer(); + score = game.playRound(player); + outputView.printScore(score.toString()); + } while (!score.isFinished()); + + outputView.printGameEnd(); + } + + private Player enrollPlayer() { + try { + outputView.printInputRequest(); + return new Player(inputView.readNumbers()); + } catch (IllegalArgumentException e) { + outputView.printError(e.getMessage()); + return enrollPlayer(); + } + } + + private boolean isRestartRequested() { + try { + String input = inputView.readNumbers(); + GameStatus status = GameStatus.from(input); + return status.isRestart(); + } catch (IllegalArgumentException e) { + outputView.printError(e.getMessage()); + return isRestartRequested(); + } + } +} From 1af32a35072f45a5e9ad3f7f6b30cd5a86a5f741 Mon Sep 17 00:00:00 2001 From: "danny.197" Date: Mon, 2 Feb 2026 11:59:12 +0900 Subject: [PATCH 12/12] =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=B3=84?= =?UTF-8?q?=20=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danny.197 --- src/test/java/.gitkeep | 0 .../baseball/domain/BaseballGameTest.java | 20 +++++ .../java/baseball/domain/ComputerTest.java | 23 +++++ .../java/baseball/domain/GameStatusTest.java | 53 ++++++++++++ src/test/java/baseball/domain/PlayerTest.java | 54 ++++++++++++ .../java/baseball/domain/RefereeTest.java | 83 +++++++++++++++++++ src/test/java/baseball/domain/ScoreTest.java | 69 +++++++++++++++ 7 files changed, 302 insertions(+) delete mode 100644 src/test/java/.gitkeep create mode 100644 src/test/java/baseball/domain/BaseballGameTest.java create mode 100644 src/test/java/baseball/domain/ComputerTest.java create mode 100644 src/test/java/baseball/domain/GameStatusTest.java create mode 100644 src/test/java/baseball/domain/PlayerTest.java create mode 100644 src/test/java/baseball/domain/RefereeTest.java create mode 100644 src/test/java/baseball/domain/ScoreTest.java diff --git a/src/test/java/.gitkeep b/src/test/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/test/java/baseball/domain/BaseballGameTest.java b/src/test/java/baseball/domain/BaseballGameTest.java new file mode 100644 index 00000000..deedb759 --- /dev/null +++ b/src/test/java/baseball/domain/BaseballGameTest.java @@ -0,0 +1,20 @@ +package baseball.domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class BaseballGameTest { + + @Test + @DisplayName("playRound는 플레이어의 숫자를 기반으로 정확한 Score를 반환해야 한다.") + void playRoundShouldReturnCorrectScore() { + BaseballGame game = new BaseballGame(); + Player player = new Player("123"); + + Score score = game.playRound(player); + + assertThat(score).isNotNull(); + } +} diff --git a/src/test/java/baseball/domain/ComputerTest.java b/src/test/java/baseball/domain/ComputerTest.java new file mode 100644 index 00000000..2859905c --- /dev/null +++ b/src/test/java/baseball/domain/ComputerTest.java @@ -0,0 +1,23 @@ +package baseball.domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ComputerTest { + + @RepeatedTest(100) + @DisplayName("컴퓨터는 3자리의 중복되지 않는 숫자를 생성한다.") + void createComputerShouldGenerateThreeUniqueNumbers() { + + Computer computer = new Computer(); + List numbers = computer.getNumbers(); + + assertThat(numbers).hasSize(3); + assertThat(numbers).doesNotHaveDuplicates(); + } +} diff --git a/src/test/java/baseball/domain/GameStatusTest.java b/src/test/java/baseball/domain/GameStatusTest.java new file mode 100644 index 00000000..0ac2708d --- /dev/null +++ b/src/test/java/baseball/domain/GameStatusTest.java @@ -0,0 +1,53 @@ +package baseball.domain; + +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 static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class GameStatusTest { + + @Test + @DisplayName("'1' 입력 시 RESTART 상태를 반환한다.") + void fromWithOneShouldReturnRestart() { + GameStatus status = GameStatus.from("1"); + + assertThat(status).isEqualTo(GameStatus.RESTART); + } + + @Test + @DisplayName("'2' 입력 시 EXIT 상태를 반환한다.") + void fromWithTwoShouldReturnExit() { + GameStatus status = GameStatus.from("2"); + + assertThat(status).isEqualTo(GameStatus.EXIT); + } + + @ParameterizedTest + @ValueSource(strings = {"3", "a", "12"}) + @DisplayName("'1' 또는 '2'가 아닌 입력 시 예외가 발생한다.") + void fromWithInvalidInputShouldThrowException(String input) { + assertThatThrownBy(() -> GameStatus.from(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 1 또는 2만 입력 가능합니다."); + } + + @Test + @DisplayName("RESTART 상태는 isRestart() 호출 시 true를 반환한다.") + void isRestartForRestartStatusShouldReturnTrue() { + GameStatus status = GameStatus.RESTART; + + assertThat(status.isRestart()).isTrue(); + } + + @Test + @DisplayName("EXIT 상태는 isRestart() 호출 시 false를 반환한다.") + void isRestartForExitStatusShouldReturnFalse() { + GameStatus status = GameStatus.EXIT; + + assertThat(status.isRestart()).isFalse(); + } +} diff --git a/src/test/java/baseball/domain/PlayerTest.java b/src/test/java/baseball/domain/PlayerTest.java new file mode 100644 index 00000000..fc8abdce --- /dev/null +++ b/src/test/java/baseball/domain/PlayerTest.java @@ -0,0 +1,54 @@ +package baseball.domain; + +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.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class PlayerTest { + + @Test + @DisplayName("플레이어는 3자리의 유효한 숫자로 생성된다.") + void createPlayerSuccess() { + String input = "123"; + + Player player = new Player(input); + List numbers = player.getNumbers(); + + assertThat(numbers).containsExactly(1, 2, 3); + } + + @ParameterizedTest + @ValueSource(strings = {"12", "1234", "abc"}) + @DisplayName("플레이어 생성 시 3자리의 1-9 숫자가 아니면 예외가 발생한다.") + void createPlayerWithInvalidFormatShouldThrowException(String input) { + assertThatThrownBy(() -> new Player(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 1-9 사이의 숫자 3개를 입력해야 합니다."); + } + + @Test + @DisplayName("플레이어 생성 시 중복된 숫자가 있으면 예외가 발생한다.") + void createPlayerWithDuplicateNumbersShouldThrowException() { + String input = "112"; + + assertThatThrownBy(() -> new Player(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 중복된 숫자가 있습니다."); + } + + @Test + @DisplayName("플레이어 생성 시 0이 포함되어 있으면 예외가 발생한다.") + void createPlayerWithZeroShouldThrowException() { + String input = "102"; + + assertThatThrownBy(() -> new Player(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("[ERROR] 1-9 사이의 숫자 3개를 입력해야 합니다."); + } +} diff --git a/src/test/java/baseball/domain/RefereeTest.java b/src/test/java/baseball/domain/RefereeTest.java new file mode 100644 index 00000000..fa720eb6 --- /dev/null +++ b/src/test/java/baseball/domain/RefereeTest.java @@ -0,0 +1,83 @@ +package baseball.domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class RefereeTest { + + @Test + @DisplayName("3스트라이크를 정확히 판정한다.") + void compare3Strikes() { + List computer = List.of(1, 2, 3); + List player = List.of(1, 2, 3); + + Score score = Referee.compare(computer, player); + + assertThat(score.getStrike()).isEqualTo(3); + assertThat(score.toString()).isEqualTo("3스트라이크"); + } + + @Test + @DisplayName("1스트라이크 2볼을 정확히 판정한다.") + void compare1Strike2Balls() { + List computer = List.of(1, 2, 3); + List player = List.of(1, 3, 2); + + Score score = Referee.compare(computer, player); + + assertThat(score.getStrike()).isEqualTo(1); + assertThat(score.toString()).isEqualTo("2볼 1스트라이크"); + } + + @Test + @DisplayName("3볼을 정확히 판정한다.") + void compare3Balls() { + List computer = List.of(1, 2, 3); + List player = List.of(3, 1, 2); + + Score score = Referee.compare(computer, player); + + assertThat(score.getStrike()).isEqualTo(0); + assertThat(score.toString()).isEqualTo("3볼"); + } + + @Test + @DisplayName("낫싱을 정확히 판정한다.") + void compareNothing() { + List computer = List.of(1, 2, 3); + List player = List.of(4, 5, 6); + + Score score = Referee.compare(computer, player); + + assertThat(score.getStrike()).isEqualTo(0); + assertThat(score.toString()).isEqualTo("낫싱"); + } + + @Test + @DisplayName("1스트라이크를 정확히 판정한다.") + void compare1Strike() { + List computer = List.of(1, 2, 3); + List player = List.of(1, 4, 5); + + Score score = Referee.compare(computer, player); + + assertThat(score.getStrike()).isEqualTo(1); + assertThat(score.toString()).isEqualTo("1스트라이크"); + } + + @Test + @DisplayName("1볼을 정확히 판정한다.") + void compare1Ball() { + List computer = List.of(1, 2, 3); + List player = List.of(4, 1, 5); + + Score score = Referee.compare(computer, player); + + assertThat(score.getStrike()).isEqualTo(0); + assertThat(score.toString()).isEqualTo("1볼"); + } +} diff --git a/src/test/java/baseball/domain/ScoreTest.java b/src/test/java/baseball/domain/ScoreTest.java new file mode 100644 index 00000000..fa050b7b --- /dev/null +++ b/src/test/java/baseball/domain/ScoreTest.java @@ -0,0 +1,69 @@ +package baseball.domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ScoreTest { + + @Test + @DisplayName("스트라이크와 볼이 모두 있을 때, 'n볼 m스트라이크' 형식으로 반환한다.") + void toStringWithStrikesAndBalls() { + Score score = new Score(1, 2); + + String result = score.toString(); + + assertThat(result).isEqualTo("2볼 1스트라이크"); + } + + @Test + @DisplayName("스트라이크만 있을 때, 'n스트라이크' 형식으로 반환한다.") + void toStringWithOnlyStrikes() { + Score score = new Score(2, 0); + + String result = score.toString(); + + assertThat(result).isEqualTo("2스트라이크"); + } + + @Test + @DisplayName("볼만 있을 때, 'n볼' 형식으로 반환한다.") + void toStringWithOnlyBalls() { + Score score = new Score(0, 2); + + String result = score.toString(); + + assertThat(result).isEqualTo("2볼"); + } + + @Test + @DisplayName("스트라이크와 볼이 모두 없을 때, '낫싱'을 반환한다.") + void toStringWithNothing() { + Score score = new Score(0, 0); + + String result = score.toString(); + + assertThat(result).isEqualTo("낫싱"); + } + + @Test + @DisplayName("3스트라이크일 때 isFinished는 true를 반환한다.") + void isFinishedWhen3StrikesShouldReturnTrue() { + Score score = new Score(3, 0); + + boolean finished = score.isFinished(); + + assertThat(finished).isTrue(); + } + + @Test + @DisplayName("3스트라이크가 아닐 때 isFinished는 false를 반환한다.") + void isFinishedWhenNot3StrikesShouldReturnFalse() { + Score score = new Score(2, 1); + + boolean finished = score.isFinished(); + + assertThat(finished).isFalse(); + } +}