Sablog Models/자작자작

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

어­리 2009. 6. 6. 19:29

지환태 님의 미니홈피에서 가져온 오목 게임입니다.
상당히 끌려서 말입니다-_-; 도와드리지 않고는 못 배기겠더군요.(?)

일단 아래는 원본.



상태가 약간 이뭐병입니다. 전역변수는 물론이고 덜떨어진 가독성이 돋보이는군요.

제가 만든다고 얼마나 나을지는 모르겠습니다만,

이 소스는 무개념으로 충만하다 못해 아주 넘치는 것 같아요.


.....-_- 장난이었구요, 죄송합니다.



코드를 살펴보면 구조가 상당히 난해합니다.

일단 main()에서 move()를 무한 반복해서 모든 프로세싱을 넘겨 줍니다.

이 때 move()는 한 번에 커서 한 칸 움직이거나 돌 한 번 놓기밖에 수행할 줄 모릅니다.

전역변수 x, y, oldx, oldy, who[3][3]가 move()에서만 쓰임에도 불구하고,

전역변수로 선언되어 있는 것은 move 내에 선언하면 변수가 계속 바뀌기 때문입니다.



아무래도 판을 수행하는 부분은 main()에 남겨 놓고,

커서를 움직이거나 돌을 움직이는 부분은 move()에 남겨 놓되,

판의 승패를 결정하고 move()를 반복하는 부분은 또 다른 함수로 바꾸어야 되겠습니다.

새로운 함수의 이름을 five_in_a_row()로 합시다.


근데 상당히 짜증나네요.

나머지 함수들은 모조리 헤더 파일 하나에 몰아 넣어 봐야 되겠습니다.

그럼 C 파일의 내용은 일단....

#include "five_in_a_row.h"

int main()
{
    while (!(five_in_a_row()));
    return 0;
}

애석하게도 대충 이따구로 변형할 수 있겠습니다.

그리고 아래는 five_in_a_row.h입니다.
/* five_in_a_row.h
 * by ZFanta & UNique
 */
#ifndef FIVE_IN_A_ROW
#define FIVE_IN_A_ROW


#include "tool.h"

#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
#define ENTER 13

int x = 0, y = 0;
int oldx = 0, oldy = 0;
int board[38][19];
int turn = 1;
char who[3][3] = {"", "흑", "백"};
char stone[3][3] = {"", "○", "●"}; 


void draw()
{        
    char a[39][39]=
    {
        "┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐",
        "├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤",
        "└┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘"
    };
    int count;
    printf("%s\n", a[0]); 
    for(count = 0; count < 17; count++)
        printf("%s\n", a[1]);
    printf("%s", a[2]);
}

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

    //가로
    px = x;
    py = y;
    count = 0;    

    while(px > 1 && board[px-2][y] == turn)
        px -= 2;
    while(px <= 36 && board[px][y] == turn)
    {
        count++;
        px += 2;
    }

    if(count == 5)
    {
        return 1;
    }

    //세로
    px = x;
    py = y;
    count = 0;

    while(py > 0 && board[x][py-1] == turn)
        py--;
    while(py <= 18 && board[x][py++] == turn)
        count++;

    if(count==5)
    {
        return 1;
    }

    //대각선 ↘
    px = x;
    py = y;
    count = 0;

    while(px > 0 && py > 0 && board[px-2][py-1] == turn)
    {
        px -= 2;
        py--;
    }

    while(px <= 36 && py <= 18 && board[px][py++] == turn)
    {
        px += 2;
        count++;
    }
    if(count == 5)
    {
        return 1;
    }

    //대각선 ↙
    px = x;
    py = y;
    count = 0;

    while(px < 36 && py > 0 && board[px+2][py-1] == turn)
    {
        px += 2;
        py--;
    }

    while(px >= 0 && py <= 18 && board[px][py++] == turn)
    {
        px -= 2;
        count++;
    }
    if(count == 5)
    {
        return 1;
    }
    return 0;
}

int knock(int x, int y)
{
    gotoxy(x,y);
    puts(stone[board[x][y]]);
    if(board[x][y] != 0)
        return 0;

    else
        return 1;
}

