Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a5b8549
docs(guide): 구현 기능 목록 작성
pkalsh Feb 15, 2021
1649c59
feat: 게임 전체 골격 설계
pkalsh Feb 18, 2021
34cbe18
feat: 프린터 구현
pkalsh Feb 18, 2021
85863a6
refactor: 프린터 리팩토링
pkalsh Feb 18, 2021
d5f1041
feat: 입력기 구현
pkalsh Feb 18, 2021
f5b9d91
feat: 사용자 입력 숫자 검증 메소드 구현
pkalsh Feb 18, 2021
32974a8
feat: 올바르지 않은 입력에 대한 경고 메시지 구현
pkalsh Feb 18, 2021
e35e434
refactor: try-catch 문 추출
pkalsh Feb 18, 2021
d5eeeaf
test: 입력 숫자 검증 테스트 케이스
pkalsh Feb 18, 2021
02bd97d
feat: 컴퓨터의 세자리 난수 생성 메서드 구현
pkalsh Feb 18, 2021
fef00e1
refactor: 난수 생성 메서드 static 메서드화
pkalsh Feb 18, 2021
7612ab7
test: 난수 생성기 테스트 작성
pkalsh Feb 18, 2021
2b11336
feat: 결과 클래스 구현
pkalsh Feb 18, 2021
6f9cf8f
feat: 사용자 숫자와 난수를 비교하는 메서드 구현
pkalsh Feb 18, 2021
58835ef
fix: digits 접근 로직 변경
pkalsh Feb 18, 2021
d252b82
test: 비교하여 결과 설정하는 모든 테스트 케이스 구현
pkalsh Feb 18, 2021
8ed095f
fix: 참조형 매개변수의 널값 검사 코드 추가
pkalsh Feb 18, 2021
52121be
fix: 게임내 숫자 검증 메소드 변경
pkalsh Feb 18, 2021
6dde9e5
fix: Scanner에 대한 예외 처리 추가
pkalsh Feb 19, 2021
c0f94c9
fix: root 클래스에 NullPointerException 에러 처리
pkalsh Feb 19, 2021
098f663
fix: 게임 시작/종료 조건 변경
pkalsh Feb 19, 2021
40d4fb7
fix: 출력 양식에 맞춰 출력문 수정
pkalsh Feb 19, 2021
0ca42fc
fix: 입력 오류시 한번 더 입력을 받아야 정상적으로 작동하는 버그 수정
pkalsh Feb 19, 2021
f657de3
fix: 사용자 입력 받는 도중 비정상 입력 발생시 무한 루프를 도는 버그 수정
pkalsh Feb 19, 2021
eac391e
Update src/main/java/baseball/GameManager.java
pkalsh Feb 22, 2021
38297df
style: 중괄호+공백삽입 컨벤션 적용
pkalsh Feb 22, 2021
02816f9
style: [제어문 키워드와 여는 소괄호 사이에 공백 삽입] 컨벤션 적용
pkalsh Feb 22, 2021
e3a49c3
style: 명시적 변수 초기화 불필요
pkalsh Feb 22, 2021
2437266
style: 상수의 위치 변경
pkalsh Feb 22, 2021
f47285c
refactor: 게임 내 숫자를 생성하고 입력받는 메소드에서 GameNumber 객체를 생성하는 방법 변경
pkalsh Feb 22, 2021
d1a6dd7
refactor: InputReceiver가 게임을 다시 시작하는가를 판단하는 기능을 분리
pkalsh Feb 22, 2021
6f894de
fix: 게임 결과가 초기화되지 않아 게임을 재시작해도 승리하는 버그 수정
pkalsh Feb 22, 2021
cc08041
refactor: 로직을 드러내는 메소드명이 아닌 서비스 친화적인 메소드명으로 변경
pkalsh Feb 22, 2021
98e2b64
refactor: NPE throw 코드 모두 삭제
pkalsh Feb 22, 2021
35fa32e
refactor: 시드 번호와 입력 번호 비교 로직 책임 재분배 및 쪼개기
pkalsh Feb 22, 2021
9aabea9
refactor: InputReceiver의 receiveUserNumber 메소드 반환 타입 변경
pkalsh Feb 22, 2021
1652c2b
refactor: 상수를 private static final로 선언
pkalsh Feb 25, 2021
46e34c8
style: 필드와 메소드, 메소드와 메소드 사이에 빈 라인 추가
pkalsh Feb 25, 2021
0037ff6
style: 필드와 메소드 사이에 빈 라인 추가
pkalsh Feb 25, 2021
6f3ca99
style: 할당 연산자 앞뒤에는 공백 삽입
pkalsh Feb 25, 2021
58578cf
style: 스트림 사용시 가독성을 위해 개행
pkalsh Feb 25, 2021
41f6bc6
refactor: for문의 반복 변수에는 임시 변수명 사용 가능
pkalsh Feb 27, 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
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,88 @@
# 미션 - 숫자 야구 게임

