Maze 문제를 풀기 위해 사용할 수 있다.


1. 앞으로 간다

2. 아직 미로 안에 갖혀 있다면

    2.1 시계 방향으로 90도 돈다.

    2.2 만약 벽이 앞에 있다면 반시계 방향으로 90도 돈다.


#include <dos.h>
#include <conio.h>
#include <bios.h>
#include <stdlib.h>

#define MAZE_SIZE  19
#define ROBOT       2

int maze[MAZE_SIZE][MAZE_SIZE] =
    { { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
      { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 },
      { 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1 },
      { 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1 },
      { 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1 },
      { 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 },
      { 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
      { 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
      { 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
      { 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
      { 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
      { 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1 },
      { 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1 },
      { 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1 },
      { 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1 },
      { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 },
      { 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1 },
      { 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };

int sx = MAZE_SIZE - 1, sy = MAZE_SIZE - 2;

int *rec;  /* record robot's path */

#define UP     1
#define RIGHT  2
#define DOWN   4
#define LEFT   8

int  get_shape(int m[][MAZE_SIZE], int x, int y)  //벽의 모양을 정의
    {
    static shape[] =
        {  32, 179, 196, 192, 179, 179, 218, 195, 196, 217, 196,
          193, 191, 180, 194, 197 };
    int s = 0;
    if (m[y][x])
        {
        if (y > 0  &&  m[y-1][x]) s |= UP;
        if (y < MAZE_SIZE - 2  &&  m[y+1][x]) s |= DOWN;
        if (x > 0  &&  m[y][x-1]) s |= LEFT;
        if (x < MAZE_SIZE - 2  &&  m[y][x+1]) s |= RIGHT;
        }
    return shape[s];
    }

void draw_maze(int m[][MAZE_SIZE]) //미로를 그림
    {
    int i, j;
    for (j = 0; j < MAZE_SIZE; j++)
        for (i = 0; i < MAZE_SIZE; i++)
            {
            gotoxy(i + 1, j + 1); //gotoxy() 를 이용하는 경우, 좌측 상단이 (0,0) 이 아니라 (1,1) 이기 때문
            putch(get_shape(m, i, j));
            }
    }

void record(int x, int y) //이동 경로 저장
    {
    static int index = 0;
    rec[index++] = x;
    rec[index++] = y;
    }

void forward(int *x, int *y, int dir) //특정 방향으로 이동
    {
    gotoxy(*x + 1, *y + 1);
    putch(' ');

    *x = (dir == LEFT)  ? --(*x) :
         (dir == RIGHT) ? ++(*x) : *x;
    *y = (dir == UP)    ? --(*y) :
         (dir == DOWN)  ? ++(*y) : *y;

    record(*x, *y);
    gotoxy(*x + 1, *y + 1);
    putch(ROBOT);
    }

void right(int *dir) //오른쪽으로 90도 방향 전환
    {
    *dir <<= 1;
    *dir = (*dir > LEFT) ? UP : *dir;
    }

void left(int *dir) //왼쪽으로 90도 방향 전환
    {
    *dir >>= 1;
    *dir = (*dir == 0) ? LEFT : *dir;
    }

int still_in_maze(int x, int y) //아직 미로 안에 있는지 확인
    {
    if (x > 0  &&  x < MAZE_SIZE - 1  &&  y > 0  &&  y < MAZE_SIZE - 1)
        return 1;
    else
        return 0;
    }

int wall_ahead(int m[][MAZE_SIZE], int x, int y, int dir) //진행 방향에 벽이 있는지 확인
    {
    x = (dir == LEFT)  ? --x :
        (dir == RIGHT) ? ++x : x;
    y = (dir == UP)    ? --y :
        (dir == DOWN)  ? ++y : y;
    return m[y][x];
    }

void right_hand(int m[][MAZE_SIZE], int x, int y, int dir)
    {
    gotoxy(x + 1, y + 1);
    putch(ROBOT);
    record(x, y); //첫 좌표

    forward(&x, &y, dir);
    while (still_in_maze(x, y))
        {
        delay(100);
        right(&dir);
        while (wall_ahead(m, x, y, dir))
            left(&dir);
        forward(&x, &y, dir);
        }
    record(-1, -1);  /* end of path */
    }

int del_path(int i, int j) //중복되는 경로 (i ~ (j-1) 사이) 를 제거
    {
    int k = i;
    while (rec[j] >= 0) // j ~ 마지막 좌표까지 값을 , i ~ 에다가 overwrite
        rec[i++] = rec[j++];
    rec[i] = -1; //마지막 좌표 다시 표시
    return k;   /* k is j position after deleting */ //현재 index 위치 다시 리턴
    }

void shortest_path(void) // right_hand() 를 통해 저장된 경로 중, 중복되는 경로를 제거하여 최단경로 찾아냄
    {
    int i = 0;
    int x, y;
    int j;
    int x1, y1;

    while (rec[i] >= 0) //마지막 좌표(-1, -1)가 아닌 경우
        {
        x = rec[i];
        y = rec[i + 1];
        j = i + 2;
        while (rec[j] >=0) //다음 좌표가 유효한지 확인
            {
            x1 = rec[j];
            y1 = rec[j + 1];
            if (x == x1  &&  y == y1) //현재 좌표와 같이 같은 좌표가 있으면, 중복 경로 삭제
                j = del_path(i, j);

            j = j + 2; //다음 좌표
            }

        i = i + 2; //다음 좌표
        }
    i = 0; //최단 경로를 화면에 애니메이션
    while (rec[i] >= 0)
        {
        x = rec[i++];
        y = rec[i++];
        gotoxy(x + 1, y + 1);
        putch(ROBOT);
        delay(100);
        gotoxy(x + 1, y + 1);
        putch(' ');
        }
    }


void main(void)
    {
    rec = (int*)malloc(MAZE_SIZE * MAZE_SIZE);
    if (rec == NULL)
        {
        cputs("\r\n Memory allocation error ! ");
        exit(1);
        }
    clrscr();
    draw_maze(maze);

    gotoxy(40, 5);
    cputs("Simulation of Micro Mouse");
    gotoxy(40, 10);
    cputs("  Press any key to start...");
    bioskey(0);
    right_hand(maze, sx, sy, LEFT);

    gotoxy(40, 10);
    cputs("  Press any key to see shortest path...");
    bioskey(0);
    shortest_path();

    gotoxy(40, 10);
    cputs("  Press any key to end program...      ");
    bioskey(0);
    }

* 출처 : C로 배우는 알고리즘


'SW > 알고리즘' 카테고리의 다른 글

Tree Traversal2 - Inorder traversal  (0) 2019.02.23
Tree Traversal1 - Preorder Traversal  (0) 2019.02.23
Eratosthenes's Sieve  (0) 2018.12.30
Prime Number  (0) 2018.12.24
Asymptotic Analysis  (0) 2018.12.23

+ Recent posts