/ C

리눅스에서 슬라이딩 퍼즐 만들기 with C

리눅스에서 슬라이딩 퍼즐 만들기 with C

직접 코딩하면서 공부하기 리눅스 우분투 환경에서 C언어 gcc 컴파일러로 구현하여 타운영체제나 프로그램에서 실행되지 않을 수 있습니다.

슬라이딩 퍼즐

어렸을 때 즐겨하던 게임 중에 슬라이딩 퍼즐이 있습니다. 1~15의 블록으로 이루어진 4x4 배열에서 블록을 움직이며 순서를 맞추는 퍼즐입니다.

슬라이딩 퍼즐 기능

  1. 슬라이딩 퍼즐의 기능

    • 실행명령 옵션으로 1과 2를 입력 받습니다.(int main 파라미터)
    • 1이 입력되면 화면을 클리어하고 올바른 순서의 슬라이딩 퍼즐을 생성합니다.
    • 1의 경우 퍼즐을 최소한 한 번은 움직여야 성공 문장이 출력됩니다.
    • 2가 입력되면 화면을 클리어하고 랜덤한 순서로 슬라이딩 퍼즐을 생성합니다.(실행할 때 마다 다른 순서로 출력해야합니다.)
    • 마찬가지로 퍼즐이 맞춰지면 성공 문장이 출력되고 “3초”후에 프로그램이 종료됩니다.
    • 퍼즐의 이동은 i,j,k,l 로 합니다.
    • 입력은 getch 함수를 구현하여 엔터키 없이 바로 입력되도록 합니다.

SlidingPuzzle.c

String헤더파일

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <termio.h>
#include <unistd.h>

void setRandom(int (*puzzle)[4]);
bool compareArray(int(*puzzle)[4]);
void right(int(*puzzle)[4]);
void left(int(*puzzle)[4]);
void up(int(*puzzle)[4]);
void down(int(*puzzle)[4]);

//바로 입력되는 getch 
int getch(void)
{
    int ch;
    struct termios buf;
    struct termios save;
    tcgetattr(0, &save);
    buf = save;
    buf.c_lflag &= ~(ICANON | ECHO);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(0, TCSAFLUSH, &buf);
    ch = getchar();
    tcsetattr(0, TCSAFLUSH, &save);
    
    return ch;
}

//메인 함수 파라미터로 옵션 입력 받기
int main(int argc, char* argv[])
{
    int puzzle[4][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 0 } };
    int set = atoi(*(argv+1));
    //실행마다 다른 랜덤값 생성
    srand(time(NULL));
    if(set == 2)
        setRandom(puzzle);

    bool isQuit = true;
    bool isMove = false;
    while (isQuit) {
        system("clear");
        for (int i = 0; i < 4; i++) {
            printf("\t");
            for (int j = 0; j < 4; j++) {
                if (puzzle[i][j] == 0)
                    printf("   ");
                else
                    printf("%3d", puzzle[i][j]);
            }
            putchar('\n');
        }

        char key;
        key = getch(); 

        switch(key) {
	    case 'l':
	        right(puzzle);
	        isMove = true;
	        break;
	    case 'j':
	        left(puzzle);
		break;
	    case 'i':
	        up(puzzle);
	        break;
	    case 'k':
	        down(puzzle);
                isMove = true;
	        break;
	    case 'q':
	        isQuit = false;
	        break;
        }

        if (isMove) {
            if (compareArray(puzzle)) {
                system("clear");
                for (int i = 0; i < 4; i++) {
                    printf("\t");
                    for (int j = 0; j < 4; j++) {
                        if (puzzle[i][j] == 0)
                            printf("   ");
                        else
                            printf("%3d", puzzle[i][j]);
                    }
                    putchar('\n');
                }
                printf("\n\t   축하합니다.\n");
                sleep(3);
                isQuit = false;
            }
        }
    }


    return 0;
}

//랜덤 배열 생성 함수
void setRandom(int(*puzzle)[4])
{
    int tmpArray[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
    for (int i = 0; i < 16; i++) {
        tmpArray[i] = rand() % 16;
        for (int j = 0; j < i; j++) {
            if (tmpArray[i] == tmpArray[j]) {
                i--;
                break;
            }
        }
    }

    int k = 0;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            puzzle[i][j] = tmpArray[k];
            k++;
        }
    }
}

//성공 확인 함수
bool compareArray(int(*puzzle)[4])
{
    int checkArray[4][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 0 } };
    bool isBreak = false;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (!(puzzle[i][j] == checkArray[i][j])) {
                isBreak = true;
                break;
            }
        }
        if (isBreak)
            break;
    }

    return !isBreak;
}

//이동 함수(벽이 있으면 이동 불가)
void right(int(*puzzle)[4])
{
    int i, j;
    bool isBreak = false;
    for (i = 0; i < 4; i++) {
        for (j = 0; j < 4; j++) {
            if (puzzle[i][j] == 0) {
                isBreak = true;
                break;
            }
        }
        if (isBreak)
            break;
    }

    if (j > 0) {
        int tmp;
        tmp = puzzle[i][j - 1];
        puzzle[i][j - 1] = puzzle[i][j];
        puzzle[i][j] = tmp;
    }
}

void left(int(*puzzle)[4])
{
    int i, j;
    bool isBreak = false;
    for (i = 0; i < 4; i++) {
	for (j = 0; j < 4; j++) {
	    if (puzzle[i][j] == 0) {
	        isBreak = true;
	        break;
	    }
	}
	if (isBreak)
	    break;
    }

    if (j < 3) {
	int tmp;
	tmp = puzzle[i][j + 1];
	puzzle[i][j + 1] = puzzle[i][j];
	puzzle[i][j] = tmp;
    }
}

void up(int(*puzzle)[4])
{
    int i, j;
    bool isBreak = false;
    for (i = 0; i < 4; i++) {
	for (j = 0; j < 4; j++) {
	    if (puzzle[i][j] == 0) {
	        isBreak = true;
	        break;
	    }
	}
	if (isBreak)
	    break;
    }

    if (i < 3) {
	int tmp;
	tmp = puzzle[i + 1][j];
	puzzle[i + 1][j] = puzzle[i][j];
	puzzle[i][j] = tmp;
    }
}

void down(int(*puzzle)[4])
{
    int i, j;
    bool isBreak = false;
    for (i = 0; i < 4; i++) {
	for (j = 0; j < 4; j++) {
	    if (puzzle[i][j] == 0) {
	        isBreak = true;
	        break;
	    }
	}
	if (isBreak)
	    break;
    }

    if (i > 0) {
        int tmp;
	tmp = puzzle[i - 1][j];
	puzzle[i - 1][j] = puzzle[i][j];
	puzzle[i][j] = tmp;
    }
}

결과

./a.out 1 실행

퍼즐 움직이기

./a.out 2 실행

랜덤 생성된 퍼즐