Lee算法(Java)的问题

时间:2019-11-29 21:51:45

标签: java algorithm interface

这是Java中实现Lee的算法。问题是回溯中的偏差(在屏幕截图上):

how it work and how it should work 1

how it work and how it should work 2

请帮忙吗?

import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.JComboBox;

public class Main {

JFrame frame;
//GENERAL VARIABLES
private int cells = 20;
private int delay = 30;

private int startx = -1;
private int starty = -1;
private int finishx = -1;
private int finishy = -1;
private int tool = 0;
private int checks = 0;
private int length = 0;
private int WIDTH = 850;
private final int HEIGHT = 650;
private final int MSIZE = 600;
private int CSIZE = MSIZE/cells;
//UTIL ARRAYS
private String[] tools = {"Start","Finish","Wall", "Eraser"};
//BOOLEANS
private boolean solving = false;
//UTIL
Node[][] map;
Algorithm Alg = new Algorithm();
Random r = new Random();
//SLIDERS
JSlider size = new JSlider(1,5,4);
JSlider speed = new JSlider(0,500,delay);

//LABELS
JLabel toolL = new JLabel("Toolbox");
JLabel sizeL = new JLabel("Size:");
JLabel cellsL = new JLabel(cells+"x"+cells);
JLabel delayL = new JLabel("Delay:");
JLabel msL = new JLabel(delay+"ms");

JLabel checkL = new JLabel("Checks: "+checks);
JLabel lengthL = new JLabel("Path Length: "+length);
//BUTTONS
JButton searchB = new JButton("Search");
JButton resetB = new JButton("Reset");
JButton clearMapB = new JButton("Clear");
//DROP DOWN
JComboBox toolBx = new JComboBox(tools);
//PANELS
JPanel toolP = new JPanel();
//CANVAS
Map canvas;

public static void main(String[] args) {    //MAIN METHOD
    new Main();
}

public Main() { //CONSTRUCTOR
    clearMap();
    initialize();
}


public void clearMap() {    //CLEAR MAP
    finishx = -1;   //RESET THE START AND FINISH
    finishy = -1;
    startx = -1;
    starty = -1;
    map = new Node[cells][cells];   //CREATE NEW MAP OF NODES
    for(int x = 0; x < cells; x++) {
        for(int y = 0; y < cells; y++) {
            map[x][y] = new Node(3,x,y);    //SET ALL NODES TO EMPTY
        }
    }
    reset();    //RESET SOME VARIABLES
}

public void resetMap() {    //RESET MAP
    for(int x = 0; x < cells; x++) {
        for(int y = 0; y < cells; y++) {
            Node current = map[x][y];
            if(current.getType() == 4 || current.getType() == 5)    //CHECK TO SEE IF CURRENT NODE IS EITHER CHECKED OR FINAL PATH
                map[x][y] = new Node(3,x,y);    //RESET IT TO AN EMPTY NODE
        }
    }
    if(startx > -1 && starty > -1) {    //RESET THE START AND FINISH
        map[startx][starty] = new Node(0,startx,starty);
        map[startx][starty].setHops(0);
    }
    if(finishx > -1 && finishy > -1)
        map[finishx][finishy] = new Node(1,finishx,finishy);
    reset();    //RESET SOME VARIABLES
}

private void initialize() { //INITIALIZE THE GUI ELEMENTS
    frame = new JFrame();
    frame.setVisible(true);
    frame.setResizable(false);
    frame.setSize(WIDTH,HEIGHT);
    frame.setTitle("Lee Algorithm");
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(null);

    int space = 25;
    int buff = 45;

    toolP.setLayout(null);
    toolP.setBounds(10,10,210,600);

    searchB.setBounds(40,space, 120, 25);
    toolP.add(searchB);
    space+=buff;

    resetB.setBounds(40,space,120,25);
    toolP.add(resetB);
    space+=buff;


    clearMapB.setBounds(40,space, 120, 25);
    toolP.add(clearMapB);
    space+=40;

    toolL.setBounds(40,space,120,25);
    toolP.add(toolL);
    space+=25;

    toolBx.setBounds(40,space,120,25);
    toolP.add(toolBx);
    space+=buff;

    sizeL.setBounds(15,space,40,25);
    toolP.add(sizeL);
    size.setMajorTickSpacing(10);
    size.setBounds(50,space,100,25);
    toolP.add(size);
    cellsL.setBounds(160,space,40,25);
    toolP.add(cellsL);
    space+=buff;

    delayL.setBounds(15,space,50,25);
    toolP.add(delayL);
    speed.setMajorTickSpacing(5);
    speed.setBounds(50,space,100,25);
    toolP.add(speed);
    msL.setBounds(160,space,40,25);
    toolP.add(msL);
    space+=buff;


    checkL.setBounds(15,space,100,25);
    toolP.add(checkL);
    space+=buff;

    lengthL.setBounds(15,space,100,25);
    toolP.add(lengthL);

    frame.getContentPane().add(toolP);

    canvas = new Map();
    canvas.setBounds(230, 10, MSIZE+1, MSIZE+1);
    frame.getContentPane().add(canvas);

    searchB.addActionListener(new ActionListener() {        //ACTION LISTENERS
        @Override
        public void actionPerformed(ActionEvent e) {
            reset();
            if((startx > -1 && starty > -1) && (finishx > -1 && finishy > -1))
                solving = true;
        }
    });
    resetB.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            resetMap();
            Update();
        }
    });

    clearMapB.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            clearMap();
            Update();
        }
    });

    toolBx.addItemListener(new ItemListener() {
        @Override
        public void itemStateChanged(ItemEvent e) {
            tool = toolBx.getSelectedIndex();
        }
    });
    size.addChangeListener(new ChangeListener() {
        @Override
        public void stateChanged(ChangeEvent e) {
            cells = size.getValue()*5;
            clearMap();
            reset();
            Update();
        }
    });
    speed.addChangeListener(new ChangeListener() {
        @Override
        public void stateChanged(ChangeEvent e) {
            delay = speed.getValue();
            Update();
        }
    });

    startSearch();  //START STATE
}

