raymaze0.1.3.mp4
This is a little maze generator written in C. It uses the raylib
and raygui
to draw graphics. It also uses the C standard library, as many C programs do. The rest of the code is completely handwritten.
I really like mazes. I'm not alone in this, I swear! I recently learned C and realized that finally I knew enough to use raylib
to make something actually interesting. I knew that maze generation tends to be a pretty straightforward project from past experience, and figured that it would be a nice challenge to do it in C. I was right on both counts!
The first prototype had ANSI terminal graphics. I was able to split up the terminal display code and the maze-generation code fairly easily – the maze generator was more-or-less unmodified for the first iteration of the GUI.
The text-only generator creates a maze in one shot: call carve_maze()
, boom, you have a maze. I wanted something a little fancier, and figured it would look cool if I could watch the algorithm carve a really large maze, one cell at a time. I could've used something like curses
to make animations in the terminal, but I figured that without using special characters, the resolution would be quite bad. So I wanted to write a proper frontend for it.
raymaze.mp4
Pictured above: The first GUI prototype.
The recursive carve()
function in the original program poses a problem: To animate it, I would need to introduce a delay between every recursive call to carve()
.
Ideally, I would stop the function mid-execution, draw what it had carved so far, then resume execution. The usual primitive for this kind of thing is a coroutine, and while using them would have been quite elegant, C doesn't exactly have easy-to-use built-in coroutines. (Although some people have written some truly cursed macros to mimic them.)
Instead the solution I came to was to make an explicit stack, separate from the call stack, and rewrite carve()
to do one step of the algorithm and alter the stack after it finished. The beautiful, recursive carve()
becomes a slightly uglier, iterative carve_iter()
, which needs a reference to the maze data, and he aforementioned stack to do its dark work.
Then, we simply call carve_iter()
as needed in every draw call: Keep a frame counter frames
, incrementing it every draw()
, then call carve_iter()
when frames
is a multiple of 3, or some other factor. (Higher factors make for slower maze generation.) Animation: achieved!
its_maze.mp4
Then I jazzed up the program a little bit, adding GUI elements with raygui
to control the speed of the generation, and to reset the generator's progress:
raymaze_demo.mp4
(It also goes through a user-defined colour gradient as it carves! :D
)
I also decided to make my own file format, mostly for fun, and also for some semi-practical reasons. Here's a (somewhat) detailed description of the .MAZ file format.
Because I can't resist learning cute DSLs, I also learned enough Tcl to write a Hex Fiend Binary Template, which let me pretty-print the .MAZ
data in my favourite hex editor. Find it in other/MAZ.tcl
in this repository.
- Jamis Buck, for writing the best maze-related content on the web.
- My friends, for putting up with weeks of my maze generation exploits, and cheerleading for me.
- The ASAN team, for releasing a tool that almost makes me feel like I'm writing memory-safe C.