Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2e1c0d3
docs(readme): 기능 구현 목록 정리
Gyuchool Nov 25, 2021
1838457
feat(InputView): 유저의 입력을 받는 기능 구현
Gyuchool Nov 25, 2021
bb5cdf3
feat(user): 입력받은 값을 저장하는 기능 구현
Gyuchool Nov 26, 2021
3a0f417
docs(readme): Random Api가 있으므로 직접 클래스 생성 삭제
Gyuchool Nov 26, 2021
21dd2b2
feat(computer): 생성된 랜덤 숫자 정답을 저장하는 기능 구현
Gyuchool Nov 26, 2021
04a59d4
refactor(user): 유저가 저장하는 숫자의 자료형을 배열로 수정
Gyuchool Nov 26, 2021
46f875b
refactor(game): Game 생성자를 통해서 객체 초기화
Gyuchool Nov 26, 2021
59473f3
feat: 유저 넘버와 컴퓨터의 저장된 값을 비교하여 볼, 스트라이크, 낫싱 판단하는 기능 구현
Gyuchool Nov 26, 2021
6f18e3b
feat: Referee로부터 받은 결과를 출력하는 기능 구현
Gyuchool Nov 26, 2021
893fcf2
refactor: getResult() 반환형 private으로 변경 및 getJudgment()의 인수 자료형 변경
Gyuchool Nov 26, 2021
f8dcd97
feat(outputview): 3개의 숫자를 모두 맞췄을때 게임 종료 멘트를 출력한다.
Gyuchool Nov 26, 2021
966d83e
feat(inputview): 게임 재시작 여부를 입력받는 기능 구현
Gyuchool Nov 26, 2021
8869783
feat(game): 3개의 숫자를 모두 맞히면 종료한 후, 게임을 재시작할지 결정하는 기능 구현
Gyuchool Nov 26, 2021
7b290bc
docs(readme): 예외처리 사항 변경
Gyuchool Nov 26, 2021
6ea705f
feat(exception): 유저의 입력값이 3자리가 아닐떄 예외 처리
Gyuchool Nov 26, 2021
5e2d70a
feat(exception): 정수가 아닌 다른 값을 입력받았을 때 예외 처리
Gyuchool Nov 26, 2021
99c6a7d
feat(exception): 유저의 입력값에 중복이 있으면 예외 처리
Gyuchool Nov 26, 2021
42d3fa5
feat(exception): 유저의 입력값에 0이 들어있으면 예외 처리
Gyuchool Nov 26, 2021
c284623
refactor: 유저 인풋 유효성 검증하는 메서드 이름 변경
Gyuchool Nov 26, 2021
4dbc07b
feat(exception): 게임 재시작 여부를 묻는 입력이 범위를 넘어갈떄 예외 처리
Gyuchool Nov 26, 2021
6864b65
refactor: 유저 인풋 예외처리 함수 반환형 void로 변경
Gyuchool Nov 26, 2021
5dd2a20
feat(computer): 생성된 랜덤 숫자들 중복 제거 기능 구현
Gyuchool Nov 26, 2021
467b325
refactor(referee): 볼, 스트라이크 카운트 함수화 구현
Gyuchool Nov 26, 2021
1dd74fa
refactor: 불필요한 주석 제거
Gyuchool Nov 27, 2021
63bdc0e
style(conventions): 새줄 문자 lf 적용
Gyuchool Nov 29, 2021
2933d58
refactor(referee): 매개변수 이름에 의미 부여
Gyuchool Nov 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# top-most EditorConfig file
root = true

[*]
# [encoding-utf8]
charset = utf-8

# [newline-lf]
end_of_line = lf

# [newline-eof]
insert_final_newline = true

[*.bat]
end_of_line = crlf

[*.java]
# [indentation-tab]
indent_style = tab

# [4-spaces-tab]
indent_size = 4
tab_width = 4

# [no-trailing-spaces]
trim_trailing_whitespace = true

