GUI(2) 迷宫问题

来源:互联网 发布:网络基础知识入门ip 编辑:程序博客网 时间:2024/06/07 03:40

迷宫

  • 转载自:http://zpsailor.iteye.com/blog/651141
  • 使用swing组件的一个项目
  • awt 和 util 包里的list冲突,util不能写成util.*;
  • @SuppressWarnings(“serial”) //告诉编译器忽略指定的警告,不用在编译完成后出现警告信息
  • public class Maze extends JFrame implements ActionListener 自身就是监听器
  • 结合了图的深度优先遍历,高效的产生复杂的迷宫
  • 二维数组,0、1矩阵表示迷宫
  • 使用java.awt.Timer类来代替时间的线程
  • 使用java.awt.Canvas类来描述每个迷宫格子,每次只渲染两个小格字就可以了

迷宫生成算法

  • 既然要通过图的深度优先遍历来生成迷宫,我们首先需要的是一张图,这张图的节点中,要包含迷宫的开始点和结束点。在我们的算法中,最初构造了这样一张图:
  • 这里写图片描述
  • 在这张图中,每一个白色小块表示图中的一个节点,而横向和竖向上的红色方块是这个图的边。在整个图中,白色的部分表示通道,而红色部分表示的是墙壁。我们规定左上角是迷宫的入口,右下角是迷宫的出口。在这种情况下,我们只需要从入口处开始,采用深度优先遍历方法,遍历这个图,在遍历的过程中,当从一个节点移动到另一个节点的过程中,将其移动过程中的边变成通道,这样遍历完图后,就将产生一个类似下图的迷宫:
  • 这里写图片描述
  • 这样,我们的迷宫便生成好了。在这个过程中,需要用到递归算法和回溯法。

走迷宫的算法

  • 在走迷宫的过程中,需要用到两个列表结构willvisit和 comed,分别记录了当前可以移动到的位置和已经走过的位置。在willvisit中不包含comed中的记录的位置。这样利用回溯法,在当前位置的willvisit中随机选取一个位置移动,并将移动过的位置记录到comed的尾部。当当前所在位置不能产生下一个移动时,将当前位置添加到comed的头部,从comed的尾部取出一个位置,然后将这个位置作为当前位置。再判断能否移动下一步,依次这样移动,直到移动到出口处。

jframe.setDefaultCloseOperation(int operation):

  • 设置用户在此窗体上发起 “close” 时默认执行的操作。方法中的参数解释如下:
  • 为“0”或DO_NOTHING_ON_CLOSE:
  • (在 WindowConstants 中定义):不执行任何操作;要求程序在已注册的WindowListener 对象的 windowClosing 方法中处理该操作。
  • 比如实例程序代码中更改为f.setDefaultCloseOperation(f. DO_NOTHING_ON_CLOSE);或者f.setDefaultCloseOperation(0),然后查看效果,可以发现窗口无法关闭,下面是相同测试方法,不再解释了。
  • 为“1”或HIDE_ON_CLOSE
  • 调用任意已注册的 WindowListener 对象后自动隐藏该窗体。此时没有关闭程序,只是将程序界面隐藏了。可以打开任务管理器,可以看到一个叫“java.exe”的进程(如果调试运行了多个java程序,则会看到多个“java.exe”的进程),如果此时用EditPlus测试程序,会发现当单击窗口的关闭按钮关闭窗口后,却无法再次对程序进行调试,因为程序线程没有关闭,在任务管理器中关闭java.exe(如果有多个“java.exe”的进程,则先都关闭掉,再来测试该问题)基础后,EditPlus才可以重新编译改程序。
  • 为“2”或DISPOSE_ON_CLOSE
  • 调用任意已注册 WindowListener 的对象后自动隐藏并释放该窗体。但继续运行应用程序,释放了窗体中占用的资源。
  • 为“3”EXIT_ON_CLOSE(在 JFrame 中定义):
  • 使用 System exit 方法退出应用程序。仅在应用程序中使用。结束了应用程序。
  • 默认情况下,该值被设置为 HIDE_ON_CLOSE。

