代码地址如下:
http://www.demodashi.com/demo/14547.html

需求

使用深度优先算法求解迷宫路径,使用Java实现求解过程的可视化,可单步运行,形象直观。

演示效果

红色格子为迷宫终点,迷宫可放大缩小,为了录屏选择了较小的尺寸,有多种不同难度的迷宫可以加载。

  1. 简单迷宫

  2. 复杂迷宫

项目运行

文件中有两个运行脚本,Windows下直接双击win运行.bat即可,linux和Mac运行sh文件中的命令即可,喜欢用IDE的也可自行创建项目。

运行项目后,点击菜单栏左上角的Map加载迷宫地图, 点击右下角的Run开始解迷宫,Step可单步运行,可通过速度进度条调节速度。

项目结构

Maze
├── classes # 存放编译生成的class文件
├── lib.jar # 打包好的gui库
├── map # 迷宫地图文件
│ ├── EasyMaze.txt
│ ├── FinalMaze01.txt
│ ├── FinalMaze02.txt
│ ├── FinalMaze03.txt
│ ├── FinalMaze04.txt
│ └── FinalMaze05.txt
├── src
│ ├── MazeBug.java
│ └── MazeBugRunner.java
├── linux运行.sh # 运行脚本
└── win运行.bat # 运行脚本

原理方法

使用深度优先算法,每个格子下一步都有上下左右4种走法,但是这4种走法并不是都是合法的,比如有些格子有障碍物,有些格式在边界之外,去掉这些剩下的才是合法的走法。

深度优先算法的思想就是:

  1. 找出当前位置A下一步合法的的格子,选择其中一个,往前走一步到达B。
  2. 如果B相邻的有合法格子,重复第1步;如果没有合法的,后退一步回到A,选择A的其他合法格子走;
  3. 重复以上方法,直到找到迷宫终点;

算法优化:上面的方法选择下一步走的方向是随机的,或者按照上下左右的顺序选择。但是很多迷宫都有偏向性,比如如果有右偏向性,那么每次都优先往右走可以更快走出迷宫。所以在实现的时候,记录每个方向走的次数,每往一个方向走一步就加1,如果回退就该方向减1,每次走都优先走次数最多的方向,当迷宫有偏向性时,该方法效率更高。

以项目中的迷宫为例,大部分情况下偏向性所需步数更少。

 普通方法:   534 1175 350 973 1052
偏向性: 552 761 330 175 420

代码实现

/*
* 节点:存储方向和该方向所走的次数
* 往一个方向前进则加1,后退则减1
*/
class Node {
private int dir; // 方向,角度值
private int ct; // 该方向所走次数 public Node(int initdir, int initct) {
dir = initdir;
ct = initct;
} public int getDir() {
return dir;
} public int getCt() {
return ct;
} public void setCt(int deta) {
ct += deta;
}
} // 深度优先算法解迷宫,并且以小甲虫的形式呈现
public class MazeBug extends Bug {
private Location next; // 下一步要走的格子
private Integer stepCount = 0; // 所走的步数
private boolean isEnd = false; // 是否到达迷宫出口
private boolean hasShown = false; // 是否显示了结束信息
private Stack<Location> path = new Stack<>(); // 存储走过的路径
private ArrayList<Node> arr = new ArrayList<>(); public MazeBug() {
setColor(Color.GREEN);
arr.add(new Node(0, 0));
arr.add(new Node(90, 0));
arr.add(new Node(270, 0));
arr.add(new Node(180, 0));
} // 周期性执行
public void act() {
boolean willMove = canMove(); // 是否还能继续移动 if (isEnd) { // 是否结束
if (!hasShown) { // 是否显示结束消息
String msg = stepCount.toString() + " steps";
JOptionPane.showMessageDialog(null, msg);
hasShown = true;
}
return;
} else if (willMove) { // 向前移动一个,步数加1
move();
++stepCount;
} else { // 不能移动,后退一步,将该方向的计数器减1
Grid<Actor> grid = getGrid();
Location loc = this.getLocation();
Location top = path.pop();
++stepCount;
grid.remove(top);
this.setDirection(loc.getDirectionToward(top));
this.moveTo(top);
// 在走过的死路留下一朵白花
Flower flower = new Flower(Color.WHITE);
flower.putSelfInGrid(getGrid(), loc); // 方向计数器减1
int dir = 180 + ((getDirection() / 90) % 2) * 180 - getDirection();
for (Node node : arr)
if (node.getDir() == dir) {
node.setCt(-1);
return;
}
}
} // 找出和当前位置相邻的、合法的并且从未走过的格子
public Location getValid(Location loc) {
Grid<Actor> gr = getGrid();
if (gr == null)
return null; // 将每个方向走过的次数从大到小排序,下一步优先选次数多的方向走
Location adjLocation;
arr.sort(new Comparator<Node>() {
@Override
public int compare(Node a, Node b) {
return (a.getCt() < b.getCt()) ? 1 : -1;
}
}); for (Node node : arr) {
adjLocation = this.getLocation().getAdjacentLocation(node.getDir());
if (gr.isValid(adjLocation)
&& (gr.get(adjLocation) == null || gr.get(adjLocation).getColor().equals(Color.RED))) {
node.setCt(1);
return adjLocation;
}
}
return null;
} // 判断当前位置是否可以继续移动
public boolean canMove() {
Grid<Actor> gr = getGrid();
Actor adj;
Location loc = this.getValid(this.getLocation());
if (loc != null) {
adj = gr.get(loc);
next = loc;
isEnd = adj != null && adj.getColor().equals(Color.RED);
return true;
}
return false;
} // 将甲虫的方向转向下一格,往前移动一步,将原来的位置压栈,并放置一朵绿花,表示走过的路径
public void move() {
Grid<Actor> gr = getGrid();
if (gr == null)
return;
Location loc = this.getLocation();
path.push(loc);
this.setDirection(loc.getDirectionToward(next));
this.moveTo(next);
Flower flower = new Flower(this.getColor());
flower.putSelfInGrid(gr, loc);
}
}

