pathforge

    A MoonBit graph search and grid pathfinding toolkit with BFS, Dijkstra and A*.

    pathfinding
    graph
    astar
    dijkstra
    bfs
    Download zip
    Author
    Version
    0.1.0
    License
    MIT
    Last updated
    3 months ago
    Downloads
    35

    No dependencies

    #PathForge

    PathForge is a lightweight MoonBit graph search and grid pathfinding toolkit. It packages reusable data structures and algorithms for route planning, game AI, algorithm teaching, and WebAssembly demos.

    #Features

    • Directed weighted graph based on adjacency lists
    • BFS for shortest paths by hop count
    • Dijkstra for minimum-cost paths with non-negative edge costs
    • A* with custom heuristics and node reopening for admissible inconsistent heuristics
    • Grid adapter with blocked cells and terrain movement costs
    • Unified PathReport result type with found status, cost, visited count, and path data
    • Unit tests, coverage-ready CI, and a command-line demo

    #Project Layout

    . |-- graph.mbt # Graph, BFS, Dijkstra, A* |-- grid.mbt # Grid pathfinding adapter |-- priority_queue.mbt # Min-priority queue |-- path_report.mbt # Search result type |-- pathforge_test.mbt # Unit tests |-- cmd/main/main.mbt # Demo entry point |-- docs/api.md # Public API reference |-- docs/application.md # Project application notes |-- moon.mod # MoonBit module metadata `-- moon.pkg # Root package config

    #Quick Start

    Install MoonBit, then run:

    moon check moon test moon run cmd/main

    Expected demo output:

    PathForge demo found: true cost: 15 visited: 29 path length: 16

    #Example

    let grid = @pathforge.Grid::new(8, 5)
    grid.set_blocked(@pathforge.Point::{ x: 2, y: 0 }, true)
    grid.set_blocked(@pathforge.Point::{ x: 2, y: 1 }, true)

    let result = grid.astar(
    @pathforge.Point::{ x: 0, y: 0 },
    @pathforge.Point::{ x: 7, y: 4 },
    )
    println("found: \{result.found}")
    println("cost: \{result.cost}")

    #API Documentation

    See docs/api.md for the public API reference.

    #Publishing

    The module metadata in moon.mod includes mooncakes.io fields: license, keywords, repository, description, and homepage.

    Before publishing:

    moon check --deny-warn moon test moon coverage analyze -- -f summary moon package moon publish

    #License

    MIT. See LICENSE.

    Edge

    pub(all) struct Edge {
    to : Int
    cost : Int
    }

    Graph

    pub(all) struct Graph {
    adj : Array[Array[Edge]]
    }

    Graph::add_edge

    fn Graph::add_edge(self : Graph, from : Int, to : Int, cost : Int) -> Unit

    Graph::add_node

    fn Graph::add_node(self : Graph) -> Int

    Graph::add_undirected_edge

    fn Graph::add_undirected_edge(self : Graph, a : Int, b : Int, cost : Int) -> Unit

    Graph::astar

    fn Graph::astar(self : Graph, start : Int, goal : Int, heuristic : (Int, Int) -> Int) -> PathReport

    Graph::bfs

    fn Graph::bfs(self : Graph, start : Int, goal : Int) -> PathReport

    Graph::dijkstra

    fn Graph::dijkstra(self : Graph, start : Int, goal : Int) -> PathReport

    Graph::has_path

    fn Graph::has_path(self : Graph, start : Int, goal : Int) -> Bool

    Graph::in_bounds

    fn Graph::in_bounds(self : Graph, node : Int) -> Bool

    Graph::neighbors

    fn Graph::neighbors(self : Graph, node : Int) -> Array[Edge]

    Graph::new

    fn Graph::new(size : Int) -> Graph

    Graph::node_count

    fn Graph::node_count(self : Graph) -> Int

    Graph::reachable_count

    fn Graph::reachable_count(self : Graph, start : Int) -> Int

    Grid

    pub(all) struct Grid {
    width : Int
    height : Int
    blocked : Array[Bool]
    weights : Array[Int]
    }

    Grid::astar

    fn Grid::astar(self : Grid, start : Point, goal : Point) -> PathReport

    Grid::bfs

    fn Grid::bfs(self : Grid, start : Point, goal : Point) -> PathReport

    Grid::bidirectional_bfs

    fn Grid::bidirectional_bfs(self : Grid, start : Point, goal : Point) -> PathReport

    Grid::cost_at

    fn Grid::cost_at(self : Grid, p : Point) -> Int

    Grid::dijkstra

    fn Grid::dijkstra(self : Grid, start : Point, goal : Point) -> PathReport

    Grid::index

    fn Grid::index(self : Grid, p : Point) -> Int

    Grid::inside

    fn Grid::inside(self : Grid, p : Point) -> Bool

    Grid::is_blocked

    fn Grid::is_blocked(self : Grid, p : Point) -> Bool

    Grid::new

    fn Grid::new(width : Int, height : Int) -> Grid

    Grid::point

    fn Grid::point(self : Grid, index : Int) -> Point

    Grid::set_blocked

    fn Grid::set_blocked(self : Grid, p : Point, value : Bool) -> Unit

    Grid::set_cost

    fn Grid::set_cost(self : Grid, p : Point, cost : Int) -> Unit

    Grid::to_graph

    fn Grid::to_graph(self : Grid) -> Graph

    PathReport

    pub(all) struct PathReport {
    found : Bool
    cost : Int
    visited : Int
    path : Array[Int]
    }

    PathReport::first

    fn PathReport::first(self : PathReport) -> Int?

    PathReport::is_empty

    fn PathReport::is_empty(self : PathReport) -> Bool

    PathReport::last

    fn PathReport::last(self : PathReport) -> Int?

    PathReport::length

    fn PathReport::length(self : PathReport) -> Int

    PathReport::not_found

    fn PathReport::not_found(visited : Int) -> PathReport

    PathReport::single

    fn PathReport::single(node : Int) -> PathReport

    PathReport::success

    fn PathReport::success(cost : Int, visited : Int, path : Array[Int]) -> PathReport

    Point

    pub(all) struct Point {
    x : Int
    y : Int
    }

    PriorityQueue

    pub(all) struct PriorityQueue {
    data : Array[QueueItem]
    }

    PriorityQueue::is_empty

    fn PriorityQueue::is_empty(self : PriorityQueue) -> Bool

    PriorityQueue::length

    fn PriorityQueue::length(self : PriorityQueue) -> Int

    PriorityQueue::new

    PriorityQueue::pop

    PriorityQueue::push

    fn PriorityQueue::push(self : PriorityQueue, node : Int, priority : Int) -> Unit

    QueueItem

    pub(all) struct QueueItem {
    node : Int
    priority : Int
    }