迷宫A*算法
#include<iostream>
#include<cassert>
#include<ctime>
#include<windows.h>
using namespace std;
const int MAXINT = 88888; //随便取个数,大于地图上任意两点间的距离
int map_w, map_h; //地图的宽,高
inline int title_num(int x,int y){return map_w*x+y;} //由坐标转化为地图块号
inline int title_y(int n){return n%map_w;}//由块号转化为x,y坐标
inline int title_x(int n){return n/map_w;}
class treenode
{
public:
int h; //节点所在的高度,表示从起始点到该节点所有的步数
int title; //该节点的位置(块数)
treenode*father; //该节点的上一步
};
class linknode //链表结点
{
public:
treenode*node;
int f;
linknode*next;
};
linknode*open_queue; // 保存没有处理的行走方法的节点
linknode*close_queue; // 保存已经处理过的节点 (搜索完后释放)
unsigned int*map; //地图数据
unsigned int*dis_map; //保存搜索路径时,中间目标地最优解
int startx,starty,endx,endy; //地点,终点坐标
void initial() // 初始化队列
{
open_queue=new linknode();
open_queue->node=NULL;
open_queue->f=-1;
open_queue->next=new linknode();
open_queue->next->node=NULL;
open_queue->next->next=NULL;
open_queue->next->f=MAXINT;
close_queue=new linknode();
close_queue->f=-1;
close_queue->next=NULL;
close_queue->node=NULL;
}
void entrance(treenode*node, int m) // 待处理节点入队列, 依*对目的地估价距离插入排序
{
linknode*p,*priot;
p=open_queue;
while(m>p->f)
{
priot=p;
p=p->next;
assert(p);
}
linknode*q=new linknode();
q->next=p;
priot->next=q;
q->node=node;
q->f=m;
}
treenode*receive() // 将离目的地估计最近的方案出队列
{
linknode*p=open_queue->next;
open_queue->next=open_queue->next->next;
p->next=close_queue->next;
close_queue->next=p;
return p->node;
}
void pop_stack() // 释放栈顶节点
{
linknode*p=close_queue->next;
close_queue->next=close_queue->next->next;
assert(p);
delete p->node;
delete p;
}
void empty() // 释放申请过的所有节点
{
linknode*p;
while(open_queue)
{
p=open_queue;
delete p->node;
open_queue=open_queue->next;
delete p;
}
while(close_queue)
{
p=close_queue;
delete p->node;
close_queue=close_queue->next;
delete p;
}
}
int testing(int x,int y) // 估价函数,估价 x,y 到目的地的距离,估计值必须保证比实际值小
{
return abs(endx-x)+abs(endy-y);
}
int trytest(int x,int y,treenode* priot) //尝试下一步移动到 x,y 可行否
{
treenode*p;
int h;
if(0==map[title_num(x,y)])return 1;
h=priot->h+1;
if(h>=dis_map[title_num(x,y)])return 1; // 如果曾经有更好的方案移动到 (x,y) 失败
dis_map[title_num(x,y)]=h; // 记录这次到 (x,y) 的距离为历史最佳距离
// 将这步方案记入待处理队列
p=new treenode();
p->father=priot;
p->h=priot->h+1;
p->title=title_num(x,y);
entrance(p, p->h+testing(x,y));
return 0;
}
int* lookup() // 路径寻找主函数
{
treenode*root=root=new treenode();
int i;
int*paths;
memset(dis_map,0xff,map_h*map_w*sizeof(*dis_map));//填充dis_map为0XFF,表示各点未曾经过
initial();
root->title=title_num(startx,starty);
root->h=0;
root->father=NULL;
entrance(root,testing(startx,starty));
for(;;)
{
int x,y,child;
root=receive();
if(NULL==root)return NULL;
x=title_x(root->title );
y=title_y(root->title );
if(x==endx&&y==endy)break;;// 达到目的地成功返回
child=1;
child&=trytest(x,y-1,root); //尝试4个方向
child&=trytest(x,y+1,root);
child&=trytest(x-1,y,root);
child&=trytest(x+1,y,root);
if(child!=0)pop_stack();// 如果四个方向均不能移动,释放这个死节点
}
paths=new int[root->h+2];
assert(paths);
for(i=0;root;++i)
{
paths[i]=root->title;
root=root->father;
}
paths[i]=-1;
empty();
return paths;
}
void showmap();//显示地图
void showpath(int *paths) // 回溯树,将求出的最佳路径保存在 path[] 中
{
int i;
if(paths==NULL)
return;
for(i=0; paths[i]>0; ++i)
{
cout << "("
<< title_x(paths[i])
<< ","
<< title_y(paths[i])
<< ")" << " ";
}
cout<<endl;
for(i=0; paths[i]>0; ++i)
{
assert(paths[i]);
map[paths[i]]='*';
system("cls");
showmap();
}
}
void setmap() //申请dis_map的大小
{
dis_map=new unsigned int[map_w*map_h*sizeof(dis_map)];
assert(dis_map);
}
void showmap() //显示地图
{
int i,j;
assert(map);
for(i=0;i<map_h;++i)
{
for(j=0;j<map_w;++j)
{
if(i==0||j==0||i==map_h-1||j==map_w-1)
{
cout<<"■";
continue;
}
if(i==startx&&j==starty)
{
cout<<"E";
continue;
}
if(i==endx&&j==endy)
{
cout<<"S";
continue;
}
if(map[map_w*i+j]=='*')
{
cout<<"*";
continue;
}
if(map[map_w*i+j])cout<<"□";
else cout<<"■";
}
cout<<endl;
}
Sleep(800);
}
void maps() //生成地图
{
int in1;
int in2;
cout<<"请输入随机地图的宽度:";
cin>>in1;
map_w=in1+2;
cout<<"请输入随机地图的高度:";
cin>>in2;
map_h=in2+2;
cout<<endl;
cout<<"请输入地图的入口坐标x["<<1<<","<<in1<<"]"<<",y["<<1<<","<<in2<<"]\nx=";
cin>>endy;
while(endy<1||endy>in1)
{
cin.clear();
while(cin.get()!='\n')continue;
cout<<"输入错误,请重新输入\nx=";
cin>>endy;
}
cout<<"y=";
cin>>endx;
while(endx<1||endx>in2)
{
cin.clear();
while(cin.get()!='\n')continue;
cout<<"输入错误,请重新输入\ny=";
cin>>endx;
}
cout<<endl;
cout<<"请输入地图的出口坐标x["<<1<<","<<in1<<"]"<<",y["<<1<<","<<in2<<"]\nx=";
cin>>starty;
while(starty<1||starty>in1)
{
cin.clear();
while(cin.get()!='\n')continue;
cout<<"输入错误,请重新输入\nx=";
cin>>starty;
}
cout<<"y=";
cin>>startx;
while(startx<1||startx>in2)
{
cin.clear();
while(cin.get()!='\n')continue;
cout<<"输入错误,请重新输入\ny=";
cin>>startx;
}
cout<<endl;
map=new unsigned int[(map_w+1)*map_h];
int i=0,j=0,direc=2;
int ran;
for(i=0;i<map_h;i++)
for(j=0;j<map_w;j++)
map[map_w*i+j]=1; //初始化地图
srand(time(0));
i=j=0;
while(1){
if(i>=map_h-1&&j>=map_w-1)break;
ran=(int)rand()%4;
if(ran<1){
if(direc!=1&&i<map_h-1){
i++;
direc=3;
}
}
else if(ran<2){
if(direc!=2&&j>0){
j--;
direc=0;
}
}
else if(ran<3){
if(direc!=3&&i>0){
i--;
direc=1;
}
}
else {
if(direc!=0&&j<map_w-1){
j++;
direc=2;
}
}
}
for(i=0;i<map_h;i++)
for(j=0;j<map_w;j++)
if(map[map_w*i+j]==1){
ran=(int)rand()%10;
if(ran<3)map[map_w*i+j]=0;
}
map[title_num(startx,starty)]=1;
map[title_num(endx,endy)]=1;
for(i=0;i<map_h;++i)
{
for(j=0;j<map_w;++j)
{
if(i==0||j==0)map[title_num(i,j)]=0;
if(i==map_h-1||j==map_w-1)map[title_num(i,j)]=0;
}
}
}
int main()
{
while(1)
{
char anyt;
int*paths;
maps();
setmap();
system("cls");
showmap();
system("PAUSE");
paths=lookup();
if(paths==NULL)
{
system("cls");
cout<<" \\\|/// \n";
cout<<" \\ - - // \n";
cout<<" ( @ @ ) \n";
cout<<" ┏━━━━━━━oOOo-(_)-oOOo━━━━━━━┓ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ 没有出路 ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ Oooo ┃ \n";
cout<<" ┗━━━━━━━ oooO━-( )━━━━━━━┛ \n";
cout<<" ( ) ) / \n";
cout<<" \ ( (_/ \n";
cout<<" \_) \n";
}
showpath(paths);
if(dis_map)delete [] dis_map;
if(paths)delete [] paths;
if(map)delete [] map;
cout<<"搜索完成";
system("PAUSE");
system("cls");
cout<<"再来一次(Y/N)?";
cin>>anyt;
if(anyt=='n'||anyt=='N')break;
}
system("PAUSE");
return 0;
}
#include<cassert>
#include<ctime>
#include<windows.h>
using namespace std;
const int MAXINT = 88888; //随便取个数,大于地图上任意两点间的距离
int map_w, map_h; //地图的宽,高
inline int title_num(int x,int y){return map_w*x+y;} //由坐标转化为地图块号
inline int title_y(int n){return n%map_w;}//由块号转化为x,y坐标
inline int title_x(int n){return n/map_w;}
class treenode
{
public:
int h; //节点所在的高度,表示从起始点到该节点所有的步数
int title; //该节点的位置(块数)
treenode*father; //该节点的上一步
};
class linknode //链表结点
{
public:
treenode*node;
int f;
linknode*next;
};
linknode*open_queue; // 保存没有处理的行走方法的节点
linknode*close_queue; // 保存已经处理过的节点 (搜索完后释放)
unsigned int*map; //地图数据
unsigned int*dis_map; //保存搜索路径时,中间目标地最优解
int startx,starty,endx,endy; //地点,终点坐标
void initial() // 初始化队列
{
open_queue=new linknode();
open_queue->node=NULL;
open_queue->f=-1;
open_queue->next=new linknode();
open_queue->next->node=NULL;
open_queue->next->next=NULL;
open_queue->next->f=MAXINT;
close_queue=new linknode();
close_queue->f=-1;
close_queue->next=NULL;
close_queue->node=NULL;
}
void entrance(treenode*node, int m) // 待处理节点入队列, 依*对目的地估价距离插入排序
{
linknode*p,*priot;
p=open_queue;
while(m>p->f)
{
priot=p;
p=p->next;
assert(p);
}
linknode*q=new linknode();
q->next=p;
priot->next=q;
q->node=node;
q->f=m;
}
treenode*receive() // 将离目的地估计最近的方案出队列
{
linknode*p=open_queue->next;
open_queue->next=open_queue->next->next;
p->next=close_queue->next;
close_queue->next=p;
return p->node;
}
void pop_stack() // 释放栈顶节点
{
linknode*p=close_queue->next;
close_queue->next=close_queue->next->next;
assert(p);
delete p->node;
delete p;
}
void empty() // 释放申请过的所有节点
{
linknode*p;
while(open_queue)
{
p=open_queue;
delete p->node;
open_queue=open_queue->next;
delete p;
}
while(close_queue)
{
p=close_queue;
delete p->node;
close_queue=close_queue->next;
delete p;
}
}
int testing(int x,int y) // 估价函数,估价 x,y 到目的地的距离,估计值必须保证比实际值小
{
return abs(endx-x)+abs(endy-y);
}
int trytest(int x,int y,treenode* priot) //尝试下一步移动到 x,y 可行否
{
treenode*p;
int h;
if(0==map[title_num(x,y)])return 1;
h=priot->h+1;
if(h>=dis_map[title_num(x,y)])return 1; // 如果曾经有更好的方案移动到 (x,y) 失败
dis_map[title_num(x,y)]=h; // 记录这次到 (x,y) 的距离为历史最佳距离
// 将这步方案记入待处理队列
p=new treenode();
p->father=priot;
p->h=priot->h+1;
p->title=title_num(x,y);
entrance(p, p->h+testing(x,y));
return 0;
}
int* lookup() // 路径寻找主函数
{
treenode*root=root=new treenode();
int i;
int*paths;
memset(dis_map,0xff,map_h*map_w*sizeof(*dis_map));//填充dis_map为0XFF,表示各点未曾经过
initial();
root->title=title_num(startx,starty);
root->h=0;
root->father=NULL;
entrance(root,testing(startx,starty));
for(;;)
{
int x,y,child;
root=receive();
if(NULL==root)return NULL;
x=title_x(root->title );
y=title_y(root->title );
if(x==endx&&y==endy)break;;// 达到目的地成功返回
child=1;
child&=trytest(x,y-1,root); //尝试4个方向
child&=trytest(x,y+1,root);
child&=trytest(x-1,y,root);
child&=trytest(x+1,y,root);
if(child!=0)pop_stack();// 如果四个方向均不能移动,释放这个死节点
}
paths=new int[root->h+2];
assert(paths);
for(i=0;root;++i)
{
paths[i]=root->title;
root=root->father;
}
paths[i]=-1;
empty();
return paths;
}
void showmap();//显示地图
void showpath(int *paths) // 回溯树,将求出的最佳路径保存在 path[] 中
{
int i;
if(paths==NULL)
return;
for(i=0; paths[i]>0; ++i)
{
cout << "("
<< title_x(paths[i])
<< ","
<< title_y(paths[i])
<< ")" << " ";
}
cout<<endl;
for(i=0; paths[i]>0; ++i)
{
assert(paths[i]);
map[paths[i]]='*';
system("cls");
showmap();
}
}
void setmap() //申请dis_map的大小
{
dis_map=new unsigned int[map_w*map_h*sizeof(dis_map)];
assert(dis_map);
}
void showmap() //显示地图
{
int i,j;
assert(map);
for(i=0;i<map_h;++i)
{
for(j=0;j<map_w;++j)
{
if(i==0||j==0||i==map_h-1||j==map_w-1)
{
cout<<"■";
continue;
}
if(i==startx&&j==starty)
{
cout<<"E";
continue;
}
if(i==endx&&j==endy)
{
cout<<"S";
continue;
}
if(map[map_w*i+j]=='*')
{
cout<<"*";
continue;
}
if(map[map_w*i+j])cout<<"□";
else cout<<"■";
}
cout<<endl;
}
Sleep(800);
}
void maps() //生成地图
{
int in1;
int in2;
cout<<"请输入随机地图的宽度:";
cin>>in1;
map_w=in1+2;
cout<<"请输入随机地图的高度:";
cin>>in2;
map_h=in2+2;
cout<<endl;
cout<<"请输入地图的入口坐标x["<<1<<","<<in1<<"]"<<",y["<<1<<","<<in2<<"]\nx=";
cin>>endy;
while(endy<1||endy>in1)
{
cin.clear();
while(cin.get()!='\n')continue;
cout<<"输入错误,请重新输入\nx=";
cin>>endy;
}
cout<<"y=";
cin>>endx;
while(endx<1||endx>in2)
{
cin.clear();
while(cin.get()!='\n')continue;
cout<<"输入错误,请重新输入\ny=";
cin>>endx;
}
cout<<endl;
cout<<"请输入地图的出口坐标x["<<1<<","<<in1<<"]"<<",y["<<1<<","<<in2<<"]\nx=";
cin>>starty;
while(starty<1||starty>in1)
{
cin.clear();
while(cin.get()!='\n')continue;
cout<<"输入错误,请重新输入\nx=";
cin>>starty;
}
cout<<"y=";
cin>>startx;
while(startx<1||startx>in2)
{
cin.clear();
while(cin.get()!='\n')continue;
cout<<"输入错误,请重新输入\ny=";
cin>>startx;
}
cout<<endl;
map=new unsigned int[(map_w+1)*map_h];
int i=0,j=0,direc=2;
int ran;
for(i=0;i<map_h;i++)
for(j=0;j<map_w;j++)
map[map_w*i+j]=1; //初始化地图
srand(time(0));
i=j=0;
while(1){
if(i>=map_h-1&&j>=map_w-1)break;
ran=(int)rand()%4;
if(ran<1){
if(direc!=1&&i<map_h-1){
i++;
direc=3;
}
}
else if(ran<2){
if(direc!=2&&j>0){
j--;
direc=0;
}
}
else if(ran<3){
if(direc!=3&&i>0){
i--;
direc=1;
}
}
else {
if(direc!=0&&j<map_w-1){
j++;
direc=2;
}
}
}
for(i=0;i<map_h;i++)
for(j=0;j<map_w;j++)
if(map[map_w*i+j]==1){
ran=(int)rand()%10;
if(ran<3)map[map_w*i+j]=0;
}
map[title_num(startx,starty)]=1;
map[title_num(endx,endy)]=1;
for(i=0;i<map_h;++i)
{
for(j=0;j<map_w;++j)
{
if(i==0||j==0)map[title_num(i,j)]=0;
if(i==map_h-1||j==map_w-1)map[title_num(i,j)]=0;
}
}
}
int main()
{
while(1)
{
char anyt;
int*paths;
maps();
setmap();
system("cls");
showmap();
system("PAUSE");
paths=lookup();
if(paths==NULL)
{
system("cls");
cout<<" \\\|/// \n";
cout<<" \\ - - // \n";
cout<<" ( @ @ ) \n";
cout<<" ┏━━━━━━━oOOo-(_)-oOOo━━━━━━━┓ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ 没有出路 ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ ┃ \n";
cout<<" ┃ Oooo ┃ \n";
cout<<" ┗━━━━━━━ oooO━-( )━━━━━━━┛ \n";
cout<<" ( ) ) / \n";
cout<<" \ ( (_/ \n";
cout<<" \_) \n";
}
showpath(paths);
if(dis_map)delete [] dis_map;
if(paths)delete [] paths;
if(map)delete [] map;
cout<<"搜索完成";
system("PAUSE");
system("cls");
cout<<"再来一次(Y/N)?";
cin>>anyt;
if(anyt=='n'||anyt=='N')break;
}
system("PAUSE");
return 0;
}