C语言 迷宫设计

C语言 迷宫设计

一、问题描述

迷宫问题是取自心理学的一个古典实验。在该实验中,把一只老鼠从一个无顶大盒子的门放入,在盒子中设置了许多墙,对行进方向形成了多处阻挡。盒子仅有一个出口,在出口处放置一块奶酪,吸引老鼠在迷宫中寻找道路以到达出口。对同一只老鼠重复进行上述实验,一直到老鼠从入口走到出口,而不走错一步。老鼠经过多次试验最终学会走通迷宫的路线。设计一个计算机程序对任意设定的矩形迷宫如下图A所示,求出一条从入口到出口的通路,或得出没有通路的结论。

二、需求分析

(1)建立一个大小为m×n的任意迷宫(迷宫数据可由用户输入或由程序自动生成),并在屏幕上显示出来。
(2)找出一条通路的二元组(i,j)数据序列,(i,j)表示通路上某一点的坐标。
(3)用一种标志(如数字8)在迷宫中标出该条通路。
(4)在屏幕上输出迷宫和通路。
(5)上述功能可用菜单选择。

三、概要设计

栈(Stack)是限制在表的一端进行插入和删除运算的线性表,通常称插入、删除的这一端为栈顶,另一端为栈底。当表中没有元素时称为空栈。
假设栈S=(a1,a2,a3,…an),则a1称为栈底元素,an为栈顶元素。栈中元素按a1,a2,a3,…an的次序进栈,退栈的第一个元素应为栈顶元素。
由于栈是运算受限的线性表,因此线性表的存储结构对栈也适应。栈的顺序存储结构简称为顺序栈,它是运算受限的线性表。因此,可用数组来实现顺序栈。因为栈底位置是固定不变的,所以可以将栈底位置设置在数组的两端的任何一个端点。

四、程序调试与分析

1.详细设计
路径是由一组位置构成的,每个位置上都没有障碍,且每个位置都是前一个位置的右、下、左、上。
计算机走迷宫的方法是,采取一步一步试探的方法。每一步都从右开始,按顺时针对4个方向进行试探,若某方向上find(x,y)=0,表示可以通行,则走一步;若find(x,y)=1,表示不可以通行,须换方向再试,直到4个方向都试过;若find(x,y)均为1,说明此步已无路可走,需退回一步,在上一步的下一个方向重新开始探测。为此,设置了一个栈,用于记录所走过的位置和方向(i,j,dir)。当退回一步时,从栈中退出一个元素,以便在上一个位置的下一个方向上探测,如又找到一个行进方向,则把当前位置和方向重新进栈,并走到新的位置。
若探测到位置(m,n),则已经到达迷宫的出口,可以停止探测,输出存在栈中的路径;如果在某一位置的4个方向上堵塞,则退回一步,继续探测;如果已退到迷宫的入口(栈中无元素),则表示此迷宫无路径可走。
(1)为避免边界检查,将数组四周用值为1的边框包围起来
(2)为简化问题,规定(i,j)下一步位置的坐标是(x,y)。
(3)为防止重走原路,规定对已经走过的位置将原值0改为-1。

五、结果如下图

开始界面
在这里插入图片描述
成功结果
无路结果

六、直接上代码吧

#include<stdio.h>
#include<malloc.h>
#include<time.h>
#include<stdlib.h>

//位置
struct maze {
	int a[100][100];
	int w, h;
	int x, y;
	int dir;
};

//栈
typedef struct elem {
	struct maze data;
	struct elem* next;
}elem;

void  create_maze(struct maze* q);					//生成地图
int find(elem*s , struct maze* q);					//寻找出路
void print_maze(elem* s,struct maze* q,int flag);	//打印地图
elem* first(); 										//初始化一个栈
void push(elem* s, int x, int y, int dir);			//进栈
elem* pop(elem* s, int x, int y, int dir);			//出栈

//主函数
int main()
{
	struct maze Maze;
	elem* s;
	s = first();
	int option,flag=1;
	int count = 0;
			while (1) {
				system("color 0E");
				printf("\n\t\t\t1初始化迷宫\t\t\t\n\n");
				printf("\t\t\t2-出路迷宫\t\t\t\n\n");
				printf("\t\t\t0-退出游戏\t\t\t\n\n");
				printf("\t\t请输入你要选择的功能:");
				scanf("%d", &option);
				
				if (option == 1) {
						create_maze(&Maze );//初始化迷宫(w+2和h+2是为了加墙) 
						count++;
					if (count > 0) {
						flag=1;
						print_maze(s,&Maze,flag);//打印迷宫 
						count++;
						system("pause");
					}
					else {
						printf("请先初始化一个迷宫!\n");//一定要先初始化迷宫 
						system("pause");
						continue;
					}
				}
				else if (option == 2) {
					if (count > 0) {
						flag = find(s,&Maze);
						print_maze(s,&Maze,flag);
						count++;
					}
					else {
						printf("请先初始化一个迷宫!\n");//一定要先初始化迷宫 
						system("pause");
						continue;
					}
				}
				else if (option == 0) {
					system("pause");
					printf("---------------游戏结束!--------------\n");
					break;
				}
			}		
	return 0;
}