[line-length-120]
max_line_length = 120
10 changes: 10 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
*.c text eol=lf
*.cpp text eol=lf
*.h text eol=lf

# exception for visual studio project configuration
*.sln text eol=crlf
*.vs text eol=crlf
*.csproj eol=crlf
*.props eol=crlf
*.filters eol=crlf
74 changes: 60 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,48 @@
# 미션 - 숫자 야구 게임

## 🎮 기능구현 사항

### Referee

- [x] 유저 넘버와 컴퓨터의 저장된 값을 비교하여 볼의 개수를 판단하는 기능 구현
- [x] 유저 넘버와 컴퓨터의 저장된 값을 비교하여 스트라이크의 개수를 판단하는 기능 구현
- [x] 유저 넘버와 컴퓨터의 저장된 값을 비교하여 낫싱인지 판단하는 기능 구현
- [x] 스트라이크 개수와 볼의 개수를 출력해준다. 만약 낫싱이면 낫싱을 출력한다.

### Game

- 게임이 진행되는 클래스이다.
- [x] 3개의 숫자를 모두 맞히면 종료한 후, 입력으로 받은 값으로 게임을 재시작할지 종료할지 결정한다.

### Computer

- [x] 생성된 랜덤 숫자를 저장하는 클래스이다.
- [x] 생성된 숫자들은 중복이 없어야 한다.

### User

- [x] 입력받은 값을 저장하는 기능 구현

### InputView

- [x] 유저의 입력을 받는다.
- [x] 게임 재시작 여부를 입력받는다.

### OutputView

- [x] Referee로부터 받은 결과를 출력한다.
- [x] 3개의 숫자를 모두 맞췄을때 게임 종료 멘트를 출력한다.

### 예외 처리

- 괄호안의 클래스 내에서 처리한다.
- 잘못된 입력이 들어올 경우 IllegalArgumentException 을 발생시키고 애플리케이션을 종료한다.
- [x] (InputView) 유저의 입력값이 정수가 아닌 다른 값을 입력받았을 때 예외 처리
- [x] (InputView) 유저의 입력값이 3자리가 아닌 숫자가 들어왔을 때 예외 처리
- [x] (InputView) 유저의 입력값에 중복이 있으면 예외 처리
- [x] (InputView) 유저의 입력값에 0 이 들어있으면 예외 처리(1~9까지만 받는다.)
- [x] (InputView) 게임 재시작 여부를 묻는 입력이 범위를 넘어갈때 예외 처리 (ex) 1, 2가 아닐떄)

## 🔍 진행방식

- 미션은 **기능 요구사항, 프로그래밍 요구사항, 과제 진행 요구사항** 세 가지로 구성되어 있다.
Expand All @@ -8,10 +51,11 @@
## ✉️ 미션 제출 방법

