(说明:实验报告必须包含下面的每项内容,根据实验情况认真填写,封面必须打印或复印(A4纸),书写上机实验报告内容的纸张也用A4纸,最后从侧面装订)
一【上机实验目的】
1. 了解栈的应用
2. 编写迷宫程序
二【实验环境】
PC机每人1台
三【上机实验内容】
(此次上机实验老师布置的具体任务)
迷宫求解
主要利用栈实现,要求能动态生成迷宫,显示有几条路径,用图形界面显示最合适的路径。
四【上机调试程序流程图】(注:可打印)
(用传统流程图的形式表示)
五【上机调试中出现的错误信息、错误原因及解决办法】
(记录下你调试程序中出现的错误信息的英文提示,分析出错原因及可能的解决办法)
1. 马虎造成的错误
2. 程序的逻辑有问题
3. 语法用错
调试过程中,将整个程序分为一个个子块,逐个解决
六【上机调试后的源程序及还存在的问题】(注:源程序可打印)
(同时记录下你对你编写此程序的其它具体想法,)
#include<stdlib.h>
#include<time.h>
#include<stack>
#include<queue>
using namespace std;
#define OVERFLOW 0
#define OK 1
#define ERROE 0
#define TRUE 1
#define FALSE 0
#define SIZE 102//迷宫的最大范围
typedef int Status;
typedef struct{
int x;
int y;
}PosType;//坐标位置
typedef struct {
PosType seat; //通道块在迷宫中的"坐标位置"
int di; //从上一通道块走向此通道块的"方向"
}SElemType;
Status Check(char &choice);//确认输入正确
void Random(int mg[SIZE][SIZE],int size,PosType start,PosType end)
{
int i,j,k;
srand(time(NULL));
for(j=0;j<size;j++)
mg[0][j]=mg[size-1][j]=1; //设置迷宫外围"不可走",保证只有一个出口和入口
for(i=1;i<size-1;i++)
mg[i][0]=mg[i][size-1]=1;
for(i=1;i<size-1;i++)
for(j=1;j<size-1;j++){
k=rand()%4; //随机生成0、1、2、3四个数
if(k)
mg[i][j]=0;
else{
mg[i][j]=1;
}//else
}
mg[start.y][start.x]=0;
mg[end.y][end.x]=0; //将入口、出口设置为"0"即可通过
}
Status Pass(PosType e,int mg[SIZE][SIZE])
{
if (mg[e.y][e.x]==0) //0时可以通过
return OK; // 如果当前位置是可以通过,返回1
return OVERFLOW; // 其它情况返回0
}
Status FootPrint(PosType e,int mg[SIZE][SIZE])
{
mg[e.y][e.x]=7;
return OK;
}
PosType NextPos(PosType e,int dir)
{
PosType E;
switch(dir){
case 1:E.x=e.x+1; //向右
E.y=e.y;
break;
case 2:E.x=e.x; //向下
E.y=e.y+1;
break;
case 3:E.x=e.x-1; //向左
E.y=e.y;
break;
case 4:E.x=e.x; //向上
E.y=e.y-1;
break;
}
return E;
}
Status Equal(PosType e1,PosType e2)
{
if((e1.x==e2.x)&&(e1.y==e2.y))
return TRUE;
return FALSE;
}
Status MarkPath(PosType e,int mg[SIZE][SIZE],int di)
{
switch(di)
{case 1://向右
mg[e.y][e.x]=11;
break;
case 2://向下
mg[e.y][e.x]=12;
break;
case 3://向左
mg[e.y][e.x]=13;
break;
case 4://向上
mg[e.y][e.x]=14;
break;
}
return OK;
}
PosType FrontPos(PosType e,int dir)
{
PosType E;
switch(dir){
case 1:E.x=e.x-1; //向左
E.y=e.y;
break;
case 2:E.x=e.x; //向上
E.y=e.y-1;
break;
case 3:E.x=e.x+1; //向右
E.y=e.y;
break;
case 4:E.x=e.x; //向下
E.y=e.y+1;
break;
}
return E;
}
Status PathPrint(stack<SElemType> s,int mg[SIZE][SIZE])
{
SElemType e,front,tail;
int di;
e=s.top();
tail=e;
s.pop();
MarkPath(e.seat,mg,1);
while(!s.empty())
{
front=s.top();
s.pop();
if(Equal(front.seat,FrontPos(e.seat,e.di)))
{
di=e.di;
e=front;
MarkPath(e.seat,mg,di);
}
}
return OK;
}
Status PathClean(int mg[SIZE][SIZE],stack<SElemType> s)
{
SElemType e;
while(!s.empty())
{
e=s.top();
s.pop();
mg[e.seat.y][e.seat.x]=0;
}
return OK;
}
Status MazePath(PosType start,PosType end,int mg[SIZE][SIZE],stack<SElemType> &s)
{
queue<SElemType> q;
SElemType e;
int di=0;
e.di=di;
e.seat=start;// 设定"当前位置"为"入口位置"
q.push(e);
s.push(e);
do
{
e=q.front();//得到队首的值
q.pop();///重复使用时,用这个初始化
for(di=1;di<=4;di++)
{
e.seat=NextPos(e.seat,di);
e.di=di;
if(Pass(e.seat,mg))
{
q.push(e);
s.push(e);
FootPrint(e.seat,mg);
if(Equal(e.seat,end))
{
PathPrint(s,mg);
return TRUE;
}
}
e.seat=FrontPos(e.seat,di);
}
}while(!q.empty());
printf("\n\n囧 ! 不能到达终点!");
return FALSE;
}
void PrintMaze(int mg[SIZE][SIZE],int size)
{
int i,j;
printf("\n");
for(i=0;i<size;i++)
{
for(j=0;j<size;j++)
{
switch(mg[i][j])
{
case 0:
case 7:
printf(" ");
break;
case 1:
if((1==i&&0==j)||((size-2)==i&&(size-1)==j))
printf(" ");
else
printf("■");
break;
case 11:
printf("→");
break;
case 12:
printf("↓");
break;
case 13:
printf("←");
break;
case 14:
printf("↑");
break;
}
}
printf("\n");
}
printf("\n");
}
Status Check(char &choice)
{
while(!(((choice=getchar())=='y')||(choice=='n')||(choice=='Y')||(choice=='N')))//非正确输入
{
if(choice!='\n')
{
printf("请输入确定选择(y/n)\n");
getchar();
}
}
getchar();//跳过'\n'
return OK;
}
int main(){
stack<SElemType> s;
int mg[SIZE][SIZE]={1},size;
PosType start,end;
char choice;
system("mode con cols=200 lines=200");
printf("\n==================迷宫最短路径游戏==================");
printf("\n说明:■不能走的区域");
printf("\n '空格'代表可通过的区域");
printf("\n默认起点为左上角位置,默认终点为右下角位置\n");
printf("\n============================================\n");
printf("请输入迷宫边长(3~%d),系统将为你产生一个随机迷宫:",SIZE-2);
scanf("%d",&size);
while((size>SIZE-2)||(size<1))
{
printf("输入有误!\n");
printf("请输入迷宫边长(3~%d),系统将为你产生一个随机迷宫:",SIZE-2);
scanf("%d",&size);
}
size+=2;//补上外围
getchar();//跳过'\n'
start.x=1;start.y=1; //起点坐标
end.x=size-2;end.y=size-2; //终点坐标
Random(mg,size,start,end);
PrintMaze(mg,size);
while(!((choice=='Q')||(choice=='q')))
{
printf("是否使用该迷宫?(y/n)\n");
Check(choice);
if((choice=='Y')||(choice=='y'))
{
PathClean(mg,s);
}
while((choice=='n')||(choice=='N'))
{
while(!s.empty())
s.pop();
choice=' ';
printf("请输入迷宫边长(3~%d),系统将为你产生一个随机迷宫:",SIZE-2);
scanf("%d",&size);
while((size>SIZE-2)||(size<1))
{
printf("输入有误!\n");
printf("请输入迷宫边长(3~%d),系统将为你产生一个随机迷宫:",SIZE-2);
scanf("%d",&size);
}
size+=2;//补上外围
start.x=1;start.y=1;//起点坐标
end.x=size-2;end.y=size-2; //终点坐标
getchar();//跳过'\n'
Random(mg,size,start,end);
PrintMaze(mg,size);
printf("是否使用该迷宫?(y/n)\n");
Check(choice);
}
printf("是否人工选择起点和终点(y/n)?【默认:起点(1,1),终点(%d,%d)】\n",size-2,size-2);
Check(choice);
if((choice=='y')||(choice=='Y'))
{
printf("请输入“起点”坐标(1~%d)用空格分隔:",size-2);
scanf("%d %d",&start.x,&start.y);
while(((start.x>size-2)||start.x<1)||((start.y>size-2)||(start.y<1))||!Pass(start,mg))
{
if(!Pass(start,mg)) printf("些位置不能为“起点”!\n");
else printf("输入有误!\n");
printf("请输入“起点”坐标(1~%d)用空格分隔:",size-2);
scanf("%d %d",&start.x,&start.y);
}
printf("请输入“终点”坐标(1~%d)用空格分隔:",size-2);
scanf("%d %d",&end.x,&end.y);
while(((end.x>size-2)||end.x<1)||((end.y>size-2)||(end.y<1))||!Pass(end,mg)||Equal(start,end))
{
if(!Pass(end,mg)) printf("些位置不能为“终点”!\n");
else if(Equal(start,end)) printf("该位置已为起点!\n");
else printf("输入有误!\n");
printf("请输入“终点”坐标(1~%d)用空格分隔:",size-2);
scanf("%d %d",&end.x,&end.y);
}
getchar();//跳过'\n'
}
MazePath(start,end,mg,s);
PrintMaze(mg,size);
printf("退出游戏请输入\"Q\"否则继续游戏!\n");
choice=getchar();
getchar();//跳过'\n'
}
printf("\n==========程序退出,感谢使用!==========\n");
return 0;
}
七【上机实验中的其他它问题及心得】
(在上机实验中遇到的你不能解决的其它问题,简单描述一下你此次上机的收获及感想)
迷宫问题关键是探索路径和方法,即在探索过程中记录走过的路径,能走通则继续走;如某一位置的下一位置走不通,则要沿原路退回,这点尤其重要。我们需要一个后进先出结构来保存从入口到当前位置的路径,所以对“栈”的应用必不可少。其次,对迷宫的表示方法也很重要,迷宫中每一点用二维数组坐标表示,当前位置四周的四个方向的点的坐标变化也要清楚。每走一步都要时时检测,对于此问题应掌握其方法和思想,不仅在迷宫问题,在其他很多问题中也能有所应用。对今后其他问题的研究会有很大帮助。
在实际的上机操作过程中,不仅是让我们了解数据结构的理论知识,更重要的是培养解决实际问题的能力,所以相信通过此次项目可以提高我们分析设计能力和编程能力,为后续课程的学习及实践打下良好的基础。
只有当你真正自己一步步的去编写每一行代码时,你才会有所收获。编写程序时,要做好前期规划。同时非常感谢同学和朋友们对我的热心帮助以及我们的李莉丽老师对我的细心指导。