이번 과제는 숫자 야구 게임 만들기!
어렸을 때 다들 한번쯤 해봤을 게임이다.
젊은 사람들은 아닐지도...
대충 룰을 설명하자면 이렇다
- 임의의 숫자 3자리를 정함,
중복된 숫자와0은 사용 불가 (예시 123)- 상대방이 숫자를 말함 (예시 453)
- 같은 자리에 같은 숫자가 있을 경우
Strike!- 다른 자리에 같은 숫자가 있을 경우
Ball!(예시 1S 1B)- Strike, Ball 로 추론하며 정답을 맞출 때 까지 위 과정 반복
이러한 룰을 기본으로 컴퓨터에 맞게 추가적으로 요구되는 기능들을 넣어주면 되는 과제였다.
추가 기능은 다음과 같다.
- 각 입력의 양식에 맞게 입력되었는지 확인
- 난이도(자리수) 조절 가능
- 각 게임 시작 전
난이도 선택,게임시작,기록 확인,종료하기선택 가능
나는 다음과 같이 구현하였다.
package advanced;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;
public class App {
public static void main(String[] args) {
Input input = new Input();
Confirm confirm = new Confirm();
// 매 게임 별 count 저장 List
List<Integer> games = new ArrayList<>();
// 자리수 입력 여부 저장 변수
boolean isInputLevel = false;
// 난이도
int level = 3;
label:
while (true) {
String gameType = "";
// gameType 입력 (자리수 설정이 됐을 경우 패스)
while (!isInputLevel) {
System.out.println("환영합니다! 원하시는 번호를 입력해주세요");
System.out.println("0. 자리수 설정 1. 게임 시작하기 2. 게임 기록 보기 3. 종료하기");
gameType = input.stringInput();
try {
confirm.isGameType(gameType);
break;
} catch (InputMismatchException e) {
System.out.println("올바르지 않은 입력값입니다.");
}
}
// 자리수 입력 시 바로 시작
if (isInputLevel) {
gameType = "1";
}
switch (gameType) {
case "1":
System.out.println("< 게임을 시작합니다 >");
// level 자리수에 맞는 난수 생성
CreateNum createNum = new CreateNum(level);
String number = createNum.getNumber();
// 게임 진행
Game game = new Game();
game.player(number, level);
games.add(game.getCount());
// 난이도 설정 초기화
isInputLevel = false;
break;
case "2":
for (int i = 0; i < games.size(); i++) {
System.out.println((i + 1) + "번째 게임 : 시도 횟수 - " + games.get(i));
}
break;
case "0":
while (true) {
System.out.println("설정하고자 하는 자리수를 입력하세요.");
String in = input.stringInput();
try {
// input값 유효성 확인
confirm.isValidLevel(in);
level = Integer.parseInt(in);
// 난이도 설정 여부
isInputLevel = true;
break;
} catch (InputMismatchException e) {
System.out.println("올바르지 않은 입력값입니다.");
}
}
break;
case "3":
System.out.println("종료합니다.");
break label;
}
}
}
}
package advanced;
public class CreateNum {
private String number = "";
public CreateNum(int level) {
// 길이를 기준으로 중복되지 않은 값만 추가
while (this.number.length() < level) {
String num = (int) (Math.random() * 9 + 1) + "";
if (!this.number.contains(num)) {
this.number += num;
}
// TODO: 작동 시 정답 보기 위함 -> 추후 삭제
System.out.println(number);
}
}
// number Getter
public String getNumber() {
return this.number;
}
}
package advanced;
import java.util.Scanner;
public class Input {
private final Scanner sc = new Scanner(System.in);
public String stringInput() {
String str = sc.next().trim();
sc.nextLine();
return str;
}
}
package advanced;
import java.util.InputMismatchException;
public class Game {
// 맞출때까지 걸린 횟수 count
private int count = 0;
// count Getter
public int getCount() {
return count;
}
private int[] checkAnswer(String inputAns, String answer) throws Exception {
int[] answerArr = {0, 0};
// 정답일 경우 throw -> catch 로 player while 종료
if (inputAns.equals(answer)) {
throw new Exception();
}
for (int i = 0; i < inputAns.length(); i++) {
// 같은 자리에 같은 숫자 -> strike(answerArr[0])++
if (inputAns.charAt(i) == answer.charAt(i)) {
answerArr[0]++;
} else if (answer.contains(Character.toString(inputAns.charAt(i)))) {
// 다른 자리에 같은 숫자 -> ball(answerArr[1])++
answerArr[1]++;
}
}
return answerArr;
}
public void player(String number, int level) {
Input input = new Input();
Confirm confirm = new Confirm();
while (true) {
System.out.print("숫자를 입력하세요: ");
String inputAnswer = input.stringInput();
try {
// 숫자 유효성 검사
confirm.isValidNumber(inputAnswer, level);
} catch (InputMismatchException e) {
System.out.println("올바르지 않은 입력값입니다.");
continue;
}
// 입력된 숫자 문제 없을 시 입력횟수 추가
this.count += 1;
int[] result = {0, 0};
try {
// strike, ball 을 담을 result에 checkAnswer로 결과값 대입
result = checkAnswer(inputAnswer, number);
System.out.println(result[0] + "S " + result[1] + "B");
} catch (Exception e) {
// 정답인 경우 throw 를 catch
System.out.println("정답");
break;
}
}
}
}
package advanced;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.Set;
import java.util.regex.Pattern;
public class Confirm {
private static final String TYPE_NUMBER_REG = "^[0-3]*$";
private static final String NUMBER_REG = "^[1-9]*$";
private static final String LEVEL_NUMBER_REG = "^[3-5]*$";
public void isGameType(String gameType) throws InputMismatchException {
// 0-4 가 아닐 경우
if (!Pattern.matches(TYPE_NUMBER_REG, gameType)) {
throw new InputMismatchException();
}
}
public void isValidNumber(String number, int level) throws InputMismatchException {
// 자리수가 맞지 않을 경우
if (number.length() != level) {
throw new InputMismatchException();
}
// 중복된 숫자 검증을 위한 Set
Set<Character> set = new HashSet<>();
// 숫자로 이루어지지 않은 경우
if (!Pattern.matches(NUMBER_REG, number)) {
throw new InputMismatchException();
}
// Set에 각 자리수 추가 (중복 숫자 자동 삭제로 size가 다름)
for (int i = 0; i < number.length(); i++) {
set.add(number.charAt(i));
}
if (set.size() != level) {
throw new InputMismatchException();
}
}
public void isValidLevel(String input) throws InputMismatchException {
// 숫자가 아닌 값이 입력된 경우
if (!Pattern.matches(LEVEL_NUMBER_REG, input)) {
throw new InputMismatchException();
}
int level = Integer.parseInt(input);
// 난이도의 범위가 맞지 않는 경우
if (level > 5 || level < 3) {
throw new InputMismatchException();
}
}
}
각 코드에 주석이 추가되어 있지만 간단하게 설명하자면
- 기본적인 동작을 수행
- List에 각 게임별 count 저장
- 반복문을 이용한 게임 계속하기
- 난이도(자리수)를 전달받아 호출되며 난수 생성
- Getter 를 통한 난수 접근 가능
- count 정보 저장 및 Getter를 통한 접근 가능
- checkAnswer 메서드를 통해 정답 여부 확인 및 Strike, Ball 리턴
- player 를 통해 게임 플레이
- Scanner를 이용해 입력 받기
- isGameType : 게임 타입 유효성 검사
- isValidNumber : 입력된 정답 유효성 검사
- isValidLevel : 입력된 난이도 유효성 검사
계산기와 크게 난이도 차이가 없어 어렵지 않게 진행했다.
리팩토링할 부분을 찾아보도록 해야겠다.