public void startSearch() { //START STATE
    if(solving)
    {
      Alg.LeeAlg();
    }
    pause();    //PAUSE STATE
}

public void pause() {   //PAUSE STATE
    int i = 0;
    while(!solving) {
        i++;
        if(i > 500)
            i = 0;
        try {
            Thread.sleep(1);
        } catch(Exception e) {}
    }
    startSearch();  //START STATE
}

public void Update() {  //UPDATE ELEMENTS OF THE GUI

    CSIZE = MSIZE/cells;
    canvas.repaint();
    cellsL.setText(cells+"x"+cells);
    msL.setText(delay+"ms");
    lengthL.setText("Path Length: "+length);

    checkL.setText("Checks: "+checks);
}

public void reset() {   //RESET METHOD
    solving = false;
    length = 0;
    checks = 0;
}

public void delay() {   //DELAY METHOD
    try {
        Thread.sleep(delay);
    } catch(Exception e) {}
}

class Map extends JPanel implements MouseListener, MouseMotionListener{ //MAP CLASS

    public Map() {
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public void paintComponent(Graphics g) {    //REPAINT
        super.paintComponent(g);
        for(int x = 0; x < cells; x++) {    //PAINT EACH NODE IN THE GRID
            for(int y = 0; y < cells; y++) {
                switch(map[x][y].getType()) {
                    case 0:
                        g.setColor(Color.GREEN);
                        break;
                    case 1:
                        g.setColor(Color.BLUE);
                        break;
                    case 2:
                        g.setColor(Color.BLACK);
                        break;
                    case 3:
                        g.setColor(Color.WHITE);
                        break;
                    case 4:
                        g.setColor(Color.GRAY);
                        break;
                    case 5:
                        g.setColor(Color.YELLOW);
                        break;
                }
                g.fillRect(x*CSIZE,y*CSIZE,CSIZE,CSIZE);
                g.setColor(Color.BLACK);
                g.drawRect(x*CSIZE,y*CSIZE,CSIZE,CSIZE);
            }
        }
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        try {
            int x = e.getX()/CSIZE;
            int y = e.getY()/CSIZE;
            Node current = map[x][y];
            if((tool == 2 || tool == 3) && (current.getType() != 0 && current.getType() != 1))
                current.setType(tool);
            Update();
        } catch(Exception z) {}
    }

    @Override
    public void mouseMoved(MouseEvent e) {}

    @Override
    public void mouseClicked(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

    @Override
    public void mousePressed(MouseEvent e) {
        resetMap(); //RESET THE MAP WHENEVER CLICKED
        try {
            int x = e.getX()/CSIZE; //GET THE X AND Y OF THE MOUSE CLICK IN RELATION TO THE SIZE OF THE GRID
            int y = e.getY()/CSIZE;
            Node current = map[x][y];
            switch(tool) {
                case 0: {   //START NODE
                    if(current.getType()!=2) {  //IF NOT WALL
                        if(startx > -1 && starty > -1) {    //IF START EXISTS SET IT TO EMPTY
                            map[startx][starty].setType(3);
                            map[startx][starty].setHops(-1);
                        }
                        current.setHops(0);
                        startx = x; //SET THE START X AND Y
                        starty = y;
                        current.setType(0); //SET THE NODE CLICKED TO BE START
                    }
                    break;
                }
                case 1: {//FINISH NODE
                    if(current.getType()!=2) {  //IF NOT WALL
                        if(finishx > -1 && finishy > -1)    //IF FINISH EXISTS SET IT TO EMPTY
                            map[finishx][finishy].setType(3);
                        finishx = x;    //SET THE FINISH X AND Y
                        finishy = y;
                        current.setType(1); //SET THE NODE CLICKED TO BE FINISH
                    }
                    break;
                }
                default:
                    if(current.getType() != 0 && current.getType() != 1)
                        current.setType(tool);
                    break;
            }
            Update();
        } catch(Exception z) {} //EXCEPTION HANDLER
    }

    @Override
    public void mouseReleased(MouseEvent e) {}
}

class Algorithm {      // ALGORITHM CLASS
    public void LeeAlg() {
        ArrayList<Node> priority = new ArrayList<Node>();    //CREATE A PRIORITY QUE
        priority.add(map[startx][starty]);    //ADD THE START TO THE QUE
        while (solving) {
            if (priority.size() <= 0) {    //IF THE QUE IS 0 THEN NO PATH CAN BE FOUND
                solving = false;
                break;
            }
            int hops = priority.get(0).getHops() + 1;    //INCREMENT THE HOPS VARIABLE
            ArrayList<Node> explored = exploreNeighbors(priority.get(0), hops);    //CREATE AN ARRAYLIST OF NODES THAT WERE EXPLORED
            if (explored.size() > 0) {
                priority.remove(0);    //REMOVE THE NODE FROM THE QUE
                priority.addAll(explored);    //ADD ALL THE NEW NODES TO THE QUE
                Update();
                delay();
            } else {    //IF NO NODES WERE EXPLORED THEN JUST REMOVE THE NODE FROM THE QUE
                priority.remove(0);
            }
        }
    }

    public ArrayList<Node> exploreNeighbors(Node current, int hops) {   //EXPLORE NEIGHBORS
        ArrayList<Node> explored = new ArrayList<Node>();   //LIST OF NODES THAT HAVE BEEN EXPLORED
        for(int a = -1; a <= 1; a++) {
            for(int b = -1; b <= 1; b++) {
                int xbound = current.getX()+a;
                int ybound = current.getY()+b;
                if((xbound > -1 && xbound < cells) && (ybound > -1 && ybound < cells)) {    //MAKES SURE THE NODE IS NOT OUTSIDE THE GRID
                    Node neighbor = map[xbound][ybound];
                    if((neighbor.getHops()==-1 || neighbor.getHops() > hops) && neighbor.getType()!=2) {    //CHECKS IF THE NODE IS NOT A WALL AND THAT IT HAS NOT BEEN EXPLORED
                        explore(neighbor, current.getX(), current.getY(), hops);    //EXPLORE THE NODE
                        explored.add(neighbor); //ADD THE NODE TO THE LIST
                    }
                }
            }
        }
        return explored;
    }

    public void explore(Node current, int lastx, int lasty, int hops) { //EXPLORE A NODE
        if(current.getType()!=0 && current.getType() != 1)  //CHECK THAT THE NODE IS NOT THE START OR FINISH
            current.setType(4); //SET IT TO EXPLORED
        current.setLastNode(lastx, lasty);  //KEEP TRACK OF THE NODE THAT THIS NODE IS EXPLORED FROM
        current.setHops(hops);  //SET THE HOPS FROM THE START
        checks++;
        if(current.getType() == 1) {    //IF THE NODE IS THE FINISH THEN BACKTRACE TO GET THE PATH
            backtrace(current.getLastX(), current.getLastY(),hops);
        }
    }

    public void backtrace(int lx, int ly, int hops) {   //BACKTRACE
        length = hops;
        while(hops > 1) {   //BACKTRACE FROM THE END OF THE PATH TO THE START
            Node current = map[lx][ly];
            current.setType(5);
            lx = current.getLastX();
            ly = current.getLastY();
            hops--;
        }
        solving = false;
    }
}

class Node {

    // 0 = start, 1 = finish, 2 = wall, 3 = empty, 4 = checked, 5 = finalpath
    private int cellType = 0;
    private int hops;
    private int x;
    private int y;
    private int lastX;
    private int lastY;

    public Node(int type, int x, int y) {   //CONSTRUCTOR
        cellType = type;
        this.x = x;
        this.y = y;
        hops = -1;
    }

    public int getX() {return x;}       //GET METHODS
    public int getY() {return y;}
    public int getLastX() {return lastX;}
    public int getLastY() {return lastY;}
    public int getType() {return cellType;}
    public int getHops() {return hops;}

    public void setType(int type) {cellType = type;}        //SET METHODS
    public void setLastNode(int x, int y) {lastX = x; lastY = y;}
    public void setHops(int hops) {this.hops = hops;}
    }
 }

也就是说,地图上的最短路径在侧面某处,并且应该在一条直线上。代码中应纠正什么?

1 个答案:

答案 0 :(得分:0)

问题是,根据算法,给出的答案与海峡线一样好。怪异的对角线路径和海峡所需路径都需要4个步骤才能达到目标,因此它们都是相等的。要解决这个问题,您应该增加权重。当您沿对角线移动时,跳数不一定总是增加1,而是增加1.4(sqrt(2))。这样,在对角线上移动就具有权重,并且所需的海峡路径将是最快的(就像在现实世界中一样)。