寻路(A*算法)

来源:互联网 发布:php内存回收的机制 编辑:程序博客网 时间:2024/06/05 15:49

在一张图片中寻找起点与终点的最短路径,图片是bmp格式

代码分为三个类,一个是GUI界面,另一个是核心的A*算法,还有一个是定义的'点'的类

GUI界面

import java.io.*;import java.awt.*;import javax.swing.*;import java.util.*;import java.awt.event.*;import javax.swing.event.*;import javax.imageio.ImageIO;import java.awt.image.BufferedImage;public class MainFram extends JFrame implements ActionListener{//现在面板上把图片画出来,然后给按钮添加空间,发生点击时间时重绘图片,算法写在重绘的方法里JLabel l1;JButton b1,b2,b;JPanel panBasic,pan1,pan2;BufferedImage img;String str="E:\\Editplus\\寻路图片\\1.bmp";int i=1;AStar load;//zhijingxunlu load;MainFram(){setTitle("寻路算法");l1=new JLabel("图片1");b1=new JButton("<<");b2=new JButton(">>");b=new JButton("开始寻路");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   setLayout(null);this.setSize(650,400);this.setLocation(200,200);panBasic=new Mypanel();l1.setBounds(270,10,50,30);panBasic.setBounds(150,50,330,230);b1.setBounds(180,290,50,30);b2.setBounds(260,290,50,30);b.setBounds(350,290,100,30);this.add(l1);this.add(panBasic);this.add(b1);this.add(b2);this.add(b);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);b1.addActionListener(this);b2.addActionListener(this);b.addActionListener(this);}public static void main(String[] args) {new MainFram();}public void paint(){//绘制寻路图片的方法Graphics g=panBasic.getGraphics();//获得当前界面上的值,后面改变图片都是重绘pan1,只有pan1由Graphicsload=new AStar();//load=new zhijingxunlu();//Pointload.setImage(img);g.setColor(Color.red);g.drawString("起点",load.getsNode().getX(), load.getsNode().getY());g.fillRect(load.getsNode().getX(), load.getsNode().getY(), 3, 3);g.fillRect(load.geteNode().getX(), load.geteNode().getY(), 3, 3);g.drawString("终点", load.geteNode().getX()-25,load.geteNode().getY());System.out.println("起点:("+load.getsNode().getX()+","+load.getsNode().getY()+")");System.out.println("终点:("+load.geteNode().getX()+","+load.geteNode().getY()+")");load.search();//寻路算法Nodefor(int i=0;i<load.resultList.size();i++){g.fillRect(load.resultList.get(i).getX(),load.resultList.get(i).getY(),1,1);}System.out.println(load.resultList.size()+"个节点");}class Mypanel extends JPanel{public void paint(Graphics g){super.paint(g);try{img=ImageIO.read(new File(str));}catch(IOException e){System.out.println(e.toString());}g.drawImage(img,0,0,null);}}public void actionPerformed(ActionEvent e){if(e.getSource()==b1){if(i>1){--i; str="E:\\Editplus\\寻路图片\\"+i+".bmp";pan1=new Mypanel();l1.setText("图片"+i);this.repaint();}}if(e.getSource()==b2){if(i<15){++i;str="E:\\Editplus\\寻路图片\\"+i+".bmp";pan2=new Mypanel();l1.setText("图片"+i);this.repaint();}}if(e.getSource()==b){paint();}}}

像素点的类
class Node{private int x;//节点在地图中的横坐标private int y;//节点在地图中的纵坐标private int g;//从起始点移动到此点的距离private int h;//到终点的曼哈顿距离private int f;//g+h,判断依据Node parNode;Node(int i, int j, Node node){this.x = i;this.y = j;this.parNode = node;}public void setX(int i){this.x = i;}public void setY(int i){this.y = i;}public void setparNode(Node node){this.parNode = node;}public int getX(){return this.x;}public int getY(){return this.y;}public Node getparNode(){return this.parNode;}public void setF(int i){this.f = i;}public void setG(int i){this.g = i;}public void setH(int i){this.h = i;}public int getF(){return this.f;}public int getH(){return this.h;}public int getG(){return this.g;}}

A*算法:A*算法用于找寻地图中两点之间的最短路径,详细讲解大家可以看这篇连接。点击打开链接(侵删)

import java.util.*;import java.awt.List;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.awt.image.BufferedImage;public class AStar {//输入图片     返回一个结果数组private int map_Width;// 得到图片的宽的private int map_Height;//得到图片的高度private Node sNode;  //创建初始点private Node eNode; //创建终结点private BufferedImage img=null; //传入的图片private final int cost_straight=10;//上下左右移动private final int cost_diagonal=14;//斜线上的移动private final int stepLength=1;//寻找下一个点时的步长private int map[][]; //地图ArrayList<Node> openList=new ArrayList(); //开启列表ArrayList<Node> closedList=new ArrayList(); //关闭列表ArrayList<Node> resultList=new ArrayList(); //结果列表AStar(){//构造函数}public void setImage(BufferedImage img){//传入图片this.img=img;this.map_Height=img.getHeight();this.map_Width=img.getWidth();initmap();setNodes();setNodee();}public void setNodes(){Node n;int x=2,y=0;for(int i=0;i<img.getHeight();i++){if(map[x][i]==1){y=i;break;}}n=new Node(x,y,null);this.sNode=n;System.out.println("起点的坐标是:("+x+","+y+")");}public void setNodee(){Node n;int x=img.getWidth()-2,y=0;for(int i=0;i<img.getHeight();i++){if(map[x][i]==1){y=i;break;}}n=new Node(x,y,null);this.eNode=n;System.out.println("终点的坐标是:("+x+","+y+")");} public void initmap(){map=new int[map_Width+1][map_Height+1];for(int i=0;i<map_Width;i++){for(int j=0;j<map_Height;j++){//像素颜色由红,绿,蓝三色组成,三色的值[0-255]2进制下的8位  16进制下的2位 用移位的方法分别获得//三原色全部位0组成的就是黑色int RGB=img.getRGB(i, j);//获得图片的16进制像素值int R=(RGB&0xff0000)>>16;//获得16进制下的前两位,也就是2进制下的前8位int G=(RGB&0xff00)>>8;//位与代表取那几位int B=(RGB&0xff);if(R==0&&G==0&&B==0){map[i][j]=1;}else{map[i][j]=0;}}}}public void setsNode(Node n){this.sNode=n;}public void seteNode(Node n){this.eNode=n;}public Node getsNode(){return sNode;}public Node geteNode(){return eNode;}public void run(){search();}public void search(){if(sNode.getX()<0||sNode.getX()>map_Width ||sNode.getY()<0||sNode.getY()>map_Height ||eNode.getY()<0||eNode.getY()>map_Width ||eNode.getY()<0||eNode.getY()>map_Height){//判断是否出界System.out.println("超出了图像范围!");return;}if(map[sNode.getX()][sNode.getY()]==0||map[eNode.getX()][eNode.getY()]==0){System.out.println("节点选择不正确!!!");return;}openList.add(sNode);//刚开始就将初始点添加到开启列表中long begintime=System.currentTimeMillis();resultList=search(sNode,eNode);//重载search方法,调用A*算法if(resultList.size()==0){System.out.println("没有找到路线");return;}long endtime=System.currentTimeMillis();System.out.println("寻路时间="+(endtime-begintime)+"ms");return;}public ArrayList<Node> search(Node sNode,Node eNode){//返回一个结果集boolean flag=false;Node node=null;//当前节点while(openList.size()>0){node=openList.get(0);//当前节点位上一下的F值最小的点if(node.getX()==eNode.getX()&&node.getY()==eNode.getY()){flag=true;//如果当前节点等于最终节点,那么跳出循环break;}//检查当前节点周围的所有节点//上if(node.getY()-1>0){checkPath(node.getX(),node.getY()-1,node,eNode,cost_straight);}//下if(node.getY()+1<map_Height){checkPath(node.getX(),node.getY()+1,node,eNode,cost_straight);}//左if(node.getX()-1>0){checkPath(node.getX()-1,node.getY(),node,eNode,cost_straight);}//右if(node.getX()+1<map_Width){checkPath(node.getX()+1,node.getY(),node,eNode,cost_straight);}//四个方向,八个方向更为精确,但是耗时较大//左下if(node.getX()-1>0&&node.getY()+1<map_Height){checkPath(node.getX()-1,node.getY()+1,node,eNode,cost_diagonal);}//右下if(node.getX()+1<map_Width&&node.getY()+1<map_Height){checkPath(node.getX()+1,node.getY()+1,node,eNode,cost_diagonal);}//左上if(node.getX()-1>0&&node.getY()-1>0){checkPath(node.getX()-1,node.getY()-1,node,eNode,cost_diagonal);}//右上if(node.getX()+1<map_Width&&node.getY()-1>0){checkPath(node.getX()+1,node.getY()-1,node,eNode,cost_diagonal);}closedList.add(openList.remove(0));Collections.sort(openList,new CompareNode());}if(flag){getPath(resultList, node);//由终点节点往前回溯找到结果集}return resultList;//结果集  路径所有的点都包含在其中}//如果没有处于开启列表中,那么添加到开启列表中,如果已经处于开启列表中,那么进行判断://是经过上一个节点再到达此处G值小还是原本的G值小,H值不变,G值的大小决定了F的大小//如果经父节点的G值更小,那么更新此点的参数值,并将父节点指向上一个节点public void checkPath(int x,int y,Node parNode,Node eNode,int cost){Node node=new Node(x,y,parNode);if(map[x][y]==0){closedList.add(node);  return;//点在路外}if(isListContains(closedList, x, y)!=-1){return ;//说明点处于关闭列表中}int dex=-1;if((dex=isListContains(openList, x, y))!=-1){//说明在开启列表中  if(node.getparNode().getG()+cost<openList.get(dex).getG()){node.setparNode(parNode);//检测新的路线是否更好,如果是改变他的父节点CountG(node,cost);CountF(eNode);  }}else{//不在关闭列表中  且不在开启列表中 就添加进来node.setparNode(parNode);Count(node,eNode,cost);openList.add(node);}}public int isListContains(ArrayList<Node> list,int x,int y){//检测这个点是否在这种状态集中for(int i=0;i<list.size();i++){if(list.get(i).getX()==x&&list.get(i).getY()==y){return i;//返回i说明在这个集合中,并且索引值就是i}}return -1;//说明不在}//从终点回溯到起点public void getPath(ArrayList<Node> list,Node n){if(n.getparNode()!=null){getPath(list,n.getparNode());}list.add(n);}//重新更新节点的参数public void Count(Node n,Node eNode,int cost){CountF(n);CountG(n,cost);CountH(n,eNode);}public void CountF(Node n){n.setF(n.getG()+n.getH());}public void CountG(Node n,int cost){if(n.getparNode()==null){n.setG(cost);}elsen.setG(n.getparNode().getG()+cost);}public void CountH(Node n,Node eNode){n.setH(Math.abs(eNode.getX()-n.getX())+Math.abs(eNode.getY()-n.getY()));}//按照F的大小进行排序class CompareNode implements Comparator<Node>{//集成了接口一下是接口中的抽象方法public int compare(Node o1, Node o2) {//o1-o2是按照升序排列return o1.getF()-o2.getF();}}}



原创粉丝点击