@SuppressWarnings(“serial”)

  • 简介:java.lang.SuppressWarnings是J2SE 5.0中标准的Annotation之一。可以标注在类、字段、方法、参数、构造方法,以及局部变量上。
  • 作用:告诉编译器忽略指定的警告,不用在编译完成后出现警告信息。
  • 使用:
  • @SuppressWarnings(“”)
  • @SuppressWarnings({})
  • @SuppressWarnings(value={})


  • 根据sun的官方文档描述:

  • value - 将由编译器在注释的元素中取消显示的警告集。允许使用重复的名称。忽略第二个和后面出现的名称。出现未被识别的警告名不是 错误:编译器必须忽略无法识别的所有警告名。但如果某个注释包含未被识别的警告名,那么编译器可以随意发出一个警告。
  • 各编译器供应商应该将它们所支持的警告名连同注释类型一起记录。鼓励各供应商之间相互合作,确保在多个编译器中使用相同的名称。
  • @SuppressWarnings(“unchecked”)
  • 告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
  • @SuppressWarnings(“serial”)
  • 如果编译器出现这样的警告信息:The serializable class WmailCalendar does not declare a static final serialVersionUID field of type long 使用这个注释将警告信息去掉。
  • @SuppressWarnings(“deprecation”)
  • 如果使用了使用@Deprecated注释的方法,编译器将出现警告信息。 使用这个注释将警告信息去掉。
  • @SuppressWarnings(“unchecked”, “deprecation”)
  • 告诉编译器同时忽略unchecked和deprecation的警告信息。
  • @SuppressWarnings(value={“unchecked”, “deprecation”})
  • 等同于@SuppressWarnings(“unchecked”, “deprecation”)

Maze.java

