Package: pyastar2d
PyAstar2DThis is a very simple C++ implementation of the A* algorithm for pathfinding
on a two-dimensional grid.  The solver itself is implemented in C++, but is
callable from Python.  This combines the speed of C++ with the convenience of
Python.I have not done any formal benchmarking, but the solver finds the solution to a
1802 by 1802 maze in 0.29s and a 4008 by 4008 maze in 0.83s when running on my
nine-year-old Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz.  SeeExample
Resultsfor more details.Seesrc/cpp/astar.cppfor the core C++ implementation of the A* shortest
path search algorithm,src/pyastar2d/astar_wrapper.pyfor the Python wrapper
andexamples/example.pyfor example usage.When determining legal moves, 4-connectivity is the default, but it is possible
to setallow_diagonal=Truefor 8-connectivity.InstallationInstructions for installingpyastar2dare given below.From PyPIThe easiest way to installpyastar2dis directly from the Python package index:pip install pyastar2dFrom sourceYou can also installpyastar2dby cloning this repository and building it
yourself.  If running on Linux or MacOS, simply runpipinstall.from the root directory.  If you are using Windows you may have to install Cython manually first:pipinstallCython
pipinstall.To check that everything worked, run the example:pythonexamples/example.pyAs a dependencyIncludepyastar2din yourrequirements.txtto install frompypi, or add
this line torequirements.txt:pyastar2d @ git+git://github.com/hjweide/pyastar2d.git@master#egg=pyastar2dUsageA simple example is given below:importnumpyasnpimportpyastar2d# The minimum cost must be 1 for the heuristic to be valid.# The weights array must have np.float32 dtype to be compatible with the C++ code.weights=np.array([[1,3,3,3,3],[2,1,3,3,3],[2,2,1,3,3],[2,2,2,1,3],[2,2,2,2,1]],dtype=np.float32)# The start and goal coordinates are in matrix coordinates (i, j).path=pyastar2d.astar_path(weights,(0,0),(4,4),allow_diagonal=True)print(path)# The path is returned as a numpy array of (i, j) coordinates.array([[0,0],[1,1],[2,2],[3,3],[4,4]])Note that all grid points are represented as(i, j)coordinates.  An example
of usingpyastar2dto solve a maze is given inexamples/maze_solver.py.Example ResultsTo test the implementation, I grabbed two nasty mazes from Wikipedia.  They are
included in themazesdirectory, but are originally from here:SmallandLarge.
I load the.pngfiles as grayscale images, and set the white pixels to 1
(open space) and the black pixels toINF(walls).To run the examples specify the input and output files using the--inputand--outputflags.  For example, the following commands will solve the small and
large mazes:python examples/maze_solver.py --input mazes/maze_small.png --output solns/maze_small.png
python examples/maze_solver.py --input mazes/maze_large.png --output solns/maze_large.pngSmall Maze (1802 x 1802):timepythonexamples/maze_solver.py--inputmazes/maze_small.png--outputsolns/maze_small.png
Loadedmazeofshape(1802,1802)frommazes/maze_small.png
Foundpathoflength10032in0.292794s
Plottingpathtosolns/maze_small.png
Done

real0m1.214s
user0m1.526s
sys0m0.606sThe solution found for the small maze is shown below:Large Maze (4002 x 4002):timepythonexamples/maze_solver.py--inputmazes/maze_large.png--outputsolns/maze_large.png
Loadedmazeofshape(4002,4002)frommazes/maze_large.png
Foundpathoflength783737in0.829181s
Plottingpathtosolns/maze_large.png
Done

real0m29.385s
user0m29.563s
sys0m0.728sThe solution found for the large maze is shown below:MotivationI recently needed an implementation of the A* algorithm in Python to find the
shortest path between two points in a cost matrix representing an image.
Normally I would simply usenetworkx, but for
graphs with millions of nodes the overhead incurred to construct the graph can
be expensive.  Considering that I was only interested in graphs that may be
represented as two-dimensional grids, I decided to implement it myself using
this special structure of the graph to make various optimizations.
Specifically, the graph is represented as a one-dimensional array because there
is no need to store the neighbors.  Additionally, the lookup tables for
previously-explored nodes (their costs and paths) are also stored as
one-dimensional arrays.  The implication of this is that checking the lookup
table can be done in O(1), at the cost of using O(n) memory.  Alternatively, we
could store only the nodes we traverse in a hash table to reduce the memory
usage.  Empirically I found that replacing the one-dimensional array with a
hash table (std::unordered_map) was about five times slower.TestsThe default installation does not include the dependencies necessary to run the
tests.  To install these, first runpipinstall-rrequirements-dev.txtbefore runningpy.testThe tests are fairly basic but cover some of the
more common pitfalls.  Pull requests for more extensive tests are welcome.ReferencesA* search algorithm on WikipediaPathfinding with A* on Red Blob Games