Generating, visualising, playing around with mazes
A hobby project to familiarize myself with Git.
But mazes are so amazing that, after writing code to build arbitrarily large ones, I naturally had to extend functionality to have them solved, printed, drawn and colored in by the computer, too.
In essence, mazing.py
provides a handy Maze
class to mess around with.
To play around with implemented functionality, run playground.py
directly to try stuff out on the command line.
I tried adding Google-style docstrings to everything, so help(...)
might yield sensible information for usage of any script/module (c.f. code examples in last section).
Functionality includes but is not limited to
- Randomly carving (so-called) 'perfect' mazes with a unique solution.
- Common maze (graph) algorithms implemented [Growing tree, backtracker, (simplified) Prim's, Kruskal's, Wilson's, divide-and-conquer]
- Mix of different methods ('x-divide-and-conquer')
- Text art.
- 7 different ways to print maze as text (including 3 w/ solution path)
- Imaging.
- Normal PNG
- Solution path
- Colored by distance from entrance (heatmap)
- Colored by algorithm usage (for mixed maze generation)
- Animation.
- Use any of above imaging methods to visualize building of a maze
- Computing information.
- Solution path
- Longest possible path through maze, and other interesting stats
Timeless maze art for any(?)(!) console.
ASCII 'frame'
+ +---+---+---+---+---+---+---+---+---+
| | |
+ +---+ + +---+---+---+ +---+ +
| | | | | | |
+ + + +---+ + +---+---+ +---+
| | | | |
+ +---+ + +---+---+---+---+---+ +
| | | | | | | |
+ + +---+ + + +---+ + + +
| | | | | | | |
+ +---+ +---+---+ + +---+ + +
| | | | | | |
+ + +---+---+ + +---+---+---+ +
| | | | | |
+ + + + +---+---+---+---+ + +
| | | | | | | |
+ + + + + + + + +---+ +
| | | | | | | | | |
+ +---+ +---+---+ +---+ + + +
| | | |
+---+---+---+---+---+---+---+---+---+ +
'Minimalist' ASCII frame
, ______________________________,
| ,__ |___, |_, , , |___, |___, |
| | , , ,_| __| |_|_, | | __, | |
|_|_| | |__ __|__ | | , | , | , |
| |__ | |___, | ,_| __|___| |_| |
| ,___| | __|__ | | , | ____|_, |
| |__ |_| ________|_|_|___| __| |
| ____| ,_, __| , , |____ ,__ | |
|____ |_| | , |_| |__ , , |_____|
| |_, | ,___|_| |_| , |_|_| ____|
| ,_|__ | | ,__ | ,_|_| | |__ | |
| | | __, ,_| __|_| |_, , |__ , |
| , | , | |__ , |__ __| |__ , | |
| | ,_| |_| , | , __, ,_| __|_| |
| |_| |_| |_| | |_, | | |__ __|_|
| ,__ | , |___|_| |_| | , ,__ __|
|_|_____|___|_________|_|_|____ |
Note
Certain special box/frame characters may not display/align correctly.
Show Unicode arts
'Frame'
β· βββββββββββββ¬ββββββββββββββ¬ββββ
β β΅ β· βββββ¬ββ΄ βββββ΄ β· βββββββ β· β
β βΆββΌββ β· βββββββββ βββ β· βΆββ¬ββ β
βββ΄ β βΆββΌββββββ¬ββ΄ β β βββ΄ββ΄ β βββ€
β β· βββ΄ βββ΄ βΆββ€ βΆββ΄ββ βββ¬ββββ β β
β βββββββ€ βββ βββββ¬ββββ β βΆββ¬ββ β
β β βΆββββ β βββββ β βΆββββ΄ββ β βΆββ€
β β βΆββ¬ββ¬ββ΄ββ΄ βββ β βββββ β΅ βββ΄ β
β βββ β β β· βΆββ΄ββ¬ββ βββ βββ β΅ β· β
βββ΄ β β΅ β βββββ βββββ βββ΄ βββ¬ββ β
β β· β β· β βββ΄ βββ¬ββ¬ββ β βββββ€ βββ€
β β βββ€ β βββ β΅ β β βΆββ βββ β΅ β β
β βββ β΅ β΅ β β βΆββ€ βββββββββΌββ¬ββ β
β β β βββ΄ β βββ΄ β βββββ΄ β· β΅ β β· β
β β β β βββ β βββ βββ βΆββ΄ββ¬ββ΄ββ β
β β΅ β βββ βββ βββββ΄ βββββ΄ βββ΄ β· β
βββββ΄ββββββ΄ββββββββββ΄ββββββββββ β΅
'Half-block'
β βββββββββββββββββββββββββββββββ
βββ βββ βββ βββ βββ β βββββ βββ β
βββββ βββββββ βββββ βββββββ βββββ
βββ βββ βββ β βββ βββ βββ βββββ β
βββββββ βββββββββ βββββββββββββββ
β βββ βββββ βββ βββ βββ βββ β βββ
βββ βββββββ βββββββββ βββββββ βββ
β βββββ βββ β βββββ β βββββ βββ β
βββββββββ βββββββββββββββββββββββ
βββ β βββ βββ βββ βββββ β βββ βββ
βββ βββββββββββ βββββββ β βββββββ
βββ β βββββ β βββββ βββ βββ βββ β
βββ βββββββββββββββ βββββββββββββ
βββ β βββββ βββ βββ β βββ βββββ β
βββββ βββββ βββββ βββββββββββββ β
βββ βββ β βββββ βββ βββ βββ βββ β
βββββββββββββββββββββββββ βββββββ
'Quarter-block'
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββ
'Pipes'
ββββββββββββββββββββββββββββββββββββββββββββββββ
β ββ ββ ββ ββββββ ββ ββ ββ ββ ββ ββ β
β ββ ββ ββ ββββββ ββ ββ ββ ββ ββ ββ β
β ββ ββ ββ ββ ββββββ ββββββ ββ ββ ββ β
β ββ ββ ββ ββ ββββββ ββββββ ββ ββ ββ β
β ββββββ ββ ββ ββββββββββ ββββββββββ βββββ
β ββββββ ββ ββ ββββββββββ ββββββββββ βββββ
β ββ ββββββββββββββ ββ ββ ββββββ ββ ββ β
β ββ ββββββββββββββ ββ ββ ββββββ ββ ββ β
β ββββββ ββ ββ ββ ββ ββββββ ββββββ βββββ
β ββββββ ββ ββ ββ ββ ββββββ ββββββ βββββ
β ββ ββ ββ ββ ββ ββ ββ ββ ββ ββ ββ β
β ββ ββ ββ ββ ββ ββ ββ ββ ββ ββ ββ β
β ββββββββββ ββββββ ββ ββββββ ββ ββββββ β
β ββββββββββ ββββββ ββ ββββββ ββ ββββββ β
β ββ ββ ββ ββ ββββββ ββ ββ ββββββ ββ β
β ββ ββ ββ ββ ββββββ ββ ββ ββββββ ββ β
β ββ ββ ββ ββ ββ ββββββ ββββββ ββ ββ β
β ββ ββ ββ ββ ββ ββββββ ββββββ ββ ββ β
βββββ ββ ββ ββββββ ββ ββ ββ ββββββ ββ β
βββββ ββ ββ ββββββ ββ ββ ββ ββββββ ββ β
β ββββββ ββββββ ββ ββ ββ ββ ββ ββββββ β
β ββββββ ββββββ ββ ββ ββ ββ ββ ββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββ
This 20Γ20 maze was generated by a randomized-DFS carving method, which usually leads to long, winding tunnels compared to other methods.
Solution of a 128Γ128 randomized-Kruskal maze.
'Great Wave off Kanagawa'
1920Γ1080 maze wallpaper variation (see others here)
'Magma' colormap.
'x-divide-and-conquer' (better name pending) is a variation on normal divide-and-conquer where any recursive call may decide to let an arbitrary algorithm finish the remaining subsection. This allows mazes to be correctly and seamlessly built using independent perfect maze algorithms. (*Note that actual implementation includes a clear-area subalgorithms, because having empty rooms in the maze is fun)
Generate a simple maze and print it to console (Unicode & ASCII).
from mazing import Maze
# Blank, new maze
my_maze = Maze(16,16)
# Randomize maze
my_maze.backtracker()
# Use a Unicode string function
print(my_maze.str_frame())
# Use an ASCII string function
print(my_maze.str_frame_ascii())
Generate a large maze and save a normal image and a solution.
from mazing import Maze
# Blank, new maze
my_maze = Maze(100,100)
# Randomize maze
my_maze.growing_tree()
# Generate normal image, then save it
img = my_maze.generate_image()
img.save(img.filename)
# Generate solution image, then save it
imgsol = my_maze.generate_solutionimage()
imgsol.save(imgsol.filename)
Generate an animation of how `backtracker` works.
from mazing import Maze
# Generate animation frames
(frames, _resulting_maze) = Maze.generate_animation(16,16, Maze.backtracker)
# Save frames as .gif animation
frames[0].save(
frames[0].filename,
save_all=True,
append_images=frames[1:],
duration=30,
)
Make a very large maze to be used as HD desktop wallpaper.
from mazing import Maze
import colortools as ct
# Blank, new maze
my_maze = Maze(1920,1080) # (<!- Python be slow)
# Randomize maze
my_maze.backtracker()
# Precomputes distances
my_maze.compute_distances()
# Generate image
imgdst = my_maze.generate_colorimage(
gradient_colors=ct.COLORMAPS['acton'][::-1], # (Makes bright -> dark)
raster=my_maze.generate_raster(
wall_air_ratio=(0,1), # (No walls, Only air)
show_distances=True # (Color in distances)
)
)
# Save image
imgdst.save(imgdst.filename)
Generate an interesting maze, then slowly escalate customization when saving images.
from mazing import Maze
import colortools as ct
my_maze = Maze(256,256)
my_maze.xdivision()
# 1) Solution image
imgsol = my_maze.generate_solutionimage()
imgsol.save(imgsol.filename)
# 2) Normal image, altered colors
img = my_maze.generate_image(
wall_air_colors=(ct.COLORS['sepia'],ct.COLORS['vellum']),
)
img.save(img.filename)
# 3) Algorithms map, raster adapted
imgalg = my_maze.generate_algorithmimage(
raster=my_maze.generate_raster(
decolumnated=True,
wall_air_ratio=(1,2),
show_algorithms=True,
),
)
imgalg.save(imgalg.filename)
# 4) Branch distances, colors and raster adapted
my_maze.compute_branchdistances()
imgdst = my_maze.generate_colorimage(
gradient_colors=ct.COLORMAPS['redyellowblue'][::-1], # makes bright -> dark
raster=my_maze.generate_raster(
decolumnated=True,
wall_air_ratio=(1,2),
show_distances=True,
),
)
imgdst.save(imgdst.filename)
Messing with mazes is tons of fun, and their graph algorithms are interesting (lots of different 'flavors' of mazes), also ASCII art is cool, and, then I uh, kinda got lost learning about different color spaces and what makes good color gradients for scientific graphs too, and, and Python decorators kept me occupied (& did you know that yield from
is a valid syntax struct in Python?), so anyway uh....
Purposes of each file;
-
mazing.py
- Main maze functionality (see above) -
playground
- Sandbox functionality to trymazing
. -
benchmark.py
- Personal mini-benchmark script. -
colortools.py
- Homebrewn color module.- Common/useful color constants
- Interpolation functions
- Color gradient presets
- Conversion between color spaces
-
benchtools.py
- Minimal timing decorators.timed
to time a function by its name- explicit
timed_titled
for lambdas
-
prototype_gridrunner.py
- Unfinished top-down maze navigator implemented usingcurses
. I don't intend on continuing work on it.- Should correctly display and appropriately scroll large mazes.
- Navigate the maze on-screen using arrow keys or w, a, s, d.
- Use shift in combination with the latter to jump to next wall.
- Jamis Buck
- Walter Pullen
- Javidx9
- armin-reichert