import java.awt.*;import java.awt.event.*;import java.util.ArrayList;import java.util.LinkedList;import java.util.List;import java.util.TimerTask; //这里不能写成java.util.*; 因为awt包里面也有List,会冲突import javax.swing.*;@SuppressWarnings("serial") // 告诉编译器忽略指定的警告,不用在编译完成后出现警告信息public class Maze extends JFrame implements ActionListener {    private int ROW = 25;// ROW 和COL目前暂定只能是奇数    private int COL = 25;    private JPanel panel;      private JPanel northPanel;      private JPanel centerPanel;      private MazeGrid grid[][];      private JButton restart;      private JButton dostart;      private List<String> willVisit = new ArrayList<String>(); // 记录了当前可以移动到的位置                                                              // ,在willvisit中不包含comed中的记录的位置    private List<String> visited = new ArrayList<String>();    private LinkedList<String> comed = new LinkedList<String>(); // 已经走过的位置    private long startTime;    private long endTime;    public Maze() {        init();        this.setTitle("回溯法--走迷宫");        this.add(panel);        this.pack(); // 不加pack就只剩标题栏了        this.setVisible(true);        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 用户单击窗口的关闭按钮时程序执行的操作    }    public void init() {        panel = new JPanel();          northPanel = new JPanel();          centerPanel = new JPanel();          panel.setLayout(new BorderLayout());          restart = new JButton("重新生成迷宫");          dostart = new JButton("开始走迷宫");          grid = new MazeGrid[ROW][COL];          centerPanel.setLayout(new GridLayout(ROW, COL, 1, 1));        centerPanel.setBackground(new Color(0, 0, 0));        northPanel.add(restart);        northPanel.add(dostart);        dostart.addActionListener(this);        restart.addActionListener(this);        for (int i = 0; i < grid.length; i++)            for (int j = 0; j < grid[i].length; j++) {                if (j % 2 == 0 && i % 2 == 0)                    grid[i][j] = new MazeGrid(true, 20, 20);                else                    grid[i][j] = new MazeGrid(false, 20, 20);            }        grid[0][0].setVisited(true);        grid[0][0].setPersonCome(true);        grid[0][0].setStart(true);        visited.add("0#0");        grid[ROW - 1][COL - 1].setEnd(true);        grid = createMap(grid, 0, 0);        for (int i = 0; i < grid.length; i++)            for (int j = 0; j < grid[i].length; j++) {                grid[i][j].repaint();                centerPanel.add(grid[i][j]);            }        panel.add(northPanel, BorderLayout.NORTH);        panel.add(centerPanel, BorderLayout.CENTER);    }    public MazeGrid[][] createMap(MazeGrid mazeGrid[][], int x, int y) {        int visitX = 0;        int visitY = 0;        if (x - 2 >= 0) {            if (!mazeGrid[x - 2][y].isVisited()) {                willVisit.add((x - 2) + "#" + y);            }        }        if (x + 2 < COL) {            if (!mazeGrid[x + 2][y].isVisited()) {                willVisit.add((x + 2) + "#" + y);            }        }        if (y - 2 >= 0) {            if (!mazeGrid[x][y - 2].isVisited()) {                willVisit.add(x + "#" + (y - 2));            }        }        if (y + 2 < ROW) {            if (!mazeGrid[x][y + 2].isVisited()) {                willVisit.add(x + "#" + (y + 2));            }        }        if (!willVisit.isEmpty()) {            int visit = (int) (Math.random() * willVisit.size());            String id = willVisit.get(visit);            visitX = Integer.parseInt(id.split("#")[0]);            visitY = Integer.parseInt(id.split("#")[1]);            mazeGrid[(visitX + x) / 2][(visitY + y) / 2].setMark(true);            mazeGrid[visitX][visitY].setVisited(true);            if (!visited.contains(id)) {// 将这个点加到已访问中去                visited.add(id);            }            willVisit.clear();            createMap(mazeGrid, visitX, visitY);        } else {            if (!visited.isEmpty()) {                String id = visited.remove(visited.size() - 1);// 取出最后一个元素                visitX = Integer.parseInt(id.split("#")[0]);                visitY = Integer.parseInt(id.split("#")[1]);                mazeGrid[visitX][visitY].setVisited(true);                createMap(mazeGrid, visitX, visitY);            }        }        return mazeGrid;    }    public String goMaze(MazeGrid mazeGrid[][], int x, int y) {        int comeX = 0;        int comeY = 0;        // left        if (x - 1 >= 0) {            if (mazeGrid[x - 1][y].isMark()) {                if (!comed.contains((x - 1) + "#" + y))                    willVisit.add((x - 1) + "#" + y);            }        }        // right        if (x + 1 < COL) {            if (mazeGrid[x + 1][y].isMark()) {                if (!comed.contains((x + 1) + "#" + y))                    willVisit.add((x + 1) + "#" + y);            }        }        // up        if (y - 1 >= 0) {            if (mazeGrid[x][y - 1].isMark()) {                if (!comed.contains(x + "#" + (y - 1)))                    willVisit.add(x + "#" + (y - 1));            }        }        // down        if (y + 1 < ROW) {            if (mazeGrid[x][y + 1].isMark()) {                if (!comed.contains(x + "#" + (y + 1)))                    willVisit.add(x + "#" + (y + 1));            }        }        if (!willVisit.isEmpty()) {            int visit = (int) (Math.random() * willVisit.size());            String id = willVisit.get(visit);            comeX = Integer.parseInt(id.split("#")[0]);            comeY = Integer.parseInt(id.split("#")[1]);            mazeGrid[x][y].setPersonCome(false);            mazeGrid[comeX][comeY].setPersonCome(true);            mazeGrid[x][y].repaint();            mazeGrid[comeX][comeY].repaint();            willVisit.clear();            comed.add(x + "#" + y);        } else {            if (!comed.isEmpty()) {                String id = comed.removeLast();                comeX = Integer.parseInt(id.split("#")[0]);                comeY = Integer.parseInt(id.split("#")[1]);                mazeGrid[x][y].setPersonCome(false);                mazeGrid[comeX][comeY].setPersonCome(true);                mazeGrid[x][y].repaint();                mazeGrid[comeX][comeY].repaint();                comed.addFirst(x + "#" + y);            }        }        return comeX + "#" + comeY;    }    int comeX = 0;    int comeY = 0;    @Override    public void actionPerformed(ActionEvent e) {        if (e.getActionCommand().equals("重新生成迷宫")) {            refreshMap(grid);        } else if (e.getActionCommand().equals("开始走迷宫")) {            startTime = System.currentTimeMillis();            dostart.setVisible(false);            restart.setText("禁止刷新");            int delay = 1000;            int period = 500;// 循环间隔            java.util.Timer timer = new java.util.Timer();            timer.scheduleAtFixedRate(new TimerTask() {                public void run() {                    if (grid[ROW - 1][COL - 1].isPersonCome()) {                        endTime = System.currentTimeMillis();                        JOptionPane.showMessageDialog(null, "已经走出迷宫,耗时" + (endTime - startTime) / 1000 + "秒", "消息提示",                                JOptionPane.ERROR_MESSAGE);                        this.cancel();                        restart.setText("重新生成迷宫");                    } else {                        String id = goMaze(grid, comeX, comeY);                        comeX = Integer.parseInt(id.split("#")[0]);                        comeY = Integer.parseInt(id.split("#")[1]);                    }                }            }, delay, period);        }    }    public void refreshMap(MazeGrid mazeGrid[][]) {        comeX = 0;        comeY = 0;        willVisit.clear();        visited.clear();        comed.clear();        this.remove(panel);        init();        this.add(panel);        this.pack();        this.setVisible(true);    }    public static void main(String args[]) {        long start = System.currentTimeMillis();        new Maze();        long end = System.currentTimeMillis();        System.out.println("使用ArrayList生成迷宫耗时:" + (end - start) + "毫秒");    }}

