AStar

    技术2022-05-11  80

        以前对A*算法的理解停留在人工智能书本上面,但是最近2天看了Stanford的一个游戏介绍网站http://theory.stanford.edu/~amitp/GameProgramming/之后,觉得对A*算法有了比较深刻的了解。那个网站对A*描述没有课本1条又1条的公式化,更多的是图形,结合游戏本身实际来描述,觉得帮助很大。

        现在用Java编写了一个算法演示,效果还不错,不过现在open列表是链表形式,效率o(n)比较差,下一步可以考虑用堆插入查找来实现o(lgn)(不过其实现在100×100看起来还可以吧,暂时没有什么动力做,看以后需要吧)

    附:算法源代码,不妥之处,还望各位指正。 

    AStar.java(算法核心)

     

    /** *  */ package  Arithmetic; import  java.util. * ; import  GUI. * ; /** * @author 冯家耀 * */ public   class  AStar  {    final int BARRIER = -3;    final int START = -1;    final int END = -2;    Node [][]grid;    List<Node> open = new LinkedList();    Set close = new HashSet();    Node startNode;    Node endNode;    int [][]result;//1:找过 2:找到 0:空    final int EVEN_FIND = 1;    final int SUC_FIND = 2;    final int NOT_FIND = 0;    int gridRows;    int gridCols;    int D = 1;    public AStar(GridValue [][]g){        if(g==null)return;        gridRows = g.length;        gridCols = g[0].length;        grid = new Node[gridRows][gridCols];        result = new int[gridRows][gridCols];        boolean hasfindfirst = false;        boolean hasfindend = false;        for(int i=0;i<gridRows;i++){            for(int j = 0; j < gridCols; j++){                grid[i][j] = new Node(i,j,g[i][j].toInt());                if(! hasfindfirst){                    if(grid[i][j].cost == START){                        hasfindfirst = true;                        startNode = grid[i][j];                    }                }                if(! hasfindend){                    if(grid[i][j].cost == END){                        hasfindend = true;                        endNode = grid[i][j];                    }                }            }        }    }    class Node{        Node parent;        int row;        int col;        int cost;        int f;        int g;        public Node(int row,int col, int cost){            this.row = row;            this.col = col;            this.cost = cost;        }        @Override        public boolean equals(Object obj) {            if(obj instanceof Node && ((Node)obj).row == row && ((Node)obj).col == col)return true;            else return false;        }        @Override        public int hashCode() {            return row*gridCols+col;        }    }    int estimateH(Node node){        //return D*( (Math.abs(node.row) - endNode.row) + Math.abs(node.col - endNode.col) );        //return D*( Math.max((Math.abs(node.row) - endNode.row) , Math.abs(node.col - endNode.col)) );        int deltay = node.row - endNode.row;        int deltax = node.col - endNode.col;        return (int)(D*Math.sqrt((deltay*deltay + deltax*deltax)));    }    public boolean findPath(){        insertIntoOpen(startNode);        while(!open.isEmpty()){            Node node = open.remove(0);            System.out.println("Scan open");            result[node.row][node.col] = EVEN_FIND;            if(node.equals(endNode)){                markEven(node);                createPath();                return true;            }            else{                List neighborNodeList = findNeighbor(node);                Iterator<Node> it = neighborNodeList.iterator();                while(it.hasNext()){                    Node neighborNode = it.next();                    if(close.contains(neighborNode)){                        continue;                    }                    else{//FIXME 效率超低                        if(! open.contains(neighborNode)){                            neighborNode.g = node.g + neighborNode.cost;                            neighborNode.f = neighborNode.g + estimateH(neighborNode);                            neighborNode.parent = node;                            insertIntoOpen(neighborNode);                        }                        else{                            if(node.g + neighborNode.cost +  estimateH(neighborNode) < neighborNode.f){                                neighborNode.g = node.g + neighborNode.cost;                                neighborNode.f = neighborNode.g + estimateH(neighborNode);                                open.remove(neighborNode);                                neighborNode.parent = node;                                insertIntoOpen(neighborNode);                            }                        }                    }                }                            }            close.add(node);        }                return false;    }    private void markEven(Node node){        result[node.row][node.col] = -1;    }    private void createPath(){        LinkedList pathlist = new LinkedList();        Node tmp = endNode;        while(tmp.parent != null){            result[tmp.row][tmp.col] = SUC_FIND;            tmp = tmp.parent;        }    }    private List findNeighbor(Node node){        List<Node> list = new ArrayList();        int left = node.col-1;        int up = node.row-1;        int down = node.row+1;        int right = node.col+1;        if(left > 0){            if(grid[node.row][left].cost != BARRIER)                list.add(grid[node.row][left]);            if(up>0){                if(grid[up][node.col].cost != BARRIER)                    list.add(grid[up][node.col]);                if(grid[up][left].cost != BARRIER)                    list.add(grid[up][left]);            }            if(down < gridRows - 1){                if(grid[down][node.col].cost != BARRIER)                    list.add(grid[down][node.col]);                if(grid[down][left].cost != BARRIER)                    list.add(grid[down][left]);            }        }        if(right < gridCols - 1){            if(grid[node.row][right].cost != BARRIER)                list.add(grid[node.row][right]);            if(up>0){                if(grid[up][right].cost != BARRIER)                    list.add(grid[up][right]);            }            if( down < gridRows - 1){                if(grid[down][right].cost != BARRIER)                    list.add(grid[down][right]);            }        }        return list;    }    public int[][] getResult(){        return result;    }    private void insertIntoOpen(Node node){        int size = open.size();        Iterator<Node>it = open.iterator();        int i = 0;        while(it.hasNext()){            if(it.next().f > node.f)break;            i++;        }        open.add(i, node);        System.out.println("OPEN ADD NODE:("+ node.row+","+node.col+")" );    }}

     GridValue.java

    package  GUI; public   enum  GridValue {    BARRIER(-3),    START(-1),    END(-2),    LEN1(1),    LEN10(10),    LEN50(50),    LEN100(100),    LEN150(150);        private int value;    private GridValue(int value){        this.value = value;    }    public int toInt(){        return this.value;    }}

     

    MainForm.java(界面展示)

    package  GUI; import  java.awt. * ; import  java.awt.event.ActionEvent; import  java.awt.event.ActionListener; import  java.awt.event.MouseAdapter; import  java.awt.event.MouseEvent; import  javax.swing.BoxLayout; import  javax.swing.JButton; import  javax.swing.JFrame; import  javax.swing.JLabel; import  javax.swing.JOptionPane; import  javax.swing.JPanel; import  javax.swing.JSplitPane; import  javax.swing.WindowConstants; import  sun.font.GlyphLayout.GVData; /*** This code was edited or generated using CloudGarden's Jigloo* SWT/Swing GUI Builder, which is free for non-commercial* use. If Jigloo is being used commercially (ie, by a corporation,* company or business for any purpose whatever) then you* should purchase a license for each developer using Jigloo.* Please visit www.cloudgarden.com for details.* Use of Jigloo implies acceptance of these licensing terms.* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.*/ public   class  MainForm  extends  javax.swing.JFrame  {    private JSplitPane jSplitPane1;    private JButton jButton3;    private JButton jButton2;    private JButton jButton1;    private JPanel jPanel17;    private JPanel jPanel1;    private JLabel jLabel3;    private JLabel jLabel4;    private JLabel jLabel5;    private JPanel jPanel1Start;    private JLabel jLabel7;    private JPanel jPanel1End;    private JPanel jPanel14;    private JPanel jPanel16;    private JLabel jLabel6;    private JPanel jPanel12;    private JPanel jPanel1Barrier;    private JPanel jPanel10;    private JPanel jPanelLength150;    private JPanel jPanel8;    private JPanel jPanelLength100;    private JPanel jPanel6;    private JLabel jLabel2;    private JPanel jPanelLength50;    private JPanel jPanel4;    private JLabel jLabel1;    private JPanel jPanelLength10;    private GridPanel gridPanel;    private JPanel jPanel2;    /**    * Auto-generated main method to display this JFrame    */    public static void main(String[] args) {        MainForm inst = new MainForm();        inst.setVisible(true);        inst.setTitle("A*算法演示");    }        public MainForm() {        super();        initGUI();    }                private void initGUI() {        try {            setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);            {                jSplitPane1 = new JSplitPane();                getContentPane().add(jSplitPane1, BorderLayout.CENTER);                jSplitPane1.setDividerSize(1);                jSplitPane1.setDividerLocation(412);                jSplitPane1.setResizeWeight(1.0);                {                    gridPanel = new GridPanel();                    gridPanel.setBackground(Color.BLACK);                    gridPanel.setPreferredSize(new Dimension(411,411));                    jSplitPane1.setLeftComponent(gridPanel);//                    gridPanel.addMouseListener(new )                }                {                    jPanel2 = new JPanel();                    FlowLayout jPanel2Layout = new FlowLayout();                    jPanel2Layout.setAlignment(FlowLayout.LEFT);                    jSplitPane1.setRightComponent(jPanel2);                    jPanel2.setBackground(Color.GRAY);                    jPanel2.setPreferredSize(new Dimension(40,400));                    jPanel2.setLayout(jPanel2Layout);                    {                        jPanel1 = new JPanel();                        FlowLayout jPanel1Layout = new FlowLayout();                        jPanel1Layout.setAlignment(FlowLayout.LEFT);                        jPanel1.setLayout(jPanel1Layout);                        jPanel2.add(jPanel1);                        jPanel1.setPreferredSize(new java.awt.Dimension(165,26));                        jPanel1.setBackground(new java.awt.Color(128,128,128));                        {                            jPanelLength10 = new JPanel();                            jPanel1.add(jPanelLength10);                            GridLayout jPanel3Layout = new GridLayout(11);                            jPanel3Layout.setHgap(5);                            jPanel3Layout.setVgap(5);                            jPanel3Layout.setColumns(1);                            jPanelLength10.setLayout(jPanel3Layout);                            jPanelLength10.setPreferredSize(new java.awt.Dimension(1513));                            jPanelLength10.setBackground(new java.awt.Color(33,233,0));                            jPanelLength10.addMouseListener(new MouseAdapter() {                                public void mousePressed(MouseEvent evt) {                                    gridPanel.setCurrentValue(GridValue.LEN10);                                }                            });                        }                        {                            jLabel1 = new JLabel();                            jPanel1.add(jLabel1);                            jLabel1.setText("10");                        }                    }                    {                        jPanel4 = new JPanel();                        FlowLayout jPanel4Layout = new FlowLayout();                        jPanel4Layout.setAlignment(FlowLayout.LEFT);                        jPanel4.setLayout(jPanel4Layout);                        jPanel2.add(jPanel4);                        jPanel4.setPreferredSize(new java.awt.Dimension(165,26));                        jPanel4.setBackground(new java.awt.Color(128,128,128));                        {                            jPanelLength50 = new JPanel();                            GridLayout jPanel5Layout = new GridLayout(11);                            jPanel5Layout.setHgap(5);                            jPanel5Layout.setVgap(5);                            jPanel5Layout.setColumns(1);                            jPanel4.add(jPanelLength50);                            jPanelLength50.setBackground(new java.awt.Color(255,128,128));                            jPanelLength50.setPreferredSize(new java.awt.Dimension(15,13));                            jPanelLength50.setLayout(jPanel5Layout);                            jPanelLength50.addMouseListener(new MouseAdapter() {                                public void mousePressed(MouseEvent evt) {                                    gridPanel.setCurrentValue(GridValue.LEN50);                                }                            });                        }                        {                            jLabel2 = new JLabel();                            jPanel4.add(jLabel2);                            jLabel2.setText("50");                        }                    }                    {                        jPanel6 = new JPanel();                        jPanel2.add(jPanel6);                        FlowLayout jPanel6Layout = new FlowLayout();                        jPanel6Layout.setAlignment(FlowLayout.LEFT);                        jPanel6.setLayout(jPanel6Layout);                        jPanel6.setPreferredSize(new java.awt.Dimension(165,26));                        jPanel6.setBackground(new java.awt.Color(128,128,128));                        {                            jPanelLength100 = new JPanel();                            GridLayout jPanel7Layout = new GridLayout(11);                            jPanel7Layout.setHgap(5);                            jPanel7Layout.setVgap(5);                            jPanel7Layout.setColumns(1);                            jPanel6.add(jPanelLength100);                            jPanelLength100.setBackground(new java.awt.Color(255,255,128));                            jPanelLength100.setPreferredSize(new java.awt.Dimension(15,13));                            jPanelLength100.setLayout(jPanel7Layout);                            jPanelLength100                                .addMouseListener(new MouseAdapter() {                                public void mousePressed(MouseEvent evt) {                                    gridPanel.setCurrentValue(GridValue.LEN100);                                }                                });                        }                        {                            jLabel3 = new JLabel();                            jPanel6.add(jLabel3);                            jLabel3.setText("100");                        }                    }                    {                        jPanel8 = new JPanel();                        FlowLayout jPanel8Layout = new FlowLayout();                        jPanel8Layout.setAlignment(FlowLayout.LEFT);                        jPanel8.setLayout(jPanel8Layout);                        jPanel2.add(jPanel8);                        jPanel8.setPreferredSize(new java.awt.Dimension(165,26));                        jPanel8.setBackground(new java.awt.Color(128,128,128));                        {                            jPanelLength150 = new JPanel();                            GridLayout jPanel9Layout = new GridLayout(11);                            jPanel9Layout.setHgap(5);                            jPanel9Layout.setVgap(5);                            jPanel9Layout.setColumns(1);                            jPanel8.add(jPanelLength150);                            jPanelLength150.setBackground(new java.awt.Color(128,255,128));                            jPanelLength150.setPreferredSize(new java.awt.Dimension(15,13));                            jPanelLength150.setLayout(jPanel9Layout);                            jPanelLength150                                .addMouseListener(new MouseAdapter() {                                public void mousePressed(MouseEvent evt) {                                    gridPanel.setCurrentValue(GridValue.LEN150);                                }                                });                        }                        {                            jLabel4 = new JLabel();                            jPanel8.add(jLabel4);                            jLabel4.setText("150");                        }                    }                    {                        jPanel10 = new JPanel();                        FlowLayout jPanel10Layout = new FlowLayout();                        jPanel10Layout.setAlignment(FlowLayout.LEFT);                        jPanel10.setLayout(jPanel10Layout);                        jPanel2.add(jPanel10);                        jPanel10.setPreferredSize(new java.awt.Dimension(165,26));                        jPanel10.setBackground(new java.awt.Color(128,128,128));                        {                            jPanel1Barrier = new JPanel();                            GridLayout jPanel11Layout = new GridLayout(11);                            jPanel11Layout.setHgap(5);                            jPanel11Layout.setVgap(5);                            jPanel11Layout.setColumns(1);                            jPanel10.add(jPanel1Barrier);                            jPanel1Barrier.setBackground(new java.awt.Color(128,255,255));                            jPanel1Barrier.setPreferredSize(new java.awt.Dimension(15,13));                            jPanel1Barrier.setLayout(jPanel11Layout);                            jPanel1Barrier.addMouseListener(new MouseAdapter() {                                public void mousePressed(MouseEvent evt) {                                    gridPanel.setCurrentValue(GridValue.BARRIER);                                }                            });                        }                        {                            jLabel5 = new JLabel();                            jPanel10.add(jLabel5);                            jLabel5.setText("固体");                        }                    }                    {                        jPanel12 = new JPanel();                        FlowLayout jPanel12Layout = new FlowLayout();                        jPanel12Layout.setAlignment(FlowLayout.LEFT);                        jPanel12.setLayout(jPanel12Layout);                        jPanel2.add(jPanel12);                        jPanel12.setPreferredSize(new java.awt.Dimension(165,26));                        jPanel12.setBackground(new java.awt.Color(128,128,128));                        {                            jPanel1Start = new JPanel();                            GridLayout jPanel13Layout = new GridLayout(11);                            jPanel13Layout.setHgap(5);                            jPanel13Layout.setVgap(5);                            jPanel13Layout.setColumns(1);                            jPanel12.add(jPanel1Start);                            jPanel1Start.setBackground(new java.awt.Color(255,0,255));                            jPanel1Start.setPreferredSize(new java.awt.Dimension(15,13));                            jPanel1Start.setLayout(jPanel13Layout);                            jPanel1Start.addMouseListener(new MouseAdapter() {                                public void mouseClicked(MouseEvent evt) {                                    gridPanel.setCurrentValue(GridValue.START);                                }                            });                        }                        {                            jLabel6 = new JLabel();                            jPanel12.add(jLabel6);                            jLabel6.setText("起点");                        }                    }                    {                        jPanel16 = new JPanel();                        jPanel2.add(jPanel16);                        jPanel16.setBackground(new java.awt.Color(128,128,128));                        jPanel16.setPreferredSize(new java.awt.Dimension(165,26));                        {                            jPanel14 = new JPanel();                            FlowLayout jPanel14Layout = new FlowLayout();                            jPanel14Layout.setAlignment(FlowLayout.LEFT);                            jPanel14.setLayout(jPanel14Layout);                            jPanel16.add(jPanel14);                            jPanel14.setBackground(new java.awt.Color(                                128,                                128,                                128));                            jPanel14.setPreferredSize(new java.awt.Dimension(                                165,                                26));                            {                                jPanel1End = new JPanel();                                GridLayout jPanel15Layout = new GridLayout(11);                                jPanel15Layout.setHgap(5);                                jPanel15Layout.setVgap(5);                                jPanel15Layout.setColumns(1);                                jPanel14.add(jPanel1End);                                jPanel1End.setBackground(new java.awt.Color(128,0,255));                                jPanel1End.setPreferredSize(new java.awt.Dimension(15,13));                                jPanel1End.setLayout(jPanel15Layout);                                jPanel1End.addMouseListener(new MouseAdapter() {                                    public void mouseClicked(MouseEvent evt) {                                        gridPanel.setCurrentValue(GridValue.END);                                    }                                });                            }                            {                                jLabel7 = new JLabel();                                jPanel14.add(jLabel7);                                jLabel7.setText("终点");                            }                        }                    }                    {                        jPanel17 = new JPanel();                        GridBagLayout jPanel17Layout = new GridBagLayout();                        jPanel17Layout.rowWeights = new double[] {0.10.00.0};                        jPanel17Layout.rowHeights = new int[] {73535};                        jPanel17Layout.columnWeights = new double[] {0.1};                        jPanel17Layout.columnWidths = new int[] {7};                        jPanel17.setLayout(jPanel17Layout);                        jPanel2.add(jPanel17);                        jPanel17.setPreferredSize(new java.awt.Dimension(170197));                        jPanel17.setBackground(new java.awt.Color(128,128,128));                        {                            jButton1 = new JButton();                            jPanel17.add(jButton1, new GridBagConstraints(01110.00.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0000), 00));                            jButton1.setText("计算");                            jButton1.setPreferredSize(new java.awt.Dimension(13025));                            jButton1.addActionListener(new ActionListener() {                                public void actionPerformed(ActionEvent evt) {                                    Arithmetic.AStar astar = new Arithmetic.AStar(gridPanel.getGrid());                                    if(                                            astar.findPath()                                                                        ){                                        gridPanel.setResult(astar.getResult());                                        JOptionPane.showConfirmDialog(MainForm.this"FOUND");                                    }                                    else JOptionPane.showConfirmDialog(MainForm.this"NOT FOUND");                                    gridPanel.repaint();                                }                            });                        }                        {                            jButton2 = new JButton();                            jPanel17.add(jButton2, new GridBagConstraints(02210.00.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0000), 00));                            jButton2.setText("消除路径");                            jButton2.setPreferredSize(new java.awt.Dimension(13025));                            jButton2.addMouseListener(new MouseAdapter() {                                public void mouseClicked(MouseEvent evt) {                                    System.out                                        .println("jButton2.mouseClicked, event="                                            + evt);                                    //TODO add your code for jButton2.mouseClicked                                }                            });                        }                        {                            jButton3 = new JButton();                            jPanel17.add(jButton3, new GridBagConstraints(00110.00.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0000), 00));                            jButton3.setText("清空所有");                            jButton3.setPreferredSize(new java.awt.Dimension(130,25));                            jButton3.addMouseListener(new MouseAdapter() {                                public void mouseClicked(MouseEvent evt) {                                    gridPanel.clearAll();                                    gridPanel.setResult(null);                                    gridPanel.repaint();                                }                            });                        }                    }                }            }            pack();            this.setSize(600450);            //this.setExtendedState(JFrame.MAXIMIZED_BOTH);        } catch (Exception e) {            e.printStackTrace();        }    }    @Override    public void paint(Graphics g) {        // TODO 自动生成方法存根        super.paint(g);            }} class  GridPanel  extends  JPanel {        final int rows = 20;    final int cols = 20;    GridValue [][]grid = new GridValue[rows][cols];    final int gridPanelWidth = 411;    final int gridPanelHeight = 411;    int [][]result;    int rowspan = (gridPanelHeight - 10 - 1/ rows;    int colspan = (gridPanelWidth - 10 - 1/ cols;    int edge = 5;        private GridValue currentValue = GridValue.LEN1;    public GridPanel() {        for(int i = 0; i < rows; i++)            for(int j = 0; j < cols;j++){                grid[i][j] = GridValue.LEN1;            }        addMouseListener(new MouseAdapter(){            @Override            public void mousePressed(MouseEvent e) {                int xgrid = (e.getX() - edge) / colspan;                int ygrid = (e.getY() - edge) / rowspan;                grid[ygrid][xgrid] = currentValue;                repaint();            }        });    }    public GridValue[][] getGrid(){        return grid;    }    public void  setResult(int[][]result){        this.result = result;    }    public void clearAll(){        for(int i = 0; i < rows; i++){            for(int j = 0; j < cols;j++){                grid[i][j] = GridValue.LEN1;            }        }        repaint();    }    public void setCurrentValue(GridValue value){        currentValue = value;    }    public void drawGrid(Graphics g,int row,int col){        //grid[row][col] = value;        int startrow = edge + rowspan*row;        int startcol = edge + colspan*col;        boolean draw = true;        switch(grid[row][col]){        case BARRIER:            g.setColor(new java.awt.Color(128,255,255));            break;        case START:            g.setColor(new java.awt.Color(255,0,255));            break;        case END:            g.setColor(new java.awt.Color(128,0,255));            break;        case LEN1:                        draw = false;            break;        case LEN10:            g.setColor(new java.awt.Color(33,233,0));            break;        case LEN50:            g.setColor(new java.awt.Color(255,128,128));            break;        case LEN100:            g.setColor(new java.awt.Color(255,255,128));            break;        case LEN150:            g.setColor(new java.awt.Color(128,255,128));            break;        default:break;        }        if(draw)            g.fillRect(startcol + colspan/4, startrow+rowspan/4, rowspan/2, colspan/2);    }    public void drawResult(Graphics g,int row,int col){        if(result == null)return;        int startrow = edge + rowspan*row;        int startcol = edge + colspan*col;        int r = result[row][col];        boolean draw = true;        if(r == 0)return;        if(r == 1)g.setColor(Color.WHITE);        if(r == 2)g.setColor(Color.YELLOW);        g.drawOval(startcol + colspan/2, startrow+rowspan/2, colspan/4, rowspan/4);    }    @Override    public void paint(Graphics g) {        super.paint(g);        g.setColor(Color.WHITE);        for(int i = 0;i < rows+1;i++){            g.drawLine(edge, edge + rowspan*i, gridPanelWidth - edge - 1, edge + rowspan*i);        }        for(int i = 0;i < cols+1;i++){            g.drawLine( edge + colspan*i, edge, edge + colspan*i, gridPanelHeight - edge - 1);        }        for(int i = 0; i < rows; i++){            for(int j = 0; j < cols;j++){                drawGrid(g, i, j);                drawResult(g,i,j);            }        }    }}

     

     


    最新回复(0)