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