Prim's Algorithm in ClojureScript

If you want to jump to the animation in its natural habitat, see it here. If you want to jump to the code: see the ClojureScript or JavaScript on GitHub.

After being interested in maze generation and after checking out the Wikipedia page, I thought it’d be cool to implement one in JavaScript. After that, it looked like a good opportunity to try porting some JavaScript to ClojureScript.

For the sake of brevity I’m leaving some of the more boilerplate functions out of this post. For the full code in each language, see the GitHub links above.

Von Neumann neighborhood

Von Neumann neighborhood

var vonNeumannNeighborhood = function(cell) {
  return [[-1, 0], [1, 0], [0, -1], [0, 1]].map(function(dir) {
    var y = cell[0] + dir[0];
    var x = cell[1] + dir[1];
    return [y, x];
  });
};
(defn von-neumann-neighborhood [coord]
  [(map
    (fn [dir]
      [(+ (first coord) (first dir)) (+ (last coord) (last dir))])
    [[-1 0] [1 0] [0 -1] [0 1]]))])

Opposite Cell

In Prim’s algorithm, on each turn we need to pick the opposite wall. The translation is pretty straightforward.

var oppositeCoord = function(from, to) {
  var yDiff = to[0] - from[0];
  var xDiff = to[1] - from[1];
  return [to[0] + yDiff, to[1] + xDiff];
};
(defn opposite-coord [from to]
  (let [yDiff (- (first to) (first from))
        xDiff (- (last to) (last from))]
    [(+ (first to) yDiff) (+ (last to) xDiff)]))

At coordinate

Frequently we need to see what’s at a certain coordinate in our graph data structure. Clojure’s get-in makes working with nested data structures ridiculously easy, since our coordinates (e.g. (y, x)) map directly to the nested data elements.

var at = function(coord) {
  return coord && graph[coord[0]] && graph[coord[0]][coord[1]];
};
(defn at [coord]
  (get-in @graph coord))

Place at coordinate

The opposite of our getter, at, above, place is our setter.

var place = function(coord, item) {
  graph[coord[0]][coord[1]] = item;
};
(defn place [coord item]
  (swap! graph assoc-in coord item))

requestAnimationFrame polyfill

Here we’re using an outer IIFE to cycle through and find the first built-in requestAnimationFrame that exists. If it falls through, we simply supply a regular setTimeout.

window.requestAnimFrame = (function(){
  return window.requestAnimationFrame       ||
         window.webkitRequestAnimationFrame ||
         window.mozRequestAnimationFrame    ||
         function(callback) {
           window.setTimeout(callback, 17);
         };
})();
(def request-animation-frame
  (or (.-requestAnimationFrame js/window)
      (.-webkitRequestAnimationFrame js/window)
      (.-mozRequestAnimationFrame js/window)
      (.-msRequestAnimationFrame js/window)
      (fn [callback] (js/setTimeout callback 17))))