diff --git a/README.md b/README.md
index 1bee39036..f9925dd6a 100644
--- a/README.md
+++ b/README.md
@@ -1,130 +1,18 @@
-# 미션 - 숫자 야구 게임
+# 🖋구현할 기능 목록
-## 🔍 진행방식
+1. 컴퓨터가 1에서 9까지 서로 다른 임의의 3자리의 난수를 생성한다.
-- 미션은 **기능 요구사항, 프로그래밍 요구사항, 과제 진행 요구사항** 세 가지로 구성되어 있다.
-- 세 개의 요구사항을 만족하기 위해 노력한다. 특히 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행한다.
+2. 사용자는 컴퓨터가 생각하고 있는 3자리의 수를 입력한다.
+3. 입력값이 3자리의 수가 아니거나 숫자가 아닐 경우 예외 처리를 한다.
-## ✉️ 미션 제출 방법
+4. 입력된 수와 컴퓨터가 생성한 난수를 비교하여 `볼`, `스트라이크`, `낫싱` 여부를 계산한다.
+ - 같은 수가 같은 자리에 있으면 `스트라이크`
+ - 같은 수가 다른 자리에 있으면 `볼`
+ - 같은 수가 전혀 없으면 `낫싱`
-- 미션 구현을 완료한 후 GitHub을 통해 제출해야 한다.
- - GitHub을 활용한 제출 방법은 [프리코스 과제 제출 문서](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 를 참고해 제출한다.
-- GitHub에 미션을 제출한 후 [우아한테크코스 지원 플랫폼](https://apply.techcourse.co.kr) 에 접속하여 프리코스 과제를 제출한다.
- - 자세한 방법은 [링크](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse#제출-가이드) 를 참고한다.
- - **Pull Request만 보내고, 지원 플랫폼에서 과제를 제출하지 않으면 최종 제출하지 않은 것으로 처리되니 주의한다.**
+5. 비교한 결과를 출력한다.
+6. `3스트라이크`인 경우 게임 종료를 알리고, 게임 재시작 여부를 묻고 입력받는다.
+ - 1을 입력하면 게임 재시작
+ - 2를 입력하면 게임 종료
-## ✔️ 과제 제출 전 체크리스트 - 0점 방지
-
-- 터미널에서 `java -version`을 실행해 자바 8인지 확인한다. 또는 Eclipse, IntelliJ IDEA와 같은 IDE의 자바 8로 실행하는지 확인한다.
-- 터미널에서 맥 또는 리눅스 사용자의 경우 `./gradlew clean test`, 윈도우 사용자의 경우 `gradlew.bat clean test` 명령을 실행했을 때 모든 테스트가 통과하는지 확인한다.
-
----
-
-## 🚀 기능 요구사항
-
-기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다.
-
-- 같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 같은 수가 전혀 없으면 포볼 또는 낫싱이란 힌트를 얻고, 그 힌트를 이용해서 먼저 상대방(컴퓨터)의 수를 맞추면 승리한다.
- - 예) 상대방(컴퓨터)의 수가 425일 때
- - 123을 제시한 경우 : 1스트라이크
- - 456을 제시한 경우 : 1볼 1스트라이크
- - 789를 제시한 경우 : 낫싱
-- 위 숫자 야구 게임에서 상대방의 역할을 컴퓨터가 한다. 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게임 플레이어는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과를 출력한다.
-- 이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다.
-- 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다.
-- 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료되어야 한다.
-- 아래의 프로그래밍 실행 결과 예시와 동일하게 입력과 출력이 이루어져야 한다.
-
-
-
-## ✍🏻 입출력 요구사항
-
-### ⌨️ 입력
-
-- 3자리의 수
-- 게임이 끝난 경우 재시작/종료를 구분하는 1과 2 중 하나의 수
-
-### 🖥 출력
-
-- 입력한 수에 대한 결과를 볼, 스트라이크 개수로 표시
-
-```
-1볼 1스트라이크
-```
-
-- 하나도 없는 경우
-
-```
-낫싱
-```
-
-- 3개의 숫자를 모두 맞힐 경우
-
-```
-3스트라이크
-3개의 숫자를 모두 맞히셨습니다! 게임 종료
-```
-
-### 💻 프로그래밍 실행 결과 예시
-
-```
-숫자를 입력해주세요 : 123
-1볼 1스트라이크
-숫자를 입력해주세요 : 145
-1볼
-숫자를 입력해주세요 : 671
-2볼
-숫자를 입력해주세요 : 216
-1스트라이크
-숫자를 입력해주세요 : 713
-3스트라이크
-3개의 숫자를 모두 맞히셨습니다! 게임 종료
-게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.
-1
-숫자를 입력해주세요 : 123
-1볼
-…
-```
-
-
-
----
-
-## 🎱 프로그래밍 요구사항
-
-- 프로그램을 실행하는 시작점은 `Application`의 `main()`이다.
-- JDK 8 버전에서 실행 가능해야 한다. **JDK 8에서 정상 동작하지 않을 경우 0점 처리**한다.
-- 자바 코드 컨벤션을 지키면서 프로그래밍한다.
- - https://naver.github.io/hackday-conventions-java
-- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
- - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
- - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.
-- 3항 연산자를 쓰지 않는다.
-- 함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라.
-
-### 프로그래밍 요구사항 - Randoms, Console
-
-- JDK에서 기본 제공하는 Random, Scanner API 대신 `camp.nextstep.edu.missionutils`에서 제공하는 `Randoms`, `Console` API를 활용해 구현해야 한다.
- - Random 값 추출은 `camp.nextstep.edu.missionutils.Randoms`의 `pickNumberInRange()`를 활용한다.
- - 사용자가 입력하는 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용한다.
-- 프로그램 구현을 완료했을 때 `src/test/java` 디렉터리의 `ApplicationTest`에 있는 모든 테스트 케이스가 성공해야 한다. **테스트가 실패할 경우 0점 처리한다.**
-
-
-
----
-
-## 📈 과제 진행 요구사항
-
-- 미션은 [java-baseball-precourse](https://github.com/woowacourse/java-baseball-precourse) 저장소를 Fork/Clone해 시작한다.
-- **기능을 구현하기 전에 java-baseball-precourse/README.md 파일에 구현할 기능 목록을 정리**해 추가한다.
-- **Git의 커밋 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위**로 추가한다.
- - [AngularJS Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 참고해 commit log를 남긴다.
-- 과제 진행 및 제출 방법은 [프리코스 과제 제출 문서](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 를 참고한다.
-
-
-
----
-
-## 📝 License
-
-This project is [MIT](https://github.com/woowacourse/java-baseball-precourse/blob/master/LICENSE) licensed.
+7. 사용자가 잘못된 값을 입력한 경우 `IllegalArgumentException`을 발생시키고 애플리케이션을 종료한다.
\ No newline at end of file
diff --git a/src/main/java/baseball/Application.java b/src/main/java/baseball/Application.java
index 7f1901b8b..45bbd0c26 100644
--- a/src/main/java/baseball/Application.java
+++ b/src/main/java/baseball/Application.java
@@ -1,7 +1,8 @@
package baseball;
public class Application {
- public static void main(String[] args) {
- //TODO: 숫자 야구 게임 구현
- }
+ public static void main(String[] args) {
+ BaseballGame baseballGame = new BaseballGame();
+ baseballGame.play();
+ }
}
diff --git a/src/main/java/baseball/BaseballGame.java b/src/main/java/baseball/BaseballGame.java
new file mode 100644
index 000000000..9ce184a0d
--- /dev/null
+++ b/src/main/java/baseball/BaseballGame.java
@@ -0,0 +1,34 @@
+package baseball;
+
+public class BaseballGame {
+ private final Computer computer;
+ private final Player player;
+ private final CompareNumbers compareNumbers;
+
+ public BaseballGame() {
+ computer = new Computer();
+ player = new Player();
+ compareNumbers = new CompareNumbers();
+ }
+
+ public void play() {
+ boolean continuePlaying = true;
+
+ while (continuePlaying) {
+ compareNumbers.compareNumbers(player, computer);
+
+ if (compareNumbers.isGameOver()) {
+ System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");
+ String replayInput = player.inputReplay();
+
+ if ("1".equals(replayInput)) {
+ // 게임 재시작
+ computer.resetRandomNumberList(); // 새로운 난수 생성
+ } else if ("2".equals(replayInput)) {
+ // 게임 종료
+ continuePlaying = false;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/baseball/CompareNumbers.java b/src/main/java/baseball/CompareNumbers.java
new file mode 100644
index 000000000..7462784e4
--- /dev/null
+++ b/src/main/java/baseball/CompareNumbers.java
@@ -0,0 +1,67 @@
+package baseball;
+
+import java.util.List;
+
+public class CompareNumbers {
+ private boolean gameOver;
+
+ public void compareNumbers(Player player, Computer computer) {
+ List randomNumberList = computer.getRandomNumberList();
+ player.playerInputNumber(); // 플레이어가 숫자를 입력
+ List playerNumberList = player.getInputNumberList();
+
+ int strikes = calculateStrikes(randomNumberList, playerNumberList);
+ int balls = calculateBalls(randomNumberList, playerNumberList);
+
+ // 결과 출력
+ if (strikes == 0 && balls == 0) {
+ System.out.println("낫싱");
+ } else if (strikes > 0 && balls > 0) {
+ System.out.println(balls + "볼 " + strikes + "스트라이크");
+ } else if (strikes > 0) {
+ System.out.println(strikes + "스트라이크");
+ } else {
+ System.out.println(balls + "볼");
+ }
+
+ // 3 스트라이크인 경우 게임 종료
+ if (strikes == 3) {
+ printGameOverMessage();
+ gameOver = true;
+ } else {
+ gameOver = false;
+ }
+ }
+
+ private int calculateStrikes(List randomNumberList, List playerNumberList) {
+ int strikes = 0;
+
+ for (int i = 0; i < randomNumberList.size(); i++) {
+ if (randomNumberList.get(i).equals(playerNumberList.get(i))) {
+ strikes++;
+ }
+ }
+
+ return strikes;
+ }
+
+ private int calculateBalls(List randomNumberList, List playerNumberList) {
+ int balls = 0;
+
+ for (int i = 0; i < randomNumberList.size(); i++) {
+ if (randomNumberList.contains(playerNumberList.get(i)) && !randomNumberList.get(i).equals(playerNumberList.get(i))) {
+ balls++;
+ }
+ }
+
+ return balls;
+ }
+
+ public boolean isGameOver() { // 게임 오버 여부
+ return gameOver;
+ }
+
+ private void printGameOverMessage() {
+ System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
+ }
+}
diff --git a/src/main/java/baseball/Computer.java b/src/main/java/baseball/Computer.java
new file mode 100644
index 000000000..574036324
--- /dev/null
+++ b/src/main/java/baseball/Computer.java
@@ -0,0 +1,37 @@
+package baseball;
+
+import camp.nextstep.edu.missionutils.Randoms;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Computer {
+ private List randomNumberList;
+
+ public Computer() {
+ this.randomNumberList = generateRandomNumberList();
+ }
+
+ private List generateRandomNumberList() {
+ Set notDuplicatedNumbers = new HashSet<>();
+
+ while (notDuplicatedNumbers.size() < 3) {
+ int num = Randoms.pickNumberInRange(1, 9); // 1 ~ 9 난수 생성
+
+ notDuplicatedNumbers.add(num);
+ }
+
+ return new ArrayList<>(notDuplicatedNumbers);
+ }
+
+
+ public List getRandomNumberList() {
+ return this.randomNumberList;
+ }
+
+ public void resetRandomNumberList() {
+ this.randomNumberList = generateRandomNumberList();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/baseball/InputException.java b/src/main/java/baseball/InputException.java
new file mode 100644
index 000000000..97d66e412
--- /dev/null
+++ b/src/main/java/baseball/InputException.java
@@ -0,0 +1,56 @@
+package baseball;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class InputException {
+ private static final String NOT_NUMBER = "숫자가 아닙니다.";
+ private static final String NOT_NUMBER_LENGTH = "숫자의 길이가 맞지 않습니다.";
+ private static final String DUPLICATED = "중복된 숫자가 있습니다.";
+ private static final String OUT_OF_RANGE = "숫자가 1~9 범위를 벗어났습니다.";
+ private static final String NUMBER_REGEX = "^[0-9]*$";
+
+ private InputException() {
+ }
+
+ public static void validatesNumber(String inputNumbers) {
+ isNumber(inputNumbers);
+ isLength(inputNumbers);
+ isDuplicated(inputNumbers);
+ isInRange(inputNumbers);
+ }
+
+ public static void isNumber(String inputNumbers) {
+ if (!Pattern.matches(NUMBER_REGEX, inputNumbers)) {
+ exception(NOT_NUMBER);
+ }
+ }
+
+ public static void isLength(String inputNumbers) {
+ if (inputNumbers.length() != 3) {
+ exception(NOT_NUMBER_LENGTH);
+ }
+ }
+
+ public static void isDuplicated(String inputNumbers) {
+ List inputNumberList = Arrays.asList(inputNumbers.split(""));
+ if (inputNumberList.stream().distinct().count() < 3) {
+ exception(DUPLICATED);
+ }
+ }
+
+ public static void isInRange(String inputNumbers) {
+ String[] inputNumberList = inputNumbers.split("");
+ for (String num : inputNumberList) {
+ int number = Integer.parseInt(num);
+ if (number < 1 || number > 9) {
+ exception(OUT_OF_RANGE);
+ }
+ }
+ }
+
+ private static void exception(String message) {
+ throw new IllegalArgumentException(message);
+ }
+}
diff --git a/src/main/java/baseball/Player.java b/src/main/java/baseball/Player.java
new file mode 100644
index 000000000..8ff6d3a0a
--- /dev/null
+++ b/src/main/java/baseball/Player.java
@@ -0,0 +1,41 @@
+package baseball;
+
+import camp.nextstep.edu.missionutils.Console;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static baseball.InputException.validatesNumber;
+
+public class Player {
+ private final List inputNumberList;
+
+ public Player() {
+ this.inputNumberList = new ArrayList<>();
+ }
+
+ public void playerInputNumber() { // 사용자 입력 메서드
+ System.out.print("숫자를 입력해주세요 : ");
+ String input = Console.readLine();
+ validatesNumber(input);
+
+ inputNumberList.clear(); // 이전 입력값을 비우기
+ for (char ch : input.toCharArray()) { // 입력받은 숫자를 List에 저장
+ inputNumberList.add(Character.getNumericValue(ch));
+ }
+ }
+
+ public List getInputNumberList(){
+ return this.inputNumberList;
+ }
+
+ // 게임 재시작 여부를 결정하는 메서드
+ public String inputReplay(){
+ String inputReplay = Console.readLine();
+
+ if (!inputReplay.equals("1") && !inputReplay.equals("2")) {
+ throw new IllegalArgumentException("잘못된 입력입니다. 1 또는 2를 입력하세요.");
+ }
+ return inputReplay;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/baseball/ApplicationTest.java b/src/test/java/baseball/ApplicationTest.java
index 359aacfa4..36352ef8c 100644
--- a/src/test/java/baseball/ApplicationTest.java
+++ b/src/test/java/baseball/ApplicationTest.java
@@ -9,28 +9,38 @@
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class ApplicationTest extends NsTest {
+ @Test
+ void 게임시작_후_입력() {
+ assertRandomNumberInRangeTest(
+ () -> {
+ run("123", "234", "345", "456", "2");
+ assertThat(output()).contains("낫싱", "낫싱", "2볼", "3스트라이크", "게임 종료");
+ },
+ 4, 5, 6
+ );
+ }
- @Test
- void 게임종료_후_재시작() {
- assertRandomNumberInRangeTest(
- () -> {
- run("246", "135", "1", "597", "589", "2");
- assertThat(output()).contains("낫싱", "3스트라이크", "1볼 1스트라이크", "3스트라이크", "게임 종료");
- },
- 1, 3, 5, 5, 8, 9
- );
- }
+ @Test
+ void 게임종료_후_재시작() {
+ assertRandomNumberInRangeTest(
+ () -> {
+ run("246", "135", "1", "597", "589", "2");
+ assertThat(output()).contains("낫싱", "3스트라이크", "1볼 1스트라이크", "3스트라이크", "게임 종료");
+ },
+ 1, 3, 5, 5, 8, 9
+ );
+ }
- @Test
- void 예외_테스트() {
- assertSimpleTest(() ->
- assertThatThrownBy(() -> runException("1234"))
- .isInstanceOf(IllegalArgumentException.class)
- );
- }
+ @Test
+ void 예외_테스트() {
+ assertSimpleTest(() ->
+ assertThatThrownBy(() -> runException("1234"))
+ .isInstanceOf(IllegalArgumentException.class)
+ );
+ }
- @Override
- public void runMain() {
- Application.main(new String[]{});
- }
+ @Override
+ public void runMain() {
+ Application.main(new String[]{});
+ }
}