[개발 실습] 행맨 게임 만들기

nyoung·2023년 7월 3일
2

개발실습

목록 보기
3/4

자바 콘솔을 사용하는 행맨 게임을 제작해보았다.
단계별로 요구사항을 맞춰가면서 코드를 작성하였는데, 요구사항 정의가 중요하다는 것을 느끼게 된 프로젝트이다.
조원들과 서로 코드 리뷰를 진행해가며 리팩토링하는 과정이 재미있었고 도움이 많이 되었다.


🎮 행맨 게임

행맨 게임을 할 수 있는 프로그램을 만듭니다. 컴퓨터는 미리 정의된 목록에서 단어를 무작위로 선택하고 사용자는 단어의 문자를 추측해야 합니다.
컴퓨터는 사용자의 추측에 대한 피드백을 제공하며 라운드가 진행됩니다. 사용자는 정답 단어를 추측하거나 시도 횟수가 부족할 때까지 추측을 반복하게 됩니다.

🔍 요구사항

✅ 1단계

  • 게임 횟수와 목숨 횟수를 입력한다.
  • 미리 정의된 정답 단어 중 하나가 무작위로 선택된다.
  • 매 라운드마다 목숨의 횟수와 현재까지 추측에 성공한 점수 보드를 출력한다.
  • 사용자에게 문자를 입력하라는 메시지를 표시한다.
  • 사용자의 추측에서 일치하는 위치의 알파벳이 있다면 이를 표시한다.
  • 사용자가 모든 글자를 정확히 맞춘다면 축하 메시지를 안내한다.
  • 목숨의 횟수가 끝났다면 실패 메시지를 안내한다.
ou : 게임 횟수와 목숨을 입력하세요.
in : 2, 4
ou : 1번째 게임이 시작됩니다. 정답 단어는 5글자 입니다.
ou : 1 라운드 : _____, 목숨 4
in : p
ou : 2 라운드 : _pp__, 목숨 4
in : i
ou : 3 라운드 : _pp__, 목숨 3
in : l
ou : 4 라운드 : _ppl_, 목숨 3
in : e
ou : 5 라운드 : _pple, 목숨 3
in : a
ou : 6 라운드 : apple, 목숨 3
ou : 축하합니다. 정답입니다.

ou : 다음 게임을 시작합니다.
ou : 2번째 게임이 시작됩니다. 정답 단어는 7글자 입니다.

✅ 2단계

  • 정답과 예시에서 벗어나 나올 수 있는 잘못된 시나리오들을 생각해보고 본인의 방식대로 처리한다.

✅ 3단계

  • 각 라운드에서 진행한 라운드 결과를 저장한다. 라운드 결과에는 라운드id, 라운드에 남은 목숨 수, 라운드의 점수 보드, 사용자 추측이 포함된다.
  • 각 게임의 결과를 저장한다. 게임 결과에는 게임id, 사용자 성공/실패 여부, 남은 목숨 개수, 게임의 정답이 포함된다.
  • 게임이 종료되면 해당 게임의 결과 -> 그 게임의 각 라운드 결과를 차례로 출력한다.
ou : 축하합니다. 정답입니다.
ou : 
=== Game Result ===
게임 id : 1, 추측 : 성공, 남은 목숨 : 3, 정답 : apple 

라운드 id : 1, 남은 목숨 : 4, _____, 사용자 입력 : p
라운드 id : 2, 남은 목숨 : 4, _pp__, 사용자 입력 : i
라운드 id : 3, 남은 목숨 : 3, _pp__, 사용자 입력 : l
라운드 id : 4, 남은 목숨 : 3, _ppl_, 사용자 입력 : e
라운드 id : 5, 남은 목숨 : 3, _pple, 사용자 입력 : a
===================

ou : 다음 게임을 시작합니다.
ou : 2번째 게임이 시작됩니다. 정답 단어는 7글자 입니다.

✅ 4단계

  • 게임과 라운드 결과를 조회할 수 있다. 선택 메뉴를 출력한다. 메뉴에는 게임하기, 게임 결과 보기, 라운드 결과 보기가 있다.
  • 게임하기라면 위의 1,2단계가 그대로 진행된다.
  • 게임 결과 보기라면 게임의 id를 입력하고 게임 결과를 출력한다.
  • 라운드 결과 보기라면 라운드의 id를 입력하고 라운드 결과를 출력한다.
ou : 메뉴를 선택합니다. (1 : 게임하기, 2 : 게임 결과 보기, 3 : 라운드 결과 보기)
in : 2
ou : 게임 id를 입력해주세요.
in : 1
ou : 
=== Game Result ===
게임 id : 1, 추측 : 성공, 남은 목숨 : 3, 정답 : apple 

