Java Swing实现可视化可交互的A*算法演示

项目场景:

人工智能导论课程实验要求使用知识表示来实现模拟猴子摘香蕉过程
(但是我好像理解错了。。。,不过做都做了,就发出来吧),又因为个人对Java比较熟悉,所以决定使用Java Swing来实现这个实验


实现结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


项目代码

项目结构

在这里插入图片描述

项目代码

ButtonActionListener.java

import javax.swing.*;
import java.awt.event.ActionEvent;//转载不写原作者必司马,原作者@此号已废20
import java.awt.event.ActionListener;

public class ButtonActionListener implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        //System.out.println(e.getActionCommand());
        String cmd = e.getActionCommand();
        switch (cmd) {
            case Global.SET_MON:
                Global.action = Action.setMon;
                break;
            case Global.SET_BAN:
                Global.action = Action.setBan;
                break;
            case Global.SET_BOX:
                Global.action=Action.setBox;
                break;
            case Global.SET_WALL:
                Global.action = Action.setWall;
                break;
            case Global.RECOVERY:
                Global.action = Action.normal;
                Global.monNum=0;
                Global.banNum=0;
                Global.boxNum=0;
                JTable table = Global.window.getTable();//转载不写原作者必司马,原作者@此号已废20
                for (int i = 0; i < Global.ROW; i++) {
                    for (int j = 0; j < Global.COL; j++) {
                        table.setValueAt(State.normal,i,j);
                    }
                }
        }
        System.out.println(Global.action);

    }
}

Global.java

public class Global {

    public static final int ROW = 30;
    public static final int COL = 30;
    public static final int ROW_HEIGHT = 20;
    public static final int COL_WIDTH = 20;
    public static final String SET_MON = "设置猴子";
    public static final String SET_BAN = "设置香蕉";
    public static final String SET_BOX = "设置箱子";
    public static final String SET_WALL = "设置障碍";
    public static final String RECOVERY = "复位";
    public static final String RUN = "Run";
    public static final String DFS = "深度优先";
    public static final String BFS = "广度优先";
    public static final String A = "A*";
    public static Action action=Action.normal;
    public static Algorithm algorithm = Algorithm.A;
    public static Window window;//转载不写原作者必司马,原作者@此号已废20
    public static int monNum =0;
    public static int banNum =0;
    public static int boxNum = 0;
    public static int monRow = 0;
    public static int monCol =0;
    public static int banRow = 0;
    public static int banCol =0;
    public static int boxRow = 0;
    public static int boxCol =0;


}
enum Algorithm{
    DFS,//深度优先
    BFS,//广度优先
    A
}
enum Action{
    normal,
    setMon,
    setBan,
    setBox,
    setWall,
    Recovery,

}
enum State{
    normal,
    mon,
    ban,
    box,
    wall,
    road,
    search//转载不写原作者必司马,原作者@此号已废20
}

ListListener.java

import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;//转载不写原作者必司马,原作者@此号已废20


public class ListListener implements ListSelectionListener {


    @Override
    public void valueChanged(ListSelectionEvent e) {
        //System.out.println(
        String cmd = Global.window.getAlgorithms().getSelectedValue();
        System.out.println(cmd);
        switch (cmd){
            case Global.DFS:
                Global.algorithm=Algorithm.DFS;
                break;
            case Global.BFS:
                Global.algorithm=Algorithm.BFS;
                break;
            case Global.A:
                Global.algorithm=Algorithm.A;//转载不写原作者必司马,原作者@此号已废20
                break;
        }
    }
}

myTable.java

import javax.swing.*;
import java.awt.*;

public class myTable extends JTable {
    Color color = getForeground();

    public myTable(Object[][] rowData, Object[] columnNames) {
        super(rowData, columnNames);
    }

