/*4.3.3源程序*/
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#define N 20/*迷宫的大小,可改变*/
int oldmap[N][N]/*递归用的数组,用全局变量节约时间*/
int yes=0/*yes是判断是否找到路的标志,1找到,0没找到*/
int way[100][2],wayn=0/*way数组是显示路线用的,wayn是统计走了几个格子*/
void Init(void)/*图形初始化*/
void Close(void)/*图形关闭*/
void DrawPeople(int *x,int *y,int n)/*画人工探索物图*/
void PeopleFind(int (*x)[N])/*人工探索*/
void WayCopy(int (*x)[N],int (*y)[N])/*为了8个方向的递归,把旧迷宫图拷贝给新数组*/
int FindWay(int (*x)[N],int i,int j)/*自动探索函数*/
void MapRand(int (*x)[N])/*随机生成迷宫函数*/
void PrMap(int (*x)[N])/*输出迷宫图函数*/
void Result(void)/*输出结果处理*/
void Find(void)/*成功处理*/
void NotFind(void)/*失败处理*/
void main(void)/*主函数*/
{
int map[N][N]/*迷宫数组*/
char ch
clrscr()
printf("\n Please select hand(1) else auto\n")/*选择探索方式*/
scanf("%c",&ch)
Init() /*初始化*/
MapRand(map)/*生成迷宫*/
PrMap(map)/*显示迷宫图*/
if(ch=='1')
PeopleFind(map)/*人工探索*/
else
FindWay(map,1,1)/*系统自动从下标1,1的地方开始探索*/
Result()/*输出结果*/
Close()
}
void Init(void)/*图形初始化*/
{
int gd=DETECT,gm
initgraph(&gd,&gm,"c:\\tc")
}
void DrawPeople(int *x,int *y,int n)/*画人工控制图*/
{/*如果将以下两句注释掉,则显示人工走过的路径,*/
setfillstyle(SOLID_FILL,WHITE) /*设置白色实体填充样式*/
bar(100+(*y)*15-6,50+(*x)*15-6,100+(*y)*15+6,50+(*x)*15+6)
/*恢复原通路*/
switch(n)/*判断x,y的变化,8个方向的变化*/
{
case 1: (*x)--break/*上*/
case 2: (*x)--(*y)++break /*右上*/
case 3: (*y)++break /*右*/
case 4: (*x)++(*y)++break/*右下*/
case 5: (*x)++break /*下*/
case 6: (*x)++(*y)--break/*左下*/
case 7: (*y)--break /*左*/
case 8: (*x)--(*y)--break/*左上*/
}
setfillstyle(SOLID_FILL,RED)/*新位置显示探索物*/
bar(100+(*y)*15-6,50+(*x)*15-6,100+(*y)*15+6,50+(*x)*15+6)
}
void PeopleFind(int (*map)[N])/*人工手动查找*/
{
int x,y
char c=0/*接收按键的变量*/
x=y=1/*人工查找的初始位置*/
setcolor(11)
line(500,200,550,200)
outtextxy(570,197,"d")
line(500,200,450,200)
outtextxy(430,197,"a")
line(500,200,500,150)
outtextxy(497,130,"w")
line(500,200,500,250)
outtextxy(497,270,"x")
line(500,200,450,150)
outtextxy(445,130,"q")
line(500,200,550,150)
outtextxy(550,130,"e")
line(500,200,450,250)
outtextxy(445,270,"z")
line(500,200,550,250)
outtextxy(550,270,"c")/*以上是画8个方向的控制介绍*/
setcolor(YELLOW)
outtextxy(420,290,"Press 'Enter' to end")/*压回车键结束*/
setfillstyle(SOLID_FILL,RED)
bar(100+y*15-6,50+x*15-6,100+y*15+6,50+x*15+6)/*入口位置显示*/
while(c!=13)/*如果按下的不是回车键*/
{
c=getch()/*接收字符后开始各个方向的探索*/
if(c=='w'&&map[x-1][y]!=1)
DrawPeople(&x,&y,1)/*上*/
else
if(c=='e'&&map[x-1][y+1]!=1)
DrawPeople(&x,&y,2)/*右上*/
else
if(c=='d'&&map[x][y+1]!=1)
DrawPeople(&x,&y,3)/*右*/
else
if(c=='c'&&map[x+1][y+1]!=1)
DrawPeople(&x,&y,4)/*右下*/
else
if(c=='x'&&map[x+1][y]!=1)
DrawPeople(&x,&y,5)/*下*/
else
if(c=='z'&&map[x+1][y-1]!=1)
DrawPeople(&x,&y,6)/*左下*/
else
if(c=='a'&&map[x][y-1]!=1)
DrawPeople(&x,&y,7)/*左*/
else if(c=='q'&&map[x-1][y-1]!=1)
DrawPeople(&x,&y,8)/*左上*/
}
setfillstyle(SOLID_FILL,WHITE)/*消去红色探索物,恢复原迷宫图*/
bar(100+y*15-6,50+x*15-6,100+y*15+6,50+x*15+6)
if(x==N-2&&y==N-2)/*人工控制找成功的话*/
yes=1/*如果成功标志为1*/
}
void WayCopy(int (*oldmap)[N],int (*map)[N])/*拷贝迷宫数组 */
{
int i,j
for(i=0i<Ni++)
for(j=0j<Nj++)
oldmap[i][j]=map[i][j]
}
int FindWay(int (*map)[N],int i,int j)/*递归找路*/
{
if(i==N-2&&j==N-2)/*走到出口*/
{
yes=1/*标志为1,表示成功*/
return
}
map[i][j]=1/*走过的地方变为1*/
WayCopy(oldmap,map)/*拷贝迷宫图*/
if(oldmap[i+1][j+1]==0&&!yes)/*判断右下方是否可走*/
{
FindWay(oldmap,i+1,j+1)
if(yes)/*如果到达出口了,再把值赋给显示路线的way数组,也正是这个原因,所以具体路线是从最后开始保存*/
{
way[wayn][0]=i
way[wayn++][1]=j
return
}
}
WayCopy(oldmap,map)
if(oldmap[i+1][j]==0&&!yes)/*判断下方是否可以走,如果标志yes已经是1也不用找下去了*/
{
FindWay(oldmap,i+1,j)
if(yes)
{
way[wayn][0]=i
way[wayn++][1]=j
return
}
}
WayCopy(oldmap,map)
if(oldmap[i][j+1]==0&&!yes)/*判断右方是否可以走*/
{
FindWay(oldmap,i,j+1)
if(yes)
{
way[wayn][0]=i
way[wayn++][1]=j
return
}
}
WayCopy(oldmap,map)
if(oldmap[i-1][j]==0&&!yes)/*判断上方是否可以走*/
{
FindWay(oldmap,i-1,j)
if(yes)
{
way[wayn][0]=i
way[wayn++][1]=j
return
}
}
WayCopy(oldmap,map)
if(oldmap[i-1][j+1]==0&&!yes)/*判断右上方是否可以走*/
{
FindWay(oldmap,i-1,j+1)
if(yes)
{
way[wayn][0]=i
way[wayn++][1]=j
return
}
}
WayCopy(oldmap,map)
if(oldmap[i+1][j-1]==0&&!yes)/*判断左下方是否可以走*/
{
FindWay(oldmap,i+1,j-1)
if(yes)
{
way[wayn][0]=i
way[wayn++][1]=j
return
}
}
WayCopy(oldmap,map)
if(oldmap[i][j-1]==0&&!yes)/*判断左方是否可以走*/
{
FindWay(oldmap,i,j-1)
if(yes)
{
way[wayn][0]=i
way[wayn++][1]=j
return
}
}
WayCopy(oldmap,map)
if(oldmap[i-1][j-1]==0&&!yes)/*判断左上方是否可以走*/
{
FindWay(oldmap,i-1,j-1)
if(yes)
{
way[wayn][0]=i
way[wayn++][1]=j
return
}
}
return
}
void MapRand(int (*map)[N])/*开始的随机迷宫图*/
{
int i,j
cleardevice()/*清屏*/
randomize()/*随机数发生器*/
for(i=0i<Ni++)
{
for(j=0j<Nj++)
{
if(i==0||i==N-1||j==0||j==N-1)/*最外面一圈为墙壁*/
map[i][j]=1
else
if(i==1&&j==1||i==N-2&&j==N-2)/*出发点与终点表示为可走的*/
map[i][j]=0
else
map[i][j]=random(2)/*其它的随机生成0或1*/
}
}
}
void PrMap(int (*map)[N])/*输出迷宫图*/
{
int i,j
for(i=0i<Ni++)
for(j=0j<Nj++)
if(map[i][j]==0)
{
setfillstyle(SOLID_FILL,WHITE)/*白色为可走的路*/
bar(100+j*15-6,50+i*15-6,100+j*15+6,50+i*15+6)
}
else
{
setfillstyle(SOLID_FILL,BLUE)/*蓝色为墙壁*/
bar(100+j*15-6,50+i*15-6,100+j*15+6,50+i*15+6)
}
}
void Find(void)/*找到通路*/
{
int i
setfillstyle(SOLID_FILL,RED)/*红色输出走的具体路线*/
wayn--
for(i=wayni>=0i--)
{
bar(100+way[i][1]*15-6,50+way[i][0]*15-6,100+
way[i][1]*15+6,50+way[i][0]*15+6)
sleep(1)/*控制显示时间*/
}
bar(100+(N-2)*15-6,50+(N-2)*15-6,100+
(N-2)*15+6,50+(N-2)*15+6)/*在目标点标红色*/
setcolor(GREEN)
settextstyle(0,0,2)/*设置字体大小*/
outtextxy(130,400,"Find a way!")
}
void NotFind(void)/*没找到通路*/
{
setcolor(GREEN)
settextstyle(0,0,2)/*设置字体大小*/
outtextxy(130,400,"Not find a way!")
}
void Result(void)/*结果处理*/
{
if(yes)/*如果找到*/
Find()
else/*没找到路*/
NotFind()
getch()
}
void Close(void)/*图形关闭*/
{
closegraph()
}
//*********************//迷宫
//*********************
#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>
char map[5][5] = {{'1','1','1','1','1'},{'0','0','0','1','1'},{'0','0','1','1','0'},{'1','1','1','0','0'},{'1','1','1','1','1'}}
//*************
//生成地图
//**************
void CreateMap()
{
for(int i =0i <5i++)
{
for(int j = 0j <5j++)
{
// printf("%c",map[i][j])
cout <<map[i][j]
}
cout <<endl
}
}
//*************************
//画出迷宫地图
//************************
void draw()
{
for(int i= 0i <5i++)
{
for(int j =0 j <5j++)
{
printf("%c",map[i][j])
}
putchar('\n')
}
}
//*********************
//判断下一步是否走得通
//********************
bool Judgenext(int row, int cloumn)
{
if(map[row][cloumn] == '1')
{
return 1
}
return 0
}
//******************
//离开迷宫
//******************
bool ExitMaze(int row, int cloumn)
{
bool done = 0
if(row == 4 &&cloumn == 4)
{
done = 1
}
else
{
if(Judgenext(row, cloumn) == 1)
{
map[row][cloumn] = 'B'
done = ExitMaze(row+1, cloumn)
if(done == 0)
{
done = ExitMaze(row, cloumn+1)
}
if(done == 0)
{
done = ExitMaze(row-1, cloumn)
}
if(done == 0)
{
done = ExitMaze(row, cloumn-1)
}
if(done == 1)
{
map[row][cloumn] = 'P'
}
}
}
return done
}
//***********************************
//解决问题
//***********************************
void slove()
{
bool done
done = ExitMaze(0,0)
if(done == 1)
{
printf("该迷宫可以走通!具体的步骤如下:\n")
draw()
}
else
{
printf("对不起,该迷宫无法走出!\n")
}
}
int main(void)
{
printf("This is a maze:\n")
CreateMap()
system("pause")
slove()
return 0
}
将C改为C++很简单。。。
本程序的前提是将迷宫保存在一个二维数组里,可走的地方为0,不可走的地方为1。由于采用回朔算法,不使用递归,所以首先应该建立一个栈来保存路径,路径是用一个一个点来表示的,也就是说栈中保存的是一系列点的列表。栈节点类型说明:
struct StackNode
{
POINT Point
struct StackNode *Next, *Prev//双向链表形式
}
栈结构用一个类(CPointStack)实现,声明如下:
class CPointStack
{
public:
void ClearStack()//清空栈
void InitStack()//初始化栈
bool Pop(POINT &pt)//d出顶端元素,并给出该点的坐标,返回是否d出成功
bool Push(POINT pt)//将pt点的信息压入栈,返回是否压入成功
CPointStack()
virtual ~CPointStack()
protected:
StackNode *m_psnTop//栈顶指针
StackNode m_snBottom//栈底,不保存点信息
}
以下为成员函数实现,都是一些数据结构的 *** 作,应该没什么好说的:
//构造时初始化栈
CPointStack::CPointStack()
{
InitStack()
}
//析构时清空栈
CPointStack::~CPointStack()
{
ClearStack()
}
//将点压入栈(成功返回true,失败返回false)
bool CPointStack::Push(POINT pt)
{
StackNode* NewNode = new StackNode
//是否返回true主要看这里申请内存是否成功
if(!NewNode)
return false
NewNode->Point = pt
NewNode->Prev = m_psnTop
NewNode->Next = NULL
m_psnTop->Next = NewNode
m_psnTop = NewNode
return true
}
//将点d出栈(成功返回true,栈为空则返回false)
bool CPointStack::Pop(POINT &pt)
{
if(m_psnTop == &m_snBottom)//是否返回true主要看这里栈是否为空
return false
StackNode *p
p = m_psnTop
m_psnTop = m_psnTop->Prev
pt = p->Point
delete p
m_psnTop->Next = NULL
return true
}
//初始化栈
void CPointStack::InitStack()
{
m_psnTop = &m_snBottom
m_snBottom.Next = NULL
m_snBottom.Prev = NULL
}
//清空栈
void CPointStack::ClearStack()
{
StackNode *p
while(m_psnTop != &m_snBottom)
{
p = m_psnTop
m_psnTop = m_psnTop->Prev
delete p
}
}
接下来设计怎样走出这个迷宫,也就是迷宫算法的主体部分。再次用一个类实现。
在设计这个类时,我考虑到以下几点:
1、迷宫入口和出口的坐标
2、保存迷宫的2维数组
3、获得路径的函数
但是实际设计时由于没有考虑太多问题,只是以设计迷宫算法和解决一个具体迷宫为目的,所以没有考虑动态大小的迷宫,而是将迷宫大小定为601×401。而且在设计迷宫算法后没有将路径顺序输出而是直接在原图中标识(在保存迷宫数据的表中设置经过的点为2而将死路点设置为3)。
这样迷宫类(CGoMaze)的声明为:
class CGoMaze
{
public:
void Go()//寻找路径的函数
POINT m_ptIn//入口坐标
POINT m_ptOut//出口坐标
BYTE m_btArrMaze[401][601]//保存迷宫的二维表
CGoMaze()
virtual ~CGoMaze()
}
最后让我们来看一下CGoMaze::Go()这个函数:
我们模仿人走迷宫时的思路,设置一个当前点,一个目标点(下一个要走的点)。初始情况下当前点为入口,终止条件为当前点为出口,这样,我们的函数大概结构就出来了。
在从入口到出口的过程中程序对当前点的上、下、左、右四个点依次进行判断,当发现任一个方向是未走过的区域时,就将当前点指向那个点进行尝试,同时将当前点入栈并做标记。而当4个方向都不通或已走过时,则为死路,标记当前点为死路并从栈中d出上一个点继续进行尝试,这时因为当前点已被标记为死路,则d出上一个点时就不会重复这条路,达到寻找正确路径的效果。
Go函数的具体实现如下,其实挺简单的^_^:
void CGoMaze::Go()
{
CPointStack psPath//保存路径的栈
POINT ptCur = m_ptIn, ptNext//设置当前点为入口
while(ptCur.x != m_ptOut.x || ptCur.y != m_ptOut.y)//判断是否已经走出
{
ptNext = ptCur//设置目标点为当前点,便于下面偏移
if(m_btArrMaze[ptCur.y - 1][ptCur.x] == 0)
ptNext.y --//如果上方是空的,则目标点向上偏移
else if(m_btArrMaze[ptCur.y][ptCur.x - 1] == 0)
ptNext.x --//如果左边是空的,则目标点向左偏移
else if(m_btArrMaze[ptCur.y + 1][ptCur.x] == 0)
ptNext.y ++//如果下方是空的,则目标点向下偏移
else if(m_btArrMaze[ptCur.y][ptCur.x + 1] == 0)
ptNext.x ++//如果右边是空的,则目标点向右偏移
else
{//这里是没有路的状态
m_btArrMaze[ptCur.y][ptCur.x] = 3//标记为死路
psPath.Pop(ptCur)//d出上一次的点
continue//继续循环
}
//如果有路的话会执行到这里
m_btArrMaze[ptCur.y][ptCur.x] = 2//标记当前点为路径上的点
psPath.Push(ptCur)//当前点压入栈中
ptCur = ptNext//移动当前点
}
}
其实这个部分可以将栈设置为CGoMaze类的成员,然后在Go函数里加上:
psPath.ClearStack()
这样就可以用Timer来演示走迷宫的过程了
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)