라운드 id : 1, 남은 목숨 : 4, _____, 사용자 입력 : p
라운드 id : 2, 남은 목숨 : 4, _pp__, 사용자 입력 : i
라운드 id : 3, 남은 목숨 : 3, _pp__, 사용자 입력 : l
라운드 id : 4, 남은 목숨 : 3, _ppl_, 사용자 입력 : e
라운드 id : 5, 남은 목숨 : 3, _pple, 사용자 입력 : a
===================

ou : 메뉴를 선택합니다. (1 : 게임하기, 2 : 게임 결과 보기, 3 : 라운드 결과 보기)
in : 3
ou : 라운드 id를 입력해주세요.
in : 4 
=== Round Result ===
라운드 id : 4, 남은 목숨 : 3, _ppl_, 사용자 입력 : e
===================

ou : 메뉴를 선택합니다. (1 : 게임하기, 2 : 게임 결과 보기, 3 : 라운드 결과 보기)
...

🖥️ 코드 리뷰

1️⃣ try-catch-resource 활용하기

처음 스캐너를 열어주고 프로그램 종료시까지 계속 사용하였는데, 닫아주어야 한다고 코멘트 받아서 try-catch-resource 구문으로 수정하였다.

// 리뷰 전
public class HangManApplication {
    private static final Scanner scanner = new Scanner(System.in);
// 리뷰 후
public class HangManApplication {
    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
        ...
        }

2️⃣ try-catch와 재귀함수 예외처리에 활용하기

입력 예외를 처리하는 과정에서 while문을 사용하였는데, 다른 분들이 보기에 코드가 가독성 있지 않고 복잡해보였다. while문이 아니라 try-catch로 재귀함수 돌리는 방법도 있다고 코멘트 받아서 수정하였다.

// 리뷰 전
 while (!isValidInput) {
            try {
                System.out.println("게임 횟수와 목숨을 입력하세요.");
                scanner.nextLine();
                String str = scanner.nextLine();
                String[] input = str.split(",");
                if (input.length < 2) {
                    throw new IllegalArgumentException("숫자, 숫자 형태로 입력해주세요.");
                }
                System.out.println("\n다음 게임을 시작합니다.");
            }
            System.out.println(gameId + "번째 게임이 시작됩니다. 정답 단어는 " + answer.length() + "글자 입니다.");
            playRound(gameId, userLife, answer, blind, scanner);
            gameId++;
        }
    }
// 리뷰 후
public static void startGame() {
        try {
            System.out.println("게임 횟수와 목숨을 입력하세요.");
            String str = reader.readLine();
       ...
            runGames(user, startGameID);
        } catch (NumberFormatException e) {
            System.out.println("숫자, 숫자 형태로 입력해주세요.");
            startGame();
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
            startGame();
        } catch (IOException e) {
            System.out.println("입력 오류가 발생했습니다.");
        }
    }

3️⃣ User 객체의 확장성 고려하기

user class가 가장 애매했는데(사실상 따로 클래스를 나눈것도 의미는 없는 기분, 확장성도 고려되지 않음) user 객체가 점점 많아진다면? 이라는 코멘트를 받아 아예 userName변수까지 추가해서 추후 user객체들을 List로 관리하도록 수정하였다.

// 리뷰 전
public class User {
    private Integer life;
    private Integer gameNum;
    ...
    }
// 리뷰 후
public class UserList {
    private Map<String, User> users;
    ...
    }
public class HangManApplication {
    private static final UserList userList = new UserList();

    public static void main(String[] args) {
		System.out.println("사용자 이름을 입력하세요.");
		String userName = br.readLine();
		User user = new User(userName, life, gameNum);
		userList.addUser(user);
        ...
        }

4️⃣ 미리 제외할 수 있는 상황 체크하기

만약 게임이 한번도 진행되지 않은 경우에도 게임 id와 라운드 id를 입력해야 게임 진행 여부를 확인할 수 있었는데, 이 부분을 코멘트 받아 미리 걸러줄 수 있도록 추가하였다.

// 리뷰 후
if (games.isEmpty()){
            System.out.println("진행된 게임이 없습니다.");
            return;
        }

🤔 후기

코드 리뷰를 해주면서 리팩토링 하는 과정이 즐거웠고, 내가 항상 놓치는 부분에서도 피드백 받을 수 있어서 도움이 많이 되었다. 특히 try-resource 구문은 다른 프로젝트에서도 애용하게 되었다. 추후 행맨 프로젝트를 스프링부트를 사용해 웹어플리케이션으로 전환해보고 싶은데, 아직 스프링에서 허우적대는 수준이라 언제 완성될지는 모르겠다 🥺
깃에서 자세히 보기

profile
새싹 개발자

0개의 댓글