MazeGrid.java

import java.awt.*;@SuppressWarnings("serial")  public class MazeGrid extends Canvas {  //Canvas控件代表一个矩形区域,应用程序可以画的东西,或者可以由用户创建的接收输入。                                    //用法类似与Frame    private boolean mark;// 标记是否是通路,TRUE为通路,FALSE为不通      private boolean isVisited;// 标记是否是访问过的,这是在生成迷宫的时候判断的。      private boolean isPersonCome;// 标记是否已经走过      private boolean isStart;// 判断是否为入口      private boolean isEnd;// 判断是否为出口      public MazeGrid() {          this.setBackground(new Color(120, 0, 0));          this.setSize(25, 25);      }      public MazeGrid(boolean mark, int width, int height) {          this.mark = mark;          this.setSize(width, height);          if (mark == true) {              this.setBackground(new Color(255, 255, 255));          } else {              this.setBackground(new Color(120, 0, 0));          }      }      public boolean isMark() {          return mark;      }      public void setMark(boolean mark) {          this.mark = mark;      }      public void paint(Graphics g) {          if (this.mark) {              if (this.isStart || this.isEnd) {                  this.setBackground(new Color(255,0,0));              } else                  this.setBackground(new Color(255, 255, 255));          } else {              this.setBackground(new Color(120, 0, 0));          }          if (this.isPersonCome) {              g.setColor(Color.BLACK);              g.fillOval(2, 2, 15, 15);          }      }      public boolean isVisited() {          return isVisited;      }      public void setVisited(boolean isVisited) {          this.isVisited = isVisited;      }      public boolean isPersonCome() {          return isPersonCome;      }      public void setPersonCome(boolean isPersonCome) {          this.isPersonCome = isPersonCome;      }      public boolean isStart() {          return isStart;      }      public void setStart(boolean isStart) {          this.isStart = isStart;      }      public boolean isEnd() {          return isEnd;      }      public void setEnd(boolean isEnd) {          this.isEnd = isEnd;      }  }  
1 0
原创粉丝点击