9 ms·
Show HN: Visual A* pathfinding and maze generation in Python
I was fascinated reading through another recent HN submission about a highly efficient implementation of A* in Lisp, which got me thinking about how I could do something similar in Python. However, these kinds of pathfinding algorithms really need complex terrain/mazes with interesting obstructions to showcase what they can do and how they work. So, I started thinking about how I could generate cool and diverse random "mazes" (they aren't really mazes, but I'm not sure what the best term is). I got a bit carried away thinking of lots of different cool ways to generate these mazes, such as cellular automata, fractals, Fourier transforms, etc.
Then it turned out that many of the generated mazes weren't actually solvable, so I spent some time coming up with various strategies to test and validate the generated mazes and then modify them so they would work better for this purpose. I spent a fair amount of effort trying to optimize the performance as much as possible using tools like Numba where applicable, but I also got tired of the code bringing my very powerful machine to its knees. So, I tried to make it play nice with the rest of the system while also saturating a big computer with tons of CPU cores. This was done using concurrent futures with some tweaks, like using a Semaphore and lowering the CPU priority. People might find this project interesting just for these performance-tuning features.
I also spent a lot of time trying to make beautiful-looking animations that show multiple randomly generated mazes side by side, where you can see A* "races" as it tries to solve all the mazes at the same time, showing the current progress. When a solution is found, it is traced out on the screen. It's actually not that easy to get really slick/beautiful looking results straight out of Matplotlib, but if you use custom fonts and tweak a lot of parameters, it starts to look pretty polished.
Now you can just run this on a spare Linux machine and come back in a few hours to have a bunch of cool-looking animations to check out. By changing the grid sizes, you can get very different-looking effects, although larger grids can take a lot of compute power to render. Anyway, I hope you guys like it! I'm happy to answer any questions. I'm sure there are still some bugs, but it has been running pretty well for me and generating lots of cool-looking animations. Note: I know that the pulsating title at the top in the demo video is annoying— I already slowed this way down in the code but didn't want to wait for it to regenerate the video.
- eigenvalue 2y agoHere's a direct link to the YouTube demo video: https://www.youtube.com/watch?v=iA6XJRE6CTM https://www.youtube.com/watch?v=iA6XJRE6CTM Also, here's the Lisp implementation post that inspired me (and which I based my Python code on): https://news.ycombinator.com/item?id=41145528 https://news.ycombinator.com/item?id=41145528 And here are a few other sample videos using different settings-- I'll add more during the day as they finish generating: https://www.dropbox.com/scl/fo/q13cxuvgy8vxr3ksi06uw/APkL57-Lb4wON0QPmpoGG2E?rlkey=2414vt1legk3b872jrbp2kh62&st=jgwwpvik&dl=0 https://www.dropbox.com/scl/fo/q13cxuvgy8vxr3ksi06uw/APkL57-...
- ryandrake 2y agoUgh, it would be nice to be able to pause the final frame of animation to compare each generated path. Instead YouTube replaces it with their obnoxious "next video" suggestions. If you generate another video, I'd suggest artificially "freezing" the results frame for about 5 seconds so it can be seen and compared.
- eigenvalue 2y agoCheck out the other sample videos I linked to in my comment, those are easy to pause in VLC. I can look into extending the final frame for a few seconds, too.
- noufalibrahim 2y agoI like this..I recently used A* to implement laying out connectors between nodes in a graph. I really like the abstraction of a heuristic function. I was able to add in all sorts of things to make the implementation work the way i want (penalise turns, crossing over lines etc.). This would automatically create "last resort" style solutions and minimise ugliness in the diagram.
- eigenvalue 2y agoYes, doing it that way sort of goes beyond the standard A* and becomes more of a "build your own custom pathfinder toolbox" where you can insert any additional considerations you have in your specific problem domain. Sort of like how you can add different factors to a loss function in machine learning (like trying to minimize non-zero parameter count for LASSO in addition to minimizing mean squared error).