(local { : view } (require :fennel)) (local { : merge } (require :lume)) ;; who needs a test framework when you have lisp macros? (macro expect [text actual expected] `(let [actual# ,actual] (or (match actual# ,expected true _# false) (assert false (view { :text ,text :expected ,expected :actual actual# }))))) (fn rotate [direction rotation] (let [chooser (match rotation :r { :n :e :e :s :s :w :w :n } :l { :n :w :w :s :s :e :e :n })] (. chooser direction))) (fn command [rover string] (match string :f (match rover.direction :n (merge rover {:y (+ rover.y 1)}) :s (merge rover {:y (- rover.y 1)}) :w (merge rover {:x (- rover.x 1)}) :e (merge rover {:x (+ rover.x 1)})) :r (merge rover {:direction (rotate rover.direction :r)}) :l (merge rover {:direction (rotate rover.direction :l)}) _ (assert false (. "unrecognised command " string)))) (fn execute [rover [cmd & cmds]] (let [r1 (command rover cmd)] (if (next cmds) (r1:execute cmds) r1))) (fn rover [x y direction] {: x : y : direction : execute }) (let [r (rover 7 15 :n)] (expect "rover knows (x,y) and the direction (N,S,E,W) it is facing" r {:x 7 :y 15 :direction :n})) (let [r (rover 0 0 :n)] (expect "The rover receives a character array of commands" (r:execute [:f :f :f]) {})) (let [r (rover 0 0 :n)] (expect "Moves north when pointing north and asked to move forward" (r:execute [:f]) {:x 0 :y 1 :direction :n})) (let [r (rover 3 2 :s)] (expect "Moves south when pointing south and asked to move forward" (r:execute [:f]) {:x 3 :y 1 :direction :s})) (let [r (rover 0 0 :w)] (expect "Moves west when pointing west and asked to move forward" (r:execute [:f]) {:x -1 :y 0 :direction :w})) (let [r (rover 0 0 :e)] (expect "Moves east when pointing east and asked to move forward" (r:execute [:f]) {:x 1 :y 0 :direction :e})) (let [r (rover 1 1 :s)] (expect "The rover acts on multiple commands" (r:execute [:f :f :f]) {:x 1 :y -2 :direction :s})) (let [r (rover 2 4 :e)] (expect "Rotates to south when pointing east and asked to turn right" (r:execute [:r]) {:x 2 :y 4 :direction :s})) (let [r (rover 2 4 :s)] (expect "Rotates to east when pointing south and asked to turn left" (r:execute [:l]) {:x 2 :y 4 :direction :e})) (let [r (rover 2 4 :w)] (expect "Rotates to north when pointing west and asked to turn right" (r:execute [:r]) {:x 2 :y 4 :direction :n})) (print "OK")