diff --git a/README.md b/README.md index 04dc4f6ae..bf4eec121 100644 --- a/README.md +++ b/README.md @@ -1,129 +1,39 @@ -# 과제 - 숫자 야구 게임 +# 기능 +------------------------------------------------------------ -## 🔍 진행 방식 +## 1. 랜덤 볼 생성기 -- 과제는 **기능 요구 사항, 프로그래밍 요구 사항, 과제 진행 요구 사항** 세 가지로 구성되어 있다. -- 세 개의 요구 사항을 만족하기 위해 노력한다. 특히 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행한다. -- 기능 요구 사항에 기재되지 않은 내용은 스스로 판단하여 구현한다. + 상대방 역할을 하기 위하여 컴퓨터로 랜덤 숫자를 생성한다. + +## 2. 정답 입력 ---- + 랜덤 숫자를 맞추기 위해 사용자가 입력을 한다. + +## 3. 입력 한 수 exception 체크 -## 📈 과제 진행 및 제출 방법 + 사용자가 입력한 수가 조건에 위배 되는지를 체크하고 위배된다면 오류를 던짐. + +## 4. count strike, ball -- 과제는 [java-baseball](https://github.com/LandvibeDev/java-baseball) 저장소를 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) 를 참고한다. - - base repository를 `LandvibeDev/java-baseball`로 지정해서 PR 생성하면됨 + 스트라이크와 볼의 개수를 센다. + +## 5. 출력할 스트링 문장 설정 -
+ 스트라이크와 볼의 개수에 따라 정답문, 혹은 힌트문 출력 +## 6. 게임 진행 -### 테스트 실행 가이드 + 위에서 구현한 메서드들로 게임을 진행한다. + +## 7. 게임 재시작 -- 터미널에서 `java -version`을 실행하여 Java 버전이 14인지 확인한다. 또는 Eclipse 또는 IntelliJ IDEA와 같은 IDE에서 Java 14로 실행되는지 확인한다. -- 터미널에서 Mac 또는 Linux 사용자의 경우 `./gradlew clean test` 명령을 실행 하고, - Windows 사용자의 경우 `gradlew.bat clean test` 명령을 실행할 때 동작 하는지 만 확인(테스트는 실패). + 정답을 맞춘 후 게임을 다시 시작할지 혹은 그만둘지 정한다. ---- +# 구조 -## 🚀 기능 요구사항 +## Class Ball -기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다. + 컴퓨터가 생성하는 랜덤 숫자 -- 같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 같은 수가 전혀 없으면 포볼 또는 낫싱이란 힌트를 얻고, 그 힌트를 이용해서 먼저 상대방(컴퓨터)의 수를 맞추면 승리한다. - - 예) 상대방(컴퓨터)의 수가 425일 때 - - 123을 제시한 경우 : 1스트라이크 - - 456을 제시한 경우 : 1볼 1스트라이크 - - 789를 제시한 경우 : 낫싱 -- 위 숫자 야구 게임에서 상대방의 역할을 컴퓨터가 한다. 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게임 플레이어는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과를 출력한다. -- 이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다. -- 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다. -- 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료되어야 한다. -- 아래의 프로그래밍 실행 결과 예시와 동일하게 입력과 출력이 이루어져야 한다. +## Enum Class BallBoundary -
- -## ✍🏻 입출력 요구사항 - -### ⌨️ 입력 - -- 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볼 -… -``` - -
- ---- - -## 🎱 프로그래밍 요구사항 -- -- JDK 14 버전에서 실행 가능해야 한다. -- 프로그램을 실행하는 시작점은 `Application`의 `main()`이다. -- `build.gradle` 파일을 변경할 수 없고, 외부 라이브러리를 사용하지 않는다. -- [Java 코드 컨벤션](https://naver.github.io/hackday-conventions-java) 가이드를 준수하며 프로그래밍한다. -- 프로그램 종료 시 `System.exit()`를 호출하지 않는다. -- 프로그램 구현이 완료되면 `ApplicationTest`의 모든 테스트가 성공해야 한다. -- 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 이름을 수정하거나 이동하지 않는다. -- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다. - - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. - - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다. -- 3항 연산자를 쓰지 않는다. -- 함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라. -- JUnit 5와 AssertJ를 이용하여 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인한다. -- 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다. - - 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다. -- else 예약어를 쓰지 않는다. - - 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다. - - else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. -- Java Enum을 적용한다. -- 도메인 로직에 단위 테스트를 구현해야 한다. 단, UI(System.out, System.in, Scanner) 로직은 제외한다. - - 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 분리해 구현한다. - -### 라이브러리 - Randoms, Console - -- JDK에서 기본 제공하는 Random, Scanner API 대신 [`camp.nextstep.edu.missionutils`](https://github.com/woowacourse-projects/mission-utils)에서 제공하는 `Randoms`, `Console` API를 활용해 구현해야 한다. - - Random 값 추출은 `camp.nextstep.edu.missionutils.Randoms`의 `pickNumberInRange()`를 활용한다. - - 사용자가 입력하는 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용한다. -- 프로그램 구현을 완료했을 때 `src/test/java` 디렉터리의 `ApplicationTest`에 있는 모든 테스트 케이스가 성공해야 한다. **테스트가 실패할 경우 0점 처리한다.** + 세자리 수의 경계를 정해두었다. diff --git a/src/main/java/baseball/Application.java b/src/main/java/baseball/Application.java index 7f1901b8b..eef2c138f 100644 --- a/src/main/java/baseball/Application.java +++ b/src/main/java/baseball/Application.java @@ -1,7 +1,105 @@ package baseball; +import baseball.ball.Ball; +import baseball.ball.BallBoundary; +import camp.nextstep.edu.missionutils.Console; + public class Application { + public static String createRandomBall(){ + Ball ball = new Ball(BallBoundary.MAX_VALUE.getValue(), BallBoundary.MIN_VALUE.getValue()); + return ball.getBallNumber(); + } + public static String input(){ + System.out.print("숫자를 입력해주세요 : "); + String temp = Console.readLine(); + return temp; + } + + public static void checkException(String number){ + if(number.length() != Numbers.LENGTH.getValue()) { + throw new IllegalArgumentException(); // 세자리 수 + } + if(number.contains("0")) { + throw new IllegalArgumentException(); // 0이 있는지 + } + for(int i = 0; i < number.length(); i++){ + if(!(number.charAt(i) > '0' && number.charAt(i) <= '9')) throw new IllegalArgumentException(); //숫자가 아닌지 + } + checkRepeated(number); + } + + private static void checkRepeated(String number) { + for(int i = 0; i < number.length()-1; i++){ + for(int j = i+1; j < number.length(); j++){ + if(number.charAt(i) == number.charAt(j))throw new IllegalArgumentException(); + } + } + } + + public static int countStrike(String randomNum, String inputNum){ + int count = 0; + for(int i = 0; i < Numbers.LENGTH.getValue(); i++){ + if(randomNum.charAt(i) == inputNum.charAt(i)) count++; + } + return count; + } + public static int countBall(String randomNum, String inputNum){ + int count = 0; + for(int i = 0; i < Numbers.LENGTH.getValue(); i++) { + for(int j = 0; j < Numbers.LENGTH.getValue(); j++){ + if(randomNum.charAt(i) == inputNum.charAt(j) && i != j) count++; + } + } + return count; + } + public static String printHint(int strike, int ball){ + String str; + if(strike != 0 && ball != 0){ + str = ball + HintString.BALL.getValue() + strike + HintString.STRIKE.getValue();; + return str; + } + else if(strike == 0 && ball != 0){ + str = ball +HintString.BALL.getValue();; + return str; + } + else if(strike != 0 && ball == 0){ + str = strike + HintString.STRIKE.getValue(); + return str; + } + return HintString.NOTHING.getValue(); + } + public static void startGame(){ + String randNum = createRandomBall(); + String inputNum = ""; + while(!randNum.equals(inputNum)) { + inputNum = input(); + checkException(inputNum); + int strike = countStrike(randNum, inputNum); + int ball = countBall(randNum, inputNum); + String result = printHint(strike, ball); + System.out.println(result); + if (strike == Numbers.LENGTH.getValue()) { + System.out.println(Numbers.LENGTH.getValue() + "개의 숫자를 모두 맞히셨습니다! 게임 종료"); + return; + } + } + } + public static boolean repeatGame(){ + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); + String num = Console.readLine(); + if(num.equals("1")) return true; + return false; + } + public static void game(){ + while(true){ + startGame(); + if(!repeatGame())return; + } + } + + public static void main(String[] args) { //TODO: 숫자 야구 게임 구현 + game(); } } diff --git a/src/main/java/baseball/HintString.java b/src/main/java/baseball/HintString.java new file mode 100644 index 000000000..7ce095db8 --- /dev/null +++ b/src/main/java/baseball/HintString.java @@ -0,0 +1,13 @@ +package baseball; + +public enum HintString { + + STRIKE("스트라이크 "), BALL("볼 "),NOTHING("낫싱 "); + private final String value; + HintString(String value){ + this.value = value; + } + public String getValue(){ + return value.toString(); + } +} diff --git a/src/main/java/baseball/Numbers.java b/src/main/java/baseball/Numbers.java new file mode 100644 index 000000000..f5cd76e8e --- /dev/null +++ b/src/main/java/baseball/Numbers.java @@ -0,0 +1,8 @@ +package baseball; + +public enum Numbers { + LENGTH(3); + private final int value; + Numbers(int value) {this.value = value;} + public int getValue(){return value;} +} diff --git a/src/main/java/baseball/ball/Ball.java b/src/main/java/baseball/ball/Ball.java new file mode 100644 index 000000000..c62c23ef2 --- /dev/null +++ b/src/main/java/baseball/ball/Ball.java @@ -0,0 +1,18 @@ +package baseball.ball; + +import camp.nextstep.edu.missionutils.Randoms; + +public class Ball { + String ballNumber = new String(); + + + public Ball(int max_value,int min_value){ + while(ballNumber.length() < 3){ + String temp = String.valueOf(Randoms.pickNumberInRange(min_value,max_value)); + if(!ballNumber.contains(temp)) ballNumber += temp; + } + } + public String getBallNumber(){ + return ballNumber.toString(); + } +} diff --git a/src/main/java/baseball/ball/BallBoundary.java b/src/main/java/baseball/ball/BallBoundary.java new file mode 100644 index 000000000..363a6c2b2 --- /dev/null +++ b/src/main/java/baseball/ball/BallBoundary.java @@ -0,0 +1,8 @@ +package baseball.ball; + +public enum BallBoundary { + MAX_VALUE(9),MIN_VALUE(1); + private final int value; + BallBoundary(int value) {this.value = value;} + public int getValue(){return value;} +}