线段交叉法 构造迷宫
来源:互联网 发布:游开服表数据 编辑:程序博客网 时间:2024/04/30 07:04
迷宫是算法经常用到的问题, 一般构造迷宫的方法是自己定义矩阵, 0 表示平地, 1表示墙
最近我想了一种另类的方法构造迷宫, 下面介绍一下
基本原理
构造一个"表格"
去掉表格中的某些线段,就自动生成迷宫了
下面程序生成图
如何保证迷宫一定有出路
思路就是:画出一条路径, 把交叉的代表墙的直线,全部去掉
上图中绿色就是路径, 红色是要去掉的'墙'
源代码
package com.pnp.maze;import java.awt.Color;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Image;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.util.ArrayList;import javax.swing.JFrame;public class Maze {static class Point {int x;int y;public Point(int x, int y) {this.x = x;this.y = y;}public String toString() {return "<"+x+":"+y+">";}}static class Line {Point p1;Point p2;double k;double b;ArrayList<Point> crossPoints;public Line( Point p1, Point p2 ) {this.p1 = p1;this.p2 = p2;canclulateKB();}public String toString() {return "<"+p1.x+":"+p1.y+">-<"+p2.x+":"+p2.y+">";}void canclulateKB(){if ( p2.x == p1.x ) {k = 0x7FFFFFFF;} else { k = (p2.y - p1.y) / ( p2.x - p1.x); b = p1.y - k * p1.x;}}public boolean isVertical() {return p1.x == p2.x; }public boolean isHorizontal() {return p1.y == p2.y; }public void addCrossPoint(Point p) {if ( crossPoints == null)crossPoints = new ArrayList<Point>();crossPoints.add(p);}static public Point getCrossPoint(Line l1, Line l2) {if ( l2.k == l1.k) { // paralif ( l1.b == l2.b) {if ( l1.k == 0x7FFFFFFF ) {if ( l1.p1.x != l2.p1.x)return null;else if ( Math.abs(( l1.p2.y + l1.p1.y ) /2 - ( l2.p2.y + l2.p1.y )/2) <= ( l1.p2.y - l1.p1.y ) /2 + ( l2.p2.y - l2.p1.y )/2) return l1.p1;} else if ( Math.abs(( l1.p2.x + l1.p1.x ) /2 - ( l2.p2.x + l2.p1.x )/2) <= ( l1.p2.x - l1.p1.x ) /2 + ( l2.p2.x - l2.p1.x )/2) return l1.p1;} elsereturn null; } int x,y;if ( l1.k == 0x7FFFFFFF ) {x = l1.p1.x;y = (int) (l2.k * x + l2.b);} else if ( l2.k == 0x7FFFFFFF ) {x = l2.p1.x;y = (int) (l1.k * x + l1.b);} else {x = (int)(-(l2.b - l1.b)/(l2.k-l1.k));y = (int)(l1.k * x + l1.b);}if ( x >= l1.p1.x && x <= l1.p2.x && y >= l1.p1.y && y <= l1.p2.y &&x >= l2.p1.x && x <= l2.p2.x && y >= l2.p1.y && y <= l2.p2.y )return new Point(x,y);return null;}static public void addCrossPointToLines(Line l1, Line l2) {Point p = getCrossPoint(l1,l2);if (p == null)return;l1.addCrossPoint(p);l2.addCrossPoint(p);}} // end class LineArrayList<Line> verticalLines = new ArrayList<Line>();ArrayList<Line> HorizontalLines = new ArrayList<Line>();ArrayList<Line> shortLines = new ArrayList<Line>();ArrayList<Line> cutPaths = new ArrayList<Line>();ArrayList<Line> removedLines = new ArrayList<Line>(); Point point1 = new Point(MAZE_PATH_EDGE,MAZE_PATH_EDGE); Point point2 = new Point(WIDTH - MAZE_PATH_EDGE,HEIGHT - MAZE_PATH_EDGE); MyJFrame frame;final static int WIDTH = 800;final static int HEIGHT = 600;final static int MAZE_PATH_EDGE = 20;final static int MAX_LINE_LEN = 50;final static int MIN_LINE_LEN = 10;final static int BREAK_LINE_FACTOR = 50; // ( 0-100, the bigger, the more possible to break linesclass MyJFrame extends JFrame {Image offScreenImage = null;public void paint(Graphics g) {if (offScreenImage == null)offScreenImage = this.createImage(this.getWidth(),this.getHeight());Graphics goffScreen = offScreenImage.getGraphics();goffScreen.setColor(Color.white);goffScreen.fillRect(0, 0, this.getWidth(), this.getHeight());goffScreen.translate(50, 50);// goffScreen.setColor( Color.white);// goffScreen.fillRect(0, 0, this.getWidth(),this.getHeight());// draw linesgoffScreen.setColor(Color.black);for (int i = 0; i < shortLines.size(); i++) {Line l = shortLines.get(i);goffScreen.drawLine(l.p1.x, l.p1.y, l.p2.x, l.p2.y);}goffScreen.setColor(Color.green);for (int i = 0; i < cutPaths.size(); i++) {Line l = cutPaths.get(i);goffScreen.drawLine(l.p1.x, l.p1.y, l.p2.x, l.p2.y);}goffScreen.setColor(Color.RED);for (int i = 0; i < removedLines.size(); i++) {Line l = removedLines.get(i);goffScreen.drawLine(l.p1.x, l.p1.y, l.p2.x, l.p2.y);}Graphics2D g2d = (Graphics2D) g;g2d.drawImage(offScreenImage, 0, 0, null);}}private void dynamicInit() {genShortLines();generatePaths2();cutPathsFromMaze();shortLines.add(new Line(new Point(0,0), new Point(WIDTH,0)));shortLines.add(new Line(new Point(0,HEIGHT), new Point(WIDTH,HEIGHT)));shortLines.add(new Line(new Point(0,0), new Point(0,HEIGHT)));shortLines.add(new Line(new Point(WIDTH,0), new Point(WIDTH,HEIGHT)));}private void generateLines() {for (int x = 0; x < WIDTH;) {Point p1 = new Point(x, 0);Point p2 = new Point(x, HEIGHT);verticalLines.add(new Line(p1, p2));if ( x == WIDTH-1 ) break;double inter;while ((inter = Math.random() * MAX_LINE_LEN) < MIN_LINE_LEN);x += inter;if ( WIDTH - x < MIN_LINE_LEN)x = WIDTH-1;}for (int y = 0; y < HEIGHT;) {Point p1 = new Point(0, y);Point p2 = new Point(WIDTH, y);HorizontalLines.add(new Line(p1, p2));if ( y == HEIGHT-1 ) break;double inter;while ((inter = Math.random() * MAX_LINE_LEN) < MIN_LINE_LEN);y += inter;if ( HEIGHT - y < MIN_LINE_LEN)y = HEIGHT-1;}}void calculateCrossPoints() {for (int i = 0; i < verticalLines.size(); i++) {Line l1 = verticalLines.get(i);for (int j = 0; j < HorizontalLines.size(); j++) {Line l2 = HorizontalLines.get(j);Line.addCrossPointToLines(l1, l2);}}}void breakLine(ArrayList<Line> lines) {for (int i = 1; i < lines.size() - 1; i++) { // won't consider the first// and last, since it// form the frameLine l = lines.get(i);ArrayList<Point> points = l.crossPoints;if ( points == null) {//System.out.println("crossPoints for "+l+" is null");break;}for (int j = 0; j < points.size() - 1; j++) {Point p1 = points.get(j);if ((Math.random() * 100) > BREAK_LINE_FACTOR) {Point p2 = points.get(j + 1);shortLines.add(new Line(p1, p2));}}}}void genShortLines() {shortLines.clear();breakLine(verticalLines);breakLine(HorizontalLines);}private void generatePaths1() {for (int x = MAZE_PATH_EDGE; x < WIDTH - MAZE_PATH_EDGE;) {Point p1 = new Point(x, 1);Point p2 = new Point(x, HEIGHT - 1);cutPaths.add(new Line(p1, p2));double inter;while ((inter = Math.random() * 200) < 100);x += inter;if ( WIDTH - x < MAZE_PATH_EDGE)break;}for (int y = MAZE_PATH_EDGE; y <= HEIGHT - MAZE_PATH_EDGE;) {Point p1 = new Point(1, y);Point p2 = new Point(WIDTH - 1, y);cutPaths.add(new Line(p1, p2));double inter;while ((inter = Math.random() * 200) < 100);y += inter;if ( HEIGHT - y < MAZE_PATH_EDGE)break;}}private void generatePaths2() {int beginX = MAZE_PATH_EDGE;int beginY = MAZE_PATH_EDGE;int endX = WIDTH - MAZE_PATH_EDGE;int endY = HEIGHT - MAZE_PATH_EDGE;cutPaths.clear();int x = beginX;int y = beginY;while ( x < endX || y < endY ) {int nextX = x; int nextY = y;int flag;if ( (int)(Math.random() * 100) % 3 == 0 )flag = -1;else flag = 1;double rate = (double)WIDTH / (WIDTH + HEIGHT);if ( Math.random() < rate )nextX += (int)(Math.random() * MAX_LINE_LEN*3);elsenextY += flag* (int)(Math.random() * MAX_LINE_LEN*3);if ( nextX > endX )nextX = endX;if ( nextX < beginX) nextX = beginX;if ( nextY > endY ) nextY = endY;if ( nextY < beginY) nextY = beginY;Point p1 = new Point(x, y);Point p2 = new Point(nextX, nextY );Line l = new Line(p1, p2);/*int crossFlag = 0;for( int i= 0; i < cutPaths.size()-1; i++){Line ll = cutPaths.get(i);if ( Line.getCrossPoint(l, ll) != null ) {crossFlag = 1;break;}}if( crossFlag == 0 ) {cutPaths.add(l);x = nextX;y = nextY;}*/cutPaths.add(l);x = nextX;y = nextY;}}static int ct = 0; private void cutPathsFromMaze() {removedLines.clear();for (int j = 0; j < cutPaths.size(); j++) {Line path = cutPaths.get(j);for (int i = 0; i < shortLines.size(); ) {Line l = shortLines.get(i);Point p = Line.getCrossPoint(l, path);if (p != null ) {shortLines.remove(l);removedLines.add(l);}elsei++;}}}public void show() {generateLines();calculateCrossPoints();dynamicInit(); // cut line for gen the Mazeframe = new MyJFrame();frame.addMouseListener(new MouseAdapter() {public void mouseClicked(MouseEvent event) {dynamicInit();}});frame.setTitle("Maze");frame.setBounds(0, 0, WIDTH + 100, HEIGHT + 100);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);}public static void main(String[] args) {/*for( int i=0; i < 10 ; i++)System.out.println(Math.random()*100);*/(new Maze()).show();}}
生成参数
通过调节图的生成参数
final static int MAX_LINE_LEN = 5; final static int MIN_LINE_LEN = 3; final static int BREAK_LINE_FACTOR = 50; // ( 0-100, the bigger, the more possible to break lines
将看到令人吃惊的效果
路径生成不太合理, 此算法以后还要改进
- 线段交叉法 构造迷宫
- 交叉编译环境构造
- 线段树构造
- 线段树的构造
- 线段树的构造
- Codeforces482B【线段树构造】
- 计算几何:线段相交(迷宫寻宝)
- 基于创建型模式的“迷宫”构造
- 算法5-5:线段交叉问题
- 根据数组构造线段树
- LintCode:线段树的构造
- 线段树的构造 II
- hdu6025-构造or线段树
- lintcode -- 线段树的构造
- 线段树的构造-LintCode
- 构造嵌入式Linux系统----准备交叉编译器
- 利用buildroot构造powerpc交叉编译环境
- nyoj 83 迷宫寻宝(二)(线段相交问题)
- Tomcat 虚拟主机配置
- 基础面试题
- spring定时任务
- 第一次恢复Oracle数据库经历
- vc6.0移植到vs2008下问题总结
- 线段交叉法 构造迷宫
- Android显示系统之SurfaceFlinger(一)
- Spring <context:annotation-config /> 详解
- onload 、onunload 、onbeforeunload区别
- csdn头像怎么改不了解决方法
- SQL Server数据库ROW_NUMBER()函数使用详解
- postfix 自动转发邮件
- CSS3初体验与在线制作
- Android屏幕解锁图案破解