我正在工作或了解如何创建一个简单的 java 2d迷宫 ,如下所示:
int [][] maze =
{ {1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,1,0,1,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,1,1,1,0,1},
{1,0,0,0,1,1,1,0,0,0,0,0,1},
{1,0,1,0,0,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,0,0,1},
{1,0,1,0,1,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1}
};
这个已创建的想法是设置一个起点和目标点并通过使用递归深度首先找到路径。但必须说我有困难创造迷宫。
您对如何操作有任何建议吗?
或者也许是教程的链接?
我现在主要关注的是创造迷宫。
答案 0 :(得分:6)
迷宫实施有很多变化。
全部取决于您想要使用哪些方面?
以下是一些起点Maze generation algorithm。
我过去试图解决这个问题。我猜这个代码片段,而不是很多单词,我猜这个代码片段。
迷宫生成器代码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;
public class MyMaze {
private int dimensionX, dimensionY; // dimension of maze
private int gridDimensionX, gridDimensionY; // dimension of output grid
private char[][] grid; // output grid
private Cell[][] cells; // 2d array of Cells
private Random random = new Random(); // The random object
// initialize with x and y the same
public MyMaze(int aDimension) {
// Initialize
this(aDimension, aDimension);
}
// constructor
public MyMaze(int xDimension, int yDimension) {
dimensionX = xDimension;
dimensionY = yDimension;
gridDimensionX = xDimension * 4 + 1;
gridDimensionY = yDimension * 2 + 1;
grid = new char[gridDimensionX][gridDimensionY];
init();
generateMaze();
}
private void init() {
// create cells
cells = new Cell[dimensionX][dimensionY];
for (int x = 0; x < dimensionX; x++) {
for (int y = 0; y < dimensionY; y++) {
cells[x][y] = new Cell(x, y, false); // create cell (see Cell constructor)
}
}
}
// inner class to represent a cell
private class Cell {
int x, y; // coordinates
// cells this cell is connected to
ArrayList<Cell> neighbors = new ArrayList<>();
// solver: if already used
boolean visited = false;
// solver: the Cell before this one in the path
Cell parent = null;
// solver: if used in last attempt to solve path
boolean inPath = false;
// solver: distance travelled this far
double travelled;
// solver: projected distance to end
double projectedDist;
// impassable cell
boolean wall = true;
// if true, has yet to be used in generation
boolean open = true;
// construct Cell at x, y
Cell(int x, int y) {
this(x, y, true);
}
// construct Cell at x, y and with whether it isWall
Cell(int x, int y, boolean isWall) {
this.x = x;
this.y = y;
this.wall = isWall;
}
// add a neighbor to this cell, and this cell as a neighbor to the other
void addNeighbor(Cell other) {
if (!this.neighbors.contains(other)) { // avoid duplicates
this.neighbors.add(other);
}
if (!other.neighbors.contains(this)) { // avoid duplicates
other.neighbors.add(this);
}
}
// used in updateGrid()
boolean isCellBelowNeighbor() {
return this.neighbors.contains(new Cell(this.x, this.y + 1));
}
// used in updateGrid()
boolean isCellRightNeighbor() {
return this.neighbors.contains(new Cell(this.x + 1, this.y));
}
// useful Cell representation
@Override
public String toString() {
return String.format("Cell(%s, %s)", x, y);
}
// useful Cell equivalence
@Override
public boolean equals(Object other) {
if (!(other instanceof Cell)) return false;
Cell otherCell = (Cell) other;
return (this.x == otherCell.x && this.y == otherCell.y);
}
// should be overridden with equals
@Override
public int hashCode() {
// random hash code method designed to be usually unique
return this.x + this.y * 256;
}
}
// generate from upper left (In computing the y increases down often)
private void generateMaze() {
generateMaze(0, 0);
}
// generate the maze from coordinates x, y
private void generateMaze(int x, int y) {
generateMaze(getCell(x, y)); // generate from Cell
}
private void generateMaze(Cell startAt) {
// don't generate from cell not there
if (startAt == null) return;
startAt.open = false; // indicate cell closed for generation
ArrayList<Cell> cells = new ArrayList<>();
cells.add(startAt);
while (!cells.isEmpty()) {
Cell cell;
// this is to reduce but not completely eliminate the number
// of long twisting halls with short easy to detect branches
// which results in easy mazes
if (random.nextInt(10)==0)
cell = cells.remove(random.nextInt(cells.size()));
else cell = cells.remove(cells.size() - 1);
// for collection
ArrayList<Cell> neighbors = new ArrayList<>();
// cells that could potentially be neighbors
Cell[] potentialNeighbors = new Cell[]{
getCell(cell.x + 1, cell.y),
getCell(cell.x, cell.y + 1),
getCell(cell.x - 1, cell.y),
getCell(cell.x, cell.y - 1)
};
for (Cell other : potentialNeighbors) {
// skip if outside, is a wall or is not opened
if (other==null || other.wall || !other.open) continue;
neighbors.add(other);
}
if (neighbors.isEmpty()) continue;
// get random cell
Cell selected = neighbors.get(random.nextInt(neighbors.size()));
// add as neighbor
selected.open = false; // indicate cell closed for generation
cell.addNeighbor(selected);
cells.add(cell);
cells.add(selected);
}
}
// used to get a Cell at x, y; returns null out of bounds
public Cell getCell(int x, int y) {
try {
return cells[x][y];
} catch (ArrayIndexOutOfBoundsException e) { // catch out of bounds
return null;
}
}
public void solve() {
// default solve top left to bottom right
this.solve(0, 0, dimensionX - 1, dimensionY -1);
}
// solve the maze starting from the start state (A-star algorithm)
public void solve(int startX, int startY, int endX, int endY) {
// re initialize cells for path finding
for (Cell[] cellrow : this.cells) {
for (Cell cell : cellrow) {
cell.parent = null;
cell.visited = false;
cell.inPath = false;
cell.travelled = 0;
cell.projectedDist = -1;
}
}
// cells still being considered
ArrayList<Cell> openCells = new ArrayList<>();
// cell being considered
Cell endCell = getCell(endX, endY);
if (endCell == null) return; // quit if end out of bounds
{ // anonymous block to delete start, because not used later
Cell start = getCell(startX, startY);
if (start == null) return; // quit if start out of bounds
start.projectedDist = getProjectedDistance(start, 0, endCell);
start.visited = true;
openCells.add(start);
}
boolean solving = true;
while (solving) {
if (openCells.isEmpty()) return; // quit, no path
// sort openCells according to least projected distance
Collections.sort(openCells, new Comparator<Cell>(){
@Override
public int compare(Cell cell1, Cell cell2) {
double diff = cell1.projectedDist - cell2.projectedDist;
if (diff > 0) return 1;
else if (diff < 0) return -1;
else return 0;
}
});
Cell current = openCells.remove(0); // pop cell least projectedDist
if (current == endCell) break; // at end
for (Cell neighbor : current.neighbors) {
double projDist = getProjectedDistance(neighbor,
current.travelled + 1, endCell);
if (!neighbor.visited || // not visited yet
projDist < neighbor.projectedDist) { // better path
neighbor.parent = current;
neighbor.visited = true;
neighbor.projectedDist = projDist;
neighbor.travelled = current.travelled + 1;
if (!openCells.contains(neighbor))
openCells.add(neighbor);
}
}
}
// create path from end to beginning
Cell backtracking = endCell;
backtracking.inPath = true;
while (backtracking.parent != null) {
backtracking = backtracking.parent;
backtracking.inPath = true;
}
}
// get the projected distance
// (A star algorithm consistent)
public double getProjectedDistance(Cell current, double travelled, Cell end) {
return travelled + Math.abs(current.x - end.x) +
Math.abs(current.y - current.x);
}
// draw the maze
public void updateGrid() {
char backChar = ' ', wallChar = 'X', cellChar = ' ', pathChar = '*';
// fill background
for (int x = 0; x < gridDimensionX; x ++) {
for (int y = 0; y < gridDimensionY; y ++) {
grid[x][y] = backChar;
}
}
// build walls
for (int x = 0; x < gridDimensionX; x ++) {
for (int y = 0; y < gridDimensionY; y ++) {
if (x % 4 == 0 || y % 2 == 0)
grid[x][y] = wallChar;
}
}
// make meaningful representation
for (int x = 0; x < dimensionX; x++) {
for (int y = 0; y < dimensionY; y++) {
Cell current = getCell(x, y);
int gridX = x * 4 + 2, gridY = y * 2 + 1;
if (current.inPath) {
grid[gridX][gridY] = pathChar;
if (current.isCellBelowNeighbor())
if (getCell(x, y + 1).inPath) {
grid[gridX][gridY + 1] = pathChar;
grid[gridX + 1][gridY + 1] = backChar;
grid[gridX - 1][gridY + 1] = backChar;
} else {
grid[gridX][gridY + 1] = cellChar;
grid[gridX + 1][gridY + 1] = backChar;
grid[gridX - 1][gridY + 1] = backChar;
}
if (current.isCellRightNeighbor())
if (getCell(x + 1, y).inPath) {
grid[gridX + 2][gridY] = pathChar;
grid[gridX + 1][gridY] = pathChar;
grid[gridX + 3][gridY] = pathChar;
} else {
grid[gridX + 2][gridY] = cellChar;
grid[gridX + 1][gridY] = cellChar;
grid[gridX + 3][gridY] = cellChar;
}
} else {
grid[gridX][gridY] = cellChar;
if (current.isCellBelowNeighbor()) {
grid[gridX][gridY + 1] = cellChar;
grid[gridX + 1][gridY + 1] = backChar;
grid[gridX - 1][gridY + 1] = backChar;
}
if (current.isCellRightNeighbor()) {
grid[gridX + 2][gridY] = cellChar;
grid[gridX + 1][gridY] = cellChar;
grid[gridX + 3][gridY] = cellChar;
}
}
}
}
}
// simply prints the map
public void draw() {
System.out.print(this);
}
// forms a meaningful representation
@Override
public String toString() {
updateGrid();
String output = "";
for (int y = 0; y < gridDimensionY; y++) {
for (int x = 0; x < gridDimensionX; x++) {
output += grid[x][y];
}
output += "\n";
}
return output;
}
// run it
public static void main(String[] args) {
MyMaze maze = new MyMaze(20);
maze.solve();
maze.draw();
}
}
这不是最好的解决方案,我此时的任务是自己实现这个算法。它有明确的评论。
<强> 输出: 强>
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X * X ********* X ***** X X X
X * X * XXXXX * X * X * X X X X
X ***** X ***** X * X * X X X X
XXXXXXXXX * XXXXX * X * X X X X
X X ***** X * X * X X X
X X XXXXX * X * X * XXXXXXXXX X
X X X ***** X * X
X XXXXXXXXXXXXXXXXX * XXXXXXXXXXXXX
X ***************** X ***** X X
X * XXXXXXXXXXXXX * XXXXX * X X X
X ***** X X ********* X X X
XXXXX * X XXXXXXXXXXXXXXXXXXXXX X
X ***** X ***** X ***** X
X * XXXXXXXXXXXXX * X * XXXXX * X * X
X ************* X * X * X ***** X * X
XXXXXXXXXXXXX * X * X * X * XXXXX * X
X ***** X ***** X * X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
我希望它可以作为一些解决方案的例证。
答案 1 :(得分:1)
我知道这可能已经完全过时了,但是...
首先,您应该意识到这种迷宫的底层结构是二维网格上的无向图。现在要创建所谓的“完美迷宫”,您只需创建完整网格图的任何生成树。为此,有很多算法,从随机图遍历(BFS,DFS)到从已知最小生成树算法(Kruskal,Prim,Boruvka,Reverse-Delete)派生的算法,再到创建“均匀随机”生成树的算法(Wilson,Aldous-Broder)排除其他不适用于这些类别的算法,例如“递归除法”,“埃勒氏”等。
我基于网格图结构实现了许多这样的算法,您可以在这里找到我的实现方式:
答案 2 :(得分:0)
如果我理解你的问题,我会做的是: 1.创建一个特定大小的板(将所有坐标更改为您想要的数字 - 在您的示例中为'1')。 我不会使用递归函数,因为你可能最终会绘制整个板(想想会使递归停止的原因)。
你可以创建一个接收起始协调,结束协调的功能, 和阵列(板)。 函数的伪代码: 为下一个绘画方向设置一个变量(将其设置为起始协调)。 画下一个协调0。 而下一个协调!=到结束协调: 画下一个协调0。 使用Random将协调设置为4个方向之一。
你应该添加限制(如果下一个协调是彩绘的/迷宫的边界等...选择不同的协调)。 祝你好运!