问题
Here generating a maze by backtracking works correctly but the thing is that I am trying to implement this in a pixel game (Minecraft)... so the problem is in drawing the maze. In this game, the size of the wall blocks should be the exact same as the size of an empty block/space, so the only solution I thought of was a bonus 2d array called totalmaze. Its purpose is to store both empty spaces and wall blocks so I made its size (x*3, y*3) and tried outputting the walls but unfortunately this causes a lot of problems such as too much empty space / blocked paths. Note : X, Z because it is a 3d maze.
If this was JavaScript and a simple app, I would just draw the walls as lines but in Minecraft, the sizes should be the same so this is where things become troublesome even though the algorithm is correct. Please help.
This is how I am trying to fix it but perhaps is not the way : https://prnt.sc/fbp88o
public function generateMaze($dim_x, $walls_height, $dim_z){
$maze = array();
$moves = array();
$cell_count = $dim_x*$dim_z;
for($position=0; $position<$cell_count; $position++){
$maze[$position] = "01111"; // visited, NSEW
}
$pos=0;
$maze[0]{0} = 1; /// initial
$visited = 1;
// determine possible directions
while($visited<$cell_count){
$possible = "";
if((floor($pos/$dim_x)==floor(($pos-1)/$dim_x)) and ($maze[$pos-1]{0}==0)){
$possible .= "W";
}
if((floor($pos/$dim_x)==floor(($pos+1)/$dim_x)) and ($maze[$pos+1]{0}==0)){
$possible .= "E";
}
if((($pos+$dim_x)<$cell_count) and ($maze[$pos+$dim_x]{0}==0)){
$possible .= "S";
}
if((($pos-$dim_x)>=0) and ($maze[$pos-$dim_x]{0}==0)){
$possible .= "N";
}
if($possible){
$visited ++;
array_push($moves,$pos);
$direction = $possible{rand(0,strlen($possible)-1)};
switch($direction){
case "N":
$maze[$pos]{1} = 0;
$maze[$pos-$dim_x]{2} = 0;
$pos -= $dim_x;
break;
case "S":
$maze[$pos]{2} = 0;
$maze[$pos+$dim_x]{1} = 0;
$pos += $dim_x;
break;
case "E":
$maze[$pos]{3} = 0;
$maze[$pos+1]{4} = 0;
$pos ++;
break;
case "W":
$maze[$pos]{4} = 0;
$maze[$pos-1]{3} = 0;
$pos --;
break;
}
$maze[$pos]{0} = 1;
}
else{
$pos = array_pop($moves);
}
}
$totalmaze = array();
for($i=0; $i<$dim_x*3+1; $i++){
$totalmaze[$i][0] = 1;
$totalmaze[$i][$dim_z*3-1]=1;
}
for($i=0; $i<$dim_z*3+1; $i++){
$totalmaze[0][$i] = 1;
$totalmaze[$dim_x*3-1][$i]=1;
}
for($position=0; $position<$cell_count; $position++){
$x = $position % $dim_x;
$z = floor($position / $dim_x);
if($maze[$position]{1} == 1){
$totalmaze[$x*3+1][$z*3]=1;
}
if($maze[$position]{2} == 1){
$totalmaze[$x*3+1][$z*3+2]=1;
}
if($maze[$position]{3} == 1){
$totalmaze[$x*3+2][$z*3+1]=1;
}
if($maze[$position]{4} == 1){
$totalmaze[$x*3][$z*3+1]=1;
}
}
回答1:
I think it's hard to explain the randomized Prim's algorithm in the comments. So I decided to post a new answer.
The wall cells in randomized Prim's algorithm actually have "directions". Consider the maze below where # indicates a wall and . indicates an empty cell (the positions are 0-based).
#####
#...#
###.#
#...#
#####
The wall positioned at (2, 1) links two cells (1, 1) and (3, 1), but not (2, 0) and (2, 2) (as both of them are walls). As soon as we pick our very first empty cell, the directions of all walls are determined. That is because the walls serve as edges in a graph, and the graph is determined when we choosw the first empty cell. You can draw some mazes on paper and see it yourself.
I've also written a python example of the randomized Prim's algorithm. Try to run it.
import random
SIZE = 21
# Fill the maze with walls
maze = [['#' for j in range(0, SIZE)] for i in range(0, SIZE)]
# Create an empty wall list
wall_list = []
# Check if the given position is in the maze and not on the boundary
def in_maze(row, col):
return row > 0 and row < SIZE-1 and col > 0 and col < SIZE-1
# Add the neighboring walls of the cell (row, col) to the wall list
def add_walls(row, col):
global maze, wall_list
# It's a 4-connected grid maze
dir = ((0, 1), (1, 0), (0, -1), (-1, 0))
for k in range(0, len(dir)):
# Calculate the neighboring wall position and the cell position
wall_row = row + dir[k][0]
wall_col = col + dir[k][1]
cell_row = wall_row + dir[k][0]
cell_col = wall_col + dir[k][1]
# Make sure the wall grid is in the range of the maze
if not in_maze(wall_row, wall_col) or not in_maze(cell_row, cell_col):
continue
# Add the wall and the neighboring cell to the list
wall_list.append(((wall_row, wall_col), (cell_row, cell_col)))
# Pick a random grid first
cell_row = random.randint(1, SIZE-2)
cell_col = random.randint(1, SIZE-2)
maze[cell_row][cell_col] = '.'
add_walls(cell_row, cell_col)
while len(wall_list) > 0:
# Pick a random wall
id = random.randint(0, len(wall_list)-1)
wall_row, wall_col = wall_list[id][0]
cell_row, cell_col = wall_list[id][1]
wall_list.pop(id)
# Skip if it is no longer a wall
if maze[wall_row][wall_col] != '#':
continue
# Skip if the two cells that the wall divides are visited
if maze[cell_row][cell_col] == '.':
continue
# Make the two grid as passages
maze[wall_row][wall_col] = '.'
maze[cell_row][cell_col] = '.'
# Add the neighboring walls
add_walls(cell_row, cell_col)
# Print the maze
for row in maze:
print(''.join(row))
You should get something like this
#####################
#.#.....#.#.#.......#
#.###.###.#.###.#.###
#.#.....#...#.#.#.#.#
#.###.#.###.#.###.#.#
#...#.#...#...#.....#
#.#.###.#####.#.#####
#.#.#.........#...#.#
###.#########.###.#.#
#.#...........#...#.#
#.#########.#.###.#.#
#.........#.#...#...#
#####.###.###.#####.#
#...#.#.#...........#
###.###.#####.###.###
#.......#.....#.....#
#.#.###.#####.#####.#
#.#.#...#...#.#.....#
#####.#.###.#####.###
#.....#.............#
#####################
回答2:
To generate a "block" maze there are better ways. Why not try some spanning-tree algorithm like Kruskal? Check the link below.
https://en.wikipedia.org/wiki/Maze_generation_algorithm#Randomized_Kruskal.27s_algorithm
来源:https://stackoverflow.com/questions/44167341/php-backtracking-maze-generation-converting-everything-to-2d-array