## 📄 구현 기능 목록

### 게임 관리자

- 게임의 전체적 순서를 보장한다.
- 게임의 종료 여부를 결정한다.
- 한 게임 내에서 전역적으로 유지 되어야 할 상태를 유지시킨다.
- 숫자 생성기에 의해 생성된 숫자

### 숫자 생성기

- 임의의 3자리 숫자를 생성한다.
- 각 자리의 숫자는 1-9사이의 숫자이다.
- 각 자리의 숫자는 서로 다르다.

- 생성된 숫자는 한 게임 동안 유지될 수 있도록 한다.

### 게임 내 사용자 입력기

- 게임 내에서 진행되는 숫자를 입력받는 입력기이다.
- 표준 입력으로부터 사용자 입력을 받는다.

- 사용자 입력은 3자리 수이어야만 한다.
- [Option] 3자리 이상일 경우
- 오류를 출력하고 입력을 다시 받는다.
- 혹은, 앞의 3자리만 잘라서 받는다.
- 3자리 미만일 경우
- 오류를 출력하고 입력을 다시 받는다.
- 숫자가 아닐 경우
- 오류를 출력하고 입력을 다시 받는다.
- [Option] 한 자리의 숫자가 다른 자리의 것과 같은 숫자인 경우
- ex) 777, 121, 334, 515
- 오류를 출력하고 입력을 다시 받는다.
- 혹은, 정상적으로 게임을 진행한다.
- [Option] 생성 숫자가 751이고, 사용자 입력 숫자가 777인 경우
- 1스트라이크 2볼을 출력한다.
- 혹은, 1스트라이크를 출력한다.

- 잘못된 입력으로 인한 예외는 IllegalArgumentException을 발생시킨다.
- 입력된 숫자는 비교 결과가 생성되어 출력될 때까지 유지한다.

### 게임 외 사용자 입력기

- 게임 종료후 새로운 게임을 시작하는 이벤트를 발생시키거나 프로그램을 종료시킬 수 있는 이벤트를 발생시킬 수 있는 입력기이다.
- 입력으로 "yes"를 받을 경우 출력기에게 다시시작 메시지를 전달한다.
- 입력으로 "no"를 받을 경우 출력기에게 종료 메시지를 전달한다.
- 둘 중 어느 것에도 포함되지 않는 입력을 받을 경우 에러 메시지를 전달한다.

### 결과 출력기

- 비교기로부터 넘겨받은 비교 결과를 출력한다.
- 스트라이크 카운트에 "스트라이크" 문자열을 이어 출력한다.
- 볼 카운트에 "볼" 문자열을 이어 출력한다.
- 스트라이크 카운트 혹은 볼 카운트가 0일 경우 출력하지 않는다.
- ex) 스트라이크 카운트가 0이고, 볼 카운트가 1일 경우, "1볼"만 출력한다.
- 스트라이크 카운트가 0이고, 볼 카운트가 0일 경우 "낫싱"을 출력한다.

- 3스트라이크일 경우 게임 외 출력기에게 메시지를 출력하도록 이벤트를 발생시킨다.

### 게임 외 출력기

- 게임을 종료하는 메시지를 출력한다.
- 다른 게임 시작 의사 여부를 묻는 메시지를 출력한다.
- ex) "다시 시작하시겠습니까? (yes/no)"

- 게임 외 사용자 입력기에게 입력을 받도록 이벤트를 발생시킨다.
- 게임 외 사용자 입력기로부터 메시지를 전달받으면 적절한 메시지를 출력하고 처리를 진행한다.
- 다시시작 메시지라면 "게임을 다시시작합니다."를 출력하고 게임 관리자에게 다시시작하는 메시지를 전달한다.
- 종료 메시지라면 "종료합니다."를 출력하고 게임 관리자에게 종료하는 메시지를 전달한다.
- 에러 메시지라면 "다시 시작하시겠습니까? (yes/no)"를 다시 출력하고 반복한다.



### 입력 비교기

- 생성기로부터 유지된 생성값을 사용자 입력과 비교한다.
- 같은 자리에 같은 숫자가 있는 경우 스트라이크 카운트를 증가시킨다.
- 다른 자리에 생성된 숫자가 포함하는 숫자를 가지고 있는 경우 볼 카운트를 증가시킨다.

- 비교 결과는 결과 출력기에 넘겨줄 수 있다.



## 🚀 기능 요구사항
- 이 게임은 프로그램이 1에서 9까지 서로 다른 임의의 수 3개를 정하고 이를 플레이어가 맞추는 게임이다.
- 정답을 맞추기 위해 3자리수를 입력하고 힌트를 받는다.
Expand All @@ -11,6 +94,7 @@
- 아래의 프로그래밍 실행 결과 예시와 동일하게 입력과 출력이 이루어져야 한다.

<br>


## ✍🏻 입출력 요구사항
### ⌨️ 입력
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/baseball/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
public class Application {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// TODO 구현 진행
GameManager manager = new GameManager(scanner);
manager.run();
scanner.close();
}
}
86 changes: 86 additions & 0 deletions src/main/java/baseball/GameManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package baseball;

import baseball.generator.RandomNumberGenerator;
import baseball.receiver.ConsoleInputReceiver;
import baseball.receiver.InputReceiver;
import baseball.number.GameNumber;
import baseball.printer.ConsolePrinter;
import baseball.printer.Printer;
import baseball.result.Result;

import java.util.InputMismatchException;
import java.util.Objects;
import java.util.Scanner;

public class GameManager {
private static final int START_GAME = 1;

private final Printer printer;
private final InputReceiver receiver;
private GameNumber seedNumber;
private GameNumber userNumber;

public GameManager(Scanner scanner) {
Objects.requireNonNull(scanner);
printer = new ConsolePrinter();
receiver = new ConsoleInputReceiver(scanner);
}

public void run() {
printer.greet();
printer.askStartGame();

boolean continueGame = isContinueGame();

while (continueGame) {
Result result = new Result();
seedNumber = RandomNumberGenerator.generate();
startGame(result);
printer.noticeWin();
printer.askStartGame();
continueGame = isContinueGame();
}
}

private boolean isContinueGame() {
int select = receiver.receiveContinueGameSelect();
try {
throwIfInputIsNotOneOrTwo(select);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
return isContinueGame();
}
return (select == START_GAME);
}

private void throwIfInputIsNotOneOrTwo(int select) {
if (select != 1 && select != 2) {
throw new IllegalArgumentException("올바르지 않은 입력입니다.\n시작은 1, 종료는 2 입니다.");
}
}

private void startGame(Result result) {
while (!result.isWin()) {
boolean isValidInput = receiveUserInput();

if (!isValidInput) {
continue;
}
result.calculateResult(seedNumber, userNumber);
printer.printResult(result);
}
}

private boolean receiveUserInput() {
try {
printer.requestUserNumber();
String userInput = receiver.receiveUserNumber();
userNumber = GameNumber.from(userInput);
} catch (IllegalArgumentException | InputMismatchException e) {
receiver.dealWithExceptionalInput();
printer.warnInvalidInput();
return false;
}
return true;
}
}
22 changes: 22 additions & 0 deletions src/main/java/baseball/generator/RandomNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package baseball.generator;

import baseball.number.GameNumber;
import utils.RandomUtils;

