Difference between revisions of "Dynamically Sized Maze"
(14 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
This article will describe a technique to build mazes that can grow in all directions, | This article will describe a technique to build mazes that can grow without limits in all directions, differently from a traditional maze that is bounded by its outer walls. | ||
=== Example === | === Example === | ||
Line 5: | Line 5: | ||
<pre> | <pre> | ||
$ ./dynamic.pl 250 1419689539 | $ ./dynamic.pl 250 1419689539 | ||
########## | ###################################################### | ||
######## | ############ ! ! ! !################################## | ||
########## | ##########_ _ _!################################ | ||
########## | ############_!_! _ _! !############################## | ||
##########_ | ############_ _! _ _! !########################## | ||
############_ | ############_ ! ! !_ _ _!######################## | ||
########## | ##############_! ! ! ! _ _!###### ! ! ! !########## | ||
##########_ | ############_ _!_ _! !_ _!## ! ! ! _! ! !#### | ||
############ | ############_ _! _! _ _!_ _ _!_ _!_ _ _ _!## | ||
############_ | ##############_! _! _! _!_ ! ! ! _ _ ! _ _!## | ||
############ | ##############_ ! _ _!_! _! !_ _ ! ! _! ! _!## | ||
############_ _! | ##############_ ! _!##_ _! _ ! ! ! _ _!_! _!## | ||
##############_!_! | ##############_ _!##_ ! _! ! !_ ! ! _!## | ||
################_!_!######_!_!_!_ ! ! !_ ! _!## | |||
############################_ _ _! ! _!_!_!_!_!#### | |||
############################_! | ############################_ ! _!############ | ||
############################ | ##############################_!_!_!_! _!############ | ||
###################### ! | ##################################_ _!############ | ||
################## | ######################## ! ! ! ! !_ !_!############## | ||
################_ | #################### !_ _ _ ! _ ! _!############## | ||
################ | ##################_ _ ! !_ ! _! ! !########## | ||
################ | ##################_ !_ ! !_ ! !_!_! _ _!######## | ||
################_ _ !_ | ##################_ ! ! !_ _! ! ! ! _! _!######## | ||
########## | ##################_ _ !_ ! ! _! _!######## | ||
######## ! | ############ ! !##_ _ _!_!_!_!_!_!_!_!_ _!######## | ||
###### ! | ########## ! _! ! _!################_ _!######## | ||
## ! ! | ######## ! _!_ _ _!##############_ _!######## | ||
#### ! ! _! _!_!_!################_ !_!########## | |||
##_ _ _! _! _!#### ! ! !########_ _ _! !######## | |||
## | ##_ _ _ ! !_ ! ! !_ _ ! ! ! !##_ _ _!###### | ||
## | ####_ _! !_ !_ _ ! !##_!_! _!###### | ||
####_ | ####_ _ !_! !_!_!_!_!##_!_! !_ !_ !_!######## | ||
####_ | ######_ ! !_! _!##########_ _ _!_ !_!_!########## | ||
##### | ######_ _!##########_ _ ! _!############ | ||
####################### | ########_!_!_!_!##############_!_ !_!############## | ||
##################################_!_!################ | |||
###################################################### | |||
</pre> | </pre> | ||
Line 130: | Line 132: | ||
=== Description === | === Description === | ||
# Start carving from (x0,y0) into a random direction. | |||
# Start carving from (x0,y0) into a | |||
# Calculate the new coordinates (x1,y1). | # Calculate the new coordinates (x1,y1). | ||
# Return if the new position was already visited. | # Return if the new position was already visited. | ||
# Repeat the process from the new position, trying all possible directions. | # Repeat the process from the new position, trying all possible directions. | ||
It is important to count the number of steps ($count), so we can exit the routine when the maze reaches the desired size ($CELLS). (Otherwise the maze would keep growing forever). Since the maze can become very sparse, we store the positions in a hash table instead of an array. | |||
=== Usage === | === Usage === | ||
Line 265: | Line 263: | ||
</pre> | </pre> | ||
[[Category:Developing]] | === Advantages === | ||
The main advantage of this technique is that, since cells are stored in a hash, memory usage grows only one cell at a time. | |||
It is also easily customizable because this technique is just one (recursive backtracker covered by one cell long dead-ends) of the many possible implementations of the Growing tree algorithm described by Walter D. Pullen on Think Labyrinth [http://www.astrolog.org/labyrnth/algrithm.htm]. With only a few minor changes, the results can be very different. "For example, if you always pick the most recent cell added to it, this algorithm turns into the recursive backtracker. If you always pick cells at random, this will behave similarly but not exactly to Prim's algorithm. If you always pick the oldest cells added to the list, this will create Mazes with about as low a river factor as possible, even lower than Prim's algorithm. If you usually pick the most recent cell, but occasionally pick a random cell, the Maze will have a high river factor but a short direct solution. If you randomly pick among the most recent cells, the Maze will have a low river factor but a long windy solution." | |||
If you remove the inner walls, you get a [[Dynamically Sized Cave]]. | |||
[[Category:Developing]][[Category:Articles]][[Category:Maps]] |
Latest revision as of 15:25, 14 April 2021
This article will describe a technique to build mazes that can grow without limits in all directions, differently from a traditional maze that is bounded by its outer walls.
Example
$ ./dynamic.pl 250 1419689539 ###################################################### ############ ! ! ! !################################## ##########_ _ _!################################ ############_!_! _ _! !############################## ############_ _! _ _! !########################## ############_ ! ! !_ _ _!######################## ##############_! ! ! ! _ _!###### ! ! ! !########## ############_ _!_ _! !_ _!## ! ! ! _! ! !#### ############_ _! _! _ _!_ _ _!_ _!_ _ _ _!## ##############_! _! _! _!_ ! ! ! _ _ ! _ _!## ##############_ ! _ _!_! _! !_ _ ! ! _! ! _!## ##############_ ! _!##_ _! _ ! ! ! _ _!_! _!## ##############_ _!##_ ! _! ! !_ ! ! _!## ################_!_!######_!_!_!_ ! ! !_ ! _!## ############################_ _ _! ! _!_!_!_!_!#### ############################_ ! _!############ ##############################_!_!_!_! _!############ ##################################_ _!############ ######################## ! ! ! ! !_ !_!############## #################### !_ _ _ ! _ ! _!############## ##################_ _ ! !_ ! _! ! !########## ##################_ !_ ! !_ ! !_!_! _ _!######## ##################_ ! ! !_ _! ! ! ! _! _!######## ##################_ _ !_ ! ! _! _!######## ############ ! !##_ _ _!_!_!_!_!_!_!_!_ _!######## ########## ! _! ! _!################_ _!######## ######## ! _!_ _ _!##############_ _!######## #### ! ! _! _!_!_!################_ !_!########## ##_ _ _! _! _!#### ! ! !########_ _ _! !######## ##_ _ _ ! !_ ! ! !_ _ ! ! ! !##_ _ _!###### ####_ _! !_ !_ _ ! !##_!_! _!###### ####_ _ !_! !_!_!_!_!##_!_! !_ !_ !_!######## ######_ ! !_! _!##########_ _ _!_ !_!_!########## ######_ _!##########_ _ ! _!############ ########_!_!_!_!##############_!_ !_!############## ##################################_!_!################ ######################################################
Source code
#!/usr/bin/env perl
use strict;
use warnings;
no warnings 'uninitialized';
no warnings 'recursion';
use List::Util qw/min max shuffle/;
# Command-line options
my $CELLS = $ARGV[0] || 250;
my $SEED = $ARGV[1] || time();
srand($SEED);
# Constants
my %DIRECTIONS = (
N => { dy => -1, opposite => 'S' },
S => { dy => 1, opposite => 'N' },
E => { dx => 1, opposite => 'W' },
W => { dx => -1, opposite => 'E' },
);
# Variables
my $map = {};
my ( $min_x, $min_y, $max_x, $max_y ) = ( 0, 0, 0, 0 );
my $count = 0;
# Code
carve( 0, 0, 'E' );
print output();
print "$0 $CELLS $SEED # => ( $min_x, $min_y, $max_x, $max_y )\n";
sub carve {
my ( $x0, $y0, $direction ) = @_;
my $x1 = $x0 + $DIRECTIONS{$direction}{dx};
my $y1 = $y0 + $DIRECTIONS{$direction}{dy};
return if defined $map->{$y1}{$x1}; # already visited
$min_x = min( $min_x, $x1 );
$max_x = max( $max_x, $x1 );
$min_y = min( $min_y, $y1 );
$max_y = max( $max_y, $y1 );
$map->{$y0}{$x0}{$direction} = 1;
$map->{$y1}{$x1}{ $DIRECTIONS{$direction}{opposite} } = 1;
return if $count++ > $CELLS;
for my $new_direction ( shuffle keys %DIRECTIONS ) {
carve( $x1, $y1, $new_direction );
}
}
sub output {
my $output = '';
for my $y ( $min_y - 1 .. $max_y + 1 ) {
for my $x ( $min_x - 1 .. $max_x + 1 ) {
if ( ref $map->{$y}{$x} ) {
$output .= $map->{$y}{$x}{S} ? ' ' : '_';
$output .= $map->{$y}{$x}{E} ? ' ' : '!';
}
else {
$output .= '##';
}
}
$output .= "\n";
}
return $output;
}
Description
- Start carving from (x0,y0) into a random direction.
- Calculate the new coordinates (x1,y1).
- Return if the new position was already visited.
- Repeat the process from the new position, trying all possible directions.
It is important to count the number of steps ($count), so we can exit the routine when the maze reaches the desired size ($CELLS). (Otherwise the maze would keep growing forever). Since the maze can become very sparse, we store the positions in a hash table instead of an array.
Usage
$ ./dynamic.pl [length] [random seed]
More examples
$ ./dynamic.pl 250 1419687187 ################################## ! !######################################## ################################_ ! ! ! !################################## ################################_ !_ _ _ _!################################ ################################_ ! _! _ _!################################ ################################_ ! _ _!################################## ##############################_ _! _!_!#################### ! ! !########## ##############################_ ! ! ! !####################_ _! !###### ##############################_ !_ _ ! !####################_!_! _!#### ##############################_ !_ _!################_ !_!_! _! !## ############################## !_!_! ! _ _!###### ! ! !##_ _!_ !_ _ _ _! ############################_ _ _ _! _!######_ _ _!_ !_ !_ _ _! ##########################_ _! _ _! ! ! !## !_ ! _ _!##_!_ ! !_ _ !_!## ##########################_ ! _ ! _ _ !_ _ _! _! !_ _ _! !_ _!## ##########################_ !_ _!_ _! !_ !_ _!_ _ _! _ _! !_!#### ########################_ _! _ ! !_!_!_ ! _! _ _!_ _!_!###### ########################_ _!_!_!_!_! _!_ !_!_ _ ! !_ _ _!#### ##########################_!_!_!######## !_! _!##_!_!####_ ! _!#### ################################ ! ! !_ _!############_!_!_!_!_!_!###### ##############################_ _ ! !_!_!################################ ################## ! !########_ ! ! ! !_!#################################### ################_ ! ! !##_ _!_ _ _ _! ! !################################ ################_ ! _ _!_ _ _ _ _ _ _!############################## ################_ !_! ! _!##_! !_ _ _ _! _!############################## ################_ !_ _! ! !_ ! _ !_ _!############################ ############ ! !_ _ ! _ !_ !_!_!_!_ _!############################ ##########_ !_ !_!_!_ _!######_!_!_!############################## ##########_ ! !_!######_!_!_!############################################ #### ! !##_ !_!_!_!########################################################## ##_ !_ _!############################################################## _ _!_ !_!################################################################ _ _ _ !_!_!################################################################## _ ! _!#################################################################### _ !_ _!#################################################################### _ _ !_!###################################################################### _ _!###################################################################### ##_!_!########################################################################
$ ./dynamic.pl 250 1419687341 ######## ! !############################################################ #### !_ _!########################################################## ##_ _ _! ! ! ! !###################################################### _ _!_ _ _ ! ! ! ! !############################################## _ !_!_!_ _ _ ! ! ! !######################################## ##_!_!_! _! !##_!_!_ _! _ _!###################################### ######_ _!####_ ! _! _! ! !#################################### ########_!_! _!##_ _! _! _ _!#################### ! !########## ############_! _!##_!_ !_ ! _ _!########## ! !####_ ! ! ! ! !## ############ !_! _!####_ _ _! _!##########_ ! ! !_ ! _! ######## !_ _!######_!_ _ _!#### ! ! !_ ! _ _ ! !_!_!_!_!_!## ######_ !_!_!########## !_ _!##_ _ ! !_!_ _! _!########## ####_ !_!_!######## ! ! ! ! _!##_ ! !_!##_ _!########## ####_ !_! !########_ _ _ _!_ _ _!####_! !_!_!######_!_!_!############ ####_ _!######_ _ ! ! ! ! ! ! !_ _!########################## ######_!_! _!########_!_ _ ! _!########################## ########_ _!############_!_!_!_!_!_ !_!############################ ######_ _ _!#### ! ! ! ! !##########_!_!############################## ######_ _ _!##_ _ _!########################################## ####_ _ _ _! ! ! _!_!_! _!########################################## ####_ _ _ ! _ _ _! !_ _!########################################## ####_ _! _!_! _ _!########################################## ####_ !_! _ _!_ !_!_!_!############################################ ####_ _!####_! _!################################################ ######_!_!_!####_ _ _!################################################ ################_ _ _!################################################ ###### ! ! ! !##_ _!################################################ ## !_ _ !_ _!_!################################################## _ _ !_!_ !_ _ _ _!################################################ _ !_! !_ ! _ ! _!################################################ ##_! _ ! ! ! ! ! _! !############################################## ####_!_! _!_ _! _! _ _!############################################ ######_ _! ! _!_ _! _!############################################ ####_ _ _!_ _!_ ! !_!############################################## ####_ _ ! !_ ! _!############################################## ######_!_ ! ! ! !_!_!################################################ ########_ ! ! !_!#################################################### ########_ !_!_!###################################################### ##########_!_!##########################################################
$ ./dynamic.pl 250 1419687903 ############## ! !###################################################################################################### ########## ! ! _!#################################################################################################### ########_ _ _! _!#################################################################################################### ########_ _ _ !_ _! !######################################################## ! !#################################### ########_ _ _ _! ! _!############################################## ! ! ! ! _!################################## ########_ ! ! _ _! ! _! ! ! !###### ! ! ! !######## ! ! ! !######## ! ! _ ! _! ! ! ! !######################## ########_ _ !_ ! _! ! ! _! ! ! _ _! !##_ _ _ _!####_ _! _!_!_! _!###################### ######## ! ! ! _! _! ! !_ ! ! _ _!_! _! ! _! _ _!####_ _!_!_!######_!_!_!_!_! _!########## ! ! ! !## ###### ! _ _!_ _ _ _! _!_!_!_! _!####_!_! _! ! _!##_ ! ! !##################_! _! !####_ _ _ _! ####_ _! ! ! ! ! !##_!_!########_!_!##########_!_!_!_!_ ! _! ! ! _!##################_! _! !_ _! _! ####_ _ _ ! _ _ _!####################################_!_!_! !_ _! _!####################_!_! _! ! _!_!## ######_ _!_ ! ! _!##########################################_!_! _!########################_!_! ! _!_ _!## ###### !_ _ _ _! _ _!##############################################_!_!_!_!############################_ ! _!## ## ! ! _! !_ _!################################################################################## !_!_! !_!_!#### _ ! ! ! _ _!################################################################################_ ! _!###### ##_!_!_!_!_!_! _!################################################################################_ _! ! !_!######## ##############_!_!##################################################################################_ !_ _!######## ####################################################################################################_ !_!_! ! !###### ######################################################################################################_! ! ! _!#### ######################################################################################################_ ! ! ! _!#### ################################################################################################ ! ! !##_!_!_ !_ _!## ##############################################################################################_ _ !_ _ ! ! ! _!## ################################################################################################_!_ !_ ! ! ! _!## ####################################################################################################_!_!_! ! ! ! ! _!## ########################################################################################################_ _! ! ! _!## ########################################################################################################_ _ !_ ! _!## ##########################################################################################################_ _ !_! _!## ############################################################################################################_ _!## ##############################################################################################################_!_!_!####
Advantages
The main advantage of this technique is that, since cells are stored in a hash, memory usage grows only one cell at a time.
It is also easily customizable because this technique is just one (recursive backtracker covered by one cell long dead-ends) of the many possible implementations of the Growing tree algorithm described by Walter D. Pullen on Think Labyrinth [1]. With only a few minor changes, the results can be very different. "For example, if you always pick the most recent cell added to it, this algorithm turns into the recursive backtracker. If you always pick cells at random, this will behave similarly but not exactly to Prim's algorithm. If you always pick the oldest cells added to the list, this will create Mazes with about as low a river factor as possible, even lower than Prim's algorithm. If you usually pick the most recent cell, but occasionally pick a random cell, the Maze will have a high river factor but a short direct solution. If you randomly pick among the most recent cells, the Maze will have a low river factor but a long windy solution."
If you remove the inner walls, you get a Dynamically Sized Cave.