본문 바로가기
Java/코드

[Java] 숫자 야구 게임 만들기

by 리요_ 2023. 2. 10.

숫자 야구 게임

1부터 9까지 서로 다른 수로 이루어진 3 자리의 수를 맞추는 게임입니다.

  • 사용되는 숫자는 0에서 9까지 서로 다른 숫자이다.
  • 숫자는 맞지만 위치가 틀렸을 경우 [볼].
  • 숫자와 위치가 전부 맞으면 [스트라이크].
  • 숫자와 위치가 전부 틀리면 [아웃].
  • 물론 무엇이 볼이고 스트라이크인지는 알려주지 않는다.
  • 두 숫자가 중복되면 경우의 수가 많아져서 그런지 중복 숫자는 잘 사용하지 않는다.

예시

아래 결과는 정답이 0 3 2 일 때의 예시이다.


BaseballGameMain 클래스

package game;

import java.util.ArrayList;

public class BaseballGameMain {
	public static void main(String[] args) {
		//필요한 객체 일괄 생성
		RandomNumber randomNum = new RandomNumber();
		InputNumber input = new InputNumber();
		Umpire umpire = new Umpire();
		RestartGame restartGame = new RestartGame();
		
		
		boolean restart = true; //게임 재시작 여부
		//반복1- 게임 재시작
		System.out.println("<>===== BASEBALL GAME =====<>");
		while(restart) {
			//게임 레벨 설정(숫자의 갯수)
			int level = input.getLevel();
			System.out.println(">>>> PLAY BALL!!! <<<<");
			//랜덤 숫자 생성
			ArrayList<Integer> defenceNumber = randomNum.Generate(level);
			System.out.println(defenceNumber);
			//반복2 - 숫자 정답 전까지 반복(10회 제한) 제한이 없다면 while(true) 반드시 탈출조건
			//레벨별 반복횟수 차이 3-10 4-15 5-20
			for(int i=5*(level-1)-1;i>=0;i--) {
				//입력
				ArrayList<Integer> attackNumber = input.generatePlayerNumber(level);
				System.out.println(attackNumber);
				//결과 판정
				String result = umpire.decide(defenceNumber,attackNumber);
				//출력
				System.out.println(result);
				if(result.equals(level+"스트라이크")) break;
				System.out.printf("남은 기회: %d회\n",i);
				if(i==0) {
					System.out.println("경기종료");
					break;
				}
			}
			//경기 재시작
			restart = restartGame.askOp();
		}
	}
}

InputNumber 클래스

package game;

import java.util.ArrayList;
import java.util.Scanner;

public class InputNumber {
	Scanner scanner = new Scanner(System.in);

	public ArrayList<Integer> generatePlayerNumber(int level) {
        ArrayList<Integer> attackNum = new ArrayList<>();
        String input;
        while(true) {
        	System.out.println(level+"자리 숫자를 입력해주세요.");
        	input = scanner.next();
        	//if(input.length()!=level) {
        	if(!input.matches("\\d{"+level+"}") || duplicateInputCheck(input)) {
        		System.out.println("올바른 입력이 아닙니다.");
        		continue;
        	}
        	break;
        }
        for(String number: input.split("")){
            attackNum.add(Integer.parseInt(number));
        }
        return attackNum;
	}

	public int getLevel() {
		System.out.println("레벨을 선택하세요.");
		System.out.printf("1: 초보  2: 숙련  3: 달인\n입력:");
		String input;
		while(true) {
			input = scanner.next();
			if(!input.matches("[1-3]{1}")) {
				System.out.print("레벨을 선택하세요. 입력:");
				continue;
			}
			break;
		}
		return Integer.parseInt(input)+2;
	}
	
	public boolean duplicateInputCheck(String input) {
		for(int i=0;i<input.length();i++) {
			if(input.substring(i+1).contains(input.substring(i,i+1))) {
				System.out.println("중복숫자가 있습니다.");
				return true;
			}
		}
		return false;
	}
	
}

String.matches() 

특정 패턴 (정규 표현식-Regex) 의 문자열을 포함하는지 확인할 수 있는 메서드입니다. 

문자열에 정규표현식이 일치하는지 boolean 타입으로 리턴합니다.

정규표현식을 사용하지 않아도 가능하지만 정확히 일치해야합니다.

 

특정 문자열을 검색할 때 사용하기보다 정규표현식을 이용하여 한글, 숫자 등과 같이 해당 텍스트의 형태가 존재하는지, 원하는 패턴 형식에 맞는 텍스트가 있는지 알아볼 때 사용합니다.

ex) 이메일, 아이디, 주민등록번호, 전화번호 등

 

정규표현식 (Regex = Regular Expression)

특정한 규칙을 가진 문자열의 집합을 표현하기 위해 쓰이는 형식 언어입니다.

원하는 입력값을 정해진 형식에 맞춰 입력하였는지 검증해야 할 때 정규표현식을 사용하면 쉽게 구현이 가능합니다.


RandomNumber 클래스

package game;

import java.util.ArrayList;
import java.util.Scanner;

public class InputNumber {
	Scanner scanner = new Scanner(System.in);

	public ArrayList<Integer> generatePlayerNumber(int level) {
        ArrayList<Integer> attackNum = new ArrayList<>();
        String input;
        while(true) {
        	System.out.println(level+"자리 숫자를 입력해주세요.");
        	input = scanner.next();
        	//if(input.length()!=level) {
        	if(!input.matches("\\d{"+level+"}") || duplicateInputCheck(input)) {
        		System.out.println("올바른 입력이 아닙니다.");
        		continue;
        	}
        	break;
        }
        for(String number: input.split("")){
            attackNum.add(Integer.parseInt(number));
        }
        return attackNum;
	}

	public int getLevel() {
		System.out.println("레벨을 선택하세요.");
		System.out.printf("1: 초보(3)  2: 숙련(4)  3: 달인(5)\n입력:");
		String input;
		while(true) {
			input = scanner.next();
			if(!input.matches("[1-3]{1}")) {
				System.out.print("레벨을 선택하세요. 입력:");
				continue;
			}
			break;
		}
		return Integer.parseInt(input)+2;
	}
	
	public boolean duplicateInputCheck(String input) {
		for(int i=0;i<input.length();i++) {
			if(input.substring(i+1).contains(input.substring(i,i+1))) {
				System.out.println("중복숫자가 있습니다.");
				return true;
			}
		}
		return false;
	}
	
}

RestartGame 클래스

package game;

import java.util.ArrayList;
import java.util.Random;

public class RandomNumber {
	//랜덤 숫자 생성
	public int randomNumberMake() {
		int result;
//		result = (int)(Math.random()*9+1); // Math.random 사용 
		Random random = new Random(); //Random class 사용
		result = random.nextInt(9)+1; // random.nextInt(max) + min;
		return result;
	}
	
	public ArrayList<Integer> Generate(int level) {
		ArrayList<Integer> defenceNumber = new ArrayList<>();
		while(defenceNumber.size()<level) {
			int randomNumber = randomNumberMake();
			if(defenceNumber.contains(randomNumber)) {
				continue;
			}else {
				defenceNumber.add(randomNumber);
			}
		}
		return defenceNumber;
	}
}

Umprire 클래스

package game;

import java.util.ArrayList;

class CheckNumber{
	public int countAll(ArrayList<Integer> defence, ArrayList<Integer> attack) {
		int result = 0;
		for(int i = 0; i < attack.size(); i++){
			if(defence.contains(attack.get(i))){
				result += 1;
			}
		}
		return result;
	}
	public int countStrike(ArrayList<Integer> defence, ArrayList<Integer> attack) {
		int strike=0;
        for(int i = 0; i < attack.size(); i++){
            if(defence.get(i) == attack.get(i)){
                strike += 1;
            }
        }
        return strike;
	}
}
public class Umpire {
	CheckNumber check = new CheckNumber();
	public String decide(ArrayList<Integer> defenceNumber, ArrayList<Integer> attackNumber) {
		String result="";
		int all = check.countAll(defenceNumber,attackNumber);
		int strike = check.countStrike(defenceNumber,attackNumber); 
		int ball = all-strike;
		if(all==0) {
			result="Nothing";
		}else {
			if(strike!=0){
				result+=strike+"스트라이크";
			}
			if(ball!=0) {
				result+=ball+"볼";
			}
		}
		return result;
	}
}

실행 결과

입력값 [1] : 초보 단계 3 자리의 숫자로 게임을 시작합니다.

입력값 [2] : 숙련 단계 4 자리의 숫자로 게임을 시작합니다.

입력값 [3] : 달인 단계 5 자리의 숫자로 게임을 시작합니다.


BaseballGameMain 클래스의 main 에서

System.out.println(defenceNumber);

 

 

해당 코드를 주석처리 하여 defenceNumber를 확인하지 않고 게임을 플레이할 수 있습니다.


아래는 숫자야구게임의 다른 코드입니다.

import java.util.Random;
import java.util.Scanner;

public class BaseBallVarGame {

	public static void main(String[] args) {
		
		Random random = new Random();
		Scanner scanner = new Scanner(System.in);
		
		//게임에서 사용할 변수
		int com1, com2, com3;		
		int user1, user2, user3;
		int randomCnt = 0;//난수생성 카운트
		int gameCount = 0;//게임 카운트
		int strikeCnt=0, ballCnt=0;//스크라이크,볼 카운트
		
		//게임전체반복	
		while(true) {		
			//중복되지 않는 3개의 난수생성
			while(true) {
				//몇번만에 난수가 생성되는지 확인
				randomCnt++;				
				//1~9사이의 난수생성
				com1 = random.nextInt(100) % 9 + 1;
				com2 = random.nextInt(100) % 9 + 1;
				com3 = random.nextInt(100) % 9 + 1;
				if(!(com1==com2 || com2==com3 || com3==com1)) {				
					//중복되지 않는 난수 생성에 성공하면 루프탈출
					break;
				}
			}////while end
			
			//난수확인
			System.out.println(randomCnt+"회:"+com1+" "+com2+" "+com3);
			
			while(true) {
				//사용자로부터 3개의 정수를 입력받는다.
				System.out.println("3개의정수를 입력하세요(1~9)");
				System.out.println("스페이스로 구분하시고 마지막에 Enter를 눌러주세요");				
				user1 = scanner.nextInt();
				user2 = scanner.nextInt();
				user3 = scanner.nextInt();
				
				//게임카운트 1회 증가
				gameCount++;
				
				//판단1 - 스크라이크(숫자와 위치까지 일치)
				if(com1==user1) strikeCnt++;
				if(com2==user2) strikeCnt++;
				if(com3==user3) strikeCnt++;
				
				//판단2 - 볼(숫자는 일치하나 위치가 다를때)
				if(com1==user2 || com1==user3) ballCnt++;
				if(com2==user1 || com2==user3) ballCnt++;
				if(com3==user1 || com3==user2) ballCnt++;
				
				//게임종료판단
				if(strikeCnt==3) {
					System.out.println("3스트라이크 게임종료");
					System.out.println(gameCount+"번만에 맞추셨습니다.");
					break;//루프탈출
				}
				else {
					//하나도 못맞추는 경우
					if(strikeCnt==0 && ballCnt==0) {
						System.out.println("아웃입니다");
					}
					else {
						System.out.printf("%d스트라이크, %d볼\n",
								strikeCnt, ballCnt);
					}
					//스트라이크, 볼 카운트 초기화
					strikeCnt = 0;
					ballCnt = 0;
					//continue문은 필요없음.
				}
			}////while end
			
			System.out.println("한게임 더 하시겠습니까?(0:종료,1:재시작)");
			int restart = scanner.nextInt();
			if(restart==0) {
				//게임종료
				System.out.println("\n==게임이 종료되었습니다.==\n");
				//실행되는 즉시 main함수가 종료된다.
				System.exit(0);
			}
			else if(restart==1){
				//게임을 재시작하기 위해 카운트변수 초기화
				strikeCnt = 0;
				ballCnt = 0;
				gameCount = 0;
				System.out.println("\n==게임을 재시작합니다.==\n");
			}
		}//게임 전체 반복 while end
	}//main 메서드 end
}//class 끝

https://nakja.tistory.com/81 블로그에서 발견한 코드입니다.

코드가 간결하고 좋아서 참고용으로 첨부하였습니다.