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
- GUI(2) 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题...
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 迷宫问题
- 写的第一个接口的总结
- 医药采购之药品目录导入
- React-Native学习指南
- Unix学习笔记------Stat函数与chmod函数的配合使用
- WebMatrix快捷键
- GUI(2) 迷宫问题
- RecyclerView scrollToPosition 无效的问题
- Ubuntu与windows共享键盘鼠标 - Synergy
- 学习wtl.1
- 文章标题
- 弧形显示的texview
- 多个jquery冲突
- 如何立即取消Toast
- 【FAQ】Jenkins如何添加Dashboard视图?