文章目录
- 前言
- 一,生成迷宫
- 二,设置键盘响应及操作对象的移动
- 三,A*算法走迷宫
- 四,绘制迷宫
- 结果图
前言
这个程序需要学习prime算法,A*算法。
链接:https://pan.baidu.com/s/1ceYvQS4mQ79aNqVCj3iRVA 提取码:27qm
一,生成迷宫
迷宫是一个布尔型二维数组mg,true代表有路,false代表有墙,并且我用的是prime算法生成,代码如下
//20x20的迷宫,false为有墙,
boolean mg[][]=new boolean[20][20];
//随机创造迷宫
public boolean[][] createmg(boolean arr[][]){
//数组开始下标
int i=1;
int j=1;
//放墙
List<Integer> x=new ArrayList<Integer>();
List<Integer> y=new ArrayList<Integer>();
x.add(j);
y.add(i);
//迷宫宽高
//宽
int lenx=mg[0].length;
//高
int leny=mg.length;
//四周有多少个路
int count=0;
while(x.size()!=0) {
int index=randre(x.size());
j=x.get(index);
i=y.get(index);
count=countsum(arr,i,j);
//如果四周只有一个或没有路
if(count<=1) {
arr[i][j]=true;
for(int m=i-1;m<i+2;m++) {
for(int n=j-1;n<j+2;n++) {
//添加四个方向的墙,且不能是边界
if(m>0&&n>0&&m<leny-1&&n<lenx-1) {
if((Math.abs(m-i)+Math.abs(n-j))==1&&!arr[m][n]) {
x.add(n);
y.add(m);
}
}
}
}
}
//删除节点
x.remove(index);
y.remove(index);
}
//出口
for(i=leny-2;i>1;i--) {
int index=randre(mg.length-3)+1;
if(arr[index][lenx-2]) {
arr[index][lenx-1]=true;
break;
}
}
return arr;
}
看不懂的可以点这个链接,有个讲的很好的博客()
二,设置键盘响应及操作对象的移动
这里我使用的方向键为W(上)A(左)S(下)D(右),进行对操作对象的移动,并且创建了一个类用来控制操作对象。键盘响应代码如下:
//记录走过的路径,true为走过
boolean lj[][]=new boolean[20][20];
//设置键盘按键事件
this.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
char ch=e.getKeyChar();
if(String.valueOf(ch).equalsIgnoreCase("A")) {
mo.leftmove();
//如果越界或撞墙
if(mo.nowx<0||!mg[mo.nowy][mo.nowx]) {
mo.back();
}
}
if(String.valueOf(ch).equalsIgnoreCase("D")) {
mo.rightmove();
if(mo.nowx>=mg[0].length||!mg[mo.nowy][mo.nowx]) {
mo.back();
}
}
if(String.valueOf(ch).equalsIgnoreCase("W")) {
mo.upmove();
if(mo.nowy<0||!mg[mo.nowy][mo.nowx]) {
mo.back();
}
}
if(String.valueOf(ch).equalsIgnoreCase("S")) {
mo.downmove();
if(mo.nowy>=mg.length||!mg[mo.nowy][mo.nowx]) {
mo.back();
}
}
//每次移动都重绘一次
repaint();
//路径记录
lj[mo.nowy][mo.nowx]=true;
}
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
});
操作对象的类:
public class moveobject {
//现在横坐标
public int nowx=0;
//现在纵坐标
public int nowy=1;
//过去横坐标
public int oldx=0;
//过去纵坐标
public int oldy=1;
//移动
public void leftmove() {
oldx=nowx;
oldy=nowy;
nowx--;
}
public void rightmove() {
oldx=nowx;
oldy=nowy;
nowx++;
}
public void upmove() {
oldx=nowx;
oldy=nowy;
nowy--;
}
public void downmove() {
oldx=nowx;
oldy=nowy;
nowy++;
}
//返回
public void back() {
nowx=oldx;
nowy=oldy;
}
}
三,A*算法走迷宫
学习A*算法这里我推荐去这个链接,有代码:()
我的代码如下:
//用来记录A*算法遇到的点的各种值
public class ADO {
//横纵坐标
int x,y;
//F=G+H
int F,G,H;
}
//记录系统走迷宫路径
boolean A[][]=new boolean[20][20];
//A*算法走迷宫
public void xtzmg() {
int x=1;
int y=1;
int b[][]= {{1,0},{-1,0},{0,1},{0,-1}};
//开放标志,true为开放
boolean openflag[][]=new boolean[20][20];
//封闭标志,true为封闭
boolean closeflag[][]=new boolean[20][20];
openflag=barry(openflag);
closeflag=barry(closeflag);
closeflag[1][0]=true;
List<ADO> open=new ArrayList<ADO>();
List<ADO> close=new ArrayList<ADO>();
int exitx=0;
int exity=0;
//找到终点坐标
for(int i=0;i<mg.length;i++) {
if(mg[i][mg[0].length-1]) {
exitx=mg[0].length-1;
exity=i;
}
}
ADO p=new ADO();
p.x=x;
p.y=y;
p.H=Math.abs(exitx-x)+Math.abs(exity-y);
p.G=1;
p.F=p.G+p.H;
open.add(p);
openflag[p.y][p.x]=true;
while(open.size()!=0) {
p=open.get(open.size()-1);
x=p.x;
y=p.y;
close.add(p);
open.remove(open.size()-1);
closeflag[y][x]=true;
openflag[y][x]=false;
for(int i=0;i<4;i++) {
//添加四个方向的路
int tx=x+b[i][0];
int ty=y+b[i][1];
//如果是封闭或是墙
if(!mg[ty][tx]||closeflag[ty][tx]) {
continue;
}
//如果不是开放列表中的
if(!openflag[ty][tx]) {
//如果到出口
if(ty==exity&&tx==exitx) {
int G=close.get(close.size()-1).G;
int j=0;
x=exitx-1;
y=exity;
A[exity][exitx]=true;
A[exity][exitx-1]=true;
//将close列表逆序遍历,按照四周的G的顺序进行路径选择
while(G!=1) {
for(i=0;i<4;i++) {
System.out.println(i);
tx=x+b[i][0];
ty=y+b[i][1];
if(!closeflag[ty][tx]) {
continue;
}
for(j=0;j<close.size();j++) {
if(close.get(j).x==tx&&close.get(j).y==ty) {
if(close.get(j).G==G-1) {
A[ty][tx]=true;
x=tx;
y=ty;
G=G-1;
break;
}
}
}
if(j==close.size()) {
continue;
}
break;
}
}
A[1][0]=true;
return;
}
ADO q=new ADO();
q.x=tx;
q.y=ty;
q.H=Math.abs(exitx-tx)+Math.abs(exity-ty);
q.G=p.G+1;
q.F=q.G+q.H;
open.add(q);
openflag[ty][tx]=true;
}
//如果是开放列表中的
else {
int k=0;
for(k=0;k<open.size();k++) {
if(open.get(k).x==tx&&open.get(k).y==ty) {
break;
}
}
ADO q=open.get(k);
//若经由当前节点到这个节点的G小于原先的G
if(p.G+1<q.G) {
//更新
q.G=p.G+1;
q.F=q.G+q.H;
open.remove(k);
open.add(q);
}
}
}
}
}
四,绘制迷宫
这里要用到paint(绘制),repaint(调用paint)
paint代码:
//画图,绿色为操作对象,蓝色为走过的路径,黑色为墙,红色为系统路径
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2=(Graphics2D)g;
for(int i=0;i<mg.length;i++) {
for(int j=0;j<mg[i].length;j++) {
g2.setColor(Color.RED);
if(A[i][j]) {
g2.fillRect(8+j*20, 33+i*20, 20, 20);
}
g2.setColor(Color.BLACK);
if(!mg[i][j]) {
g2.fillRect(8+j*20, 33+i*20, 20, 20);
}
g2.setColor(Color.BLUE);
if(lj[i][j]) {
g2.fillRect(8+j*20, 33+i*20, 20, 20);
}
}
}
g2.setColor(Color.GREEN);
g2.fillOval(8+mo.nowx*20,33+ mo.nowy*20, 20, 20);
if(mo.nowx==mg.length-1) {
// mytd.stop();
// new end(getX(),getY());//创建结束对话框,拓展
try {
Thread.sleep(3000); //停顿3秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(0);
}
}
结果图