一 实验要求
1、迷宫随机生成
2、玩家走迷宫,留下足迹;
3、系统用A*算法寻路,输出路径
解决问题
1、如何显示迷宫的图形界面;
2、如何生成随机的迷宫;
3、怎样移动游戏中走迷宫的“玩家”;
4、用A*算法求解迷宫;
二 实验算法
1.显示迷宫路径
prime算法 :首先,生成迷宫全部都是围墙设为1表示围墙的值就是1。其次,把迷宫之外的轮廓设置为0表示边框,然后设置起点和重点的值分别为2和2.
接下来就要判断起始点下下个低方判断是否是围墙,因为防止打穿围墙或者达到之前的路上在围墙中不断的挖路从而生成迷宫。方法主要是从起点开始每一个上下左右,当发现有围墙,则往围墙移动,然后继续判断最终不断递归。
2.基于A*迷宫求解
节点放入开放列表(开始节点的F和G值都视为0);
三i. 在开放列表中查找具有最小F值的节点,并把查找到的节点作为当前节点;
ii.把当前节点从开放列表删除, 加入到封闭列表;
iii.对当前节点相邻的每一个节点依次执行以下步骤:
1. 如果该相邻节点不可通行或者该相邻节点已经在封闭列表中,则什么操作也不执行,继续检验下一个节点;
2. 如果该相邻节点不在开放列表中,则将该节点添加到开放列表中, 并将该相邻节点的父节点设为当前节点,同时保存该相邻节点的G和F值;
3. 如果该相邻节点在开放列表中, 则判断若经由当前节点到达该相邻节点的G值是否小于原来保存的G值,若小于,则将该相邻节点的父节点设为当前节点,并重新设置该相邻节点的G和F值. 循环结束条件:当终点节点被加入到开放列表作为待检验节点时, 表示路径被找到,此时应终止循环;或者当开放列表为空,表明已无可以添加的新节点,而已检验的节点中没有终点节点则意味着路径无法被找到,此时也结束循环;
3. 从终点节点开始沿父节点遍历, 并保存整个遍历到的节点坐标,遍历所得的节点就是最后得到的路径;
搜索区域(The Search Area):搜索区域被划分为简单的二维数组,数组每个元素对应一个结点。
开放列表(Open List):将寻路过程中待检测的结点存放于Open List中,而已检测过的结点则存放于Close List中。
路径排序(Path Sorting):下一步怎么移动由以下公式确定;F(n)=G+H。F(n)为估价函数,G代表的是从初始位置Start沿着已生成的路径到指定待检测结点移动开销。H表示待检测结点到目标节点B的估计移动开销。
启发函数(Heuristics Function): H为启发函数,可以看作是一种试探,由于在找到唯一路径前,不确定在前面会出现什么障碍物,因此用了一种计算H的算法,具体可以根据实际情况决定。为了简化问题,H采用的是传统的曼哈顿距离,也就是横纵向走的距离之和。
3.此实验运用广度优先算法搜索路径
广度优先算法(BFS)
广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历算法这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。基本过程,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用队列数据结构来辅助实现BFS算法。
三代码实现
生成迷宫
void MAZE::mazeInit()
{
//迷宫围墙,nn*2+2是规划的迷宫地图大小
for(int i=0; i<=nn*2+2; ++i)
for(int j=0; j<=nn*2+2; ++j)
maze[i][j] = 1;
//在迷宫之外的的轮廓默认为过道
for(int i=0, j=2*nn+2; i<=2*nn+2; ++i)
{
maze[i][0] = 0;
maze[i][j] = 0;
}
for(int i=0, j=2*nn+2; i<=2*nn+2; ++i)
{
maze[0][i] = 0;
maze[j][i] = 0;
}
//默认迷宫坐标第三行第一例为起点
maze[2][1] = 2;
//默认2*nn 行 和 2*nn+1列为终点
maze[2*nn][2*nn+1] = 3;
//生成无符号随机数
srand((unsigned)time(NULL));
//生成的随机数在 [0, nn+1]之间,生成路径
searchPath(rand()%nn+1, rand()%nn+1);
//将地图整体向左上方平移一个单位
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
maze[i][j] = maze[i+1][j+1];
}
}
len_path = 0;
}
int MAZE::searchPath(int x, int y)
{
//往四个方向
static int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int zx = x*2;
int zy = y*2;
int next, turn, i;
maze[zx][zy] = 0;
//设置turn为[0, 4]之间的任意一个奇数
turn = rand()%2 ? 1 : 3;
//next=rand()%4 取值范围[0, 4),
//next=(next+turn)%4 每个循环在奇数和偶数之间切换,[0, 4)遍历一遍
//在迷宫地图里,随机选一个地方,开始挖路,4次循环,往4个方向挖
for(i=0, next=rand()%4; i<4; ++i, next=(next+turn)%4)
//搜索当前位置的第二步,如果是围墙,这将当前位置的沿着指定方向的下一步设置为路
if(maze[zx+2*dir[next][0]][zy+2*dir[next][1]] == 1)
{
maze[zx+dir[next][0]][zy+dir[next][1]] = 0;
searchPath(x+dir[next][0], y+dir[next][1]);//等于searthPath(zx+2*dir[next][0]][zy+2*dir[next][1])当前位置的下一步为节点开始搜索
}
return 0;
}
画出迷宫地图
void MainWindow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
int n = m->get_n();
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
//绘制迷宫围墙
if(m->maze[i][j] ==1){
painter.setPen(Qt::black);
painter.setBrush(QBrush(Qt::black,Qt::SolidPattern));
painter.drawRect(QRect(j*size,i*size,size,size));
}
//绘制你当前的位置
else if(m->maze[i][j] == 2){
painter.setPen(Qt::yellow);
painter.setBrush(Qt::yellow);
painter.drawRect(j*20,i*20,20,20);
}
//绘制迷宫终点
else if(m->maze[i][j] == 3){
painter.setPen(Qt::red);
painter.setBrush(Qt::red);
painter.drawRect(j*20,i*20,20,20);
}
//绘制迷宫过道
else if(m->maze[i][j] == 0){
painter.setPen(Qt::white);
painter.setBrush(QBrush(Qt::white,Qt::SolidPattern));
painter.drawRect(QRect(j*size,i*size,size,size));
}
//绘制最短路径提示
else if(m->maze[i][j] == 6){
painter.setPen(Qt::white);
painter.setBrush(Qt::blue);
painter.drawRect(j*20+5,i*20+5,10,10);
}
}
}
}
键盘响应
void MainWindow::keyPressEvent(QKeyEvent *e)//键盘监听
{
if(bfs_fg){
m->recoverPath();
bfs_fg = false;
update();
}
int tx = X, ty = Y;
int n = m->get_n();
if(e->key()==Qt::Key_W)//上
{
if(X>0 && m->maze[X-1][Y] != 1)
{
X=X-1;
}
}
else if(e->key()==Qt::Key_S)//下
{
if(Xmaze[X+1][Y] != 1)
{
X=X+1;
}
}
else if(e->key()==Qt::Key_A)//左
{
if(Y>0 && m->maze[X][Y-1] != 1)
{
Y=Y-1;
}
}
else if(e->key()==Qt::Key_D)//右
{
if(Ymaze[X][Y+1] != 1)
{
Y=Y+1;
}
}
int tmp = m->maze[X][Y];
if(tmp == 3){
QMessageBox::information(this,"提示","到达终点",QMessageBox::Yes);
}else{
m->maze[X][Y] = m->maze[tx][ty];
m->maze[tx][ty] = tmp;
}
update();
}
搜索路径dfs
void MAZE::getPath(int pos)
{
while(pos != -1)
{
path[len_path].x = q[pos].x;
path[len_path].y = q[pos].y;
len_path++;
pos = q[pos].pre;
}
}
void MAZE::bfs()//寻路
{
int front, tail, sx, sy;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if(maze[i][j] == 2)
{
sx = i; sy = j;
}
front = tail = 0;
q[tail].x = sx;
q[tail].y = sy;
q[tail].pre = -1;
tail++;
int x, y, nx, ny;
bool fg = false;
while(front < tail)
{
x = q[front].x;
y = q[front].y;
for(int i = 0; i < 4; i++)
{
nx = x+dx[i];
ny = y+dy[i];
if(nx>=0&&nx=0&&ny
三 游戏测试
四 打包发布