/*=========================================================================
# 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;}