| Crates.io | astar-mumu |
| lib.rs | astar-mumu |
| version | 0.2.0-rc.4 |
| created_at | 2025-08-15 16:09:05.413714+00 |
| updated_at | 2025-10-08 03:19:35.612895+00 |
| description | A* algorithm plugin for the Lava language |
| homepage | https://lava.nu11.uk |
| repository | https://gitlab.com/tofo/astar-mumu |
| max_upload_size | |
| id | 1797039 |
| size | 125,900 |
A fast, pragmatic grid-search & map-generation plugin for the Lava/MuMu language:
• Path-finding on 2D grids (unit-cost BFS)
• Deterministic maze & “boulders” field generators
• PNG renderers for maps and solution paths
This crate builds a dynamic plugin library (libmumuastar.*) that the Lava/MuMu runtime can extend("astar"). It registers a small, cohesive toolbox for 2D grid work:
astar:maze(seed, [width=21], [height=21], [sx=0], [sy=0], [ex=width-1], [ey=height-1]) -> descriptor
Generates a perfect maze by randomized DFS carve. Width and height must be odd and ≥ 3. Returns a descriptor (keyed array) with:
dimension : [width, height]start : [sx, sy]end : [ex, ey]obj : [[x,y], ...] // walls/obstacles (closed cells)astar:boulders([ seed, width, height, count, start?, end? ]) -> descriptor
Samples several filled ellipses (“boulders”) with a deterministic RNG (via fastrand) to create a natural-looking obstacle field. Returns the same descriptor shape as astar:maze.
astar:path(descriptor, [sx,sy], [ex,ey]) -> descriptor'
Computes a unit-cost BFS from start to end. If the requested start/end are blocked, it will snap each to the nearest passable cell within a small radius (10), otherwise it fails gracefully. Returns the input map augmented with:
requested_start : [rx, ry]requested_end : [rx, ry]start : [sx, sy] // possibly snappedend : [ex, ey] // possibly snappedsnapped_start : true (optional)snapped_end : true (optional)path : [[x,y], ...] // present when a route existssuccess : boolcost : float // == path length for unit costpathLength : intastar:astar(descriptor) -> descriptor'
Accepts a single descriptor (with dimension, start, end, obj). Runs a BFS and returns the same map extended with:
path, success, cost, pathLengthsteps : int // node expansionstimeMs : int // wall-clock time at this call siteNote on the name: This crate is named astar-mumu, but the current search implementation is a fast, simple BFS for unit-weight grids. For weighted costs, an A* variant can be introduced later without changing the descriptor format.
astar:png(descriptor, "file.png") -> descriptor'
Renders a black/white image (walls black, open cells white). If path is present, it is over-painted in green. Returns the descriptor plus:
png_file : "file.png"astar:maze_png(seed, [width], [height], [...], "file.png") -> descriptor
Convenience for “generate + save”: produces the maze image and returns the descriptor.
astar:path_png(descriptor, "file.png") -> descriptor
Computes a path (BFS) for the provided descriptor and draws it directly to disk in green.
All functions in this plugin speak the same compact keyed-array schema:
[
dimension: [width:int, height:int], // 0 ≤ x < width, 0 ≤ y < height
start: [sx:int, sy:int], // optional on generators
end: [ex:int, ey:int],
obj: [[x:int, y:int], ...], // obstacles (closed cells)
// solver/renderer outputs may add:
path: [[x:int, y:int], ...],
success: bool,
cost: float, // == path length for unit grids
pathLength: int,
// solver bookkeeping:
steps: int, // node expansions (astar:astar)
timeMs: int, // runtime in ms (astar:astar)
requested_start: [rx:int, ry:int],
requested_end: [rx:int, ry:int],
snapped_start: true,
snapped_end: true,
// renderer bookkeeping:
png_file: "file.png"
]
0 ≤ x < width, 0 ≤ y < height.obj is a list of blocked coordinates (walls).path is a list of coordinates from start to end (inclusive).(width, height) must be odd to satisfy perfect-maze carving rules.astar:path will not mutate your obj; it only augments fields in the descriptor it returns.These are Lava/MuMu snippets showing typical flows. They assume your host has loaded the plugin with
extend("astar"). No install steps are shown here.
Maze → path → PNG
extend("astar")
// Create a perfect 41x41 maze and solve from top-left to bottom-right:
m = astar:maze(42, 41, 41, 0, 0, 40, 40)
s = astar:path(m, [0,0], [40,40])
astar:png(s, "maze.png") /* path painted green */
Boulders field → path → PNG
extend("astar")
desc = astar:boulders([
seed: 1337,
width: 60,
height: 40,
count: 12
])
solved = astar:path(desc, [1,1], [58,38])
astar:png(solved, "boulders.png")
Single-call solver with runtime stats
extend("astar")
input = [
dimension: [50, 30],
start: [1, 1],
end: [48, 28],
obj: [[10,10],[10,11],[10,12]] // etc...
]
out = astar:astar(input)
slog(out.steps, out.timeMs, out.success, out.pathLength)
fastrand seeded by your seed (and, for mazes, the carve also incorporates (sx, sy) to avoid trivial bias). Given the same inputs you get identical outputs.steps field in astar:astar is the expansion count; timeMs is wall-clock at the Rust call site.astar:path): If either requested endpoint is blocked, the solver tries to snap it to the nearest passable cell within a small radius (10). It records requested_* and sets snapped_* flags when that happens. If no passable cell is found within the radius, it returns success=false with an empty path.png_file.| Function | Kind | Inputs | Output (adds/returns) |
|---|---|---|---|
astar:maze(seed, [w], [h], [sx], [sy], [ex], [ey]) |
generator | integers (w,h odd, ≥3) | descriptor with dimension,start,end,obj |
astar:boulders([seed, width, height, count, start?, end?]) |
generator | keyed array | descriptor with dimension,start,end,obj |
astar:path(descriptor, [sx,sy], [ex,ey]) |
solver | descriptor + endpoints | descriptor + requested_*, (possibly snapped) start/end, path, success, cost, pathLength |
astar:astar(descriptor) |
solver | descriptor (must contain start/end) |
descriptor + path, success, cost, pathLength, steps, timeMs |
astar:png(descriptor, "file.png") |
renderer | descriptor (optionally with path) |
descriptor + png_file |
astar:maze_png(...) |
generator+renderer | seed + dims + "file.png" |
descriptor (image saved) |
astar:path_png(descriptor, "file.png") |
solver+renderer | descriptor + filename | descriptor (image saved) |
core-mumu = 0.9.0-rc.4 (see Cargo.toml).host feature; the produced dynamic library is discoverable by Lava’s loader (extend("astar") looks for libmumuastar.*).wasm feature for compilation. (Dynamic loading is a host concern; renderer functions rely on the image crate and are intended for native use.)indexmap for stable descriptor key order, fastrand for generation, and image for PNG output. Optional libloading is present for parity in host builds.Functions return descriptive errors when inputs are invalid. Typical messages include:
maze ⇒ width and height must be odd numbers ≥ 3astar:path ⇒ start must be [x,y]path_png ⇒ second arg must be single stringastar:png ⇒ descriptor missing 'dimension'At the Lava level these are surfaced as runtime errors.
Contributions that add weighted costs, true A* heuristics, diagonal move policies, or alternative map generators are welcome. The grid descriptor is intentionally minimal so extensions remain straightforward.
Dual-licensed under either of:
at your option.
See the crate’s Cargo.toml for canonical metadata and the repository for license texts.