Skip to content

Instantly share code, notes, and snippets.

@tmountain
Created November 2, 2017 14:59
Show Gist options
  • Save tmountain/0a5d39559e67d4f4dde58bb8ffa7370b to your computer and use it in GitHub Desktop.
Save tmountain/0a5d39559e67d4f4dde58bb8ffa7370b to your computer and use it in GitHub Desktop.
(defn A*
"Finds a path between start and goal inside the graph described by edges
(a map of edge to distance); estimate is an heuristic for the actual
distance. Accepts a named option: :monotonic (default to true).
Returns the path if found or nil."
[edges estimate start goal & {mono :monotonic :or {mono true}}]
(let [f (memoize #(estimate % goal)) ; unsure the memoization is worthy
neighbours (reduce (fn [m [a b]] (assoc m a (conj (m a #{}) b)))
{} (keys edges))]
(loop [q (priority-map start (f start))
preds {}
shortest {start 0}
done #{}]
(when-let [[x hx] (peek q)]
(if (= goal x)
(reverse (take-while identity (iterate preds goal)))
(let [dx (- hx (f x))
bn (for [n (remove done (neighbours x))
:let [hn (+ dx (edges [x n]) (f n))
sn (shortest n Double/POSITIVE_INFINITY)]
:when (< hn sn)]
[n hn])]
(recur (into (pop q) bn)
(into preds (for [[n] bn] [n x]))
(into shortest bn)
(if mono (conj done x) done))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment