Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
105 changes: 99 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,100 @@
# 숫자 야구 게임
## 진행 방법
* 숫자 야구 게임 요구사항을 파악한다.
* 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 과제를 제출한다.
# 숫자 야구 게임 - 어떻게 구현할 것인가?
## dataobject package
### NumBalls interface
숫자야구에서 숫자를 담을 객체들을 위한 인터페이스이다.
문제의 조건에서는 1~9만을 허용하나, 확장에 자유롭기 위하여(0 허용, 중복 허용 등의 가능성) 인터페이스를 구현하였다.

#### 메서드
* public int getNum(int index) - index번째에 해당하는 공 출력(0~size-1)
* public int getSize(); - 공이 몇 개 있는지 알 수 있는 메서드(이번 요구사항에서는 3)
* public TrialResult compare(NumBalls trial) - trial(예상 시도)를 했을 때 몇 스트라이크 몇 볼인지 출력


### NumBallsNBalls class implements NumBalls
숫자야구에서 숫자 공 n개를 저장할 data object이다.
숫자 n개가 1-9 사이의 값을 가지며, 중복되지 않음을 보장한다.
(중복되거나 1-9 사이의 값을 가지지 않는 경우 WrongNumbersException 예외를 발생시킨다)

#### 인스턴스 변수
* private final ArrayList<Integer> nums - 숫자야구에서 사용할 공 n개(1~9 사이의 숫자)를 나타낸다.
* private final int size;

#### 메서드
* private int randomlyChoose(Set<Integer> numSet) - numSet에 들어있는 값 중 랜덤한 값을 return한다.
* private void isValidNumber(ArrayList<Integer> nums) - nums가 숫자야구 조건에 맞는지 확인한다(1~9 사이의 값, 중복되지 않음), 조건에 맞지 않으면 WrongNumberException 발생.
* public NumBalls(int size) - 숫자야구 조건에 맞는 랜덤한 숫자 n개를 nums에 저장한다.
* public NumBalls(ArrayList<Integer> nums) - 지정한 nums대로 저장한다. size는 nums의 크기로 저장된다. 조건에 맞지 않으면 WrongNumberException을 발생시킨다.
* public int getNum(int index) - index번째에 해당하는 숫자 출력
* public int getSize() - size를 return
* private void compareOne(int thisIndex, int trialIndex, TrialResult result) - trial의 trialIndex번째 수가 thisIndex(없으면 -1)에 있을 때 스트라이크/볼/낫싱을 result에 갱신
* public TrialResult compare(NumBalls trial) - trial이 NumBallsNBalls의 객체인지 확인 후(같지 않으면 예외 발생), 결과를 반환

### TrialResult class
Trial을 한 결과로 나오는 a스트라이크 b볼에 대한 정보를 저장하는 data object이다.

#### 인스턴스 변수
* private int strike = 0 - 스트라이크 개수를 저장
* private int ball = 0 - 볼 개수를 저장
* private final int size - 총 공의 개수를 저장

#### 메서드
* public TrialResult(int size) - size 초기화 후, (strike,ball) = (0,0)으로 초기화하는 생성자
* public TrialResult(int strike, int ball, int size) - 매개변수대로 strike, ball, size을 초기화하는 생성자
* private chkValidNumber(int strike, int ball) - strike, ball이 가능한 경우인지(각각 0 이상의 값, 0<=strike+ball<=size, (size-1) strike 1 ball 불가능)
* getter - strike, ball, size 변수에 대해서.
* public setStrikeBall(int strike, int ball) - strike, ball을 따로 결정하는 경우 예외발생을 적절히 확인하지 못함.
***

## manager package
### ProcessManager Class
게임 전체의 lifecycle을 담당하는 클래스
ProcessManager Class와는 Aggregation 연관을 가진다.

#### 인스턴스 객체
* private GameUserInterface gameUserInterface - 입출력을 담당하는 ui객체
* private GameManager gameManager - 한 게임이 시작될 때 그 게임의 설정을 가지는 객체

#### 인스턴스 메소드
* setter - (gameManager, gameUserInterface에 대해)
* public ProcessManager(GameUserInterface gameUserInterface) - gameUserInterface를 주입
* public void execute() - 프로그램을 실행

### GameManager Class
한 게임의 시작(숫자 size개를 랜덤하게 정함)부터 끝(사용자가 size개를 다 맞춤)까지의 한 사이클을 담당하는 클래스
gameUserInterface, numBalls를 initialize하며 다 맞출 때 까지 계속 묻고 결과를 출력해준다.

#### 인스턴스 객체
* private GameUserInterface gameUserInterface - 입출력을 담당하는 ui객체
* private final NumBalls answer; - 정답을 담을 객체
* private final int size - 숫자야구 공의 개수

#### 인스턴스 메소드
* public GameManager(GameUserInterface gameUserInterface, NumBalls numBalls, int size) - 각각의 객체를 주입 및 size, answer 초기화
* public void execute() - 게임 실행 전반을 책임질 메소드
* private boolean executeOneCycle() - 게임 중 한 사이클(숫자 입력 후 출력까지)를 담당. 게임이 끝나는 경우 true 반환

***
## exception package
### WrongNumberException class extends RunTimeException
* NumBalls, TrialResult 등에서 조건에 맞지 않는 값이 입력되는 경우에 대한 예외.
### WrongTypeException class extends RunTimeException
* NumBallsNBalls.compare(NumBalls trial)에서 trial이 원래 비교대상과 형식이 같지 않는 경우 발생시킴.

***


## ui package
### GameUserInterface Interface
사용자와 어떤 입력을 받으며, 어떤 출력을 하는지에 대한 함수가 정의되어 있다.
* ArrayList<Integer> inputNumbers() - 입력을 받아 ArrayList<Integer>형태로 저장하여 return
* void printResult(TrialResult res) - TrialResult 객체를 받아 strike, ball을 출력
* void printError(Exception e) - Exception e에 따라 여러 가지의 에러 문구 표시
* void printGameClear() - 게임을 통과하였을 시에 출력
* boolean printRetry() - 다시 하시겠습니까? 출력

### GameUserInterfaceKorean Class implements GameUserInterface
UI를 구현할 클래스. 한국어로 prompt되기 때문에 GameUserInterface**Korean**으로 하였다.

### GameUserInterfaceTestStub Class implements GameUserInterface
단위 Test시 입출력을 거치지 않고 테스트하기 위한 TestStub

## 과제 제출 과정
* [과제 제출 방법](https://github.com/next-step/nextstep-docs/tree/master/ent-precourse)
8 changes: 8 additions & 0 deletions src/main/java/num3baseball/dataobject/NumBalls.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package num3baseball.dataobject;

public interface NumBalls {
public int getNum(int index);
public int getSize();

public TrialResult compare(NumBalls trial);
}
84 changes: 84 additions & 0 deletions src/main/java/num3baseball/dataobject/NumBallsNBalls.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package num3baseball.dataobject;

import num3baseball.exception.WrongNumberException;
import num3baseball.exception.WrongTypeException;

import java.util.*;

public class NumBallsNBalls implements NumBalls{

private final ArrayList<Integer> nums = new ArrayList<>();
private final int size;

private int randomlyChoose(Set<Integer> numSet){
Iterator iter = numSet.iterator();
int randomChoose = (int)(numSet.size() * Math.random());
for (int i=1;i<=randomChoose;i++){
iter.next();
}
return (int)iter.next();
}

private void isValidNumber(ArrayList<Integer> num) throws WrongNumberException{
Set<Integer> numSet = new HashSet<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9));
int initialSize = numSet.size();
for (int i:num){
numSet.remove(i);
}
int endSize = numSet.size();
if (initialSize - endSize != num.size()){ // 모든 번호가 한번씩 빠짐 = 중복되지 않고
throw new WrongNumberException();
}
}

public NumBallsNBalls(int size) throws WrongNumberException{
this.size=size;
if (size>9 || size<1){
throw new WrongNumberException();
}
Set<Integer> numSet = new HashSet<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9));
for (int i=1;i<=this.size;i++){
nums.add(randomlyChoose(numSet));
numSet.remove(nums.get(i-1));
}
isValidNumber(nums);
}

public NumBallsNBalls(ArrayList<Integer> nums) throws WrongNumberException{
this.size = nums.size();
isValidNumber(nums);
this.nums.addAll(nums);
}
@Override
public int getNum(int index) {
return nums.get(index);
}

@Override
public int getSize() {
return size;
}

private void compareOne(int thisIndex, int trialIndex, TrialResult result){
if (trialIndex==-1){
return;
}
if (thisIndex == trialIndex){
result.setStrikeBall(result.getStrike()+1, result.getBall());
}
if (thisIndex != trialIndex){
result.setStrikeBall(result.getStrike(), result.getBall()+1);
}
}
@Override
public TrialResult compare(NumBalls trial) {
if (!(trial instanceof NumBallsNBalls) || trial.getSize()!=size){
throw new WrongTypeException();
}
TrialResult result = new TrialResult(size);
for (int i=0;i<size;i++){
compareOne(i, nums.indexOf(trial.getNum(i)), result);
}
return result;
}
}
48 changes: 48 additions & 0 deletions src/main/java/num3baseball/dataobject/TrialResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package num3baseball.dataobject;

import num3baseball.exception.WrongNumberException;

public class TrialResult {
private int strike = 0;
private int ball = 0;
private final int size;

public TrialResult(int size){
this.size = size;
}

public int getStrike() {
return strike;
}

public int getBall() {
return ball;
}

public int getSize() {
return size;
}

public TrialResult(int strike, int ball, int size){
this.size = size;

chkValidNumber(strike, ball);
this.strike = strike;
this.ball = ball;
}

private void chkValidNumber(int strike, int ball){
if (strike<0 || ball<0){
throw new WrongNumberException();
}
if (strike+ball > size || (strike==size-1 && ball==1)){
throw new WrongNumberException();
}
}

public void setStrikeBall(int strike, int ball){
chkValidNumber(strike, ball);
this.strike = strike;
this.ball = ball;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package num3baseball.exception;

public class WrongNumberException extends RuntimeException{
}
4 changes: 4 additions & 0 deletions src/main/java/num3baseball/exception/WrongTypeException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package num3baseball.exception;

public class WrongTypeException extends RuntimeException{
}
12 changes: 12 additions & 0 deletions src/main/java/num3baseball/main/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package num3baseball.main;

import num3baseball.manager.ProcessManager;
import num3baseball.ui.GameUserInterfaceKorean;
import num3baseball.ui.GameUserInterfaceTestStub;

public class Main {
public static void main(String[] args){
ProcessManager processManager = new ProcessManager(new GameUserInterfaceKorean());
processManager.execute();
}
}
40 changes: 40 additions & 0 deletions src/main/java/num3baseball/manager/GameManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package num3baseball.manager;

import num3baseball.dataobject.NumBalls;
import num3baseball.dataobject.NumBallsNBalls;
import num3baseball.dataobject.TrialResult;
import num3baseball.exception.WrongNumberException;
import num3baseball.ui.GameUserInterface;

import java.sql.Array;
import java.util.ArrayList;

public class GameManager {
private GameUserInterface gameUserInterface;
private final NumBalls answer;

private final int size;

public GameManager(GameUserInterface gameUserInterface, NumBalls numBalls, int size){
this.gameUserInterface = gameUserInterface;
answer = numBalls;
this.size=size;
}

public boolean executeOneCycle(){
try{
TrialResult result = answer.compare(new NumBallsNBalls(gameUserInterface.inputNumbers()));
gameUserInterface.printResult(result);
return result.getStrike() == result.getSize();
}
catch(Exception e){
gameUserInterface.printError(e);
}
return false;
}
public void execute(){
while(!executeOneCycle()) {
}
gameUserInterface.printGameClear(size);
}
}
28 changes: 28 additions & 0 deletions src/main/java/num3baseball/manager/ProcessManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package num3baseball.manager;

import num3baseball.dataobject.NumBallsNBalls;
import num3baseball.ui.GameUserInterface;

public class ProcessManager {
private GameUserInterface gameUserInterface;
private GameManager gameManager;

public ProcessManager(GameUserInterface gameUserInterface){
this.gameUserInterface = gameUserInterface;
}

public void setGameUserInterface(GameUserInterface gameUserInterface) {
this.gameUserInterface = gameUserInterface;
}

public void setGameManager(GameManager gameManager) {
this.gameManager = gameManager;
}

public void execute(){
do{
setGameManager(new GameManager(gameUserInterface, new NumBallsNBalls(3), 3));
gameManager.execute();
}while(gameUserInterface.printRetry());
}
}
13 changes: 13 additions & 0 deletions src/main/java/num3baseball/ui/GameUserInterface.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package num3baseball.ui;

import num3baseball.dataobject.TrialResult;

import java.util.ArrayList;

public interface GameUserInterface {
public ArrayList<Integer> inputNumbers(); // input을 받아 ArrayList<Integer>로 반환
public void printResult(TrialResult res); // TrialResult 객체를 받아 strike, ball을 출력
public void printError(Exception e); // Exception e에 따라 여러 가지의 에러 문구 표시
public void printGameClear(int size); // 게임을 통과하였을 시에 출력
public boolean printRetry(); // 다시 하시겠습니까? 출력
}
Loading