devGYU World
JAVA를 활용한 3가지 GUI 게임 본문
본 프로젝트는 학부생 시절 전공 과목의 프로젝트를 위해 진행되었다.
TicTacToe와 1 to 50, 오목 총 3가지의 GUI 게임을 구현한다.
V01 개발시작
TicTacToe를 구성하기 위해서는 최소 3 x 3 이상의 보드가 필요하다고 생각하였다. 이때 보드를 board라는 이차원 배열로 선언하여 플레이어가 둔 말의 위치 정보를 저장하고, 승리조건을 계산할 때 이용하는 것으로 초기 구상을 시작하였다.
위와 같이 보드를 구성하였다. 3 x 3 보드에서 플레이어가 말을 두기 위한 위치를 입력하기 쉽게 하기 위해 행은 1~3 열은 a ~ c로 나타내었다. 그 외 보드의 빈공간은 ‘.’으로 표기해 최대한 직관적인 UI를 구성하였다.
위와 같은 형태로 초기 버전의 TicTacToe가 완성되었다. 그러나 초기버전이기에 다양한 문제가 있었다. 발견한 문제점은 아래와 같다.
플레이어 입장에서 말을 놓기가 굉장히 불편(직관적이지 않음) 코드 내부에 승리조건 부분이 굉장히 비효율적으로 구성돼 있음 같은 계산을 하는 알고리즘 부분이 플레이어마다 계산되어 비효율적임 |
이 중에서 우선적으로 보완되어야 할점은 2번었다. 보완을 위한 코드를 구상하기에 조금 더 긴 시간 동안의 생각이 필요했다. V01에서의 플레이어 ‘X’의 승리조건은 아래와 같이 구성돼 있다.
보이는 바와 같이 모든 조건에 대해서 수동적으로 계산을 수행하여 승리조건을 판단한다. 이로 인해서 플레이어에게 직접 보드 크기를 입력받는 형태의 게임에서는 승리조건을 구현하기가 굉장히 비효율적이게 될 것이다. 또한 X와 O의 승리 조건은 동일한데 같은 계산을 각각의 플레이어에 맞춰 따로 계산해야 하는 비효율적인 측면 역시 존재했다. 이와 같은 점을 수정하고자 V02를 개발하였다.
V02 개발 시작
V02는 V01에서 발견한 다양한 문제점들을 해결하기 위해 개발하였다. 기본적인 보드를 구성하는 형태는 V01과 같지만 이번에는 보드의 사이즈를 플레이어가 직접 설정할 수 있고, 이에 맞춰 승리조건 역시 입력받은 보드의 크기에 맞게 동적으로 계산할 수 있도록 수정하였다. 또한 직관적이지 못한 UI를 최대한 다듬어 일반 사용자들에게 익숙한 형태의 보드 모양으로 나올 수 있도록 수정하였다.
위 두 사진을 통해 프로그램이 이제는 직접 플레이어가 보드 크기를 설정할 수 있게 되었음을 확인할 수 있다. 이때 Scanner 함수를 통해 num이라는 변수로 보드의 크기를 저장하고, 이를 createBoard라는 함수에 보드 사이즈를 넘겨주며 보드 크기를 생성한다. 또한 기존에 구분선 없이 빈 곳은 ‘.’만으로 표기되어 구분하기 어려웠던 보드의 UI 역시 조금 더 직관적으로 개선됐다.
승리조건 역시 기존에 V01에서 보드에서 벌어지는 모든 승리의 조건을 계산하여 설정해주었던 비효율적인 방식에서 승리조건의 규칙을 찾아내어 이를 계산하는 방식으로 변경되었다. 이를 통해 보드의 크기에 맞춰 가변적인 계산이 가능해진다.
승리조건은 위의 사진과 같이 작성되었다. symbol은 플레이어의 말 즉, O와 X를 뜻한다. 각 symbol에 대해서 다음의 승리조건을 파악한다.
- 한 행을 모두 하나의 플레이어가 차지한 경우
- 한 열을 모두 하나의 플레이어가 차지한 경우
- 대각선들(정사선, 역사선) 중에서 하나라도 하나의 플레이어가 차지한 경우
행의 경우 이중 for문을 통해 보드의 크기만큼 board[i][j]를 파악한다. 즉, 모든 보드의 위치를 탐색하며 이때 if문을 통해 한 행을 탐색하던 중 현재 입력 받은 symbol과 다른 symbol이 탐색되면 그 즉시 for문을 빠져 나온다. 이를 통해 j가 보드의 크기와 같아진다면 해당하는 행은 모두 같은 symbol로 구성돼 있음을 알 수 있다. 열의 경우 행의 방식과 마찬가지이다. 대각선의 경우 정사선일 때와 역사선일 때가 갈린다. 정사선의 경우에는 인덱스가 모두 같은 board의 값이 symbol인지를 파악하면 되며, 역사선의 경우에는 board의 두번째 인덱스가 반대 방향으로 향해야 하므로 board의 크기에서 현재의 인덱스 i를 뺀만큼으로 인덱스를 설정해 symbol을 비교하면 된다.
위의 세 가지 중에서 하나라도 먼저 만족하는 symbol에 true값을 반환해주어 승리 메시지를 띄운다.
그러나 위와 같은 개선을 하였음에도 여전히 V02의 문제점들은 발견되었다. 발견된 문제점은 아래와 같다.
보드의 UI는 개선되었으나 플레이어가 말을 입력하는 방식은 여전히 불편함 수정사항이 많아짐에 따라 하나의 클래스 파일에 코드를 작성하기엔 관리가 어려움 TicTacToe의 기초적인 틀을 이용하면 이를 응용하여 다른 게임 역시 개발 가능할 것임 플레이어 수를 더 다양하게 늘리지 못함 |
우선적으로 수정하기 손쉬운 부분인 2~4번을 개선하기 위해 V03의 개발을 시작하였다.
V03 개발 시작
V03는 V02의 코드를 패키지 별로 나누어 코드의 유지보수가 간편하도록 하였다. 이를 위해 프로그램에서 수행되는 알고리즘 별로 역할을 나누어 각 역할에 맞는 패키지에 클래스가 분류된다.
위 사진과 같이 TicTacToeV03는 각 알고리즘의 역할별로 세 가지의 패키지로 구성된다. 게임의 초기화면을 구성하는 main 패키지, 게임을 진행하는 Game 패키지, 게임에 필요한 구성요소를 제공하는 Settings 패키지가 존재한다.
또한 이번 버전부터 TicTacToe의 기본적인 알고리즘을 응용하는 오목(Omok) 기능이 추가되었다. 이제 플레이어는 TicTacToe와 오목 중에서 게임을 선택하여 플레이할 수 있다.
이때 오목의 게임 동작은 기본적으로 TicTacToe와 같지만 승리조건이 다르기에 이에 대한 부분의 수정이 추가되었다.
위의 승리조건에 대한 동작 원리는 TicTacToe의 해당 부분과 유사하나 다른점은 이번에 한 행/열/정사선/역사선 전부가 하나의 symbol일 필요가 없다는 것이다. 오직 symbol은 각 경우에 4개 이상이 연속돼 있으면 된다.
이러한 조건을 만족시키기 위해 조건문 역시 symbol이 연속될 때마다 w라는 변수에 +1씩을 하였다. 즉, w가 4라는 것은 연속된 symbol이 4개라는 것이므로 이때 true를 반환한다.
또한 제안서에서 제출했던 내용에 맞게 보드 크기가 5 이상일 때부터 최대 3명의 플레이어가 게임을 즐길 수 있는 기능 역시 추가하였다. 해당 부분은 조건문을 추가함으로써 손쉽게 개선할 수 있었다.
그러나 V03 역시 이전의 문제점들을 완전히 해결하지는 못했다. 남아있는 문제점은 아래와 같다.
여전히 UI가 직관적이지 않다. 일부상황에서 오목의 경우 대각선 상황에서 승리조건을 제대로 계산해내지 못함 3명 이상의 플레이는 오히려 게임을 복잡하고 승리하기 어렵게 만듦 |
이 중에서 UI가 직관적이지 못한 것은 계속해서 이어져온 문제점이었다. 이는 플레이어가 말을 놓을 때 희망하는 위치에 클릭과 같은 행동이 아닌 좌표 입력이라는 불편한 방식으로 게임을 진행하기 생기는 문제점이다. 이와 같은 문제점을 해결하기 위해서 직접 마우스로 플레이어가 말의 위치를 결정할 수 있는 GUI 구성의 필요성을 느꼈다. 또한 GUI로 개발을 함으로써 이전에는 추가하지 못했지만 GUI를 통해 새롭게 개발할 수 있는 게임을 하나 더 추가하였다. 동시에 오목의 대각선 상황에 대한 승리조건 계산 오류는 게임 플레이에 지장을 줌으로 이또한 함께 수정할 필요성을 느꼈으며, 3번과 같이 구상 당시에는 차별성이 있어 괜찮다고 느껴진 부분인 3명 이상의 플레이어 플레이 기능은 실제 구현하고 테스트해보니 오히려 게임의 승리 조건을 더 까다롭게 만들어 진행을 지루하게 한다는 단점을 발견했다. 따라서 3번의 경우 해당 기능을 아예 삭제하기로 결정하였으며 그 외의 문제점들을 개선하고자 최종 버전의 개발을 시작하였다.
V4 최종버전 개발 시작
최종버전은 이전 버전들의 근본적인 문제점인 직관적이지 않은 UI를 개선함과 동시에 V03의 오목에서 일부 상황에서 대각선의 승리조건을 계산하지 못하는 오류를 수정하였고, GUI를 통해 개발된 만큼 이를 통해서 즐길 수 있는 새로운 게임 1 to 50을 추가 개발하였다.
또 프로그램의 이름을 ‘TicTacToe’에서 ‘Game!’으로 바꾸었다. 다양한 게임들을 메뉴에서 골라 사용자가 원하는 게임을 플레이할 수 있는 프로그램이 되었기 때문이다.
GUI를 이용하여 이전 버전에 비해 더욱 직관적인 형태를 갖춘 UI가 구성되었다. 이는 게임 메뉴뿐만이 아니라 각 게임 역시 마찬가지이다.
GUI 구현에 맞추어 TicTacToe와 Omok의 보드 생성 역시 바뀌었다. 이전에는 board라는 이차원 배열을 통해 생성하였다면, 이번에는 button을 이차원 배열로 구성하여 grid layer에 생성하였다.
오목의 경우 이전 버전에 일부 상황에 대각선 승리조건을 계산하지 못하는 경우를 위의 사진과 같이 코드를 수정하여 개선하였다. 위 코드는 아래의 규칙을 통해 작동한다.
A[i+1][j-1] | ||||
A[i][j] | ||||
A[i+1][j+1] | ||||
위의 matrix에서 특정 위치 A[i][j]에 플레이어가 둔 말이 있다고 하자. 이때 정사선 방향으로 연속된 위치에 말이 있다면 해당 값은 A[i+1][j+1]에 저장되어 있을 것이다. 또 역사선 방향으로 연속된 위치의 말은 A[i+1][j-1]에 저장되어 있을 것이다. 이를 토대로 조건문에 5개의 말이 연속돼 있는 상황이라면 true를 반환함으로써 승리를 표시하는 방식으로 개선하였다.
또한 새로 추가된 1 to 50의 게임은 아래와 같이 구성된다.
5 x 5 grid에 두번의 과정을 거치며 총 50개의 버튼을 생성한다. 이때 버튼에는 무작위로 설정된 1에서 50까지의 숫자들이 적혀 있다. 그러나 첫 25개의 버튼에 1이 없으면 게임을 진행할 수가 없으므로 생성되는 버튼을 25개 단위로 나눈다. 첫 25개의 버튼에는 1 ~ 25의 숫자들이, 이후 25개의 버튼에는 26 ~ 50의 숫자가 무작위의 위치로 나타난다.
위의 버튼들을 모두 누르면 게임이 종료되면 이때 종료되었다는 메시지와 함께 소요된 시간을 알려준다.
1 to 50은 아래와 같은 알고리즘으로 동작한다.
turn이라는 변수는 1부터 시작해서 플레이어가 현재 순서에 맞는 올바른 버튼을 눌렀는지 체크하기 위해 존재한다. 올바른 버튼이라면 +1을 해주어 차례를 넘어가고 틀리다면 -1하여 현재 차례를 넘어가지 못하게 하고 다시 클릭하기 전에 +1하여 현재 차례를 유지한다. 각 차례마다 종료 조건의 조건문을 지나치며 종료 조건을 구성하는 코드는 아래 사진과 같다.
그리드의 총합인 25만큼 버튼들을 탐색하여 모든 버튼들이 빈칸이라면 게임을 종료한다.
위와 같은 과정을 거친 Game 프로그램의 특징은 아래와 같다.
UI가 직관적 -> 모든 게임 진행은 마우스 클릭을 통해 진행됨
각 게임의 오류 대처를 위한 예외 처리 완성
각 게임에서 동작하는 알고리즘의 역할별로 패키지를 분류하여 코드의 유지보수가 용이
참고
GitHub - devGyu97/Java-Multiple-Game
Contribute to devGyu97/Java-Multiple-Game development by creating an account on GitHub.
github.com
'Study > Other' 카테고리의 다른 글
OpenCV를 활용한 얼굴인식 모자이크 실습 (0) | 2021.12.08 |
---|