    //设置table中值不可编辑
    public boolean isCellEditable(int row,int col){
        return false;
    }//,转载不写原作者必司马,原作者@此号已废20
    @Override
    public java.awt.Component prepareRenderer(javax.swing.table.TableCellRenderer renderer, int row, int column) {
        int modelRow = convertRowIndexToModel(row);
        int modelColumn = convertColumnIndexToModel(column);
        java.awt.Component comp = super.prepareRenderer(renderer, row, column);
        if (!isRowSelected(modelRow)) {
            switch ((State)Global.window.getTable().getValueAt(modelRow,modelColumn)){
                case mon:
                    comp.setBackground(Color.orange);
                    break;
                case ban:
                    comp.setBackground(Color.yellow);
                    break;
                case box:
                    comp.setBackground(Color.magenta);//转载不写原作者必司马,原作者@此号已废20
                    break;
                case wall:
                    comp.setBackground(Color.BLACK);
                    break;
                case road:
                    comp.setBackground(Color.BLUE);
                    break;
                case search:
                    comp.setBackground(Color.cyan);
                    break;
                default:
                    comp.setBackground(Color.WHITE);
            }
        }
        return comp;
    }
}

RunListener.java

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;

public class RunListener implements ActionListener {//转载不写原作者必司马,原作者@此号已废20

    @Override
    public void actionPerformed(ActionEvent e) {
        Global.window.setTipText("开始运行");
        //System.out.println("233333333");
        if(!(Global.boxNum==1&&Global.banNum==1&&Global.monNum==1))return;
        Global.action=Action.normal;
        Runnable run=null;
        switch (Global.algorithm){
            case DFS:

            case BFS:

            case A:run = new A();
        }
        List<Point> road1 = run.run(Global.monRow,Global.monCol,Global.boxRow,Global.boxCol);
        System.out.println(road1);
        Thread t1 = new Thread(new java.lang.Runnable() {
            @Override
            public void run() {
                Global.window.setTipText("猴子向箱子寻找");
                Runnable.drawRoad(road1);
            }
        });
        t1.start();//转载不写原作者必司马,原作者@此号已废20

        List<Point> road2 = run.run(Global.boxRow,Global.boxCol,Global.banRow,Global.banCol);

        System.out.println(road2);
        Thread t2 = new Thread(new java.lang.Runnable() {
            @Override
            public void run() {
                try {
                    t1.join();
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
                Global.window.setTipText("猴子向香蕉寻找");
                Runnable.drawRoad(road2);
                Global.window.setTipText("猴子已找到香蕉");
            }
        });
        t2.start();

    }
}
class Point{
    public int row;
    public int col;
    public Point parent;
    public int F;
    public int G;
    public int H;
//转载不写原作者必司马,原作者@此号已废20
    @Override
    public String toString() {
        return "("+row+","+col+")->("+( parent==null?"null":parent.row)+","+(parent==null?"null": parent.col)+")"+F+","+G+","+H;
    }

    public Point(int row, int col, int G, int H, Point parent) {
        this.row = row;
        this.col = col;
        this.G=G;
        this.H = H;
        this.F = G+H;
        this.parent = parent;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;//转载不写原作者必司马,原作者@此号已废20
        Point point = (Point) o;
        return row == point.row && col == point.col;
    }

}


abstract class Runnable {
    abstract public List<Point> run(int startRow,int startCol,int endRow,int endCol);
    public static void drawRoad(List<Point> road){

                for (int i = 1; i < road.size()-1; i++) {
                    State state = (State) Global.window.getTable().getValueAt(road.get(i).row,road.get(i).col);
                    if(state==State.normal)
                        Global.window.getTable().setValueAt(State.search,road.get(i).row,road.get(i).col);
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }//转载不写原作者必司马,原作者@此号已废20
                Point p = road.get(road.size()-1);
                while (p.parent!=null){
                    p=p.parent;
                    State state= (State) Global.window.getTable().getValueAt(p.row,p.col);
                    if(state==State.normal||state==State.search)Global.window.getTable().setValueAt(State.road,p.row,p.col);
                }



    }
}
class A extends Runnable{