- 미션 구현을 완료한 후 GitHub을 통해 제출해야 한다.
- GitHub을 활용한 제출 방법은 [프리코스 과제 제출 문서](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 를 참고해 제출한다.
- 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만 보내고, 지원 플랫폼에서 과제를 제출하지 않으면 최종 제출하지 않은 것으로 처리되니 주의한다.**
- 자세한 방법은 [링크](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse#제출-가이드) 를 참고한다.
- **Pull Request만 보내고, 지원 플랫폼에서 과제를 제출하지 않으면 최종 제출하지 않은 것으로 처리되니 주의한다.**

## ✔️ 과제 제출 전 체크리스트 - 0점 방지

Expand All @@ -25,11 +69,12 @@
기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다.

- 같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 같은 수가 전혀 없으면 포볼 또는 낫싱이란 힌트를 얻고, 그 힌트를 이용해서 먼저 상대방(컴퓨터)의 수를 맞추면 승리한다.
- 예) 상대방(컴퓨터)의 수가 425일 때
- 123을 제시한 경우 : 1스트라이크
- 456을 제시한 경우 : 1볼 1스트라이크
- 789를 제시한 경우 : 낫싱
- 위 숫자 야구 게임에서 상대방의 역할을 컴퓨터가 한다. 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게임 플레이어는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과를 출력한다.
- 예) 상대방(컴퓨터)의 수가 425일 때
- 123을 제시한 경우 : 1스트라이크
- 456을 제시한 경우 : 1볼 1스트라이크
- 789를 제시한 경우 : 낫싱
- 위 숫자 야구 게임에서 상대방의 역할을 컴퓨터가 한다. 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게임 플레이어는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한
결과를 출력한다.
- 이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다.
- 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다.
- 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료되어야 한다.
Expand Down Expand Up @@ -95,18 +140,18 @@
- 프로그램을 실행하는 시작점은 `Application`의 `main()`이다.
- JDK 8 버전에서 실행 가능해야 한다. **JDK 8에서 정상 동작하지 않을 경우 0점 처리**한다.
- 자바 코드 컨벤션을 지키면서 프로그래밍한다.
- https://naver.github.io/hackday-conventions-java
- https://naver.github.io/hackday-conventions-java
- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
- 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.
- 예를 들어 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()`을 활용한다.
- Random 값 추출은 `camp.nextstep.edu.missionutils.Randoms`의 `pickNumberInRange()`를 활용한다.
- 사용자가 입력하는 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용한다.
- 프로그램 구현을 완료했을 때 `src/test/java` 디렉터리의 `ApplicationTest`에 있는 모든 테스트 케이스가 성공해야 한다. **테스트가 실패할 경우 0점 처리한다.**

<br>
Expand All @@ -118,7 +163,8 @@
- 미션은 [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를 남긴다.
- [AngularJS Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 참고해 commit log를
남긴다.
- 과제 진행 및 제출 방법은 [프리코스 과제 제출 문서](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 를 참고한다.

<br>
Expand Down
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ repositories {
dependencies {
implementation('com.github.woowacourse-projects:mission-utils:1.0.0')
}

compileJava.options.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
test {
useJUnitPlatform()
}
11 changes: 8 additions & 3 deletions src/main/java/baseball/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package baseball;

import baseball.domain.Game;

public class Application {
public static void main(String[] args) {
//TODO: 숫자 야구 게임 구현
}
public static void main(String[] args) {
//TODO: 숫자 야구 게임 구현

Game baseballGame = new Game();
baseballGame.start();
}
}
36 changes: 36 additions & 0 deletions src/main/java/baseball/domain/Computer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package baseball.domain;

import java.util.HashSet;
import java.util.Set;

import camp.nextstep.edu.missionutils.Randoms;

public class Computer {
private static final int MIN_NUMBER = 1;
private static final int MAX_NUMBER = 9;
private static final int NUMBER_LENGTH = 3;
private Integer[] answer;

public Computer() {
answer = new Integer[NUMBER_LENGTH];
}

public void generateAnswer() {
Set<Integer> tmpSet = new HashSet<>();

while (tmpSet.size() != NUMBER_LENGTH) {
tmpSet.add(Randoms.pickNumberInRange(MIN_NUMBER, MAX_NUMBER));
}

int index = 0;
for (Integer integer : tmpSet) {
answer[index] = integer;
index++;
}

}

public Integer[] getAnswer() {
return answer;
}
}
28 changes: 28 additions & 0 deletions src/main/java/baseball/domain/Game.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package baseball.domain;

import baseball.view.InputView;

public class Game {
private final User user;
private final Computer computer;
private final Referee referee;

public Game() {
user = new User();
computer = new Computer();
referee = new Referee();
}

public void start() {
computer.generateAnswer();
do {
user.setNumberOfUser(InputView.getInput());

} while (referee.isWrongAnswer(user.getExpectedAnswer(), computer.getAnswer()));

String choice = InputView.restartOrStop();
if ("1".equals(choice)) {
start();
}
}
}
61 changes: 61 additions & 0 deletions src/main/java/baseball/domain/Referee.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package baseball.domain;

import java.util.Arrays;

import baseball.view.OutputView;

public class Referee {
private static final int RESET_TO_ZERO = 0;
private static final int NUMBER_LENGTH = 3;
private int ball;
private int strike;

public Referee() {
initBallAndStrike();
}

public boolean isWrongAnswer(Integer[] userExpectedAnswer, Integer[] answer) {
initBallAndStrike();

for (int expectedAnswerIndex = 0; expectedAnswerIndex < userExpectedAnswer.length; expectedAnswerIndex++) {
int findIndex = Arrays.asList(answer).indexOf(userExpectedAnswer[expectedAnswerIndex]);
ballAndStrikeCount(expectedAnswerIndex, findIndex);
}

if (strike == NUMBER_LENGTH) {
OutputView.printGameEnd();
return false;
}
printResult(ball, strike);
return true;
}

private void ballAndStrikeCount(int expectedAnswerIndex, int findIndex) {
if (expectedAnswerIndex == findIndex) {
strike++;
} else if (findIndex > -1) {
ball++;
}
}

private void initBallAndStrike() {
this.ball = RESET_TO_ZERO;
this.strike = RESET_TO_ZERO;
}

private static void printResult(int ball, int strike) {
if (ball == 0 && strike == 0) {
OutputView.printNothingMessage();
}
if (ball > 0 && strike > 0) {
OutputView.printBallAndStrikeMessage(ball, strike);
} else if (ball > 0) {
OutputView.printOnlyBallMessage(ball);

} else if (strike > 0) {
OutputView.printOnlyStrikeMessage(strike);
}

}

}
21 changes: 21 additions & 0 deletions src/main/java/baseball/domain/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package baseball.domain;

public class User {
private static final int NUMBER_LENGTH = 3;
private final Integer[] expectedAnswer;

public User() {
this.expectedAnswer = new Integer[NUMBER_LENGTH];
}

public void setNumberOfUser(String number) {
for (int i = 0; i < NUMBER_LENGTH; i++) {
this.expectedAnswer[i] = Character.getNumericValue(number.charAt(i));
}
}

public Integer[] getExpectedAnswer() {
return expectedAnswer;
}

}
59 changes: 59 additions & 0 deletions src/main/java/baseball/exception/InputException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package baseball.exception;

import java.util.HashSet;
import java.util.Set;

public class InputException {
private static final String INVALID_INPUT_ERROR = "[ERROR] 잘못된 값을 입력했습니다. 게임을 종료하겠습니다.";
private static final int NUMBER_LENGTH = 3;

public static void userInputValidationCheck(String input) {
if (isThreeLength(input) && isInteger(input) && haveNotDuplicatedNumber(input) && haveNotZero(input)) {
return;
}
throw new IllegalArgumentException(INVALID_INPUT_ERROR);
}

private static boolean isThreeLength(String input) {
if (input.length() == NUMBER_LENGTH) {
return true;
}
return false;
}

private static boolean isInteger(String input) {
for (int i = 0; i < NUMBER_LENGTH; i++) {
if (!Character.isDigit(input.charAt(i))) {
return false;
}
}
return true;
}

private static boolean haveNotDuplicatedNumber(String input) {
Set<Character> inputSet = new HashSet<>();
for (int i = 0; i < NUMBER_LENGTH; i++) {
inputSet.add(input.charAt(i));
}
if (inputSet.size() == input.length()) {
return true;
}
return false;
}

private static boolean haveNotZero(String input) {
for (int i = 0; i < NUMBER_LENGTH; i++) {
if ('0' == input.charAt(i)) {
return false;
}
}
return true;
}

public static void restartInputValidationCheck(String input) {
if ("1".equals(input) || "2".equals(input)) {
return;
}
throw new IllegalArgumentException(INVALID_INPUT_ERROR);
}
}
Loading