其他:

跟算法无关的代码,比如GUI方面的都打包成lib.jar了,如果想要自己更改可以自行解压。Java实现可视化迷宫

代码地址如下:
http://www.demodashi.com/demo/14547.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

Java实现可视化迷宫的更多相关文章

  1. 超级好用的 Java 数据可视化库:Tablesaw

    本文适合刚学习完 Java 语言基础的人群,跟着本文可了解和使用 Tablesaw 项目.示例均在 Windows 操作系统下演示 本文作者:HelloGitHub-秦人 HelloGitHub 推出 ...

  2. 【JAVA】可视化计算器

    import java.awt.Color; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.Actio ...

  3. java的WindowBuilder可视化插件

    一直做在安卓用xml作界面,对于java的控件不熟悉,也不习惯用代码做UI尤其是布局. 找了一下发现可以安装windowbuilder来实现java的可视化编程,但是很多资料里的连接都失效了. 刚自己 ...

  4. java可视化编程-eclipse安装windowbuilder插件(转载)

    原文地址:http://blog.csdn.net/jason0539/article/details/21219043 一直做在安卓用xml作界面,对于java的控件不熟悉,也不习惯用代码做UI尤其 ...

  5. 基于Java visualvm的可视化监控的使用

    1 Java visualVM可视化监控工具打开方式 ctrl + r 快捷键调出运行窗口,输出 jvisualvm指令,即可打开java visualVM工具.详情如下图: 2 Java Visua ...

  6. 归并排序算法 java 实现

    归并排序算法 java 实现 可视化对比十多种排序算法(C#版) [直观学习排序算法] 视觉直观感受若干常用排序算法 算法概念 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Di ...

  7. [2]R语言在数据处理上的禀赋之——可视化技术

    本文目录 Java的可视化技术 R的可视化技术 二维做图利器plot的参数配置 *权限机制 *plot独有的参数 *plot的type介绍 *title介绍 *公共参数集合--par *par的权限机 ...

  8. 7个Java项目,或许你的大学老师就会布置

    前言: 有天吃饭和朋友聊天,说到大学老师布置的开发项目,结果我们一干人说出来的都基本一样,入门级别的计算器啦,稍微大一点的记事本啦,然后到后面的图书管理系统啊,购物网站啊-- 发现这些项目都是大学老师 ...

  9. 并发编程 || Java线程详解

    通用线程模型 在很多研发当中,实际应用是基于一个理论再进行优化的.所以,在了解JVM规范中的Java线程的生命周期之前,我们可以先了解通用的线程生命周期,这有助于我们后续对JVM线程生命周期的理解. ...

随机推荐

  1. 关于deselectRowAtIndexPath

    有没有遇到过,导航+UITableView,在push,back回来之后,当前cell仍然是选中的状态.当然,解决办法简单,添加一句[tableView deselectRowAtIndexPath: ...

  2. Android SDK目录及版本号区别

    来自:http://www.2cto.com/kf/201604/496917.html 今天又有人问Tools,Build-Tools,Platform-tools有什么区别,是干嘛的? 现在对SD ...

  3. 5-05. QQ帐户的申请与登陆(25)(map运用)(ZJU_PAT)

    题目链接:http://pat.zju.edu.cn/contests/ds/5-05 实现QQ新帐户申请和老帐户登陆的简化版功能. 最大挑战是:据说如今的QQ号码已经有10位数了. 输入格式说明: ...

  4. jquery 判断元素是否存在于数组中

    要判断数组中是否包含某个元素,从原理来来说,就是遍历整个数组,然后判断是否相等 可以使用Jquery提供的方法: $.inArray("元素(字符串)",数组名称) 进行判断 ,当 ...

  5. LODOP打印控件之LODOP.NewPageA()方法

    通过lodop的强制分页方法,当我们一次性需要打印多张单页面的时候,可以通过该方法实现一次性打出,而不是重复调用打印方法,容易出问题 LODOP.NewPageA(); 说明:强制分页,注意是.New ...

  6. TFS WorkItem Permission Setting

    TFS非常强大,但是权限设置确实非常的恶心复杂,这貌似是一切NB又傲慢的软件的通病. 那么,在哪里设置 WorkItem 的权限呢? 第一步: 第二步: 第三步,下面你将一目了然. 第四步,Share ...

  7. 使用自由软件Icarus Verilog Simulator进行仿真

    Icarus Verilog Simulator(http://iverilog.icarus.com/home)使用iverilog作为源代码编译器,编译生成vvp程序文本,使用vvp作为运行时引擎 ...

  8. go语言之进阶篇结构体指针类型匿名字段

    1.结构体指针类型匿名字段 示例: package main import "fmt" type Person struct { name string //名字 sex byte ...

  9. 遇到问题描述:Android Please ensure that adb is correctly located at问题解决

    遇到问题描述: 运行android程序控制台输出 [2013-11-04 16:18:26 - ] The connection to adb is down, and a severe error ...

  10. eclipse启动优化文章集合

    1. eclipse启动优化,终于不那么卡了! http://www.cfei.net/archives/445