int move()
{
    char input = 0;
    input = getch();

    switch(input)
    {
    case UP :
        if(y>0)
        {
            y -= 1;
            oldy = y + 1;
            gotoxy(x, y);
            puts("⊙");
            if(knock(x, oldy))
            {
                gotoxy(x, oldy);
                if(oldy == 18)
                {
                    if(x == 0)
                    {
                        puts("└");
                    }
                    if(x == 36)
                    {
                        puts("┘");
                    }
                    else if(x != 0 && x != 36)
                    {
                        puts("┴");
                    }
                }
                else if(x == 0)
                {
                    puts("├");
                }
                else if(x == 36)
                {
                    puts("┤");
                }
                else
                {
                    puts("┼");
                }
            }

        }
        return 1;
        break;

    case DOWN :
        if(y<18)
        {
            y+=1;
            oldy=y-1;
            gotoxy(x,y);
            puts("⊙");
            if(knock(x, oldy))
            {
                gotoxy(x, oldy);
                if(oldy == 0)
                {
                    if(x == 0)
                    {
                        puts("┌");
                    }
                    if(x == 36)
                    {
                        puts("┐");
                    }
                    else if(x != 0 && x != 36)
                    {
                        puts("┬");
                    }
                }
                else if(x == 0)
                {
                    puts("├");
                }
                else if(x == 36)
                {
                    puts("┤");
                }
                else
                {
                    puts("┼");
                }
            }

        }
        return 1;
        break;

    case LEFT :
        if(x>0)
        {
            x -= 2;
            oldx = x + 2;
            gotoxy(x, y);
            puts("⊙");
            if(knock(oldx, y))
            {
                gotoxy(oldx, y);
                if(oldx == 36)
                {
                    if(y == 0)
                    {
                        puts("┐");
                    }
                    if(y == 18)
                    {
                        puts("┘");
                    }
                    else if(y != 0 && y != 36)
                    {
                        puts("┤");
                    }
                }
                else if(y == 18)
                {
                    puts("┴");
                }
                else if(y == 0)
                {
                    puts("┬");
                }
                else
                {
                    puts("┼");
                }
            }

        }
        return 1;
        break;

    case RIGHT :
        if(x<36)
        {
            x += 2;
            oldx = x-2;
            gotoxy(x, y);
            puts("⊙");
            if(knock(oldx, y))
            {
                gotoxy(oldx, y);
                if(oldx == 0)
                {
                    if(y == 0)
                    {
                        puts("┌");
                    }
                    if(y == 18)
                    {
                        puts("└");
                    }
                    else if(y != 0 && y != 36)
                    {
                        puts("├");
                    }
                }
                else if(y == 18)
                {
                    puts("┴");
                }
                else if(y == 0)
                {
                    puts("┬");
                }
                else
                {
                    puts("┼");
                }
            }

        }
        return 1;
        break;

    case ENTER :
        if(board[x][y] == 0)
        { 
            board[x][y] = turn;
            gotoxy(x, y);
            puts(stone[turn]);
            if(check(x, y, turn))
            {
                return 0;
            }
            turn++;
            if(turn == 3)
                turn = 1;
        }
        return 1;
        break;
    }
    return 1;
}

int five_in_a_row()
{
    /* If user wants to re-match, returns 0; or not, returns 1.
     * (only if one game successfully ended)
     */
    int i, j;
    system("CLS");
    draw();
    for (i = 0; i < 38; i++)
        for (j = 0; j < 19; j++)
            board[i][j] = 0;
    while (move());
    system("CLS");
    printf("%s 승리", who[turn]);
    system("PAUSE");

    return 0;
}


#endif

위에 보면 다른 헤더 파일이 없고 tool.h만 있습니다.

getch 관련해서 꼬박 반나절을 삽질한 탓에 열받아서 분리시켜 버렸죠.
/* tool.h (for five_in_a_row.h)
 * supports gotoxy(x, y) and getch()
 */
#include <stdio.h>
#include <windows.h>

void gotoxy(int x, int y)
{
    COORD XY = {x, y};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), XY);
}

#if defined(_MSC_VER) && (_MSC_VER > 1000)
_CRTIMP _getch();
#define getch() _getch()
#elif defined(__GNUC__) || defined(__GNUG__)
#include <termios.h>
int getch()
{
    char ch;
	struct termios buffer, status;

    tcgetattr( STDIN_FILENO, &buffer );
    status = buffer;
    status.c_lflag &= ~(ECHO | ICANON);
    tcsetattr( STDIN_FILENO, TCSANOW, &status );
    read( 0, &ch, 1 );
    tcsetattr( STDIN_FILENO, TCSANOW, &buffer );

    return ch;
}
#else
#include <conio.h>
#endif


일단 제 코딩 스타일로 가독성을 약간 높였습니다.

여전히 저 switch-case 제어문은 쩔어주게 기네요. 아니 더 길어진 듯?

저걸 처리할 방법을 다음 글에서 다루도록 하죠.