Skip to content

Instantly share code, notes, and snippets.

@daemianmack
Created April 7, 2012 11:40
Show Gist options
  • Save daemianmack/2327943 to your computer and use it in GitHub Desktop.
Save daemianmack/2327943 to your computer and use it in GitHub Desktop.
my mars-rover solution with boundary checking and an attempt at concurrency
(ns mars_rover)
(use '[clojure.string :only (split)])
(defmulti handle-move (fn [x y move facing] [(str move) facing]))
(defmethod handle-move ["M" "N"] [x y move facing] [x (+ y 1) facing])
(defmethod handle-move ["M" "E"] [x y move facing] [(+ x 1) y facing])
(defmethod handle-move ["M" "S"] [x y move facing] [x (- y 1) facing])
(defmethod handle-move ["M" "W"] [x y move facing] [(- x 1) y facing])
(defmethod handle-move ["R" "N"] [x y move facing] [x y "E"])
(defmethod handle-move ["R" "E"] [x y move facing] [x y "S"])
(defmethod handle-move ["R" "S"] [x y move facing] [x y "W"])
(defmethod handle-move ["R" "W"] [x y move facing] [x y "N"])
(defmethod handle-move ["L" "N"] [x y move facing] [x y "W"])
(defmethod handle-move ["L" "E"] [x y move facing] [x y "N"])
(defmethod handle-move ["L" "S"] [x y move facing] [x y "E"])
(defmethod handle-move ["L" "W"] [x y move facing] [x y "S"])
(defn spawn-grid [[x y]]
(def grid
(ref
(vec (replicate (inc y) (vec (replicate (inc x) \_)))))))
(defn print-grid [label]
(let [the-grid @grid]
(println label)
(doseq [y the-grid]
(println y)))
(prn))
(defn mark-grid [x y string]
(dosync
(let [the-grid (deref grid)
num-ys (count the-grid)
reversed-y (- num-ys y)]
(alter grid assoc reversed-y (assoc (the-grid reversed-y) x string)))))
(defn clear-grid [x y]
(mark-grid x y \_))
(defn spot-available? [x y rover]
(let [spot (nth (nth @grid y) x)]
(or (= spot rover)
(= spot \_))))
(defn inside-grid? [x y]
(let [max_x (count (nth @grid 0))
max_y (count @grid)]
(and (>= x 0)
(>= y 0)
(<= x max_x)
(<= y max_y))))
(defn move-valid? [x y rover]
(and (inside-grid? x y)
(spot-available? x y rover)))
(defn manage-move [rover x y move facing]
(let [rover rover
old_x x
old_y y
old_facing facing
[x y facing] (handle-move x y move facing)]
(if (not (move-valid? x y rover))
[old_x old_y old_facing]
(do
(clear-grid old_x old_y)
(mark-grid x y rover)
(print-grid ["rover:" rover "at" old_x old_y old_facing "=>" x y facing])
[x y facing]))))
(defn do-move [instruction]
(loop [rover (instruction :rover)
x (instruction :x)
y (instruction :y)
facing (instruction :facing)
moves (instruction :moves)]
(if (empty? moves)
(print-grid "Complete.")
(let [[x y facing] (manage-move rover x y (first moves) facing)]
(Thread/sleep (rand 1000))
(recur rover x y facing (rest moves))))))
(let [rover-count (atom 0)]
(defn new-rover-id []
(swap! rover-count + 1)))
(defn parse-int [x]
(Integer/parseInt x))
(defn parse-args [input]
"Parse new-line-delimited input into 1) grid size, and 2) rover command pairs."
(let [rover 0
lines (split input #"\n")
grid (map parse-int (split (first lines) #"\s"))
cmd-pairs (partition 2 (rest lines))]
[grid cmd-pairs]))
(defn parse-rover-instructions [cmd-pairs]
"Parse new-line-delimited input into infinite series of a) x and
b) y starting coordinates, c) initial facing direction, and d) series
of turns/moves."
(for [pair cmd-pairs]
(let [rover (new-rover-id)
xyf (split (nth pair 0) #"\s")
x (Integer/parseInt (nth xyf 0))
y (Integer/parseInt (nth xyf 1))
facing (nth xyf 2)
moves (nth pair 1)]
{:rover rover :x x :y y :facing facing :moves moves})))
(def input "5 5
1 2 N
LMLMLMLMM
3 3 E
MMRMMRMRRM")
(defn -main []
(let [[grid cmd-pairs] (parse-args input)]
(spawn-grid grid)
(doseq [rover (parse-rover-instructions cmd-pairs)]
(send (agent {}) doall (do-move rover)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment