diff --git a/README.md b/README.md
index e7af80b4ff..df56327130 100644
--- a/README.md
+++ b/README.md
@@ -139,6 +139,6 @@ while (computer.size() < 3) {
## ✏️ 과제 진행 요구 사항
-- 미션은 [java-baseball-6](https://github.com/woowacourse-precourse/java-baseball-6) 저장소를 Fork & Clone해 시작한다.
+- 미션은 [java-baseball_oop-6](https://github.com/woowacourse-precourse/java-baseball-6) 저장소를 Fork & Clone해 시작한다.
- **기능을 구현하기 전 `docs/README.md`에 구현할 기능 목록을 정리**해 추가한다.
- 과제 진행 및 제출 방법은 [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서를 참고한다.
diff --git a/build.gradle b/build.gradle
index 080ed8c12e..76352c0838 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,6 +12,7 @@ repositories {
dependencies {
implementation 'com.github.woowacourse-projects:mission-utils:1.1.0'
+ implementation 'org.projectlombok:lombok:1.18.22'
}
java {
diff --git a/docs/README.md b/docs/README.md
index e69de29bb2..f7f7291b69 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -0,0 +1,48 @@
+# 요구사항 분석
+- 컴퓨터가 수를 선택한다.
+ - 수는 3자리 숫자이고, 랜덤으로 정해진다.
+- 정답을 맞출 때 까지 반복한다.
+- 컴퓨터는 입력한 숫자에 대한 결과를 출력한다.
+- 컴퓨터수와 사용자의 수를 비교해 위치는 틀리지만 수가 맞으면 볼을 출력
+- 컴퓨터수와 사용자의 수를 비교해 위치도 맞고 수가 맞으면 스트라이크를 출력
+- 컴퓨터수와 사용자의 수를 비교해 위치도, 수도 맞은게 없다면 낫싱을 출력
+- 사용자가 수를 입력할 수 있다.
+- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생 후 종료
+- 컴퓨터의 수를 맞추면 게임 종료. 종료 후 한번 더 할지, 끝낼지 입력받는다.
+
+# 역할을 나눈다.
+
+## 답을 생성하는 역할
+- 컴퓨터가 수를 선택한다.
+ - 수는 서로 다른 3자리 숫자이고, 랜덤으로 정해진다.
+
+## 정답을 입력을 할 수 있는 역할
+- 사용자가 수를 입력할 수 있다.
+ - 수는 서로 다른 3자리 숫자이다. (검증필요)
+- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생 후 종료
+
+## 정답이 맞는지 판단하고 힌트를 주는 역할
+- 컴퓨터수와 사용자의 수를 비교해 위치는 틀리지만 수가 맞으면 볼을 출력
+- 컴퓨터수와 사용자의 수를 비교해 위치도 맞고 수가 맞으면 스트라이크를 출력
+- 컴퓨터수와 사용자의 수를 비교해 위치도, 수도 맞은게 없다면 낫싱을 출력
+
+## 게임을 제어하는 역할
+- 정답을 맞출 때 까지 반복한다.
+- 정답을 맞추면 게임 종료.
+ - 게임을 종료 후 한번 더 할지, 끝낼지 입력받는다.
+
+# 도메인 설계 및 기능 목록
+
+## BaseBallGame
+- 게임을 제어하는 역할
+
+## Hitter
+- 답을 생성하는 역할
+ (왜 컴퓨터가 Hitter냐? 플레이어가 포수에게 주는 볼을 잡아서 스트라이크를 면해야되기 때문에 타자입니다.)
+## Pitcher
+- 정답을 입력을 할 수 있는 역할
+ (왜 플레이어가 Pitcher냐? 3스트라이크 즉, 3번 타자가 못치게끔 포수에게 잘 던져줘야 하기 때문에 투수입니다.)
+
+## Umpire
+- 정답이 맞는지 판단하고 힌트를 주는 역할
+
diff --git "a/docs/\353\217\204\353\251\224\354\235\270\354\204\244\352\263\204.drawio" "b/docs/\353\217\204\353\251\224\354\235\270\354\204\244\352\263\204.drawio"
new file mode 100644
index 0000000000..9c24293507
--- /dev/null
+++ "b/docs/\353\217\204\353\251\224\354\235\270\354\204\244\352\263\204.drawio"
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/main/java/baseball/Application.java b/src/main/java/baseball/Application.java
deleted file mode 100644
index dd95a34214..0000000000
--- a/src/main/java/baseball/Application.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package baseball;
-
-public class Application {
- public static void main(String[] args) {
- // TODO: 프로그램 구현
- }
-}
diff --git a/src/main/java/baseball_oop/Application.java b/src/main/java/baseball_oop/Application.java
new file mode 100644
index 0000000000..0954a25088
--- /dev/null
+++ b/src/main/java/baseball_oop/Application.java
@@ -0,0 +1,19 @@
+package baseball_oop;
+
+import baseball_oop.domain.game.BaseBallGame;
+import baseball_oop.domain.game.Game;
+import baseball_oop.domain.participant.computer.Hitter;
+import baseball_oop.domain.participant.player.Pitcher;
+import baseball_oop.domain.participant.judgment.Umpire;
+
+public class Application {
+
+ public static void main(String[] args) {
+ Game game = new BaseBallGame(
+ new Hitter(),
+ new Pitcher(),
+ new Umpire()
+ );
+ game.start();
+ }
+}
diff --git a/src/main/java/baseball_oop/domain/game/BaseBallGame.java b/src/main/java/baseball_oop/domain/game/BaseBallGame.java
new file mode 100644
index 0000000000..923e66d78b
--- /dev/null
+++ b/src/main/java/baseball_oop/domain/game/BaseBallGame.java
@@ -0,0 +1,114 @@
+package baseball_oop.domain.game;
+
+import baseball_oop.enums.ReplayOrNot;
+import baseball_oop.vo.Answer;
+import baseball_oop.domain.participant.computer.Computer;
+import baseball_oop.domain.participant.judgment.Judgment;
+import baseball_oop.domain.participant.player.Player;
+import baseball_oop.vo.Result;
+
+import static camp.nextstep.edu.missionutils.Console.readLine;
+
+public class BaseBallGame implements Game {
+ private final Computer computer;
+ private final Judgment judgment;
+ private final Player player;
+
+ public BaseBallGame(Computer computer, Player player, Judgment judgment) {
+ this.computer = computer;
+ this.judgment = judgment;
+ this.player = player;
+ }
+ @Override
+ public void start() {
+ String command;
+ PrintMessage.printGameStart();
+ do {
+ play();
+ } while (askReplay());
+ }
+
+ private void play() {
+ Answer answer = computer.generateAnswer();
+ Answer input;
+ Result result = null;
+ while (!gameEnd(result)) {
+ input = selectInputToPlayer();
+ printHint(result = judgment.judge(answer, input));
+ }
+ }
+
+ private static boolean askReplay() {
+ PrintMessage.printGameReplayOrNot();
+ return readLine().equals(ReplayOrNot.REPLAY.getCode());
+ }
+
+ private static boolean gameEnd(Result result) {
+ if (result == null) {
+ return false;
+ }
+
+ boolean isEnd = result.isWin();
+ if (isEnd) {
+ PrintMessage.printWinAndEnd();
+ }
+ return isEnd;
+ }
+
+ private Answer selectInputToPlayer() {
+ PrintMessage.printRequestInputNumber();
+ return player.generateAnswer();
+ }
+
+ private void printHint(Result result) { // TODO 코드리팩토링 필요
+ if (result == null) {
+ return;
+ }
+ int strikeCount = result.getStrikeCount();
+ int ballCount = result.getBallCount();
+
+ if (result.getBallCount() == 0 && result.getStrikeCount() == 0) {
+ PrintMessage.printResultNothing();
+ return;
+ }
+ if (strikeCount != 0 && ballCount == 0) {
+ PrintMessage.printMessage(strikeCount + PrintMessage.STRIKE);
+ }
+ if (strikeCount == 0 && ballCount != 0) {
+ PrintMessage.printMessage(ballCount + PrintMessage.BALL);
+ }
+ if (strikeCount != 0 && ballCount != 0) {
+ PrintMessage.printMessage(ballCount + PrintMessage.BALL + " " + strikeCount + PrintMessage.STRIKE);
+ }
+ }
+
+ private static class PrintMessage {
+ private final static String START = "숫자 야구 게임을 시작합니다.";
+ private final static String INPUT_NUMBER = "숫자를 입력해주세요 : ";
+ private final static String WIN = "3개의 숫자를 모두 맞히셨습니다! 게임 종료";
+ private final static String PLAY_NEXT_GAME_OR_NOT = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.";
+ private final static String NOTHING = "낫싱";
+ private final static String BALL = "볼";
+ private final static String STRIKE = "스트라이크";
+ public static void printRequestInputNumber() {
+ System.out.print(INPUT_NUMBER);
+ }
+ public static void printGameStart() {
+ System.out.println(START);
+ }
+ public static void printWinAndEnd() {
+ System.out.println(WIN);
+ }
+ public static void printGameReplayOrNot() {
+ System.out.println(PLAY_NEXT_GAME_OR_NOT);
+ }
+
+ public static void printResultNothing() {
+ System.out.println(NOTHING);
+ }
+
+ public static void printMessage(String message) {
+ System.out.println(message);
+ }
+ }
+}
diff --git a/src/main/java/baseball_oop/domain/game/Game.java b/src/main/java/baseball_oop/domain/game/Game.java
new file mode 100644
index 0000000000..2309d09612
--- /dev/null
+++ b/src/main/java/baseball_oop/domain/game/Game.java
@@ -0,0 +1,5 @@
+package baseball_oop.domain.game;
+
+public interface Game {
+ void start();
+}
diff --git a/src/main/java/baseball_oop/domain/participant/AnswerGeneratable.java b/src/main/java/baseball_oop/domain/participant/AnswerGeneratable.java
new file mode 100644
index 0000000000..67da4a6a66
--- /dev/null
+++ b/src/main/java/baseball_oop/domain/participant/AnswerGeneratable.java
@@ -0,0 +1,7 @@
+package baseball_oop.domain.participant;
+
+import baseball_oop.vo.Answer;
+
+public interface AnswerGeneratable {
+ Answer generateAnswer();
+}
diff --git a/src/main/java/baseball_oop/domain/participant/computer/Computer.java b/src/main/java/baseball_oop/domain/participant/computer/Computer.java
new file mode 100644
index 0000000000..4040ace6f3
--- /dev/null
+++ b/src/main/java/baseball_oop/domain/participant/computer/Computer.java
@@ -0,0 +1,6 @@
+package baseball_oop.domain.participant.computer;
+
+import baseball_oop.domain.participant.AnswerGeneratable;
+
+public interface Computer extends AnswerGeneratable {
+}
diff --git a/src/main/java/baseball_oop/domain/participant/computer/Hitter.java b/src/main/java/baseball_oop/domain/participant/computer/Hitter.java
new file mode 100644
index 0000000000..d24cf23efa
--- /dev/null
+++ b/src/main/java/baseball_oop/domain/participant/computer/Hitter.java
@@ -0,0 +1,11 @@
+package baseball_oop.domain.participant.computer;
+
+import baseball_oop.vo.Answer;
+
+public class Hitter implements Computer {
+
+ @Override
+ public Answer generateAnswer() {
+ return new Answer();
+ }
+}
diff --git a/src/main/java/baseball_oop/domain/participant/judgment/Judgment.java b/src/main/java/baseball_oop/domain/participant/judgment/Judgment.java
new file mode 100644
index 0000000000..79d4eb887c
--- /dev/null
+++ b/src/main/java/baseball_oop/domain/participant/judgment/Judgment.java
@@ -0,0 +1,8 @@
+package baseball_oop.domain.participant.judgment;
+
+import baseball_oop.vo.Answer;
+import baseball_oop.vo.Result;
+
+public interface Judgment {
+ Result judge(Answer answer, Answer input);
+}
diff --git a/src/main/java/baseball_oop/domain/participant/judgment/Umpire.java b/src/main/java/baseball_oop/domain/participant/judgment/Umpire.java
new file mode 100644
index 0000000000..32a6295396
--- /dev/null
+++ b/src/main/java/baseball_oop/domain/participant/judgment/Umpire.java
@@ -0,0 +1,15 @@
+package baseball_oop.domain.participant.judgment;
+
+import baseball_oop.vo.Answer;
+import baseball_oop.vo.Result;
+
+public class Umpire implements Judgment {
+ @Override
+ public Result judge(Answer answer, Answer input) {
+ int strikeCount = Answer.countSameElementAndPosition(answer.getValues(), input.getValues());
+ int ballCount = Answer.countContainElement(answer.getValues(), input.getValues()) - strikeCount;
+
+ return new Result(strikeCount, ballCount);
+ }
+
+}
diff --git a/src/main/java/baseball_oop/domain/participant/player/Pitcher.java b/src/main/java/baseball_oop/domain/participant/player/Pitcher.java
new file mode 100644
index 0000000000..05038e9169
--- /dev/null
+++ b/src/main/java/baseball_oop/domain/participant/player/Pitcher.java
@@ -0,0 +1,10 @@
+package baseball_oop.domain.participant.player;
+
+import baseball_oop.vo.Answer;
+import static camp.nextstep.edu.missionutils.Console.readLine;
+public class Pitcher implements Player {
+ @Override
+ public Answer generateAnswer() {
+ return new Answer(readLine());
+ }
+}
diff --git a/src/main/java/baseball_oop/domain/participant/player/Player.java b/src/main/java/baseball_oop/domain/participant/player/Player.java
new file mode 100644
index 0000000000..4e7de6ab38
--- /dev/null
+++ b/src/main/java/baseball_oop/domain/participant/player/Player.java
@@ -0,0 +1,7 @@
+package baseball_oop.domain.participant.player;
+
+import baseball_oop.domain.participant.AnswerGeneratable;
+
+public interface Player extends AnswerGeneratable {
+
+}
diff --git a/src/main/java/baseball_oop/enums/ExceptionMessage.java b/src/main/java/baseball_oop/enums/ExceptionMessage.java
new file mode 100644
index 0000000000..c768746fe8
--- /dev/null
+++ b/src/main/java/baseball_oop/enums/ExceptionMessage.java
@@ -0,0 +1,17 @@
+package baseball_oop.enums;
+
+public enum ExceptionMessage {
+ WRONG_INPUT_DEFAULT("잘못된 입력입니다."),
+ WRONG_INPUT_NOT_THREE_DIGITS("3자리만 입력 할 수 있습니다."),
+ WRONG_INPUT_NOT_NUMBER("숫자가 아닙니다."),
+ WRONG_INPUT_DUPLICATE_VALUE("숫자가 중복되어 있습니다.");
+ String message;
+
+ ExceptionMessage(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/src/main/java/baseball_oop/enums/ReplayOrNot.java b/src/main/java/baseball_oop/enums/ReplayOrNot.java
new file mode 100644
index 0000000000..028d268888
--- /dev/null
+++ b/src/main/java/baseball_oop/enums/ReplayOrNot.java
@@ -0,0 +1,16 @@
+package baseball_oop.enums;
+
+public enum ReplayOrNot {
+ REPLAY("1"),
+ END("2");
+
+ public final String code;
+
+ ReplayOrNot(String code) {
+ this.code = code;
+ }
+
+ public String getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/baseball_oop/vo/Answer.java b/src/main/java/baseball_oop/vo/Answer.java
new file mode 100644
index 0000000000..3623101b49
--- /dev/null
+++ b/src/main/java/baseball_oop/vo/Answer.java
@@ -0,0 +1,97 @@
+package baseball_oop.vo;
+
+import baseball_oop.enums.ExceptionMessage;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static camp.nextstep.edu.missionutils.Randoms.pickNumberInRange;
+
+public class Answer {
+ List values = new ArrayList<>();
+ private final static int LENGTH_LIMIT = 3;
+
+ public Answer() {
+ Set set = new HashSet<>();
+ while (set.size() < LENGTH_LIMIT) {
+ set.add(pickNumberInRange(1, 9));
+ }
+ this.values = set.stream().toList();
+ }
+
+
+ public Answer(String input) {
+ checkValidation(input);
+ this.values = Arrays.stream(input.split(""))
+ .map(Integer::parseInt)
+ .collect(Collectors.toList());
+ }
+
+ private static void checkValidation(String value) {
+ checkLength(value);
+ checkDuplicate(value);
+ checkNumber(value);
+ }
+
+ private static void checkDuplicate(String value) {
+ if (hasDuplicate(value)) {
+ throw new IllegalArgumentException(ExceptionMessage.WRONG_INPUT_DUPLICATE_VALUE.getMessage());
+ }
+ }
+
+ private static void checkLength(String value) {
+ if (!isLimitedLength(value)) {
+ throw new IllegalArgumentException(ExceptionMessage.WRONG_INPUT_NOT_THREE_DIGITS.getMessage());
+ }
+ }
+
+ private static void checkNumber(String value) {
+ if (!isNumber(value)) {
+ throw new IllegalArgumentException(ExceptionMessage.WRONG_INPUT_NOT_NUMBER.getMessage());
+ }
+ }
+
+ private static boolean isLimitedLength(String value) {
+ return value.length() == LENGTH_LIMIT;
+ }
+
+ private static boolean hasDuplicate(String value) {
+ Set set = new HashSet<>();
+ for (String str : value.split("")) {
+ set.add(str);
+ }
+ return set.size() != value.length();
+ }
+
+ private static boolean isNumber(String value) {
+ return value != null && value.matches("[-+]?\\d*\\.?\\d+");
+ }
+
+ public static int countSameElementAndPosition(List answerValues, List inputValues) {
+ int count = 0;
+ int index = 0;
+ for (Integer value : answerValues) {
+ if (value.equals(inputValues.get(index))) {
+ count++;
+ }
+ index++;
+ }
+ return count;
+ }
+
+ public static int countContainElement(List answerValues, List inputValues) {
+ int count = 0;
+ int index = 0;
+ for (Integer value : answerValues) {
+ if (inputValues.contains(value)) {
+ count++;
+ }
+ index++;
+ }
+ return count;
+ }
+
+ public List getValues() {
+ return this.values;
+ }
+}
diff --git a/src/main/java/baseball_oop/vo/Result.java b/src/main/java/baseball_oop/vo/Result.java
new file mode 100644
index 0000000000..f6673e0803
--- /dev/null
+++ b/src/main/java/baseball_oop/vo/Result.java
@@ -0,0 +1,26 @@
+package baseball_oop.vo;
+
+public class Result {
+ private int strikeCount;
+ private int ballCount;
+
+ private final int LENGTH_LIMIT = 3;
+
+
+ public Result(int strikeCount, int ballCount) {
+ this.strikeCount = strikeCount;
+ this.ballCount = ballCount;
+ }
+
+ public boolean isWin() {
+ return this.strikeCount == LENGTH_LIMIT;
+ }
+
+ public int getStrikeCount() {
+ return strikeCount;
+ }
+
+ public int getBallCount() {
+ return ballCount;
+ }
+}
diff --git a/src/test/java/baseball/ApplicationTest.java b/src/test/java/baseball_oop/ApplicationTest.java
similarity index 87%
rename from src/test/java/baseball/ApplicationTest.java
rename to src/test/java/baseball_oop/ApplicationTest.java
index 3fa29fa67b..a044acc8fc 100644
--- a/src/test/java/baseball/ApplicationTest.java
+++ b/src/test/java/baseball_oop/ApplicationTest.java
@@ -1,4 +1,4 @@
-package baseball;
+package baseball_oop;
import camp.nextstep.edu.missionutils.test.NsTest;
import org.junit.jupiter.api.Test;
@@ -14,7 +14,7 @@ class ApplicationTest extends NsTest {
assertRandomNumberInRangeTest(
() -> {
run("246", "135", "1", "597", "589", "2");
- assertThat(output()).contains("낫싱", "3스트라이크", "1볼 1스트라이크", "3스트라이크", "게임 종료");
+ assertThat(output()).contains("낫싱", "3스트라이크", "1볼 1스트라이크", "3스트라이크", "3개의 숫자를 모두 맞히셨습니다! 게임 종료");
},
1, 3, 5, 5, 8, 9
);