숫자 야구 게임 Lv 4
Lv 4에 들어가기에 앞서, Lv3의 게임 통계 기록하기에서 엄청 막혔다.
이를 해결하기 위해 다양한 방법을 시도했다.
처음에는 단순히 for문을 통해 게임 차수와 시도 횟수를 찍으려고 했는데, 시도 횟수가 초기화 되지 않아 실패했다. 그래서 게임 1판 이후에 'trialCoounts=0;' 을 할당하여 초기화해주었는데, 게임 3번 째 판에 가니 다시 초기화가 되지 않았다. 이후 생각한 아이디어는 1. 메서드를 만들 때 게임 판수와 시도 횟수를 매개 변수로 받아 sout으로 출력하는 것, 2. 게임 판 수마다 시도 횟수를 갖는 객체를 생성해주는 방식 등이 있었다.
1번을 통해 해결하려고 해도 첫 번째 판에서의 시도 횟수를 받아 출력하고, 두 번째 판에서의 출력 횟수를 받아 출력하는 건 게임이 끝난 후에 정리하여 보여주라는 요구에 맞지 않았다. 결국 첫 번째 판, 두 번째 판을 묶어주는 것이 필요했다.
2번을 통해 해결하려고 생각해봐도 첫 번째 판, 두 번째 판 등.... 다수의 게임 한 판 한 판을 묶어주는 것이 필요했다.
따라서 1, 2번을 모두 접고 Map<key, value> 를 통해 key 에는 게임 회차 수, value 에는 시도 횟수를 저장하고 이를 for 문을 통해 출력하기로 했다.
https://tes1194.tistory.com/32
요약:
1. 게임 통계 기록하는 일이 어려웠다.
2. 여러 방법을 떠올리며 고생했다.
3. Map<key, value>를 통해 해결했다.
- 게임 난이도 조절
- 사용자로부터 난이도를 입력받고, 그에 따라 숫자의 자릿수를 조정할 수 있습니다.
- 자리수는 3, 4, 5자리 숫자 중에서 선택할 수 있습니다.
- 3, 4, 5 이외의 값에 대해서는 예외처리
- 자리수를 입력하면 자동으로 게임이 실행됩니다.
// 예시 환영합니다! 원하시는 번호를 입력해주세요 0. 자리수 설정 1. 게임 시작하기 2. 게임 기록 보기 3. 종료하기 0 // 0번 자리수 설정 입력 설정하고자 하는 자리수를 입력하세요. 3 3자리수 난이도로 설정되었습니다. < 게임을 시작합니다 > 숫자를 입력하세요 ...
오른쪽 목록이 게임 난이도를 입력 받고 숫자의 자릿수를 조정할 때 만든 자바 파일이다. 기존의 PlayGame, InputNumber, MakeNumber, MatchNumbers 에서 난이도별로 4, 5를 추가하며 복사 붙여넣기 후 자릿수만 수정하며 만들었다. GameRecord에는 클래스가 늘어난만큼 연결하는 메서드들-로직은 같음-도 추가되어야 했다.
이렇게 만들고 나니 코드 중복이 너무 심했다. 이를 해결하기 위해 처음에는 추상 클래스나 인터페이스를 떠올렸다. 하지만 이는 객체 간의 협력에서 역할 단위로 협력 관계를 설정할 때 유용한 방법이라는 것을 깨달았다. 예를 들어 Car 라는 추상클래스는 Audi, Kia, Toyota 의 관계에 있어서 명확히 내려주는 역할을 한다. 추상 클래스는 자식 클래스에게 메서드 오버라이딩 강제성을 부여하여 안전성을 높인다. 리모콘 인터페이스는 삼성티비 클래스와 엘지티비 클래스를 연결해주는 역할을 한다.
따라서 비슷한 역할을 하는 클래스를 합치고, 그 안에서 세부적으로 나누는 방식으로 역할에 따라 통합하기로 했다. 왼쪽 빨간 점이 통합하는 클래스이다. 이를 통해 GameRecord의 메서드도 줄일 수 있었다.
요약 :
1.코드 중복이 많았다.
2. 해결책으로 추상클래스, 인터페이스 등을 떠올렸지만,
3. 난이도에 따라 같은 역할을 클래스들을 합쳤다.
1. PlayGames 로의 통합
전) Main에서 자리수에 따라 PlayGame-3자리, PlayLevel4-4자리, PlayLevel5-5자리로 나눠 연결됨.
후) 메인에서 playKey 라는 매개 변수에 자리수를 넣어, 자리수에 따라 구동되게 함.
// playKey 를 통해 몇 자리 수의 게임을 할 것인지 지정.
public void playGames (int playKey) {
// 게임을 최초 1회 무조건 실행하고 선택에 따라 게임을 반복하게 하기 위해 do-while 사용
do {
MakeNumbers makeNumbers = new MakeNumbers();
// makeNumbers()를 통해 생성된 Set을 ArrayList로 형변환.
// 인덱스가 없는 것에서 있는 것으로 변환하기 위함.
ArrayList<Integer> numberList = new ArrayList<>(makeNumbers.makeNumbers(playKey));
System.out.println(numberList);
MatchNumbers matchNumbers = new MatchNumbers();
System.out.println();
System.out.println("게임을 시작합니다");
ArrayList<Integer> Ints = InputNumbers.getInputNumbers();
if (playKey==3) {
do {
// matchNumbers 에 넣는 순서를 반대로 하여 자리수를 맞춤.
endGameKey = matchNumbers.matchNumbers(numberList, Ints.get(2),
Ints.get(1), Ints.get(0));
} while (endGameKey);
} else if (playKey==4) {
do {
endGameKey = matchNumbers.matchNumbers(numberList, Ints.get(3), Ints.get(2),
Ints.get(1), Ints.get(0));
} while (endGameKey);
} else if (playKey==5) {
do {
endGameKey = matchNumbers.matchNumbers(numberList, Ints.get(4), Ints.get(3), Ints.get(2),
Ints.get(1), Ints.get(0));
} while (endGameKey);
}
.
.
.
2. MakeNumbers 로의 통합
전) Set와 Random을 사용
LinkedHashSet<Integer> makeNumber () {
LinkedHashSet<Integer> numberSet = new LinkedHashSet<>();
a = random.nextInt(9) + 1;
numberSet.add(a);
do {
b = random.nextInt(9) + 1;
numberSet.add(b);
} while (b==a);
do {
c = random.nextInt(9) + 1;
numberSet.add(c);
} while (c==a || c==b);
return numberSet;
}
후) ArrayList와 Collections.shuffle 사용
ArrayList<Integer> makeNumbers (int a) {
ArrayList<Integer> numberSet = new ArrayList<>();
Integer[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Collections.shuffle(Arrays.asList(numbers)); // 배열 섞기
for (int i=0; i<a; i++) {
numberSet.add(i);
numberSet.set(i, numbers[i]);
}
return numberSet;
}
3. MatchNumbers 로의 통합
전) 코드 복사 붙여넣기를 하며 추가되는 자리수에 따라 로직 추가.
후) 3자리까지는 같이 쓰고, 난이도에 따라 로직 추가.
case 4 :
int d = inputNumbers[3];
if (arrayList.contains(d)) {
ballCount ++;
if (arrayList.get(3)==d) {
strikeCount ++;
ballCount --;
}
}
if (strikeCount == 4) {
strikeCount = 0;
ballCount = 0;
trialCounts++;
System.out.println("༼ つ ◕_◕ ༽つ 정답입니다");
GameRecord.gameRecord();
trialCounts = 0;
valid = false;
} else {
System.out.println("ball: " + ballCount);
System.out.println("strike: " + strikeCount);
trialCounts++;
strikeCount = 0;
ballCount = 0;
valid = true;
}
break;
case 5 :
int dd = inputNumbers[3];
int e = inputNumbers[4];
if (arrayList.contains(dd)) {
ballCount ++;
if (arrayList.get(3)==dd) {
strikeCount ++;
ballCount --;
}
}
if (arrayList.contains(e)) {
ballCount ++;
if (arrayList.get(4)==e) {
strikeCount ++;
ballCount --;
}
}
.
.
.
4. InputNumber 로의 통합
전) 코드 복사 붙여넣기를 하며 추가되는 자리수에 따라 로직 추가.
후) 몇 자리인지 판단 후 로직 수행
..... 하지만 몇 자리인지 판단 후 로직 수행하는 건 말 그대로 클래스만 합쳤을 뿐이지, 코드의 길이가 크게 줄지 않았다.
ㅎㅎ... 그래서 후후... 후후를 만들어야 했다.
후후) 튜터님의 아이디어로 입력 받는 값을 int 형이 아닌 String 타입으로 하여, String 이 갖는 장점을 활용해 코드 길이를 줄이고, 그 단점은 사전에 차단해보자.
Scanner inputNumber = new Scanner(System.in);
String strAnswerNumber = inputNumber.nextLine();
if (strAnswerNumber.length()<=2 || strAnswerNumber.length() >= 6) {
System.out.println("잘못된 입력입니다.");
} else {
valid = false;
}
try {
int number = Integer.parseInt(strAnswerNumber);
} catch (NumberFormatException e) {
System.out.println("잘못된 입력입니다.");
}
int0 = strAnswerNumber.charAt(0) - '0';
int1 = strAnswerNumber.charAt(1) - '0';
int2 = strAnswerNumber.charAt(2) - '0';
int[] Ints = {int0, int1, int2};
for (int i : Ints) {
inputArrayList.add(i);
}
if (strAnswerNumber.length() >= 4) {
int3 = strAnswerNumber.charAt(3) - '0';
inputArrayList.add(int3);
}
.
.
.