    @Override
    public List<Point> run(int startRow,int startCol,int endRow,int endCol) {
        //int startRow,startCol,endRow,endCol;
        Point end=null;
        List<Point> close = new ArrayList<Point>();
        List<Point> open = new ArrayList<Point>();
        Point start = new Point(startRow,startCol,0, 10*(Math.abs(startCol-endCol)+Math.abs(startRow-endRow)),null);
        open.add(start);
        while (!open.isEmpty()){
            Point min = open.get(0);
            close.add(min);//,转载不写原作者必司马,原作者@此号已废20
            System.out.println(min);
            //Global.window.getTable().setValueAt(State.road,min.row,min.col);
            open.remove(0);
            Set<Point> adjacentPoints= getAdjacentPoints(min,endRow,endCol);
            for (Point temp:
                    adjacentPoints) {
                if(close.contains(temp))continue;

                boolean flag =false;
                Point temp2=null;
                for (Point temp1:
                     open) {
                    if(temp1.equals(temp)){
                        flag=true;
                        temp2=temp1;
                    }
                }
                if (flag&&temp2!=null) {
                    if(temp.G< temp2.G){
                        open.remove(temp2);
                        open.add(temp);

                    }
                }else {
                    open.add(temp);
                }
            }

            Collections.sort(open, new Comparator<Point>() {
                @Override
                public int compare(Point o1, Point o2) {
                    return Integer.compare(o1.F, o2.F);
                }
            });
            end=null;
            for (Point temp:
                 open) {
                if(temp.row==endRow&&temp.col==endCol){
                    end=temp;//转载不写原作者必司马,原作者@此号已废20
                }
            }
            if(end!=null){
                close.add(end);
                break;
            }
        }
        return close;


    }
    public boolean isWalkable(int row,int col){
        if(row < 0 || row > Global.ROW - 1 || col < 0 || col > Global.COL - 1)return false;
        if(Global.window.getTable().getValueAt(row,col)==State.wall)return false;
        return true;
    }
    public Set<Point> getAdjacentPoints(Point point ,int endRow,int endCol){
        Set<Point> result = new HashSet<>();
        if(isWalkable(point.row+1,point.col+1))result.add(new Point(point.row+1,point.col+1, point.G+14, 10*(Math.abs(point.row+1-endRow)+Math.abs(point.col+1-endCol)),point));//转载不写原作者必司马,原作者@此号已废20
        if(isWalkable(point.row+1,point.col))result.add(new Point(point.row+1,point.col, point.G+10, 10*(Math.abs(point.row+1-endRow)+Math.abs(point.col-endCol)),point));
        if(isWalkable(point.row+1,point.col-1))result.add(new Point(point.row+1,point.col-1, point.G+14, 10*(Math.abs(point.row+1-endRow)+Math.abs(point.col-1-endCol)),point));
        if(isWalkable(point.row,point.col+1))result.add(new Point(point.row,point.col+1, point.G+10, 10*(Math.abs(point.row-endRow)+Math.abs(point.col+1-endCol)),point));
        if(isWalkable(point.row,point.col-1))result.add(new Point(point.row,point.col-1, point.G+10, 10*(Math.abs(point.row-endRow)+Math.abs(point.col-1-endCol)),point));
        if(isWalkable(point.row-1,point.col+1))result.add(new Point(point.row-1,point.col+1, point.G+14, 10*(Math.abs(point.row-1-endRow)+Math.abs(point.col+1-endCol)),point));
        if(isWalkable(point.row-1,point.col))result.add(new Point(point.row-1,point.col, point.G+10, 10*(Math.abs(point.row+1-endRow)+Math.abs(point.col-endCol)),point));
        if(isWalkable(point.row-1,point.col-1))result.add(new Point(point.row-1,point.col-1, point.G+14, 10*(Math.abs(point.row-1-endRow)+Math.abs(point.col-1-endCol)),point));
        return result;
    }

}

TableListener.java

import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class TableListener implements MouseListener {


    @Override
    public void mouseClicked(MouseEvent e) {//转载不写原作者必司马,原作者@此号已废20
        int col = Global.window.getTable().getSelectedColumn();
        int row = Global.window.getTable().getSelectedRow();
        //System.out.println("("+x+","+y+")");
        JTable table = Global.window.getTable();
        switch (Global.action){
            case setMon:
                if(table.getValueAt(row,col)==State.mon){
                    Global.monNum =0;
                    table.setValueAt(State.normal,row,col);
                    break;
                }
                if(Global.monNum ==0){
                    if(table.getValueAt(row,col)==State.ban){
                        Global.banNum =0;
                    }
                    if(table.getValueAt(row,col)==State.box){
                        Global.boxNum =0;
                    }
                    table.setValueAt(State.mon,row,col);
                    Global.monNum++;
                    Global.monRow=row;
                    Global.monCol=col;
                    Global.window.setTipText("猴子坐标已设置");
                }

                break;
            case setBan:
                if(table.getValueAt(row,col)==State.ban){
                    Global.banNum =0;
                    table.setValueAt(State.normal,row,col);
                    break;
                }
                if(Global.banNum ==0) {//转载不写原作者必司马,原作者@此号已废20
                    if ( table.getValueAt(row, col) == State.mon) {
                        Global.monNum = 0;
                    }
                    if ( table.getValueAt(row, col) == State.box) {
                        Global.boxNum = 0;
                    }
                    table.setValueAt(State.ban, row, col);
                    Global.banNum++;
                    Global.banRow = row;
                    Global.banCol=col;
                    Global.window.setTipText("香蕉坐标已设置");
                }
                break;
            case setBox:
                if(table.getValueAt(row,col)==State.box){
                    Global.boxNum =0;
                    table.setValueAt(State.normal,row,col);
                    break;
                }
                if(Global.boxNum ==0) {
                    if ( table.getValueAt(row, col) == State.mon) {
                        Global.monNum = 0;
                    }
                    if ( table.getValueAt(row, col) == State.ban) {
                        Global.banNum = 0;
                    }
                    table.setValueAt(State.box, row, col);
                    Global.boxNum++;
                    Global.boxRow=row;//转载不写原作者必司马,原作者@此号已废20
                    Global.boxCol=col;
                    Global.window.setTipText("盒子坐标已设置");
                }
                break;
            case setWall:
                table.setValueAt(State.wall,row,col);
                if ( table.getValueAt(row, col) == State.mon) {
                    Global.monNum = 0;
                }
                if ( table.getValueAt(row, col) == State.ban) {
                    Global.banNum = 0;
                }
                if ( table.getValueAt(row, col) == State.box) {
                    Global.boxNum = 0;
                }
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {


    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }
}

TestGUI.java

public class TestGUI {
    public static void main(String[] args) {
        Global.window = new Window();
        Global.window.init();
    }
}

Window.java

import javax.swing.*;
import javax.swing.event.TableModelListener;//转载不写原作者必司马,原作者@此号已废20
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import java.util.Arrays;

import static javax.swing.JFrame.EXIT_ON_CLOSE;

public class Window {
    private JFrame frame;
    private JPanel panel;
    private Integer[] names;
    private State[][] data;
    private JTable table;
    private JButton setMon;
    private JButton setBan;
    private JButton setBox;
    private JButton setWall;
    private JButton run;
    private JButton recovery;
    private JList<String> algorithms;
    private JLabel algLabel;
    private JLabel tip;

    public boolean init(){
        //创建窗口
        frame = new JFrame("猴子摘香蕉模拟");
        frame.setSize(800, 600);//转载不写原作者必司马,原作者@此号已废20
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        //frame.setLocation(200, 200);
        frame.setLayout(null);
        frame.setResizable(false);
        //创建panel存放table
        panel = new JPanel();
        panel.setBounds(0,0,Global.COL_WIDTH*Global.COL,Global.ROW_HEIGHT*Global.ROW);
        frame.add(panel);
        //新建table
        names = new Integer[Global.COL];
        Arrays.fill(names, 0);
        data = new State[Global.ROW][Global.COL];
        for (int i = 0; i < Global.ROW; i++) {
            for (int j = 0; j < Global.COL; j++) {
                data[i][j]=State.normal;
            }
        }
        table = new myTable(data,names);

        //设置table的行高列宽
        table.setRowHeight(Global.ROW_HEIGHT);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        for (int j = 0; j < table.getColumnCount(); j++) {//转载不写原作者必司马,原作者@此号已废20
            table.getColumnModel().getColumn(j).setPreferredWidth(Global.COL_WIDTH);
        }
        table.addMouseListener(new TableListener());
        panel.add(table);
        //设置按钮
        recovery = new JButton(Global.RECOVERY);
        recovery.setBounds(Global.COL_WIDTH*Global.COL+30,Global.ROW_HEIGHT*Global.ROW_HEIGHT-150,140,40);
        recovery.addActionListener(new ButtonActionListener());
        frame.add(recovery);
        setMon = new JButton(Global.SET_MON);
        setMon.setBounds(Global.COL_WIDTH*Global.COL+30,Global.ROW_HEIGHT*Global.ROW_HEIGHT-100,140,40);
        setMon.addActionListener(new ButtonActionListener());
        frame.add(setMon);
        setBan = new JButton(Global.SET_BAN);
        setBan.setBounds(Global.COL_WIDTH*Global.COL+30,Global.ROW_HEIGHT*Global.ROW_HEIGHT-50,140,40);
        setBan.addActionListener(new ButtonActionListener());
        frame.add(setBan);
        setBox = new JButton(Global.SET_BOX);
        setBox.setBounds(Global.COL_WIDTH*Global.COL+30,Global.ROW_HEIGHT*Global.ROW_HEIGHT,140,40);
        setBox.addActionListener(new ButtonActionListener());
        frame.add(setBox);
        setWall = new JButton(Global.SET_WALL);
        setWall.setBounds(Global.COL_WIDTH*Global.COL+30,Global.ROW_HEIGHT*Global.ROW_HEIGHT+50,140,40);
        setWall.addActionListener(new ButtonActionListener());
        frame.add(setWall);
        run = new JButton(Global.RUN);
        run.setBounds(Global.COL_WIDTH*Global.COL+30,Global.ROW_HEIGHT*Global.ROW_HEIGHT+100,140,40);
        run.addActionListener(new RunListener());
        frame.add(run);
        //设置列表
        String[] al = new String[]{"A*算法"};
        algorithms = new JList<>(al);
        algorithms.setFixedCellHeight(40);
        algorithms.setBounds(Global.COL_WIDTH*Global.COL+30,20,140,150);
        algorithms.addListSelectionListener(new ListListener());
        frame.add(algorithms);
        //设置label
        algLabel = new JLabel("已选择A*算法");//转载不写原作者必司马,原作者@此号已废20
        algLabel.setBounds(Global.COL_WIDTH*Global.COL+40,170,140,50);
        frame.add(algLabel);
        tip = new JLabel("请设置坐标");
        tip.setBounds(Global.COL_WIDTH*Global.COL+40,200,140,50);
        frame.add(tip);
        frame.setVisible(true);
        return true;
    }
    public void setAlgoLabelText(String str){
        algLabel.setText(str);
    }
    public void setTipText(String str){
        tip.setText(str);
    }
    public JFrame getFrame() {
        return frame;
    }

    public void setFrame(JFrame frame) {
        this.frame = frame;
    }

    public JPanel getPanel() {
        return panel;
    }

    public void setPanel(JPanel panel) {
        this.panel = panel;
    }

    public Integer[] getNames() {
        return names;
    }

    public void setNames(Integer[] names) {
        this.names = names;
    }

    public State[][] getData() {
        return data;
    }

    public void setData(State[][] data) {
        this.data = data;//转载不写原作者必司马,原作者@此号已废20
    }

    public JTable getTable() {
        return table;
    }

    public void setTable(JTable table) {
        this.table = table;
    }

    public JButton getSetMon() {
        return setMon;
    }

    public void setSetMon(JButton setMon) {
        this.setMon = setMon;
    }

    public JButton getSetBan() {
        return setBan;
    }

    public void setSetBan(JButton setBan) {
        this.setBan = setBan;
    }
//转载不写原作者必司马,原作者@此号已废20
    public JButton getSetWall() {
        return setWall;
    }

    public void setSetWall(JButton setWall) {
        this.setWall = setWall;
    }

    public JButton getRun() {
        return run;
    }

    public void setRun(JButton run) {
        this.run = run;
    }

    public JList<String> getAlgorithms() {
        return algorithms;
    }

    public void setAlgorithms(JList<String> algorithms) {
        this.algorithms = algorithms;//转载不写原作者必司马,原作者@此号已废20
    }

    public JLabel getAlgLabel() {
        return algLabel;
    }

    public void setAlgLabel(JLabel algLabel) {
        this.algLabel = algLabel;
    }
}

项目总结

整个项目的结构不太好,而且没有用上一些好的设计方式,但是事急从权也只能这样,好在项目可以正常运行。其中还留了一些接口等待扩展(主要是关于算法的实现,目前只有A*算法实现了),但是精力时间都有限,得等以后再说了。


参考

A*算法详解(讲的一级棒 )
java swing刷新_Swing界面刷新问题(转)
还有很多关于Java Swing的参考,但是太多了也很杂,就没有进行记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值