php - backtracking maze generation (converting everything to 2d array)

别说谁变了你拦得住时间么 提交于 2019-12-12 06:36:57

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!