先来一张女神的图片防止定定神,防止晕码
一,需求分析
1.通过识别用户输入来判断用户的操作行为。
2.要求用户自定义一个迷宫包括出入口(输入1为围墙,0为通路,迷宫最外层为一圈围墙,需要用户自己输入)。
3.迷宫若有解,则在迷宫上打印出路径,路径由 ‘*’ 组成,若是求解时走进死胡同则将死胡同用 ’@‘ 标记。
二,概要设计
1.定义栈的数据类型及基本操作。
2.定义迷宫数据类型及基本操作。
3.程序分为迷宫设计,迷宫求解,迷宫打印和路径打印四个模块。
三,详细设计
1.坐标位置类型
typedef struct//定义位置
{
int r ,c;
}PosType;
2.迷宫类型
typedef struct//定义迷宫类型
{
int m,n;
char arr[RANGE][RANGE];//各个位置取 空格,#,*,@
int flag; //标记迷宫是否建立否为0是为1
}MazeType;
************************************************************************
int Initmaze(MazeType *maze)//建立迷宫
{
int i,j;
printf("请输入迷宫行数与列数:\n");
scanf("%d %d",&(maze->m),&(maze->n));
int a[maze->m][maze->n];
maze->flag=1; //标记迷宫已经建立
printf("请输入迷宫(0代表通道 1代表障碍 )\n");
for(i=0;i<maze->m;i++) //开始建立迷宫
{
for(j=0;j<maze->n;j++)
{
scanf("%d",&a[i][j]);
switch(a[i][j])
{
case 0: maze->arr[i][j]=' ';break;
case 1: maze->arr[i][j]='#';break;
default:return error;
}
}
}
printf("迷宫建立成功!\n");
return 0;
}
************************************************************************
stack MazePath(MazeType *maze) //寻找出路(求解时在当前位置依次向东,南,西,北四个方向去探索,如果可以走通就走向那个位置,并将那个位置纳入栈,如果都走不通就退回上一个位置并把此位置移出栈如果栈没有元素可移说明无路可退,迷宫无解
{
PosType start,end,curpos;
printf("请输入入口和出口坐标\n");
scanf("%d%d%d%d",&start.r,&start.c,&end.r,&end.c);
curpos=start;
stack s;
InitStack(&s);
s.top->date.di=0;
SElemType e;
int step=1;
e=CreatElem(start,0,step);
Push(&s,e);
s.stacksize++;
maze->arr[start.r][start.c]='*';
while(1) //开始寻找出路
{
if(pass(maze,curpos,1)==1)//如果东不是来向且向东能通则往东走
{
step++; //计步器加加
curpos.c++; //当前位置更新
e=CreatElem(curpos,1,step); //创造节点数据
Push(&s,e); //此数据入栈
s.stacksize++; //栈的元素个数加一
maze->arr[curpos.r][curpos.c]='*'; //迷宫中此位置成为路径中的一步
if(comp(curpos,end)) //如果到达出口则返回
{
printf("路径已找到\n");
return s;
}
}
else if(pass(maze,curpos,2)==1)//否则如果南不是来向且向南能通则往南走
{
step++;
curpos.r++;
e=CreatElem(curpos,2,step);
Push(&s,e);
s.stacksize++;
maze->arr[curpos.r][curpos.c]='*';
if(comp(curpos,end))
{
printf("路径已找到\n");
return s;
}
}
else if(pass(maze,curpos,3)==1)//否则如果西不是来向且向西能通则往西走
{
step++;
curpos.c--;
e=CreatElem(curpos,3,step);
Push(&s,e);
s.stacksize++;
maze->arr[curpos.r][curpos.c]='*';
if(comp(curpos,end))
{
printf("路径已找到\n");
return s;
}
}
else if(pass(maze,curpos,4)==1)//否则如果北不是来向且向北能通则往北走
{
step++;
curpos.r--;
e=CreatElem(curpos,4,step);
Push(&s,e);
s.stacksize++;
maze->arr[curpos.r][curpos.c]='*';
if(comp(curpos,end))
{
printf("路径已找到\n");
return s;
}
}
else //都走不通就往来向退回
{
if(s.top!=s.base) //如果有路可退就退出否则无路可退说明迷宫无解
{
maze->arr[curpos.r][curpos.c]='@';
curpos=backpos(curpos,&s);
Pop(&s,&e);
}
else
{
printf("没有路径!\n");
return s;
}
}
}
return s;
}
************************************************************************
void PrintMaze(MazeType *M) //迷宫打印
{
int r,l,i,j;
r=M->m;
l=M->n;
if(!M||M->flag==0)
{
printf("迷宫不存在,请先创建!\n");
return ;
}
else
{
for(i=0;i<r;i++)
{
for(j=0;j<l;j++)
{
printf("%c ",M->arr[i][j]);
}
printf("\n");
}
}
return ;
}
3.栈类型
typedef struct //栈
{
SNode *top;
SNode *base;
int stacksize;
}stack;
************************************************************************
typedef struct SNode //定义节点
{
SElemType date;
struct SNode * next;
}SNode;
************************************************************************
typedef struct//定义节点数据的类型
{
int step;
PosType seat;
int di;
}SElemType;
************************************************************************
int InitStack(stack *s) //栈初始化
{
s->base=(SNode*)malloc(sizeof(SNode));
if(!s->base)
return error;
s->top=s->base;
s->top->next=NULL;
s->stacksize=0;
return ok;
}
************************************************************************
int Push(stack *s,SElemType e)//入栈
{
if(!s)
return error;
SNode *p;
p=(SNode*)malloc(sizeof(SNode));
p->date=e;
p->next=s->top->next;
s->top->next=p;
s->top=p;
return ok;
}
************************************************************************
int Pop(stack *s,SElemType *e)//出栈
{
if(!s||s->base==s->top)
return error;
SNode *p;
p=s->base;
while(p->next!=s->top)
p=p->next;
*e=s->top->date;
s->top=p;
p=p->next;
s->top->next=p->next;
free(p);
return ok;
}
4.其他必要函数
SElemType CreatElem(PosType curpos,int d,int step)//创建节点数据
{
SElemType e;
e.step=step;
e.seat=curpos;
e.di=d;
return e;
}
************************************************************************
PosType backpos(PosType curpos,stack *s) //返回上一个位置
{
PosType t=curpos;
int d;
d=s->top->date.di;
switch(d)
{
case 1:t.c--;break;//来向为东则向西返回
case 2:t.r--;break;//来向为南则向北返回
case 3:t.c++;break;//来向为西则向东返回
case 4:t.r++;break;//来向为北则向南返回
default:;
}
return t;
}
************************************************************************
PosType backpos(PosType curpos,stack *s) //返回上一个位置
{
PosType t=curpos;
int d;
d=s->top->date.di;
switch(d)
{
case 1:t.c--;break;//来向为东则向西返回
case 2:t.r--;break;//来向为南则向北返回
case 3:t.c++;break;//来向为西则向东返回
case 4:t.r++;break;//来向为北则向南返回
default:;
}
return t;
}
************************************************************************
int comp(PosType curpos,PosType end) //判断是否到达出口
{
if(curpos.r==end.r&&curpos.c==end.c)
return 1;
else
return 0;
}
************************************************************************
void footprint(stack *s) //足迹打印
{
if(!s||s->top==s->base)
{
printf("没有足迹!\n");
return ;
}
printf("足迹为此位置的行列坐标和到达此步的方向(行,列,方向)\n\n\n");//到达起始位置的方向为0
SNode *p;
p=s->base;
p=p->next;
while(p!=s->top)
{
printf("(%d,%d,%d) -> ",p->date.seat.r,p->date.seat.c,p->date.di);
p=p->next;
}
printf("(%d,%d,%d)",p->date.seat.r,p->date.seat.c,p->date.di);
return ;
}
************************************************************************
void Initialization() //初始化界面
{
system("cls");
printf("******************************************************\n");
printf(" CreatMaze--1 Mazepath--2 PrintMaze--3 Footprint--4 Quit--5\n\n");
return ;
}
5.总代码
//链式栈实现
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#define status int
#define error 0
#define ok 1
#define RANGE 20
#define ok 1
typedef struct//定义位置
{
int r ,c;
}PosType;
typedef struct//定义迷宫类型
{
int m,n;
char arr[RANGE][RANGE];//各个位置取 空格,#,*,@
int flag; //标记迷宫是否建立否为0是为1
}MazeType;
typedef struct//定义节点数据的类型
{
int step;
PosType seat;
int di;
}SElemType;
typedef struct SNode //定义节点
{
SElemType date;
struct SNode * next;
}SNode;
typedef struct //栈
{
SNode *top;
SNode *base;
int stacksize;
}stack;
int InitStack(stack *s) //栈初始化
{
s->base=(SNode*)malloc(sizeof(SNode));
if(!s->base)
return error;
s->top=s->base;
s->top->next=NULL;
s->stacksize=0;
return ok;
}
int Push(stack *s,SElemType e)//入栈
{
if(!s)
return error;
SNode *p;
p=(SNode*)malloc(sizeof(SNode));
p->date=e;
p->next=s->top->next;
s->top->next=p;
s->top=p;
return ok;
}
int Pop(stack *s,SElemType *e)//出栈
{
if(!s||s->base==s->top)
return error;
SNode *p;
p=s->base;
while(p->next!=s->top)
p=p->next;
*e=s->top->date;
s->top=p;
p=p->next;
s->top->next=p->next;
free(p);
return ok;
}
int Initmaze(MazeType *maze)//建立迷宫
{
int i,j;
printf("请输入迷宫行数与列数:\n");
scanf("%d %d",&(maze->m),&(maze->n));
int a[maze->m][maze->n];
maze->flag=1; //标记迷宫已经建立
printf("请输入迷宫(0代表通道 1代表障碍 )\n");
for(i=0;i<maze->m;i++) //开始建立迷宫
{
for(j=0;j<maze->n;j++)
{
scanf("%d",&a[i][j]);
switch(a[i][j])
{
case 0: maze->arr[i][j]=' ';break;
case 1: maze->arr[i][j]='#';break;
default:return error;
}
}
}
printf("迷宫建立成功!\n");
return 0;
}
SElemType CreatElem(PosType curpos,int d,int step)//创建节点数据
{
SElemType e;
e.step=step;
e.seat=curpos;
e.di=d;
return e;
}
PosType backpos(PosType curpos,stack *s) //返回上一个位置
{
PosType t=curpos;
int d;
d=s->top->date.di;
switch(d)
{
case 1:t.c--;break;//来向为东则向西返回
case 2:t.r--;break;//来向为南则向北返回
case 3:t.c++;break;//来向为西则向东返回
case 4:t.r++;break;//来向为北则向南返回
default:;
}
return t;
}
int pass(MazeType *maze,PosType curpos,int d)//判断当前方向是否可走 1东 2南 3西 4北
{
switch(d)
{
case 1:if(maze->arr[curpos.r][curpos.c+1]==' ')
return 1;
else
return 0;
case 2:if(maze->arr[curpos.r+1][curpos.c]==' ')
return 1;
else
return 0;
case 3:if(maze->arr[curpos.r][curpos.c-1]==' ')
return 1;
else
return 0;
case 4:if(maze->arr[curpos.r-1][curpos.c]==' ')
return 1;
else
return 0;
default: return error;
}
}
int comp(PosType curpos,PosType end) //判断是否到达出口
{
if(curpos.r==end.r&&curpos.c==end.c)
return 1;
else
return 0;
}
void footprint(stack *s) //足迹打印
{
if(!s||s->top==s->base)
{
printf("没有足迹!\n");
return ;
}
printf("足迹为此位置的行列坐标和到达此步的方向(行,列,方向)\n\n\n");//到达起始位置的方向为0
SNode *p;
p=s->base;
p=p->next;
while(p!=s->top)
{
printf("(%d,%d,%d) -> ",p->date.seat.r,p->date.seat.c,p->date.di);
p=p->next;
}
printf("(%d,%d,%d)",p->date.seat.r,p->date.seat.c,p->date.di);
return ;
}
stack MazePath(MazeType *maze) //寻找出路
{
PosType start,end,curpos;
printf("请输入入口和出口坐标\n");
scanf("%d%d%d%d",&start.r,&start.c,&end.r,&end.c);
curpos=start;
stack s;
InitStack(&s);
s.top->date.di=0;
SElemType e;
int step=1;
e=CreatElem(start,0,step);
Push(&s,e);
s.stacksize++;
maze->arr[start.r][start.c]='*';
while(1) //开始寻找出路
{
if(pass(maze,curpos,1)==1)//如果东不是来向且向东能通则往东走
{
step++; //计步器加加
curpos.c++; //当前位置更新
e=CreatElem(curpos,1,step); //创造节点数据
Push(&s,e); //此数据入栈
s.stacksize++; //栈的元素个数加一
maze->arr[curpos.r][curpos.c]='*'; //迷宫中此位置成为路径中的一步
if(comp(curpos,end)) //如果到达出口则返回
{
printf("路径已找到\n");
return s;
}
}
else if(pass(maze,curpos,2)==1)//否则如果南不是来向且向南能通则往南走
{
step++;
curpos.r++;
e=CreatElem(curpos,2,step);
Push(&s,e);
s.stacksize++;
maze->arr[curpos.r][curpos.c]='*';
if(comp(curpos,end))
{
printf("路径已找到\n");
return s;
}
}
else if(pass(maze,curpos,3)==1)//否则如果西不是来向且向西能通则往西走
{
step++;
curpos.c--;
e=CreatElem(curpos,3,step);
Push(&s,e);
s.stacksize++;
maze->arr[curpos.r][curpos.c]='*';
if(comp(curpos,end))
{
printf("路径已找到\n");
return s;
}
}
else if(pass(maze,curpos,4)==1)//否则如果北不是来向且向北能通则往北走
{
step++;
curpos.r--;
e=CreatElem(curpos,4,step);
Push(&s,e);
s.stacksize++;
maze->arr[curpos.r][curpos.c]='*';
if(comp(curpos,end))
{
printf("路径已找到\n");
return s;
}
}
else //都走不通就往来向退回
{
if(s.top!=s.base) //如果有路可退就退出否则无路可退说明迷宫无解
{
maze->arr[curpos.r][curpos.c]='@';
curpos=backpos(curpos,&s);
Pop(&s,&e);
}
else
{
printf("没有路径!\n");
return s;
}
}
}
return s;
}
void PrintMaze(MazeType *M) //迷宫打印
{
int r,l,i,j;
r=M->m;
l=M->n;
if(!M||M->flag==0)
{
printf("迷宫不存在,请先创建!\n");
return ;
}
else
{
for(i=0;i<r;i++)
{
for(j=0;j<l;j++)
{
printf("%c ",M->arr[i][j]);
}
printf("\n");
}
}
return ;
}
void Initialization() //初始化界面
{
system("cls");
printf("******************************************************\n");
printf(" CreatMaze--1 Mazepath--2 PrintMaze--3 Footprint--4 Quit--5\n\n");
return ;
}
int main() //主函数
{
int cmd=0;
stack sta;
InitStack(&sta);
MazeType M;
M.flag=0;
Initialization();//系统初始化;
while(1)
{
printf("请输入命令\n");
scanf("%d",&cmd);
switch(cmd)
{
case 1:Initmaze(&M);break;
case 2:sta=MazePath(&M);break;
case 3:PrintMaze(&M);break;
case 4:footprint(&sta);break;
case 5:exit(ok);
default :return error;
}
}
return ok;
}
结果演示
六,总结与体会
肝了两个晚上终于把功能实现了,还是小有成就感的,嘿嘿。第一篇博客就这么诞生了,nice!虽然总体还算顺利,但是过程中遇到一个非常棘手的问题就是遇到死胡同退回时位置总是乱跳,一开始没明白为什么,后来才发觉是backpos函数switch语句没有加break。。。给我愁的~~(没错我是傻瓜)
作为计算机新人语言语法的熟练果然是非常重要的!
最后希望这篇博客能够帮到有需要的人,同时也欢迎各位大佬不吝赐教!(喜欢就点个赞呗!)
附上测试迷宫
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 0 1
1 0 0 0 0 0 0 0 0 1
1 0 1 1 1 1 1 1 1 1
1 0 0 1 0 0 0 0 0 1
1 1 0 1 0 1 0 0 0 1
1 1 0 0 0 1 0 0 0 1
1 1 1 1 1 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 0 1
1 0 0 0 0 0 0 0 0 1
1 0 1 1 1 1 1 1 1 1
1 0 0 0 1 0 0 0 0 1
1 1 0 1 0 1 0 0 0 1
1 1 0 0 0 1 0 0 0 1
1 1 1 1 1 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1
1 0 0 0 1
1 0 0 1 1
1 0 0 0 1
1 1 1 1 1