Sablog Models/자작자작

환타 오목 게임 재구성. (5)

어­리 2009. 11. 12. 10:59
드디어 check()를 줄일 아이디어를 구체화시켰습니다.-_-


현재 방식 그대로라면 모듈로 분리한다 해도 거의 아무런 차이가 없으므로,

아예 검사 방식 자체를 바꾸려고 했습니다만 그게 잘 안 되고 있었습니다.


뻘소리를 좀 하자면 오늘은 2010 수능 D-day이면서 2011 수능 D-364 즉 52주...

어차피 블로깅이 많이 줄었지만 앞으로 1년간 거의 잠수 탈 것 같습니다.


새로운 검사 방식을 소개합니다.

1. 검사 방식에 있어서 생긴 차이는 아닙니다만,
일단 check()는 x와 y 인자만 받습니다.
turn 인자가 필요한데, (x, y) 인자를 정상적으로 받았다고 가정하면,
board[x][y]가 turn 인자와 같습니다.

즉,

int check(int x, int y, int turn)
{
    int px, py;
    int count;

    // 가로로 오목이 있는지 검사
    ...
}

이것을,
int check(int x, int y)
{
    int px, py;
    int count;
    int turn = board[x][y];

    // 가로로 오목이 있는지 검사
    ....
}

이렇게 바꿔도 된다는 것입니다. 물론, move()에서
int move()
{
    ...
    else if(board[x][y] == 0)
    {
        board[x][y] = turn;
        gotoxy(x * 2, y);
        puts(stone[turn]);
        if(check(x, y, turn))
            return 0;
        turn ^= 3;
    }
    return 1;
}

이 부분을,
        if(check(x, y))

이렇게 바꾸는 것도 잊지 않아야 되겠습니다.


2. 진짜 변화입니다. 크크크.
환타[지환태] 님은 검사할 때 아래의 방법을 썼습니다.
  • 횡오목: 왼쪽으로 최대한 거슬러 간 후 오른쪽으로 하나씩 세기
  • 종오목: 위쪽으로 최대한 거슬러 간 후 아래로 하나씩 세기
  • 좌상우하오목: 왼쪽 위로 최대한 거슬러 간 후 오른쪽 아래로 하나씩 세기
  • 우상좌하오목: 오른쪽 위로 최대한 거슬러 간 후 왼쪽 아래로 하나씩 세기
전체가 하나의 루틴에 순차적으로 있어서 상당히 비효율적이라고 생각하고 있었습니다.
반면에 새로 생각해 낸 방법은 이것입니다.
  • 방향을 입력받아 세는 함수(인자: 8방향)
  • 좌표를 입력받아 점검하는 함수(인자: 좌표)
    1. 8방향별로 좌표를 입력받아 세는 함수를 호출한다.
    2. 반환된 값을 각각 상+하, 좌+우, 좌상+우하, 우상+좌하 합해서 오목을 검사한다.
물론 누군가 이미 쓰고 있는 방법이라면(=...) 하는 수 없지만 말입니다.


이 작업을 위해 count()라는 함수를 만들었습니다.
int count(int x, int y, int turn, int direction)
{
    int n = 0;

    switch(direction)
    {
    case 0: // 상
        while(y > 0 && board[x][--y] == turn)
            n++;
        break;
    case 1: // 우상
        while(x < BOARD_SIZE && y > 0 && board[++x][--y] == turn)
            n++;
        break;
    case 2: // 우
        while(x < BOARD_SIZE && board[++x][y] == turn)
            n++;
        break;
    case 3: // 우하
        while(x < BOARD_SIZE && y < BOARD_SIZE && board[++x][++y] == turn)
            n++;
        break;
    case 4: // 하
        while(y < BOARD_SIZE && board[x][++y] == turn)
            n++;
        break;
    case 5: // 좌하
        while(x > 0 && y < BOARD_SIZE && board[--x][++y] == turn)
            n++;
        break;
    case 6: // 좌
        while(x > 0 && board[--x][y] == turn)
            n++;
        break;
    case 7: // 좌상
        while(x > 0 && y > 0 && board[--x][--y] == turn)
            n++;
        break;
    default:
        n = 0;
        break;
    }

    return n;
}
상당히 뻘짓하는 것으로 보일 수도 있으나,
이렇게 변화를 주면 check()의 전체는 아래처럼 획기적으로 바뀝니다!
int check(int x, int y)
{
    int turn = board[x][y];
	if (count(x, y, turn, 0) + count(x, y, turn, 4) > 3 ||
		count(x, y, turn, 1) + count(x, y, turn, 5) > 3 ||
		count(x, y, turn, 2) + count(x, y, turn, 6) > 3 ||
		count(x, y, turn, 3) + count(x, y, turn, 7) > 3 )
		return 1;
	else
		return 0;
}

이제 저는 여기서 리팩토링을 마무리하려고 합니다.

블로그에 글을 채우기 위해-_- 시작한,
거의 공중분해에 가까운 재구성을 보고도 양해해 주신 환타 님 감사합니다.

다음 글에서 세 부분으로 이루어진 파일 전체를 글에 싣고 끝내겠습니다.