编程练习:迷宫求路

 
/*=========================================================================
#    FileName: Maze.c
# Description: 迷宫求路
#      author: shuizhonglin
#  LastChange: 2012-05-31 20:31:42
=========================================================================*/
#include <stdio.h>
#include <stdlib.h>

/* C语言没有bool类型,自己定义一个 */
typedef int bool;
#define TRUE  1
#define FALSE 0
#define OK    1
#define FAIL  0

#define INIT_STACK_SIZE 100  //堆栈初始大小 
#define INCREASE_SIZE   10  //堆栈每次空间不足时新增的空间大小 

/* 记录迷宫每个位置的信息 */
typedef struct {
   int x;   //横坐标 
   int y;   //纵坐标 
   int di;  //di=0表示东南西北四条路都未走过 
			//di=1表示要走南路,其他三路未走过
			//di=2表示要走西路,南路已走过且不通,其他两路未走过
			//di=3表示要走北路,西、南路已走过且不通,东路未走过
			//di=4表示要走东路,其他三路已走过且不通
}SElem;

/* 堆栈结构体,堆栈存储指向SElem结构体的指针 */
typedef struct {
   SElem **base;
   SElem **top; 
   int stacksize;
}SqStack; 

/* 用数组画迷宫图样 */
char Maze[10][10] = { 
    {'#','#','#','#','#','#','#','#','#','#'},
    {'#',' ',' ','#',' ',' ',' ','#',' ','#'},
    {'#','#',' ',' ',' ',' ',' ','#',' ','#'},
    {'#',' ',' ',' ',' ','#',' ',' ',' ','#'},
    {'#',' ','#','#','#',' ',' ',' ',' ','#'},
    {'#',' ','#',' ','#',' ',' ','#',' ','#'},
    {' ',' ','#',' ',' ',' ','#',' ',' ','#'},
    {'#',' ','#','#','#','#','#','#',' ','#'},
    {'#','#',' ',' ',' ',' ',' ',' ',' ','#'},
    {'#','#',' ','#','#','#','#','#','#','#'}
};

SElem * pMaze[10][10];  //定义100个指向SElem结构体的指针 
SqStack PrintOnRoad; //记录所求路径 

/* 创建并初始化100个SElem结构体,并用pMaze指针数组分别指向它们 */
void InitMaze() {
    int i,j;
    for(i=0; i<10; ++i)
        for(j=0; j<10; ++j) {
            pMaze[i][j] = (SElem *)malloc( sizeof(SElem) );
            pMaze[i][j]->x = i;
            pMaze[i][j]->y = j;
            pMaze[i][j]->di = 0;
        }
}

/* 判断(xValue,yValue)对应的SElem的指针是否在堆栈S中 */
bool IsInStack(const SqStack *S,int xValue,int yValue) {
    SElem **top = S->top;
    if(S->top == S->base) return FALSE;
    do{
        top--;
        if((*top)->x == xValue && (*top)->y == yValue) return TRUE;
    } while(top != S->base);
    return FALSE;
}

/* 判断位置(x,y)是否可走 */
bool OnePass(int x,int y) {
    if( IsInStack( &PrintOnRoad,x,y ) ) return FALSE; //是否在PrintOnRoad堆栈中
    else if (pMaze[x][y]->di == 4) return FALSE; //是否之前已走过且已知不通 
    else if (Maze[x][y] == '#') return FALSE; //是否是墙
    else return TRUE; //可走 
}

/* 判断位置(x,y)四周是否有路有走 */
bool Pass(int x,int y) {
   if(!OnePass(x,y)) return FALSE; //(x,y)本身就不能走
   pMaze[x][y]->di++;
   if(x+1 <= 9) 
       if(OnePass(x+1,y)) return TRUE; //南路是否可走 
   pMaze[x][y]->di++;
   if(y-1 >= 0) 
       if(OnePass(x,y-1)) return TRUE; //西路是否可走 
   pMaze[x][y]->di++;
   if(x-1 >= 0) 
       if(OnePass(x-1,y)) return TRUE; //北路是否可走 
   pMaze[x][y]->di++;
   if(y+1 <= 9) 
       if(OnePass(x,y+1)) return TRUE; //东路是不可走 
   return FALSE; //四周都走不通 
}

/* 初始化堆栈 */
bool InitStack( SqStack *S) {
    S->base = (SElem **)malloc(INIT_STACK_SIZE * sizeof(SElem *));
    if(!S->base) return FAIL;
    S->top = S->base;
    S->stacksize = INIT_STACK_SIZE;
    return OK;
}

