文章目录

  • 前言
  • 一,生成迷宫
  • 二,设置键盘响应及操作对象的移动
  • 三,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);
  }
 }

结果图

JAVA迷宫八个方向 java写迷宫游戏_Math