public class RandomNumberGenerator {

public static GameNumber generate() {
int newSeed = 0;

for (int exponent = 0; exponent < 3; exponent++) {
int randomDigit = RandomUtils.nextInt(1, 9);
newSeed += (Math.pow(10.0, exponent) * randomDigit);
}

if (!GameNumber.validateNumber(newSeed)){
return generate();
}

return GameNumber.from(String.valueOf(newSeed));
}
}
44 changes: 44 additions & 0 deletions src/main/java/baseball/number/GameNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package baseball.number;

public class GameNumber {
private String value;

private GameNumber(String number) {
value = number;
}

public static GameNumber from(String number) {
if (!validateNumber(Integer.parseInt(number))) {
throw new IllegalArgumentException();
}
return new GameNumber(number);
}

public static boolean validateNumber(int number) {
Copy link
Member

@kouz95 kouz95 Feb 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

중복 또는 범위를 체크하는 과정이 생각보다 복잡한것 같아요.
(프로그래머가 아닌 숫자야구게임만 아는 사람이 이해할 수 있을까요?)
개선할 수 있는 방법은 없을지 고민해볼까요? 🤔

if (number <= 122 || number >=988) {
return false;
}

boolean[] digits = new boolean[10];
String strNumber = Integer.toString(number);

for (char digit : strNumber.toCharArray()) {

int integerDigit = Integer.parseInt(String.valueOf(digit));
if (integerDigit == 0) {
return false;
}
if (!digits[integerDigit]) {
digits[integerDigit] = true;
continue;
}
return false;
}

return true;
}

public String getValue() {
return value;
}
}
50 changes: 50 additions & 0 deletions src/main/java/baseball/printer/ConsolePrinter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package baseball.printer;

import baseball.result.Result;

public class ConsolePrinter implements Printer {

@Override
public void greet() {
System.out.println("숫자 야구 게임입니다.\n" +
"게임을 시작하시겠습니까?");
}

@Override
public void askStartGame() {
System.out.println("시작하려면 1, 종료하려면 2를 입력하세요.");
}

@Override
public void requestUserNumber() {
System.out.print("숫자를 입렧해주세요 : ");
}

@Override
public void warnInvalidInput() {
System.out.println("올바르지 않은 입력입니다.\n" +
"서로 다른 숫자 세 자리를 입력해주세요.");
}

@Override
public void printResult(Result result) {
if (result.isNothing()) {
System.out.println("낫싱");
return ;
}

if (result.getBallCount() != 0) {
System.out.print(result.getBallCount() + "볼 ");
}

if (result.getStrikeCount() != 0) {
System.out.print(result.getStrikeCount() + "스트라이크");
}
System.out.println();
}

@Override
public void noticeWin() {
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
}
}
17 changes: 17 additions & 0 deletions src/main/java/baseball/printer/Printer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package baseball.printer;

import baseball.result.Result;

public interface Printer {
void greet();

void askStartGame();

void requestUserNumber();

void warnInvalidInput();

void printResult(Result result);

void noticeWin();
}
49 changes: 49 additions & 0 deletions src/main/java/baseball/receiver/ConsoleInputReceiver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package baseball.receiver;

import baseball.number.GameNumber;

import java.util.InputMismatchException;
import java.util.Scanner;

public class ConsoleInputReceiver implements InputReceiver {

private final Scanner scanner;

public ConsoleInputReceiver(Scanner scanner) {
this.scanner = scanner;
}

@Override
public int receiveContinueGameSelect() {
int select;
try {
select = scanner.nextInt();
} catch (InputMismatchException e) {
cleanScannerBuffer();
System.out.println("잘못된 입력입니다. 숫자만 입력해주세요.");
return receiveContinueGameSelect();
}

return select;
}

@Override
public String receiveUserNumber() throws IllegalArgumentException, InputMismatchException {
int number = scanner.nextInt();
if (!GameNumber.validateNumber(number)) {
throw new IllegalArgumentException();
}
return Integer.toString(number);
}

@Override
public void dealWithExceptionalInput() {
cleanScannerBuffer();
}

private void cleanScannerBuffer() {
if (scanner.hasNextLine()) {
scanner.nextLine();
}
}
}
10 changes: 10 additions & 0 deletions src/main/java/baseball/receiver/InputReceiver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package baseball.receiver;

public interface InputReceiver {

int receiveContinueGameSelect();

String receiveUserNumber();

void dealWithExceptionalInput();
}
Loading