객체지향 생활체조의 원칙을 지켜가며 만드는 숫자 야구게임
어렵다...
들여쓰기 뎁스를 줄이라는 게 되게 와닿으면서도 귀찮은(또 어려운) 작업인 듯 하다. 변수명도 다듬어야 한다.
기능은 한다. 기능은 하는데...뭔가 추가 요구 사항이 왔을 경우 사망하게 될 듯 한 그런 코드
package baseboll;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.*;
public class BaseballGame {
private final BufferedReader br;
public BaseballGame(BufferedReader br) {
this.br = br;
}
public void game() throws IOException {
String answer = String.valueOf(makeRandomAnswer());
progressGame(answer);
}
private void progressGame(String answer) throws IOException {
String input = getInput(); // 사용자에게 입력값 받아오기
if (!isPossible(input)) progressGame(answer);
if (isCorrect(input, answer)) {
continueOrNot();
return;
}
countTotal(input, answer);
progressGame(answer);
}
private void countTotal(String input, String answer){
int strikeCount = strikeCountChecker(input, answer);
int ballCount = ballCountChecker(input, answer);
StringBuilder sb = new StringBuilder();
if (strikeCount == 0 & ballCount == 0) {
System.out.println("낫싱");
return;
}
if (strikeCount != 0) sb.append(strikeCount).append("스트라이크");
if (ballCount != 0) sb.append(ballCount).append("볼");
System.out.println(sb.toString());
}
private int makeRandomAnswer() {
List<Integer> digits = new ArrayList<>();
for (int i = 0; i < 10; i++) {
digits.add(i);
}
Collections.shuffle(digits);
int firstDigit = digits.get(0);
int secondDigit = digits.get(1);
int thirdDigit = digits.get(2);
return firstDigit * 100 + secondDigit * 10 + thirdDigit;
}
private String getInput() throws IOException {
System.out.println("숫자를 입력 해 주세요");
return br.readLine();
}
private void continueOrNot() throws IOException {
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");
String input = br.readLine();
if (input.equals("1")) {
game();
return;
}
if (input.equals("2")) {
return;
}
System.out.println("잘못된 입력입니다.");
}
private boolean isPossible(String s){
if (s.length() != 3){
System.out.println("3자리 숫자를 입력해주세요");
return false;
}
try {
Integer.parseInt(s);
} catch (NumberFormatException e){
System.out.println("숫자만 입력해주세요");
return false;
}
return true;
}
private int strikeCountChecker(String input, String answer){
String[] given = input.split("");
String[] ans = answer.split("");
int correctCount = 0;
for (int i = 0; i < given.length; i++) {
correctCount += strikeCheck(given[i], ans[i]);
}
return correctCount;
}
private int ballCountChecker(String input, String answer){
String[] given = input.split("");
Set<String> set = new HashSet<>(Arrays.asList(given));
int count = 0;
for (String s : set) {
count += ballCheck(s, answer);
}
int alreadyCountedStrike = strikeCountChecker(input, answer);
if (alreadyCountedStrike != 0) count -= alreadyCountedStrike;
return count;
}
private int strikeCheck(String s, String d){
return s.equals(d) ? 1 : 0;
}
private int ballCheck(String input, String answer){
return answer.contains(input) ? 1 : 0;
}
private boolean isCorrect(String input, String answer){
return input.equals(answer);
}
}
적절히 책임을 분리시켜야 한다. 강의 보기 전까지 좀 더 예쁜 모양으로 잡아가보자
UI / UX - 요구사항에 있었음. System.in, out 부분 관리하는 책임
난수를 생성하는 녀석 (생각보다 로직이 복잡했다)
스트라이크를 처리하는 녀석
볼을 처리하는 녀석 (스트라이크에게 정보를 받아와야 한다. 녀석의 상태를 입력받고 볼을 처리하면 될 듯)
해야 할 것
현재와 같이 사용자는 game() 매서드를 호출하는 것 만으로 모든 제어가 가능하게 할 것 (사용자에게 넘겨주는 인터페이스는 game() 으로 한정할 것 : 파사드)
상속을 제한하고, 최대한 적은 프로퍼티와 패러미터를 위해 노력 할 것.
반복을 줄일 것. 3번을 위해서만 2번을 타협할 것
랜덤 베이스넘버에서 난수 생성
Input을 받아서 체커한테 전달
체커는 체크한 후 아웃펏에 전달
아웃펏에서 값을 마지막 정답유무 판별하는 애한테 전달
결과를 판별, 루프 태우기
이 모든 것을 묶어서 수행하는 BaseballGame 클래스
루프 case 1 : 틀려서 돌아가야 하는 경우, 랜덤한 수는 그대로 둬야한다
2 -> 3 -> 4 -> 5 의 시퀀스를 반복해야 할것이다. 2번으로 재귀시키면 될듯하다.
루프 case 2 : 맞았으나 새로 시작하는 경우. 랜덤한 수를 생성해야 한다
1 -> 2 -> 3 -> 4 -> 5 의 시퀀스로 돌아가야 한다. 이 경우 재귀해도 될듯?
끝내는 경우 break 한다.
임의의 3자리 난수를 생성하는 녀석
UI / UX -> 입출력 담당하는 클래스 둘
InputView
OutputView
체크 클래스 (볼체크, 스트라이크체크) 와 상위 추상(혹은 인터페이스)
상위 인터페이스 : 순서에 따라 체크 (현재는 볼 -> 스트라이크 순서로) 하는 "구상" 매서드 check() 존재 (== 템플릿 매서드 패턴)
checker (상위 추상)
ballChecker (하위 구상)
StrikeChecker(하위 구상)
noneChecker (하위 구상)
입력을 받아서, 체크하고, OutputView 에 반환하는 녀석?
재귀형식으로 계속 받을 수 있는 방법?
input 매서드를 "getValidatedInput" 과 같은 형식으로 변경, 현재의 밸리데이션을 수행
계속하시겠습니까? 를 인펏받는 녀석을 하나 매서드로 파놔서, input.equals(answer) 일 시에 인펏 요청 후 받고, 그 받은 인펏을 판별하는 형태로 게임을 지속할지 중지할지 판별
0823 - 도메인에 관하여
도메인을 어떻게 설계할 것인가에 따라서 구현이 상당히 차이 날 것 같다.
도메인은 최소한의 관심사에 대하여 최대한의 구현을 도맡아야 하는 녀석이라고 생각하고 있다. 도메인을 어떻게 살찌울 것인가? 라는 것은 도메인 스스로가 최소한의 관심사에 대한 아주 작고 단단한 집합이기 때문이 아닐까?
숫자 야구 게임의 경우 어떤 도메인을 가져야 할까?
러프하게 생각해보자. 책임으로 나눠보면
랜덤한 3개의 숫자를 만들어주는 녀석
사용자에게 입력을 받는 녀석
사용자가 입력한 숫자가 랜덤한 3개의 숫자와 일치하는지 확인해주는 녀석
사용자에게 출력을 해주는 녀석
이렇게밖에 생각이 안된다...역할이 아닌 객체를 짜보라? 실생활과 닿아있는 녀석으로 구상해야하나?
넘버
게임보드
입력 (타자)
출력 (스코어판)
심판 (볼, 스트라이크 체크)
너무 어려운데?ㅋㅋ
좋은 글 감사합니다. 자주 올게요 :)