-
-
Save jnx/5babc722ce4bcceba9d6c4491a49a593 to your computer and use it in GitHub Desktop.
An implementation of the "Recursive Division" algorithm for maze generation.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -------------------------------------------------------------------- | |
# An implementation of the "Recursive Division" algorithm. This is a | |
# kind of fractal maze algorithm, recursively dividing the maze into | |
# smaller and smaller cells. This algorithm stops at the integer | |
# boundary, but theoretically the algorithm could continue infinitely | |
# to smaller and smaller scales. | |
# | |
# Note that this algorithm is implemented as a "wall adder", rather | |
# than a "passage carver", so the meaning of the bits in each cell | |
# is reversed: instead of the S bit (for instance) meaning "a passage | |
# goes south", it means "there is a wall to the south". | |
# -------------------------------------------------------------------- | |
# -------------------------------------------------------------------- | |
# 1. Allow the maze to be customized via command-line parameters | |
# -------------------------------------------------------------------- | |
width = (ARGV[0] || 10).to_i | |
height = (ARGV[1] || width).to_i | |
seed = (ARGV[2] || rand(0xFFFF_FFFF)).to_i | |
srand(seed) | |
grid = Array.new(height) { Array.new(width, 0) } | |
# -------------------------------------------------------------------- | |
# 2. Set up constants to aid with describing the passage directions | |
# -------------------------------------------------------------------- | |
S, E = 1, 2 | |
HORIZONTAL, VERTICAL = 1, 2 | |
# -------------------------------------------------------------------- | |
# 3. Helper routines | |
# -------------------------------------------------------------------- | |
def display_maze(grid) | |
print "\e[H" # move to upper-left | |
puts " " + "_" * (grid[0].length * 2 - 1) | |
grid.each_with_index do |row, y| | |
print "|" | |
row.each_with_index do |cell, x| | |
bottom = y+1 >= grid.length | |
south = (cell & S != 0 || bottom) | |
south2 = (x+1 < grid[y].length && grid[y][x+1] & S != 0 || bottom) | |
east = (cell & E != 0 || x+1 >= grid[y].length) | |
print(south ? "_" : " ") | |
print(east ? "|" : ((south && south2) ? "_" : " ")) | |
end | |
puts | |
end | |
end | |
def choose_orientation(width, height) | |
if width < height | |
HORIZONTAL | |
elsif height < width | |
VERTICAL | |
else | |
rand(2) == 0 ? HORIZONTAL : VERTICAL | |
end | |
end | |
# -------------------------------------------------------------------- | |
# 4. The recursive-division algorithm itself | |
# -------------------------------------------------------------------- | |
def divide(grid, x, y, width, height, orientation) | |
return if width < 2 || height < 2 | |
display_maze(grid) | |
sleep 0.02 | |
horizontal = orientation == HORIZONTAL | |
# where will the wall be drawn from? | |
wx = x + (horizontal ? 0 : rand(width-2)) | |
wy = y + (horizontal ? rand(height-2) : 0) | |
# where will the passage through the wall exist? | |
px = wx + (horizontal ? rand(width) : 0) | |
py = wy + (horizontal ? 0 : rand(height)) | |
# what direction will the wall be drawn? | |
dx = horizontal ? 1 : 0 | |
dy = horizontal ? 0 : 1 | |
# how long will the wall be? | |
length = horizontal ? width : height | |
# what direction is perpendicular to the wall? | |
dir = horizontal ? S : E | |
length.times do | |
grid[wy][wx] |= dir if wx != px || wy != py | |
wx += dx | |
wy += dy | |
end | |
nx, ny = x, y | |
w, h = horizontal ? [width, wy-y+1] : [wx-x+1, height] | |
divide(grid, nx, ny, w, h, choose_orientation(w, h)) | |
nx, ny = horizontal ? [x, wy+1] : [wx+1, y] | |
w, h = horizontal ? [width, y+height-wy-1] : [x+width-wx-1, height] | |
divide(grid, nx, ny, w, h, choose_orientation(w, h)) | |
end | |
print "\e[2J" # clear screen | |
divide(grid, 0, 0, width, height, choose_orientation(width, height)) | |
display_maze(grid) | |
# -------------------------------------------------------------------- | |
# 5. Show the parameters used to build this maze, for repeatability | |
# -------------------------------------------------------------------- | |
puts "#{$0} #{width} #{height} #{seed}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment