▶ 프로젝트 설명
이 프로젝트는 자바로 숫자 야구 게임을 구현한 것입니다. 1부터 9까지의 숫자 중에서 중복되지 않은 세 자리 숫자를 맞추는 게임입니다. 프로그램은 세 자리의 랜덤 숫자를 생성하고, 사용자가 숫자를 입력하면 그에 맞는 힌트를 제공합니다. 숫자의 위치와 값이 모두 맞으면 '스트라이크', 값만 맞고 위치가 틀리면 '볼', 둘 다 틀리지 않으면 '아웃'으로 표시됩니다. 사용자가 세 자리를 모두 맞출 때까지 게임이 반복됩니다.
▶ 사용된 주요 개념
- Scanner : 사용자 입력을 받는 데 사용.
- Random : 랜덤 숫자를 생성하는 데 사용.
- HashSet : 중복 없는 랜덤 숫자와 입력을 검증하기 위해 사용.
- 문자열 처리 : 사용자 입력을 검증하고 스트라이크, 볼, 아웃 여부를 계산하기 위해 사용.
▶ 코드 설명
- Main 클래스 : 메인 메뉴를 출력하고 사용자의 선택에 따라 게임을 시작하거나 종료합니다.
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> count = new ArrayList<>();
ArrayList<Integer> level = new ArrayList<>();
Scanner sc = new Scanner(System.in); // 사용자 입력을 위한 Scanner 생성
int cnt, chk, digits = 3; // cnt는 시도 횟수, chk는 사용자의 선택 담기, digits는 기본 자리수 설정값 - 3
while(true) {
System.out.println("환영합니다! 원하시는 번호를 입력해주세요");
System.out.println("0. 자리수 설정(미설정 시 3자리) / 1. 시작 / 2. 기록 / 3. 종료");
try {
chk = sc.nextInt(); // 사용자가 선택한 메뉴 입력 받음
} catch (InputMismatchException e) {
System.out.println("숫자만 입력하세요.");
sc.nextLine(); // 입력버퍼 초기화
continue;
}
switch(chk) {
case 0:
System.out.print("설정하려는 자리수를 입력하세요 : "); // 사용자가 원하는 자리수 입력받기
digits = sc.nextInt();
System.out.println(digits + " 자리수 난이도로 설정되었습니다.");
chk = 1; // 자리수값 설정 후에 break없이 바로 게임 진행
case 1:
BaseballGame game = new BaseballGame(digits); // 새로운 게임 객체 생성
System.out.println("< 게임을 시작합니다 >");
cnt = game.play(digits); // 게임 실행 후 시도 횟수 반환
System.out.println("정답입니다! 도전횟수 : " + cnt);
count.add(cnt);
level.add(digits);
break;
case 2:
System.out.println("< 게임 기록 보기 >");
if (count.isEmpty()) { // 기록된 정보가 없을 시
System.out.println("기록 없음");
} else { // 기록된 정보가 있다면 출력
for (int i = 0; i < count.size(); i++) {
System.out.println(i + 1 + "번째 게임 시도 횟수 : " + count.get(i) + "회 / 자리수 : " + level.get(i));
}
}
break;
case 3:
System.out.println("종료합니다."); // 프로그램 종료 메시지
break;
default:
System.out.println("다시 입력해주세요."); // 잘못된 입력 처리
}
if (chk == 3) break; // 종료를 선택하면 반복문 탈출
}
}
}
- BaseballGame 클래스 : 게임의 로직을 담당하며, 사용자의 입력을 받아 정답과 비교한 후 힌트를 제공합니다.
import java.util.*;
public class BaseballGame {
BaseballGameDisplay display; // 힌트 출력을 위한 디스플레이 객체
Scanner sc = new Scanner(System.in); // 사용자 입력을 받기 위한 Scanner
HashSet<Integer> test = new HashSet<>(); // 랜덤 숫자의 중복을 방지하는 HashSet
private Random rand = new Random(); // 랜덤 숫자 생성을 위한 Random 객체
private String inputnum; // 사용자 입력을 저장할 변수
String answer = ""; // 정답을 저장할 변수
int count = 0; // 시도 횟수
int strike; // 스트라이크 개수
int ball; // 볼 개수
public BaseballGame(int digits) {
display = new BaseballGameDisplay(); // 디스플레이 객체 초기화
StringBuilder sb = new StringBuilder();
// 정답 숫자를 랜덤으로 생성하고 중복되지 않도록 HashSet에 저장
while (sb.length() < digits) {
int digit = rand.nextInt(9) + 1; // 1~9 사이의 랜덤 숫자 생성
if (test.add(digit)) { // 중복이 아니면 숫자를 추가
sb.append(digit);
}
}
answer = sb.toString(); // 정답을 문자열로 저장
}
public int play(int digits) {
while (true) {
// 사용자에게 입력값을 받음
System.out.print("숫자를 입력하세요:"); /// 입력 및 출력 개선
inputnum = sc.nextLine();
// 입력값이 올바른지 검증
if (!validateInput(inputnum, digits)) {
System.out.println("제대로 입력해주세요. 중복x 이상한 문자x");
continue;
}
count++; // 시도 횟수 증가
strike = countStrike(inputnum); // 스트라이크 개수 계산
// 스트라이크 3개 맞추면 종료
if (strike == digits) {
break;
}
ball = countBall(inputnum); // 볼 개수 계산
display.displayHint(strike, ball); // 힌트 출력
}
return count; // 시도 횟수 반환
}
// 입력값 검증 메소드
protected boolean validateInput(String input, int digits) {
String regex = "[1-9]{" + digits + "}";
if (input.length() != digits || !input.matches(regex)) { // 1~9 사이의 숫자이고 3자리인지 확인
return false;
}
HashSet<Character> set = new HashSet<>();
for (char c : input.toCharArray()) {
if (!set.add(c)) { // 중복이 없으면 true
return false;
}
}
return true;
}
// 스트라이크 개수 계산 메소드
private int countStrike(String input) {
int result = 0;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == answer.charAt(i)) { // 숫자와 위치가 모두 맞으면 스트라이크
result++;
}
}
return result;
}
// 볼 개수 계산 메소드
private int countBall(String input) {
int result = 0;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) != answer.charAt(i) && answer.contains(String.valueOf(input.charAt(i)))) { // 숫자는 맞고 위치가 틀리면 볼
result++;
}
}
return result;
}
}
- BaseballGameDisplay 클래스 : 스트라이크와 볼을 화면에 출력하는 역할을 합니다.
package baseball;
public class BaseballGameDisplay {
public void displayHint(int strike, int ball) {
String hint = "";
if (strike > 0) hint += strike + " 스트라이크 ";
if (ball > 0) hint += ball + " 볼 ";
if (hint.isEmpty()) hint = "아웃"; // 스트라이크와 볼이 모두 없으면 아웃
System.out.println(hint.trim()); // 힌트 출력
}
}
▶ 회고
- 객체지향적 설계 : 각 역할별로 클래스를 분리해 관리하니, 코드의 가독성과 유지보수성이 향상되었습니다. 특히
BaseballGameDisplay
클래스를 만들어 게임 로직과 출력 로직을 분리한 점이 큰 장점이었습니다. - 입력 검증 : 사용자의 입력값을 검증하는 과정에서
HashSet
을 사용하여 중복 숫자를 쉽게 걸러낼 수 있었습니다. - Random을 이용한 숫자 생성 :
Random
클래스를 활용해 쉽게 랜덤 숫자를 생성할 수 있었고, 중복을 방지하는HashSet
과 조합하여 정답 숫자를 생성하는 과정이 원활하게 이루어졌습니다.
▶ 트러블슈팅
- 잘못된 입력 처리 문제 : 처음에는 잘못된 입력(예: 중복 숫자나 숫자가 아닌 문자)이 들어왔을 때, 제대로 검증되지 않아서 오류가 발생했습니다. 이를 해결하기 위해
validateInput
메소드를 만들어 입력값이 1~9 사이의 중복되지 않는 3자리 숫자인지 확인하는 로직을 추가했습니다. - 스트라이크와 볼 계산 오류 : 초기에 스트라이크와 볼 계산 과정에서 로직이 잘못되어 정확한 힌트가 제공되지 않는 문제가 있었습니다. 이를 해결하기 위해 스트라이크와 볼의 조건을 명확히 나누고,
String.contains()
메소드를 사용해 스트라이크와 볼을 검증하는 방법을 수정했습니다. - 스트라이크와 볼 연산 처리 문제 : 처음에는 입력받은 값과 랜덤한 정답을 HashSet에서 저장하여 시작해보거나 List를 활용하여 처리해보았으나 두 값을 비교하는 비교하는 상황에서 소스코드가 복잡해지고 특정 상황에서는 연산을 처리하지 않는 문제가 발생하거나 연속적인 연산 처리 과정에서 문제가 있었습니다. 이를 해결하기 위해 간편하게 비교하기 위한
charAt()
함수를 사용하기 위해 입력받은 값과 정답을 String 변수에 받을 수 있게끔 수정하였습니다.
▶ 개선 사항
- GUI로 확장하여 사용자 경험 개선
이 프로젝트를 통해 사용자 입력 검증, 컬렉션 활용, 로직 설계에 대한 이해도를 높일 수 있었으며, 추가 기능을 통해 더욱 발전시킬 계획입니다.
'Project' 카테고리의 다른 글
개인 프로젝트 : 일정 관리 앱 JPA ver (0) | 2024.10.16 |
---|---|
개인 프로젝트 : 일정 관리 앱 Lv 3 (0) | 2024.10.04 |
개인 프로젝트 : 계산기 만들기 Lv2 (0) | 2024.09.19 |
팀 프로젝트 : 우리 팀, 우리만의 이야기를 담을 수 있는 "팀 소개 웹페이지" 만들기 (0) | 2024.09.19 |