본문 바로가기

Languages/Java

자바 배열 활용 - 미니마블 게임 만들어보기

이번 글에서는 Java 로 간단한 미니 마블 게임을  만든 과정을 소개합니다 !


실행 결과

 

시작 출력화면
메뉴 1번 입력 - 게임시작 시 출력 화면

 

게임에서 승리시 출력화면

 

미니 마블이란?
8칸으로 이루어진 공간에서 총 3바퀴를 먼저 완주하면 이기는 게임입니다. 

 

기본 규칙

  • 이동 가능한 거리는 1~3 사이의 값
    → 1~3 외에 다른 값은 올 수 없습니다.
  • 플레이어의 이동이 끝난 곳에 상대 플레이어가 있다면 상대 플레이어의 위치는 0으로 초기화됩니다.

 

 

제가 생각한 전체적인 흐름을 플로우차트로 그려보았습니다

 

전체적인 흐름 


① 메뉴 보여주기
② 사용자로부터 메뉴 입력 받기 

  1.  게임 시작
  2.  게임 룰 출력
  3.  종료

② - ① 게임시작 

  • 이동거리 입력 받기
  • 입력 값만큼 플레이어 이동
  • 3번 완주가 끝나지 않았다면 턴 교체하여 위 동작 실행
  • 3번 완주가 끝났다면 승리 플레이어 출력 후 메뉴로 이동

 

전체적인 플로우차트

 
 

큰 흐름별로 세부적인 내용도 확인 해보겠습니다 

 

세부적인 내용 

① 메뉴 보여주기

메뉴 선택 플로우차트

 

이번 게임에서는 클래스를 이용하여

메뉴 , 게임룰을 보여주는 Show 클래스와

게임을 실행하기 위한 GameSet 클래스를 만들어 사용하였습니다

 

입력 값에 맞게 객체를 생성만 해주면 되어서 넘어가겠습니다 !
 
 

메뉴 선택 코드
Show class

   설명   
 

  • 입력값을 받기 위한 Scanner 라이브러리 이용 (1~3 사이의 수)  
  • 입력값이 3이 되기 전 까지는 무한루프 
  • Show 객체 game 생성 => 생성자 호출 (메뉴 소개)
  • 스위치 문을 이용하여 입력 값에 맞춰 각 case로 이동
  • case 1: GameSet 객체 생성  => 생성자 호출  (게임 시작)
  • case 2: game.showRule 호출 => 게임 규칙 출력
  • case 3: 무한루프 isGame = true / 종료

② - ① 게임시작 (GameSet 메인 메서드)
 

 

그리려고 하니 꽤 많은 조건들을 거쳐서 나가게 되네요 ㅎㅎ...

어떻게 코드로 작성했는지 한 번 확인해보죠 !

게임 시작 메인 코드

   설명   
 

  • 플레이어 각각의 맵 , 플레이어 , Lap , turn 변수 초기화
  • 무한루프 
    • (1) 두 플레이어 중에 3바퀴 완주를 하였는가 
    • (2) showMap 메서드 호출 => 플레이어들의 위치와 lap 값을 보여줌
    • (3) 이동할 거리 값 1~3 사이의 숫자를 inputValue 메서드로 입력을 받아 해당 차례 플레이어 변수에 값을 넣어줌
    • (4) checkLap 메서드를 통해 해당 차례 플레이어 변수의 값이 8이상이라면 8로 나눠 몫을 가져와 해당 플레이어의
            laps 에 더해주고 , 8로 나눈 나머지를 플레이어 변수로 가지게 된다 . 
    • (5) move 메서드에서 플레이어 변수의 값만큼 자리를 이동하며 , 이동 후 상대 플레이어를 잡게 되면 true를 반환하며
           if문 실행이 되며 상대 플레이어의 변수값이 0으로 초기화된다
    • (6) turn을 계속해서 바꾸며 진행한다. ( 1 - 0 = 1 , 1 -1 = 0  => 0, 1 반복)

무한 루프를 돌며 진행되는 게임 과정에 대해 좀 더 자세히 보겠습니다  

(*) 변수 초기화 

변수

 


   설명   

  • index = 0 은  1 플레이어가 가지고 1 은 2 플레이어가 가지는 변수이다.
  • 위에서 순서대로
    • 각각 8칸 짜리의 맵
    • 플레이어 1  , 2
    • Lap 1 , 2
    • turn = 0  이므로 1 player 부터 시작된다  

 
 
(1) 두 플레이어 중에 3바퀴 완주를 하였는가 

무한루프를 탈출하는 유일한 조건문
메인에서 메서드 호출
isEnd 메서드

 
   설명   

  • 배열로 만들어진 플레이어 각각의 turn에 맞는 index값을 자기의 lap으로 갖게 함
  • lap[0] 이나 lap[1] 의 값이 4라는 건 3바퀴 완주가 끝났다는 얘기
  • boolean 변수로 true 혹은 false를 반환해주며 
  • main 메서드에서 if문으로 탈출 혹은 반복한다 .


   추가  

  • 파라미터로 laps (int 형 배열) 을 받아오는거라 int [] laps 로 받아와 index로 접근하였다