/* 将e所指向的SElem *类型的指针入栈 */
bool Push(SqStack *S, SElem **e) {
    if(S->top - S->base >= S->stacksize) {
        S->base = (SElem **)realloc(S->base, (S->stacksize + INCREASE_SIZE) * sizeof(SElem *));
        if(!S->base) return FAIL;
        S->top = S->base + S->stacksize;
        S->stacksize += INCREASE_SIZE;
    }
    *(S->top) = *e;
    S->top++;
    return OK;
}

/* 出栈,并用e所指向的空间存放所弹出的表项 */
bool Pop(SqStack *S,SElem **e) {
    if(S->top == S->base) return FAIL;
    S->top--;
    *e = *(S->top);
    return OK;
}

/* 判断S堆栈是否为空 */
bool IsEmpty(const SqStack *S) {
    if(S->top == S->base) return TRUE;
    else return FALSE;
}

/* 判断(x,y)是否是出口,(xBegin,yBegin)是入口坐标 */
bool IsTheExit(int x,int y,int xBegin,int yBegin) {
    if( x == xBegin && y == yBegin) return FALSE;
    if((x == 9 || x == 0 || y == 9 || y == 0) && Maze[x][y] == ' ' ) return TRUE;
    else return FALSE;
}

/* 给定入口坐标(xBegin,yBegin),求出口坐标(*xEnd,*yEnd),并将路径存入堆栈PrintOnRoad中 */
bool MazePath(int xBegin,int yBegin,int *xEnd,int *yEnd) {
    InitStack( &PrintOnRoad );
    InitMaze();
    SElem *e = (SElem *)malloc( sizeof(SElem) );
    int x = xBegin, y = yBegin;
    do {
		/* 如果是出口则入栈并返回坐标值 */
        if( IsTheExit(x,y,xBegin,yBegin) ) {
            *xEnd = x;
            *yEnd = y;
            Push( &PrintOnRoad, &(pMaze[x][y]) );
            return OK;
        }
		/* 如果(x,y)四周有路可走 */
        if( Pass(x,y) ) {
			/* 保存该路径 */
            Push( &PrintOnRoad, &(pMaze[x][y]) );
			/* 判断该走哪条路 */
            switch( pMaze[x][y]->di ) {
                case 1 : ++x; break; //走南路 
                case 2 : --y; break; //走西路 
                case 3 : --x; break; //走北路 
                case 4 : ++y; break; //走东路 
                default: return FAIL;
            }
        }
		/* 如果(x,y)四周不通 */
        else {
			/* 是否无路可退 */
            if( !IsEmpty(&PrintOnRoad) ) {
				/* 向后退,退到四周还有路未走过的地方*/
                Pop( &PrintOnRoad, &e );
                while(e->di == 4 && !IsEmpty(&PrintOnRoad)) {
                    Pop( &PrintOnRoad, &e );
                }
				/*重新选择一条路 */
                if(e->di < 4) {
                    x = e->x;
                    y = e->y;
                    e->di++;
                    switch( e->di ) {
                        case 1 : ++x; break; //走南路 
                        case 2 : --y; break; //走西路 
                        case 3 : --x; break; //走北路 
                        case 4 : ++y; break; //走东路 
                        default: return FAIL;
                    }
					/* 重新保存该路径 */
                    Push( &PrintOnRoad, &e );
                }
            }
        }
    }while( !IsEmpty(&PrintOnRoad) ); //是否没有出口,或入口有误 
    return FAIL;
}

/* 打印迷宫 */
void PrintMaze() {
    SElem **base = PrintOnRoad.base;
    int i,j;
    int k = '0';
	/* 如果PrintOnRoad保存有路径,则用0~9,A~Z,a~...来表示路径顺序,并打印出来 */
    while(base != PrintOnRoad.top) {
        if(k <= '9')
            Maze[(*base)->x][(*base)->y] = k;
        else if(k <= 'S')
            Maze[(*base)->x][(*base)->y] = k + 7;
        else 
            Maze[(*base)->x][(*base)->y] = k + 39;
        base++;
        k++;
    } 
    for(i=0; i<10; ++i) {
        printf( "              " );
        for(j=0; j<10; ++j) {
            printf("%2c", Maze[i][j]);
        }
        putchar('\n');
    }
}


int main( int argc, const char *argv[] )
{
    int xBegin = 6, yBegin = 0, xEnd = 0,yEnd = 0;
    printf( "The maze is as follows,and we assume the entrance is at (6,0).\n\n" );
    PrintMaze();
    if( MazePath(xBegin,yBegin,&xEnd,&yEnd) ) 
        printf( "\nThe exit locate at : (%d,%d), and the route is as the follows:\n\n",xEnd,yEnd);
    else printf( "There is not exit at all or the entrance is wrong!\n" );
    PrintMaze();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值