//预编译区::
#include "stdafx.h"
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXLEN 20 //迷宫包括外墙的最大行列数
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 15
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define UNDERFLOW -3
using namespace std;
//数据结构定义区::
typedef int status;
//坐标位置类型
typedef struct {
int r; //迷宫中第r行
int c; //迷宫中第c列
}PosType;
//栈中元素值域的类型
typedef struct {
int ord; //通道块在路径上的序号
PosType seat; //通道块在迷宫上的通道位置
int di; //从此通道块走向下一通道的方向
}SElemType;
//定义链式栈的存储结构
struct LNode {
SElemType data; //数据域
LNode *next; //指针域
};
typedef struct LStack {
LNode *top; //栈顶指针
LNode *base; //栈底指针
int stacksize; //栈的大小
}SqStack;
//迷宫类型(需要打印呈现)
typedef struct {
int r;
int c;
char addr[MAXLEN][MAXLEN]; //表示通道的矩阵
}MazeType;
//函数声明区::
void InitStack(LStack &s);
status StackEmpty(LStack s);
void PushStack(LStack &s, SElemType e);
void Pop(LStack &s, SElemType &e);
status DestroyStack(LStack &s);
void OverturnStack(SqStack S, SqStack &T);
void InitMaze(MazeType &maze);
status CreatMaze(MazeType &maze, PosType &start, PosType &end);
status WhetherPass(MazeType &maze, PosType curpos);
void FootPrint(MazeType &maze, PosType curpos);
PosType NextPos(PosType &curpos, int i);
void MarkPrint(MazeType &maze, PosType curpos);
status MazePath(MazeType &maze, PosType start, PosType end, SqStack &S);
void PrintMaze(MazeType &maze, PosType start, PosType end);
void PrintStack(SqStack S);
//主函数
int main(void) {
SqStack S, T;
InitStack(S); InitStack(T);
MazeType maze;
PosType start, end;
InitMaze(maze);
start.c = start.r = 0; end.c = end.r = 0;
printf("----------------创建迷宫开始----------------\n");
if (!CreatMaze(maze, start, end)) {
printf("初始化失败!!!\n");
exit(OVERFLOW);
}
printf("----------------创建迷宫结束----------------\n");
printf("\n");
printf("----------------原始迷宫模型图----------------\n");
PrintMaze(maze, start, end);
printf("\n");
printf("----------------走出迷宫的路径----------------\n");
if (!MazePath(maze, start, end, S)) //当栈被销毁的时候,则没有一条通路
printf("没有一条通路!!!\n"); //否则打印输出栈中的元素
else {
OverturnStack(S, T); PrintStack(T); DestroyStack(S);
}
printf("----------------迷宫路径模型图(o代表一条通路)----------------\n");
PrintMaze(maze, start, end);
system("pause");
return 0;
}
//---------栈的算法开始------------
//构造一个空栈
void InitStack(LStack &s) {
s.base = (LNode*)malloc(STACK_INIT_SIZE*sizeof(LNode)); //为指针p分配空间
if (!s.base) {
printf("分配失败,退出程序!");
exit(OVERFLOW);
}
s.top=s.base; //将栈底和栈顶指针指向p指向的位置
s.base->next = NULL; //栈顶指针的指针域置空
s.stacksize = STACK_INIT_SIZE;
return;
}
//若栈s为空栈,则返回true,否则返回false
status StackEmpty(LStack s) {
if (s.top == s.base) return TRUE; //若栈顶指针与栈底指针重合,则是空栈
else return FALSE;
}
//插入元素e成为新的栈顶元素
void PushStack(LStack &s, SElemType e) {
if (s.top - s.base >= s.stacksize) {
s.base = (LNode*)realloc(s.base,(s.stacksize+STACKINCREMENT)*sizeof(LNode));
if (!s.base) exit(OVERFLOW);
s.top = s.base + s.stacksize;
s.stacksize += STACKINCREMENT;
}
(*s.top).data= e;
s.top++;
return;
}
//删除s的栈顶元素,并用e返回其值
void Pop(LStack &s, SElemType &e) {
if (s.top == s.base) exit(ERROR); //如果为空栈,退出
s.top--;
e = (*s.top).data;
return;
}
//栈s的销毁
status DestroyStack(LStack &s) {
free(s.base);
s.base= NULL;
s.top=NULL;
s.stacksize = 0;
return OK;
}
//将栈S中的所有元素翻转致栈T:用于对于路径的输出,由于栈不能直接访问栈底指针,所以需要翻转
void OverturnStack(SqStack S,SqStack &T){
SElemType e;
do{
Pop(S, e); PushStack(T, e);
} while (S.base != S.top);
return;
}
//---------栈的算法结束------------
//---------迷宫实现开始------------
//初始化迷宫
void InitMaze(MazeType &maze){
maze.c = 0;
maze.r = 0;
return;
}
//创建迷宫
status CreatMaze(MazeType &maze, PosType &start,PosType &end) {
int i, j, m=0, n=0;
printf("请输入迷宫的行数和列数(包含外墙):");
scanf_s("%d,%d", &maze.r, &maze.c);
for (i = 0; i < maze.c; i++) {
maze.addr[0][i] = '#'; //给出上下围墙
maze.addr[maze.r -1][i] = '#';
}
for (i = 1; i < maze.r-1; i++) {
maze.addr[i][0] = '#'; //给出左右围墙
maze.addr[i][maze.c - 1] = '#';
}
for (i = 1; i < maze.r-1; i++) {
for (j = 1; j < maze.c-1; j++) {
maze.addr[i][j] = ' '; //将围墙内的通道块赋空值
}
}
printf_s("\n请输入迷宫入口:");
do {
scanf_s("%d,%d", &start.r, &start.c);
if (start.r == 0 || start.r >= maze.r || start.c >= maze.c) { //超出迷宫界限的时候跳出本次循环,继续循环输入入口
printf("上一入口超出迷宫界限,请重新输入入口坐标!\n"); //入口不能设置在四角和上下两个边界上
continue;
}
else break;
} while (start.r == 0 || start.r >= maze.r || start.c >= maze.c);
printf("\n");
printf_s("请输入迷宫出口:");
do {
scanf_s("%d,%d", &end.r, &end.c);
if (end.r == 0 || end.c == 0 || end.r >= maze.r || end.c >= maze.c) { //超出迷宫界限的时候跳出本次循环,继续循环输入入口
printf_s("上一出口超出迷宫界限,请重新输入出口坐标!\n");
continue;
}
else break;
} while (end.r == 0 || end.c == 0 || end.r >= maze.r || end.c >= maze.c);
maze.addr[start.r][start.c] = ' ';
maze.addr[end.r][end.c] = ' ';
printf("\n请输入障碍物的坐标(x,y)(以x,y=-1结束):\n");
while (m != -1) {
scanf_s("%d,%d", &m, &n); //系统坐标原点默认为(0,0)
if (m == 0 || n== 0 || m >= maze.r || n > maze.c) {
printf("上一坐标输入错误,系统自动舍弃,请重新输入坐标!\n");
m = 0; n = 0; continue;
}
else if (m == -1 && n == -1) continue;
else maze.addr[m][n] = '#';
}
return OK;
}
//判断当前位置可否通过,可通过返回true
status WhetherPass(MazeType &maze, PosType curpos) {
if (maze.addr[curpos.r][curpos.c] == ' ') return TRUE;
else return FALSE;
}
//若该通道块走过并且可通,就记录下来
void FootPrint(MazeType &maze, PosType curpos) {
maze.addr[curpos.r][curpos.c] = 'o';
return;
}
//指示并返回下一位置的坐标
PosType NextPos(PosType &curpos, int i) {
switch (i) { //向各个方向前进一个单位,并返回位置值
case 1:curpos.c += 1; break; //向东前进一个单位
case 2:curpos.r += 1; break; //向南前进一个单位
case 3:curpos.c -= 1; break; //向西前进一个单位
case 4:curpos.r -= 1; break; //向北前进一个单位
default:exit(ERROR);
}
return curpos;
}
//曾经走过,但不是通路,就标记
void MarkPrint(MazeType &maze, PosType curpos) {
maze.addr[curpos.r][curpos.c] = '@';
return;
}
//若迷宫存在一条通路,则求出一条通路存放到栈中
status MazePath(MazeType &maze, PosType start, PosType end ,SqStack &S){
PosType curpos; //记录当前元素位置
int curstep = 1,flag=0; //记录能通行的通道块在栈中的路径顺序
SElemType e; //记录可压住栈中的当前通道块的信息
curpos = start;
printf("用抽象数据类型三元组【(x,y)方向】表示迷宫路径:\n");
do {
if (WhetherPass(maze, curpos)) { //如果该路径块可通行
FootPrint(maze, curpos); //记录下通行过的痕迹
e.ord = curstep; //将栈中的顺序给e的ord属性
e.seat = curpos; //将该通道块的位置给e的curpos属性
e.di = 1; //将初始方向设为向东(1)
PushStack(S, e); //将该可通的通道块压入栈
if (curpos.r == end.r&&curpos.c == end.c) { //如果遇到了出口则退出
return TRUE;
}
else { //如果没有遇到出口
curpos = NextPos(curpos, 1); //那么寻找下一个位置
curstep++; //计数器加1
}
}
else { //如果该路径块不通
if (!StackEmpty(S)) { //如果栈不为空
Pop(S, e); //将栈顶元素出栈也就是退回上一个元素,将e返回出来判断是否再次进行方向的改变,也就是将栈顶元素进行悬挂操作
while (e.di == 4 && !StackEmpty(S)) { //当四个方向都不通并且栈b不为空时
MarkPrint(maze, e.seat); //记录该通道块不通
Pop(S, e);
//将栈顶元素出栈也就是退回上一个位置
}
if (e.di < 4) { //当四个方向没有尝试完时
e.di++; //换一个方向
PushStack(S, e); //将换方向之后的位置压栈
curpos = NextPos(e.seat, e.di); //当前位置下移
}
}
}
} while (!StackEmpty(S));
return FALSE;
}
//将标记路径信息输出到终端显示屏
void PrintMaze(MazeType &maze,PosType start, PosType end) {
int i, j;
printf(" "); //10个空格
for (i = 0; i <maze.c ; i++) printf("%2d", i);
printf("\n");
for (i = 0; i < maze.r; i++) {
if (i == start.r-1) printf("entrance%2d", start.r - 1);
else if (i == start.r) printf(" ->%2d", start.r);
else printf("%10d", i);
for (j = 0; j < maze.c; j++) {
printf("%2c", maze.addr[i][j]);
if (i == end.r - 1 && j == end.c) printf(" exit");
else if (i == end.r&&j == end.c) printf("<-");
}
printf("\n");
}
return;
}
//输出栈中的路径
void PrintStack(SqStack S){
int flag=0;
printf("迷宫中的一条通路如下:\n");
do{
S.top--; //将栈顶指针指向想要输出的栈顶元素
if ( flag % 5 == 0) printf("\n");
switch (S.top->data.di) {
case 1:
printf("(%d,%d)向东->",S.top->data.seat.r, S.top->data.seat.c);
flag++; break;
case 2:
printf("(%d,%d)向南->", S.top->data.seat.r, S.top->data.seat.c);
flag++; break;
case 3:
printf("(%d,%d)向西->", S.top->data.seat.r, S.top->data.seat.c);
flag++; break;
case 4:
printf("(%d,%d)向北->", S.top->data.seat.r, S.top->data.seat.c);
flag++; break;
}
} while (S.base != S.top);
printf("结束\n");
return;
}