//初始化一个栈
elem* first()
{
	elem* p = (elem*)malloc(sizeof(elem));
	p->next= NULL;
	return p;
}

//进栈
void push(elem* s, int x, int y, int dir) {

	elem* p =(elem*)malloc(sizeof(elem));
	p->data.x = x;
	p->data.y = y;
	p->data.dir = dir;
	p->next = s->next;
	s->next = p;
}

//出栈
elem* pop(elem* s, int x, int y, int dir) {
	if (s== NULL)
		return 0;
	elem* p ;
	p = s->next;
	s->next = p->next;
	return p;
}

//生成地图
void  create_maze(struct maze* q) {
	int w,h;
	system("cls");
	printf("请输入迷宫2-98内的宽度:\n");
	scanf("%d", &w);
	printf("请输入迷宫2-98内的高度\n");
	scanf("%d", &h);
	q->w=w+2;
	q->h=h+2;
	int k;
	for (int i = 0; i < q->w; i++) {
		for (int j = 0; j < q->h; j++) {
			if (i == 0 || i == q->w - 1) {
				q->a[i][j] = 1;
			}
			if (j == 0 || j == q->h - 1) {
				q->a[i][j] = 1;
			}
			else if ((i != 0 && i != q->w - 1) && (j != 0 && j != q->h - 1)) {
				q->a[i][j] = 0;
			}
		}
	}
	for (int i = 1; i < q->w - 1; i++) {
		for (int j = 1; j < q->h - 1; j++) {
				q->a[i][j]= !(rand() % 3);
		}
	}
}

//寻找出路
int find(elem*s , struct maze* q)
{
	int x = 1, y = 1,x1 = 1, y1 = 0;
	elem* p;
	int dir;// = 1;
	push(s, 1, 0, 1);
	while ((x!=q->w-1||y!=q->h-2)&& (x != x1 || y != y1))
	{
      //向右
		if ( q->a[x][y + 1] == 0) {
			q->a[x][y] = -1;
			dir = 1;
			push(s, x, y, dir); 
			y++;
		}
      //向下
		else if ( q->a[x + 1][y] == 0) {
			q->a[x][y] = -1;
			dir = 2;
			push(s, x, y, dir);
			x++;
		}
      //向左
		else if ( q->a[x][y - 1] == 0) {
			q->a[x][y] = -1;
			dir = 3;
			push(s, x, y, dir);
			y--;
	
		}
      //向上
		else if ( q->a[x - 1][y] == 0) {
			q->a[x][y] = -1;
			dir = 4;
			push(s, x, y, dir);
			x--;	
		}
		else
		{
			q->a[x][y] = -2;
			p = pop(s, x, y, dir);
			if (p) {
				x = p->data.x;
				y = p->data.y;
				dir = p->data.dir;
				free(p);
			}
		}
	}
	if (x == q->w-1 && y == q->h-2) {
		push(s, x, y, 0);
		return 1;
	}
	return 0;
}
//打印地图
void print_maze(elem* s,struct maze* q,int flag)
{
	int w,h;
		printf("迷宫路径为:\n");
		for (int i = 0; i < q->w ; i++) {
			for (int j = 0; j < q->h ; j++) {
				q->a[1][0]=0;
				q->a[w+1][h]=0;
				printf("%d ",q->a[i][j]);
			}
			printf("\n");
		}
		for(int i = 0; i< q->w ;i++)  //方格显示
		{
			for(int j = 0; j <q->h; j++)
			{
				if(q->a[i][j]==1)
					printf("■");
				else if (q->a[i][j]==-1)
					printf("☆");
				else 
					printf("  ");
			}
			printf("\n");
		}
		if(flag==0)
		printf("\n\n\t\t此迷宫无出路!请重新初始化迷宫!!!\n\n");	
}

七、经验与体会

通过这段时间的课程设计,本人对计算机的应用,数据结构的作用以及C 语言的使用都有了更深的了解。尤其是C语言的进步让我深刻的感受到任何所学的知识都需要实践,没有实践就无法真正理解这些知识以及掌握它们,使其成为自己的财富。在设计此程序时,刚开始感到比较迷茫,然后一步步分析,试着写出基本的算法,思路渐渐清晰,最后完成程序。当然也遇到不少的问题,也正是因为这些问题引发的思考给我带了收获。
在遇到描写迷宫路径的算法时,我感到有些困难,后来经过一步步分析和借鉴书本上的穷举求解的算法,最后把算法写出来。
这次课程设计让我更加深入了解很多方面的知识,如数组的运用等等。在程序的编写中不要一味的模仿,要自己去摸索,只有带着问题反复实践,才能熟练地掌握和运用。

