收藏 分销(赏)

老鼠迷宫.doc

上传人:w****g 文档编号:2774952 上传时间:2024-06-05 格式:DOC 页数:37 大小:236.04KB 下载积分:12 金币
下载 相关 举报
老鼠迷宫.doc_第1页
第1页 / 共37页
老鼠迷宫.doc_第2页
第2页 / 共37页


点击查看更多>>
资源描述
(完整word版)老鼠迷宫 《 数 据 结 构 》课 程 设 计 3.8 老鼠迷宫 姓 名: XXX 院系: 计算机学院 专 业: 计算机科学与技术 年 级: 13级 学 号: E11314XXX 指导教师:XXX 2015年 10月 5 日 目录 1.课程设计的目的 3 2.需求分析 3 3走迷宫游戏的设计 3 3.1概要设计 3 3.1.1 主界面设计 3 3.1.2 存储结构 3 3.1.3 系统功能设计 4 3.2详细设计 4 3.2.1 系统子程序及功能设计 4 3.2.2 数据类型定义 5 3.2.3 系统主要子程序详细设计 6 3.3调试分析 15 3.4用户手册 16 4总结 16 5、程序清单:(见附录) 16 7、程序运行结果 16 附录1 22 37 / 37 1.课程设计的目的 (1) 熟练使用 C 语言编写程序,解决实际问题; (2) 了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力; (3) 初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能; (4) 提高综合运用所学的理论知识和方法独立分析和解决问题的能力。 2.需求分析 (1) 程序运行时显示一个迷宫地图,迷宫中央有一只老鼠,迷宫的右下方有一个粮仓。 (2) 按动键盘上的方向操作杆控制老鼠在规定的时间内走到粮仓。 (3) 老鼠形象可辨认,迷宫的墙足够结实,老鼠不能穿墙。 (4) 若老鼠在规定时间走到粮仓处则提示成功,否则提示失败。 (5) 添加编辑迷宫功能,可使迷宫墙变路,路变墙。 (6) 找出走出迷宫的所有路径,以及最短路径。 3走迷宫游戏的设计 3.1概要设计 3.1.1 主界面设计 图 1 主界面,如图1所示,包含六个菜单项,分别是开始游戏、编辑迷宫、读入迷宫、生成随机迷宫、最短路径、退出系统。输入数字选择对应菜单,进入子项。 3.1.2 存储结构 本系统用结构体Maze存储迷宫,该结构体由room[M][N],status[M][N]组成。room是int型数组,存储迷宫具体内容;status是int型数组,用来存放迷宫求解时通堵状态,迷宫大小M,N固定。本系统用结构体pos存储迷宫求解时每一步的信息,该结构体由x,y,parent,self,next[4]组成。x,y是整型变量,存储坐标,parent是上一步在队列数组中的位置,self是本步在队列数组中的位置,next[4]存储四个方向下一步在队列数组中的位置。本系统用结构体Queue形成队列,该结构体由p[M*N],front,rear组成。p是pos型变量,存储队列中的内容。本系统用数组实现队列操作,是为了求最短路径时,用BFS算法后,还能找到出队列的数据。 3.1.3 系统功能设计 本系统主菜单包含四个选项,功能描述如下: 菜单1:开始游戏。在菜单1中开始走迷宫游戏,老鼠用笑脸表示,初始状态老鼠在迷宫中间;通过键盘操纵老鼠上下左右移动,游戏分为6关,同一张地图,在规定时间到达粮仓可升级,否则提示失败,返回主菜单,随着级别增高最大时间逐渐减少。 菜单2:编辑迷宫。在菜单2中编辑迷宫,按上下左右操作光标☺。可输入1,控制光标走过的地方为通路,输入0控制光标走过的地方为障碍。输入非法字符退出编辑。光标默认在迷宫中间,默认情况下光标走过的地方都为通路。 菜单3:读入迷宫。在菜单3中读入已存在的迷宫文件,并输出读入的迷宫。 菜单4:随机迷宫。在菜单4中以系统时间作为种子,随机生成地图,并输出地图,询问是否保存到文件。 菜单5:最短路径。在菜单5中进行迷宫求解,若存在走出迷宫的路径,则找出最小路径,并用图形化界面输出,同时输出所有可走出迷宫的路径数目;否则,提示未找到最短路径,即该迷宫无解。 菜单0:退出系统。 3.2详细设计 3.2.1 系统子程序及功能设计 本系统设置19个子程序,各程序的函数名及功能说明如下: int maincourse()//主菜单 int inputselection(int n)//输入菜单选择,返回值为输入的选项 void initqueue(Queue &Q) //初始化队列 void enqueue(Queue &Q,pos p)//进队 void dequeue(Queue &Q,pos &p)//出队 int emptyqueue(Queue Q)//判队空 void display(Elemtype room[M][N],int degree,int t,int flag)//输出迷宫 void countdown() //倒计时进入迷宫游戏 void play(Elemtype room[M][N]) //迷宫游戏 void filesave(Maze maze) //保存地图到文件 void fileread(Maze &maze) //读入地图 void modify(Maze &maze) //编辑迷宫 void mazerand(Maze &maze) //随机生成迷宫 int pass(Maze maze,pos p) //是否可通过 void markprint(Maze &maze,pos p)//留下足迹 void stepsdisplay(Queue Q,pos p,Maze maze) //输出最短路径 void minroad(Maze maze) //最短路径 void findallroad(Maze &maze,pos p,int &num) //找所有路径 void allroad(Maze maze) //所有路径 各个函数间的调用关系如下: 主 主菜单 countdown();display(); 开始迷宫游戏play(room[M][N]) display();filesave(maze); 修改迷宫modify(maze) display(); 从文件读入地址信息fileread(maze) display();filesave(maze); 随机生成迷宫mazerand(maze) markprint();pass(); stepsdiplay(); minroad(maze) 最短路径及所有路径数目统计 allroad(maze) (maze) markprint();pass(); findallroad; 图3 3.2.2 数据类型定义 struct Maze{ Elemtype room[M][N]; //迷宫 Elemtype status[M][N]; //迷宫求解记录 }; struct pos{ int x,y,parent,self; //x,y是当前坐标,parent是上一步在队列中的位置 int next[4]; //self是本步在队列中的位置,next是下四步在队列中的位置 }; struct Queue{ pos p[M*N]; //队列中元素 int front; //队首 int rear; //队尾 }; 3.2.3 系统主要子程序详细设计 输出迷宫: void display(Elemtype room[M][N],int degree,int t,int flag){//输出迷宫 int i,j; //flag为0为游戏模式,flag为1或2为编辑模式,大于2为输出模式 printf("\n\n"); for(i=0;i<M;i++){ putchar('\t'); for(j=0;j<N;j++) switch(room[i][j]){ case 0: printf("■"); break; case 1: printf(" "); break; case 2: printf("%c ",1); break; case 3: printf("∏"); break; case 4: printf("↓"); //上 break; case 5: printf("→"); //右 break; case 6: printf("←"); //左 break; case 7: printf("↑"); //上 break; default: printf("\n迷宫格式错误!停止运行!\n"); exit(0); break; } if(flag>=3){ //其他模式 putchar('\n'); continue; } switch(i){ case 0: printf(" ------------------"); break; case 1: if(flag) printf(" 编辑迷宫! ");//编辑模式 else printf(" 欢迎进入迷宫游戏!");//游戏模式 break; case 2: printf(" ------------------"); break; case 3: printf(" ------------------"); break; case 4: printf(" 按←↑→↓操纵 "); break; case 5: printf(" ------------------"); break; case 6: printf(" ------------------"); break; case 7: if(flag) printf(" 0,路边墙;1,墙变路"); //编辑模式 else printf(" 当前等级:%d ",degree); //游戏模式 break; case 8: printf(" ------------------"); break; case 9: printf(" ------------------"); break; case 10: if(flag==2) printf(" 此时墙变路 ");//编辑模式 else if(flag==1) printf(" 此时路变墙 "); else printf(" 剩余时间:%d\t",t);//游戏模式 break; case 11: printf(" ------------------"); break; } putchar('\n'); } } 走出迷宫游戏: void play(Elemtype room[M][N]){ //迷宫游戏 countdown(); system("cls"); clock_t start,start2; start=clock(); int x=M/2,y=N/2,x1=1,y1=1; int degree=1,lefted_t=30,all_t=30; while(1){ start2=clock(); while((lefted_t=(start2-start)/second)<all_t&&!kbhit()){//计时及判断是否有输入 system("cls"); display(room,degree,all_t-lefted_t,0); while(clock()-start2<second&&!kbhit()); start2=clock(); } lefted_t=all_t-lefted_t; if(lefted_t<=0){ //时间用完 system("cls"); printf("\t\t\t******************************\n"); printf("\t\t\t 游戏结束!挑战失败! \n"); printf("\t\t\t******************************\n"); room[x][y]=1; room[M/2][N/2]=2; return; } getch(); switch(getch()){ //操纵 case 72: x1=x-1; y1=y; break; // 向上 case 80: x1=x+1; y1=y; break; // 向下 case 75: x1=x; y1=y-1; break; // 向左 case 77: x1=x; y1=y+1; // 向右 break; default: continue; } if(x1==0||x1==M-1||y1==0||y1==N-1)//撞边墙了 continue; else if(room[x1][y1]==0) //撞墙了 continue; else{ room[x][y]=1; x=x1; y=y1; if(x==N-2&&y==N-2){ //找到出口 system("cls"); degree++; all_t-=5; if(all_t==0){ //随着升级,时间减少 system("cls"); printf("\t\t\t******************************\n"); printf("\t\t\t 你赢了!\n"); printf("\t\t\t******************************\n"); room[x][y]=3; room[M/2][N/2]=2; return; } printf("\t\t\t******************************\n"); printf("\t\t\t 升级了!等级%d!\n",degree); printf("\t\t\t******************************\n"); system("pause"); start=clock();//下一关重新计时 x=M/2; y=N/2; room[x][y]=2;//更新坐标 } else room[x][y]=2;//更新坐标 } } } 编辑迷宫: void modify(Maze &maze){ //编辑迷宫 int flag=1; int laststep; int x1=M/2,y1=N/2,x=M/2,y=N/2; char c; while(1){ system("cls"); display(maze.room,0,0,flag+1); while(!kbhit()); c=getch(); if(c==-32) c=getch(); switch(c){ case 72: x1=x-1; y1=y; break; // 向上 case 80: x1=x+1; y1=y; break; // 向下 case 75: x1=x; y1=y-1; break; // 向左 case 77: x1=x; y1=y+1; // 向右 break; case 48: flag=0; //变墙 break; case 49: flag=1; //变路 break; default: system("cls"); printf("\t\t\t******************************\n"); printf("\t\t\t 退出编辑!\n"); printf("\t\t\t******************************\n"); maze.status[x][y]=maze.room[x][y]=laststep; maze.status[M/2][N/2]=maze.room[M/2][N/2]=2; filesave(maze); system("pause"); return; } if(x1==0||x1==M-1||y1==0||y1==N-1) //撞墙了 continue; else if(x1==M-2&&y1==M-2) continue; else{ if(flag) //变路 maze.status[x][y]=maze.room[x][y]=1; else //变墙 maze.status[x][y]=maze.room[x][y]=0; laststep=maze.room[x1][y1]; x=x1; y=y1; maze.status[x][y]=maze.room[x][y]=2; //定位 } } } 最短路径: void minroad(Maze maze){ //最短路径 system("cls"); printf("--------------------------------\n\t 最 短 路 径 \n"); printf("--------------------------------\n"); Queue Q; initqueue(Q); pos p1,p2; //进队用p1,出队用p2 int next[4][2]={{1,0},{0,1},{0,-1},{-1,0}}; p1.x=M/2; p1.y=N/2; p1.parent=-1; p1.self=0; enqueue(Q,p1); do{ dequeue(Q,p2); for(int i=0;i<4;i++){ //四个方向 p1.x=p2.x+next[i][0]; //下一方向的坐标 p1.y=p2.y+next[i][1]; p1.parent=Q.front-1; p1.self=Q.rear; if(pass(maze,p1)){ //判断是否可通过 markprint(maze,p1);//留下足迹 enqueue(Q,p1); Q.p[p1.parent].next[i]=Q.rear-1; //父结点指向进队的子结点 } } if(p2.x==M-2&&p2.y==N-2){ printf("输出最短路径:"); stepsdisplay(Q,p2,maze); //输出最短路径 return; } }while(!emptyqueue(Q)); printf("未找到最短路径!\n"); } 统计所有路径数目: void findallroad(Maze &maze,pos p,int &num){//找从p开始的所有路径 int next[4][2]={{1,0},{0,1},{0,-1},{-1,0}};//移动方向 pos p1; Elemtype temp; for(int i=0;i<4;i++){ //四个方向 p1.x=p.x+next[i][0]; //下一方向的坐标 p1.y=p.y+next[i][1]; if(pass(maze,p1)){ temp=maze.status[p1.x][p1.y];//保留状态 markprint(maze,p1);//留下足迹 if(p1.x==M-2&&p1.y==N-2) num++; else findallroad(maze,p1,num);//递归调用 maze.status[p1.x][p1.y]=temp;//恢复状态 } } } void allroad(Maze maze){ //所有路径 int num=0; pos p; p.x=M/2; p.y=N/2; markprint(maze,p);//留下足迹 findallroad(maze,p,num);//寻找从p开始的所有通路 if(num) printf("共有%d条路径\n",num); } 3.3调试分析 测试数据及测试结果在7中有详细给出,这里省略。 时间复杂度分析: play函数为走出迷宫游戏,其时间复杂度也不确定,与通路的块数以及通路的布局有关。 display函数为显示迷宫,被多次调用,因为要将迷宫一个一个地输出,所以时间复杂度为 modify函数为修改迷宫的函数,其时间复杂度不确定,与要修改的块相关。 fileread和filesave函数保存一个Maze型数据,时间复杂度为。 mazerand函数用rand()生成个伪随机数,所以时间复杂度为 minroad函数对可走块四个方向都要判断是否可通,若可走块的数目为,则最多需要判断次,时间复杂度为 allroad函数对可走块四个方向都要判断是否可通,时间复杂度同样为。 调试思考: 1 注意菜单选择函数的设计,它们的功能和菜单之间的联系。注意各个菜单函数中迷宫是否要初始化。 2 为了让迷宫边界更加明显,默认设置边界部分全部为障碍。 3 用键盘操作老鼠的移动方向,可用switch函数,根据输入的按键,进入不同分支,按照不同方式修改当前老鼠坐标。 4 迷宫游戏需通过计时,判断是否在规定时间内完成迷宫。计时可通过不断获取系统时间实现。同时,需在动画界面不断更新计时,每隔一段时间刷新屏幕。 5 迷宫游戏要用动画界面实现,在按动键盘或计时更新时都要刷新屏幕,可用一个while循环实现,当时间间隔足够或者键盘有操作时退出while循环并刷新屏幕。 6 迷宫编辑函数modify中为实现图形化的界面,让修改更加的直观,设置每按下一个按键就根据所按下按键修改地图,并刷新屏幕,重新输出迷宫,从而实现可直观编辑迷宫的目的。 7 求最短路径要用BFS的方法,从起点即树的根节点按层遍历,第一次到达终点也就是遍历层数最少时到达终点,求得最短路径。 8 求所有可通路径,让方向有优先级,先沿着优先级高的方向走,当走到终点或者没有通路可走时,尝试下一个方向,直至所有可走块的方向都尝试完后即可得到所有可通路径的数目。 3.4用户手册 1 本程序执行文件为maze.exe。 2 用户进入系统后根据提示,输入数字进入相应的子菜单,实现相应功能。 3 本系统可实现走出迷宫游戏、编辑迷宫、保存迷宫到文件、从文件读入迷宫、随机生成迷宫、迷宫最短路径求解、统计迷宫所有可通路径数目的功能。 4总结 本次实验的内容比较难,几乎综合了迷宫求解和动画输出界面,还好我有迷宫求解的题目,先做了迷宫求解,稍微适应一下使用堆栈求解后,再做的这个题目。事实上,这个题目的最短路径求解和迷宫求解不同,比迷宫求解要难,用BFS求最短路径很难想到,看了网上的一些代码才有思路。求所有路径也非常难,也是看了网上的提示才做的。不过这也让我意识到了从了解BFS,DFS到应用它们之间的差距。的确需要较多的练习才能用好BFS和DFS。除此之外,我也意识到要多看一些算法,如果脑子里全是自己想的不规整的方法,解决问题时会比较吃力,遇到问题不能得心应手。 5、程序清单:(见附录) 7、程序运行结果 主界面 菜单1 开始迷宫游戏 倒计时 游戏界面 超时提示失败 升级提示 菜单2 编辑迷宫 编辑前: 编辑中: 编辑后: 菜单3 读入迷宫 菜单4 随机生成迷宫 菜单5 最短路径 无路径时: 只有一条路径时: 只有两条路径时: 有很多条路径时: 菜单0 附录1 程序清单 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #include <time.h> #define N 20 #define M 20 #define Elemtype int #define second 1000 struct Maze{ Elemtype room[M][N]; //迷宫 Elemtype status[M][N]; //迷宫求解记录 }; struct pos{ int x,y,parent,self; //x,y是当前坐标,parent是上一步在队列中的位置 int next[4]; //self是本步在队列中的位置,next是下四步在队列中的位置 }; struct Queue{ pos p[M*N]; //队列中元素 int front; //队首 int rear; //队尾 }; void initqueue(Queue &Q){ //初始化队列 Q.front=0; Q.rear=0; } void enqueue(Queue &Q,pos p){//进队 if(Q.rear>M*N) return; //队列满了 Q.p[Q.rear]=p; Q.rear++; } void dequeue(Queue &Q,pos &p){//出队 if(Q.front>Q.rear) return; //队列空了 p=Q.p[Q.front]; Q.front++; } int emptyqueue(Queue Q){//判队空 if(Q.front>=Q.rear) return 1; return 0; } void display(Elemtype room[M][N],int degree,int t,int flag){//输出迷宫 int i,j; //flag为0为游戏模式,flag为1或2为编辑模式,大于2为输出模式 printf("\n\n"); for(i=0;i<M;i++){ putchar('\t'); for(j=0;j<N;j++) switch(room[i][j]){ case 0: printf("■"); break; case 1: printf(" "); break; case 2: printf("%c ",1); break; case 3: printf("∏"); break; case 4: printf("↓"); //上 break; case 5: printf("→"); //右 break; case 6: printf("←"); //左 break; case 7: printf("↑"); //上 break; default: printf("\n迷宫格式错误!停止运行!\n"); exit(0); break; } if(flag>=3){ //其他模式 putchar('\n'); continue; } switch(i){ case 0: printf(" ------------------"); break; case 1: if(flag) printf(" 编辑迷宫! ");//编辑模式 else printf(" 欢迎进入迷宫游戏!");//游戏模式 break; case 2: printf(" ------------------"); break; case 3: printf(" ------------------"); break; case 4: printf(" 按←↑→↓操纵 "); break; case 5: printf(" ------------------"); break; case 6: printf(" ------------------"); break; case 7: if(flag) printf(" 0,路边墙;1,墙变路"); //编辑模式 else printf(" 当前等级:%d ",degree); //游戏模式 break; case 8: printf(" ------------------"); break; case 9: printf(" ------------------"); break; case 10: if(flag==2) printf(" 此时墙变路 ");//编辑模式 else if(flag==1) printf(" 此时路变墙 "); else printf(" 剩余时间:%d\t",t);//游戏模式 break; case 11: printf(" ------------------"); break; } putchar('\n'); } } int inputselection(int n){//输入菜单选择,返回值为输入的选项 int flag=0; char s[100]; do{ if(flag) printf("\t 输入非法,请重新输入:"); else printf("\t 输入数字0-%d选择:",n); flag=1; scanf("%s",s); }while(strlen(s)>1||s[0]-'0'<0||s[0]-'0'>n); getchar(); return s[0]-'0'; } int maincourse(){ //主菜单 printf("\t\t --------------------------------\n"); printf("\t\t\t 1. 开始游戏 2. 编辑迷宫\n"); printf("\t\t\t 3. 读入迷宫 4. 随机迷宫\n"); printf("\t\t\t 5. 最短路径 0. 退出系统\n"); printf("\t\t --------------------------------\n\n"); return inputselection(5); } void countdown(){ //倒计时进入迷宫游戏 int i; clock_t start; system("cls"); for(i=3;i>=0;i--){ start=clock(); system("cls"); printf("\t\t\t******************************\n"); printf("\t\t\t 即将进入迷宫游戏,倒计时:%d \n",i); printf("\t\t\t******************************\n"); while(clock()-start<second); } } void play(Elemtype room[M][N]){ //迷宫游戏 countdown(); system("cls"); clock_t start,start2; start=clock(); int x=M/2,y=N/2,x1=1,y1=1; int degree=1,lefted_t=30,all_t=30; while(1){ start2=clock(); while((lefted_t=(start2-start)/second)<all_t&&!kbhit()){//计时及判断是否有输入 system("cls"); display(room,degree,all_t-lefted_t,0); while(clock()-start2<second&&!kbhit()); start2=clock(); } lefted_t=all_t-lefted_t; if(lefted_t<=0){ //时间用完 system("cls"); printf("\t\t\t******************************\n"); printf("\t\t\t 游戏结束!挑战失败! \n"); printf("\t\t\t******************************\n"); room[x][y]=1; room[M/2]
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服