(2) showMap 메서드 호출

(1) 번이 false가 나왔을 경우 진행되는 플로우차트

 

메인에서 메서드 호출
showMap 메서드

   설명   

  • 1번째 반복문에서는 index 값 0부터 시작하며 map의 length = 2 까지 총 2번 반복하며 각각 플레이어의 map 에 접근함
  • 0 은 player 1 , 1 은 player 2 임을 알려주는 index 이므로 index+1 을 함으로써  " player 1 : " / " player 2 : " 를 출력한다
  • 출력후 player 의 map에 있는 총 길이 8칸 모두 반복문을 통해 m으로 하나씩 꺼내며 m을 이어 출력한다
  • 출력이 끝난 후에는 해당 차례 플레이어에게 이동할 거리를 입력 받아야 하는 문장을 출력한다.

 
   추가  

  • 파라미터로 플레이어들의 map , laps 의 값을 배열로 가져와서 for문을 돌리며 사용하는 index를 사용하여 접근함

(3)  inputValue 메서드로 입력 받기
 

입력 값을 받아오고 간단한 유효성 검사와 플레이어 값 검사

 

메인에서 메서드 호출
inputValue 메서드

   설명   

  • 입력을 받는데 1 ~ 3 사이의 숫자라면 입력 받은 값을 return 후 해당 차례 플레이어 값에 더해준다.
  • 아니라면 반복해서 다시 입력 받기
checkLap 메서드

   설명   

  • 해당 차례 플레이어의 값이 8 이상이라면 1을 return 해주고 아니라면 0을 리턴해준다
  • 리턴받은 값은 해당 플레이어 lap에 저장된다
  • 플레이어 값이 8 미만이라면 8로 아무리 나눈 나머지로 바꿔도 같은 값이기에 
    8이상의 값을 가지고 있으면 lap += 1 , player -= 8 이 된다

 
(4) move 

플레이어 값 만큼 이동 후 상대 플레이어를 잡았는가 ?
메인에서 메서드 호출
move 메서드

 
   설명   

  • 상대 플레이어를 잡았는지 안 잡았는지 체크하는 boolean 변수를 만들어준다
  • 해당 차례 플레이어의 맵을 모두 0으로 초기화를 시켜준다
  • 해당 차례 플레이어의 값의 위치(index)에 해당 turn에 +1 한 값을 넣어준다
    ( turn 0 일땐   p1 -> 1로 위치표시 , turn 1일땐 p2 -> 2 로 위치표시 ) 
  • 상대 플레이어의 맵에 현재 플레이어 값 위치에 0 이 아닌 다른 숫자가 있다면 그건 같은자리에 있다는 얘기가 된다.
    if문을 통해 상대 플레이어 맵의 모든 값을 0으로 만들며 , catchplayer를 return한다 .
    (이부분은 쓰면서 알게 되었는데 굳이 메인 메서드에서 if문을 쓰며 조건 확인 후 플레이어 값을 0으로 만들고 있었다
       이건 그냥 player를 배열 전체로 받아 메서드 내부에서 해결해도 될듯하다)
  • true인 경우 상대 플레이어 값 자체도 0으로 만들어주며 turn 을 교체한다 

   추가  

  • 파라미터로 플레이어들의 map 값을 배열로 가져와서 for문을 돌리며 사용하는 index와 turn 을 사용하여 접근함

(5) 게임 종료 !

게임 끝
맨 처음 비교한 isEnd 조건이 true로 바뀌며 break하며 탈출

   설명   

  • isEnd 메서드가 참이 되면서 이 무한 루프를 탈출하게 된다 
  • 탈출 후 마지막으로 끝난 turn의 값을 비교하면서 승리한 플레이어를 출력하면서 다시 메뉴 선택창으로 돌아가게 된다

완성된 플로우차트

  하면서 알게된 점

  • 배열을 사용하지 않고 각각의 변수로 사용을 했더니 5줄이면 끝날 코드가 15줄 이랬는데 배열로 변경하면서 코드 간결해졌음
  • 이전 코드 Call by Value : 메서드 내에서 값 변경 힘들고 리턴값이 있어야 했다
  • 수정 후 코드 Call by reference : 메서드 내에서 배열의 주소를 직접 참조하여 수정해서 별도의 리턴 없이도 변경이 가능했음
  • 배열을 사용하면서 turn 이라는 변수의 응집도? 같은 것이 엄청 커졌던 걸 느꼈다
  • 클래스를 사용하여 목적에 맞게 분리시킨 것 같아 보기가 편해졌음
  • 리팩토링을 하면 할 수록 분명 코드는 점점 전 보다 좋아지고 있음 다만 아직 한 번에는 이렇게 작성이 안 되고 구현이 끝나고 나서 천천히 수정하면서나 가능하다 ... 꾸준함이 답인 듯 하다

 

생각보다 글로 적으려니 많이 길었던 내용이었고 ,

또 적다보니까 아쉬운 코드들도 발견되어서 나름 의미있는 블로그 쓰기였습니다

아자아자 화이팅 !