#include #include #define N1 9 #define N2 8 #define T N1*N2 #define M 4 char B[N1+1][N2+1]; int count=0; //记录路径条数 typedef struct node1 { int a1; int a2; }find,direct[M+1]; typedef struct { int b1; int b2; int id; }site; typedef struct //顺序栈 { site ht[T]; int top; }Stack; void Push(Stack *s,int a,int b) { s->top++; s->ht[s->top].b1=a; s->ht[s->top].b2=b; } void Gettop(Stack * s,int *a,int *b) { *a=s->ht[s->top].b1; *b=s->ht[s->top].b2; } void create(char *a) //从文件读出迷宫(正确) { int i=0,j=0,p=1; char x; FILE *fp; fp=fopen("in.txt","r"); if(fp==NULL) { printf("文件不能打开!\n"); exit(0); } x=fgetc(fp); while(x!=EOF) { if(x=='0') { i++; a[i]=x; } if(x=='1') { i++; a[i]=x; } x=fgetc(fp); } printf(" ~~~~~~~生成迷宫~~~~~~~\n"); x=fgetc(fp); while(p<=T) //用二维数组b记录迷宫每个位置是否可行 { for(i=1;i<=N1;i++) for(j=1;j<=N2;j++) { B[i][j]=a[p]; p++; } } printf(" "); printf("■■■■■■■■■■■■\n"); printf(" ■"); printf(" ■\n"); for(i=1;i<=N1;i++) { printf(" "); printf("■ "); for(j=1;jht[s1->top].id=id; B[x][y]='*'; while(s1->top>0) { Gettop(s1,&x,&y); id=s1->ht[s1->top].id; if(x==B1&&y==B2) { count++; fprintf(fp,"%d%c%c",count,':',' '); printf("第 %d 条路径(长度为%d):\n",count,s1->top); s1->ht[s1->top].id=0; for(i=1;itop;i++) { printf("(%d,%d,%d)->",s1->ht[i].b1,s1->ht[i].b2,s1->ht[i].id); fprintf(fp,"%c%d%c%d%c%d%c%c",'(',s1->ht[i].b1,',',s1->ht[i].b2,',',s1->ht[i].id,')',' '); if(i==0) fprintf(fp,"%c%c%c%c",'\n',' ',' ',' '); if(i%8==0) printf("\n"); } fprintf(fp,"%c",'\n'); printf("结束!\n\n"); if(s1->toptop=s1->top; min=s1->top; for(i=1;itop;i++) s2->ht[i]=s1->ht[i]; } B[x][y]='0'; s1->top--; //退栈(s1->top--) Gettop(s1,&x,&y); id=s1->ht[s1->top].id; } fun=0; while(idht[s1->top].b1; y=s1->ht[s1->top].b2; x=x+p[id].a1; y=y+p[id].a2; if(x==0||y==0||x>N1||y>N2) continue; if(B[x][y]=='0') { fun=1; break; } } if(fun==1) //找到通路 { s1->ht[s1->top].id=id; Push(s1,x,y); B[x][y]='*'; s1->ht[s1->top].id=0; } else { x=s1->ht[s1->top].b1; y=s1->ht[s1->top].b2; B[x][y]='0'; s1->top--; } } if(count==0) printf(" 无路径!\n"); else { printf("\n\n\n "); printf("所有路径已存储在文件%s 中,请去查找!\n\n",filename); } return 1; } void Print(Stack *s2,char filename[]) { int i; FILE *fp; fp=fopen(filename,"a+"); if(fp==NULL) { printf("文件不能打开!\n"); exit(0); } if(count!=0) { fprintf(fp,"%s","最短路径为:"); fprintf(fp,"%c",'\n'); printf(" "); printf("%s\n","**********最短路径**********\n"); for(i=1;itop;i++) { printf("(%d,%d,%d) ->",s2->ht[i].b1,s2->ht[i].b2,s2->ht[i].id); fprintf(fp,"%c%d%c%d%c%d%c%c",'(',s2->ht[i].b1,',',s2->ht[i].b2,',',s2->ht[i].id,')',' '); if(i==0) fprintf(fp,"%c",'\n'); if(i%7==0) printf("\n"); } fprintf(fp,"%c",'\n'); printf("结束!\n"); printf("(最短路径长度: %d)\n",s2->top); } } void main() //主函数 { char a[T+1]; //二维数组b记录迷宫的每个位置 char filename1[20],filename2[20]; int x1,x2,y1,y2,k; Stack *s1,*s2; direct f1; f1[1].a1=0; f1[1].a2=1; //判断方向(右) f1[2].a1=1; f1[2].a2=0; //(下) f1[3].a1=0; f1[3].a2=-1; //(左) f1[4].a1=-1; f1[4].a2=0; //(上) s1=(Stack *)malloc(sizeof(Stack)); s2=(Stack *)malloc(sizeof(Stack)); s1->top=0; //指向栈顶(初始化栈) s2->top=0; create(a); printf("\n\n "); printf("请输入入口坐标: "); scanf("%d%d",&x1,&x2); printf(" "); printf("请输入出口坐标: "); scanf("%d%d",&y1,&y2); printf(" "); printf("请输入存储所有路径的文件名:"); scanf("%s",filename1); printf(" "); printf("请输入存储最短路径的文件名:"); scanf("%s",filename2); system("cls"); k=search(x1,x2,y1,y2,s1,s2,f1,filename1); if(k==1) Print(s2,filename2); printf("\n"); }
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值