개발 환경
- C언어
- 오토핫키(자동화 스크립트 언어)
개발 기간
기획 의도
내기 종목은 '사천성'이라는 게임으로
간단하게 말해 같은 모양의 카드를 찾아 클릭하여 두카드를 패에서 제거하는 것이다.
단, 사방이 다른 모양의 카드로 막혀있는 경우에는 동일한 두카드는 제거할수 없으며,
사방이 막혀있지 않아, 두 카드가 이어지는 경로가 존재하지만 세번이상 꺾여서 가게되는 경로인 경우에는 두 카드를 제거할 수 없다.
친구와 내기 게임을 하던 중
'어느정도 게임에 익숙해지면 이기겠지' 라고 오만한 생각을 하였다.
하지만 이 친구는 게임할 때 만큼은 '장산범'의 속도로 카드를 제거하는 것이였다.
결국 나의 눈과 손으로는 이 친구를 이길 수 없다고 판단하였다.(부들부들)
하지만 분해 잠 못이루던 필자는 다음을 기약하며
필자의 지식과 CPU의 연산능력에 힘을 빌어 친구를 토벌하기로 마음먹어 개발을 시작하게 되었다.
허나 특정 이미지와 다른 경로로는 갈 수 없으며, 두 경로가 가능하더라도 경로는 3번이상 꺾이면 안된다는 규칙이 있다.
각 이미지의 관한 특정값을 부여한 뒤, 각 이미지를 매칭시켜 이미지에 관한 특정값(데이터를)
패의 모양과 동일한 2차원 배열(세로8 X 가로18)에 저장하자
이후 제거할 이미지를 선택하면 (출발지:스페이드♠(6,11) → 목적지:스페이드♠(5,18))
(상,하,좌,우)에 이동가능 여부를 파악하여, 이동할수 있는 좌표로 이동 후(출발지:이동한 좌표(6,12) → 스페이드♠(5,18))
다시 한번 (상,하,좌,우)에 이동가능 여부를 체크하여, 출발지와 목적지의 행과 열이 같아질 때 까지 이동하면 되는 것이다.
이는 생각하여 보니 지속적으로 이동가능여부를 체크하여 이동 하는 함수를 호출하는 형태이다.
결과적으로 재귀적 형태의 함수호출을 하는 것이다.
하지만 한가지 유념할 것이 있다.
단순히 빈공간으로만 이동할 수 있는 것만이 아닌, 세번이상 방향전환을 하였다면, 이 또한 이동할 수 없다.
이를 프로그래밍 적으로 구현하기 위해서는,
상 하 좌 우 각 이동방향에 따른 방향수를 지정하여, 이전에 호출했던 함수의 방향과 다른 방향으로 이동한다면,
방향전환 횟수가 추가되도록 코드를 작성하면 될 것이다.
이를 다시 정리하면
- 이동 가능 조건
① 뚫려 있다.
② 같은 모양의 카드이다.
③ 방향 전환 횟수가 2번 이하다.
위의 주어진 조건들과 필요한 정보들을 인자로 함수를 생각해보면,
이동가능여부 좌표이동한다(이미지의 데이터 값, 출발지.x좌표, 출발지.y좌표, 목적지.x좌표, 목적지.y좌표, 방향수, 방향전환 횟수)
위와 같은 함수로 풀어낼 수 있다.
-찾아보니까 이와같은 형태의 알고리즘을 DFS(깊이 우선 탐색)이라고 부르네요. 참고용으로 링크 걸어둡니다.
시연
고찰
개발하면서 에로사항(?)이면서 문제점이라고 생각되는 부분을 짚어보고 그 해결책에 대하여 생각해보았다.
사실 위의 구현한 프로그램은 두개의 프로그램으로 나뉘어져있다.
오토핫키 기반으로 개발한 이미지를 인식하여, 이미지에 value값을 콘솔프로그램에 입력하는 프로그램과
입력한 데이터 배열(8X18)을 알고리즘을 통해 두개의 매칭되는 패를 계산하고 클릭하여 주는 프로그램이다.
왜 이렇게 두개의 프로그램으로 분리하여놓았느냐 하면, 사실상은 전적으로 필자의 능력부족과 시간부족이다.
단순히 친구와의 내기를 위해서 다른걸 제쳐두고 C언어기반에서 이미지 인식(OpenCV)를 이용하기 위하여,
관련 기술을 공부하기에 시간도 부족하며, 이게 뭐하는 짓인가 싶기도 하였다.
(단순히 이미지를 전체화면에서 인식하는 것이 아니라 특정 좌표에서만 특정 이미지를 인식하는 것을 반복할 뿐만 아니라, 리소스의 이미지의 데이터값(바이너리값)을 단순히 동일함과 비교하는 것이 아니라, 약간의 오차범위 까지 생각하여야 한다. 예를들어 어떤 이미지의 바이너리값이 1101 1100과 1101 1011과 거의 동일하게 보아야한다. 같은 패의 모양이여도 바탕화면에서 인식할때와 완전 동일하지 않은 것으로 보이기 때문이다.)
하지만 이와 같은 복잡한 상황에서도 간단명료하게 이미지 인식을 제공하는 스크립트 언어 기반인 오토핫키로 이미지를 인식하여, 각 데이터를 산출해내는 프로그램을 오토핫키로 만들었다. 그 후 처음에는 변형된 DFS알고리즘을 오토핫키로 구현하려하였으나.
오토핫키 구버전인 B버전(Basic)에서는 배열을 제공하지 않았으며 최선버전인 L버전또한 2차원 배열을 제공하지 않으며,
구조체 또한 제공하지 않았다. (배열과 구조체의 필요성을 확실히 알았다.)
여차저차해서 (8X18)변수를 모두 선언하였다. 하지만 이뿐만이 아니라... 계산을 위해서 필요한 배열들이 많다. 마우스 클릭좌표를 담는 배열 (0,0)일떄 (x_pos = 47, y_pos 128)이렇게 클릭하는 정보를 담아야 하는데... 이는 무수한 노가다 작업에 반복이다.
또한 반복문을 이용하여 각 변수에 접근할때 tmparr%i%_%j% 이런식으로 접근하였는데, 단순히 출력하는 메세지박스에서는 이렇게 접근가능하지만 이것이 특정 함수의 파라미터값으로 들어갈때는 오토핫키에는 맞지않는 문법이라 컴파일 에러가 난다고 하였다. 결국이는 if(조건1 && 조건2)연산등과 같은 and 연산자를 이용할때도 tmp = tmparr%i%_%j%이와 같이 나눠서 먼저 tmp에 관한 연산을하고 조건2에 관한 연산을 하는등 무수한 if문의 중첩이 이뤄져야 하는경우가 있었다.
등등의 이런 복잡한 문제들로 인해 차라리 두가지의 프로그램으로 나누는 것이 효율적이라고 생각하였다.
하지만 이렇게 두개의 프로그램으로 나눠놨을때도 문제점이 발생한다.
발생하는 문제는 이미지를 인식하여 데이터를 입력하는 입출력 시간이 다소 오래걸린 다는 것이다.
영상(00:03~00:08)로 약 5초간의 시간이 발생한다. 이는 시간이 중요한 사천성게임에서 Critical한 문제점이 될 수 있다.
이러한 문제점은 입출력시간에서 비롯되는 것이기 때문에 이를 없앤다면 해결할 수 있는 문제점이다.
결국 두개의 프로그램을 합치면 되는 것이다.
그런데 어떻게 합치는가 프로세스간의 통신(IPC)를 이용하여 두개의 프로세스의 핸들값을 받아서 통신하게 할 수 있으나,
구글링을 통하여 조사해본 결과 오토핫키에서 위와같은 문법또한 제공하지 않았다.
하지만 이가 안되면 잇몸으로 하라고 하라는 말이 있지않은가, 결국 리버싱을 통해 컴파일된
두 프로그램을 어셈블리 레벨에서 접근하여
코드 인젝션(Code Injection) 기술을 통해 첫번째 프로그램에서 이미지인식을 하고 그 함수를 통해
값을 입력하는 부분의 메모리값을 DFS알고리즘에서 카드패의
데이터를 받아들이는 배열버퍼에 직접 복사하면 되는 것이다.
뭔가 너무 판이 커진 것 같지만, 어차피 필자는 현재 리버싱을 공부하는 상황이기에,
충분히 시도해볼만한 가치가 있는 프로젝트로 생각되어 진행하여 보겠다.
'IT > 프로젝트 및 실습' 카테고리의 다른 글
컴퓨터 프로그래밍 설계 과제#2_HW02 (0) | 2017.10.20 |
---|---|
컴퓨터 프로그래밍 설계 과제#2_HW01 (0) | 2017.10.20 |
컴퓨터 프로그래밍 설계 과제#1_HW03 (0) | 2017.10.20 |
컴퓨터 프로그래밍 설계 과제#1_HW02 (0) | 2017.10.20 |
컴퓨터 프로그래밍 설계 과제#1_HW01 (0) | 2017.10.20 |