#include <stdio.h>
#include <stdlib.h>
#define ROW 10
#define COL 10
/*迷宮中位置資訊*/
typedef struct position
{
int x;
int y;
}position;
/*在迷宮中的當前位置的資訊,也是入棧的基本元素*/
typedef struct SElem
{
int di;
position seat;
}SElem;
/*鏈式棧中節點的定義*/
typedef struct position_stack
{
SElem p;
struct position_stack *next;
}*Stack_pNode,Stack_Node;
void InitStack(Stack_pNode *Link)
{
*Link = NULL;
}
void push(Stack_pNode *Link,SElem e)
{
Stack_pNode new_SElem = (Stack_pNode)calloc(1,sizeof(Stack_Node));
new_SElem->p = e;
new_SElem->next = NULL;
if (*Link == NULL)
*Link = new_SElem;
else
{
new_SElem->next = *Link;
*Link = new_SElem;
}
}
int pop(Stack_pNode *Link,SElem *e)
{
if (*Link == NULL)
return 0;
*e = (*Link)->p;
Stack_pNode q = *Link;
*Link = (*Link)->next;
free(q);
return 1;
}
int top(Stack_pNode Link, SElem *e)
{
if (Link == NULL)
return 0;
*e = Link->p;
return 1;
}
int empty(Stack_pNode Link)
{
if (Link == NULL)
return 1;
else
return 0;
}
int reverse(Stack_pNode *Link)
{
Stack_pNode p, q, r;
if (*Link == NULL || (*Link)->next == NULL)
return 0;
r = *Link;
p = (*Link)->next;
q = NULL;
while (p){
r->next = q;
q = r;
r = p;
p = p->next;
}
r->next = q;
*Link = r;
}
void print(Stack_pNode Link)
{
Stack_pNode r = Link;
while (r){
printf("(%d,%d) -> ",r->p.seat.x,r->p.seat.y);
r = r->next;
}
printf("exit\n");
}
int curstep = 1;/*紀錄當前的足跡,填寫在探索前進的每一步正確的路上*/
/*迷宮地圖,1代表牆的位置,0代表可行的路,周圍有一圈牆*/
int m[ROW+2][COL+2] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1,
1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1,
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1,
1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1,
1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
/*方向優先順序設定,依次為當前位置的右,下,左,上,在位置資訊中,儲存有本次
前進的方向--陣列的下標*/
position dir_set[4] = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
/*判斷當前位置是否可行,即判斷是路,還是牆*/
int pass(position p)
{
if (m[p.x][p.y])
return 0;
else
return 1;
}
/*將當前的步數填寫在走的每一步正確的路上,當發現走不通時,會把當時寫的資訊
用‘1’抹掉,代表走不通。*/
void footPrint(position p)
{
m[p.x][p.y] = curstep;
}
/*計算下一步的座標,di代表方向,本函式只負責計算下一步座標,不判斷優先順序*/
void nextPos(position *p, int di)
{
(*p).x += dir_set[di].x;
(*p).y += dir_set[di].y;
}
/*如上面的footPrint()註釋中提到的,當發現當前路走不通時,會用‘1’把走不通的
路堵上。*/
void markPrint(position p)
{
m[p.x][p.y] = 1;
}
/*迷宮程式的主函式,形參是一個指向不帶頭節點的棧的指標的指標,一個開始位置
,一個結束位置*/
int find_path(Stack_pNode * Maze_stack,position start,position end)
{
position curpos = start;/*定義一個位置變數,用來儲存當前的位置資訊
*/
SElem e;/*棧的元素,包括位置資訊,和前進的方向*/
do
{
if (pass(curpos)){ /*如果當前節點是路,則要將當前節點入棧,
並計算下一步前進方向*/
footPrint(curpos);/*在前進節點上紀錄當前的步數*/
e.seat = curpos;/*儲存位置資訊*/
e.di = 0;/*儲存方向資訊,預設為向右*/
push(Maze_stack, e);/*將位置資訊入棧*/
++curstep;/*步數加1*/
if (curpos.x == end.x && curpos.y == end.y)/*如果當
前節點是出口,則返回執行成功的標識*/
return 1;
nextPos(&curpos, e.di);/*計算下一步的座標,是根據當
前位置資訊計算的,即已經入棧了的資訊*/
}
else{/*如果當前節點是牆,則需要從棧取出之前走過的路,即沿原
路返回,在返回的過程中,還要不斷的判斷有沒有其他的路*/
if (!empty(*Maze_stack)){/*如果棧中有元素*/
pop(Maze_stack,&e);
--curstep;
while (e.di == 3 && !empty(*Maze_stack)){/*
邊向前回溯,邊判斷是否有其他的路可走*/
markPrint(e.seat);/*用"牆"覆蓋之前
填寫的步數資訊*/
pop(Maze_stack,&e);
--curstep;
}
if (e.di < 3){/*當找到了一個還有其他的路可
走之前走過的一個方塊(最壞的情況是回到起始位置)*/
++e.di;/*按優先順序改變之前的行走方向
*/
push(Maze_stack, e);/*再次入棧*/
++curstep;/*再次將步數加1*/
curpos = e.seat;/*再次紀錄現在的位
置*/
nextPos(&curpos, e.di);/*再次計算下
次的方向,有了以上的準備,即將進行下一次的迴圈*/
}//end if
}//end if
}//end else
} while (!empty(*Maze_stack));
return 0;
}
/*列印迷宮*/
void printMaze()
{
int i, j;
for (i = 0; i < ROW+2; ++i)
{
for (j = 0; j < COL+2; ++j){
printf("%2d ", m[i][j]);
}
printf("\n");
}
}
int main()
{
//stack_test();
position start = { 1, 1 };/*迷宮入口*/
position end = { 10, 10 };/*迷宮出口*/
Stack_pNode maze_stack;/*宣告一個棧,一會兒用來存放在迷宮中走過的位
置*/
InitStack(&maze_stack);/*初始化棧*/
if (find_path(&maze_stack, start, end)){
reverse(&maze_stack);/*由於棧中存放的是倒置的資訊,需要將棧
倒置*/
print(maze_stack);/*列印帶有走過的步數資訊的迷宮地圖*/
}
else{
printf("Has no way to out of the maze.\n");
}
printMaze();
return 0;
}