Skip to content

Instantly share code, notes, and snippets.

@mikebridge
Created March 29, 2012 04:37
Show Gist options
  • Save mikebridge/2233330 to your computer and use it in GitHub Desktop.
Save mikebridge/2233330 to your computer and use it in GitHub Desktop.
Codelesson Clojure Assignment 4
(ns codelesson.assignment-4
(:require [clojure.string :as str]))
(defn rotate-left [current-dir]
{:pre [(char? current-dir)]}
((apply hash-map (seq "NWWSSEEN")) current-dir))
(defn rotate-right [current-dir]
{:pre [(char? current-dir)]}
((apply hash-map (seq "NEESSWWN")) current-dir))
(defn rotate [rover f]
(assoc rover :orientation (f (:orientation rover))))
(defn delta-xy [direction]
{:pre [(char? direction)]}
({\N [0 1] \E [1 0] \S [0 -1] \W [-1 0]} direction))
(defn new-point [& vec]
(apply map + vec))
(defn move [rover]
(assoc rover :position
(new-point (:position rover) (delta-xy (:orientation rover)))))
(defn command [cmd]
{:pre [(char? cmd)]}
(cond
(= cmd \M) (fn [rover] (move rover))
(= cmd \R) (fn [rover] (rotate rover rotate-right))
(= cmd \L) (fn [rover] (rotate rover rotate-left))))
(defn rover-hash [position-coords orientation]
{:position (vec position-coords) :orientation orientation})
(defn movement-functions [movement-commands]
(map #(command %1) movement-commands))
;; collisions result in a no-op.
(defn apply-movement [rover plateau-size move-fn]
{:pre [(map? rover) (vector? plateau-size) (fn? move-fn)]}
(let [new-pos (move-fn rover)
maxx (first plateau-size)
maxy (second plateau-size)
x (first (:position new-pos))
y (second (:position new-pos))]
(if (or (< x 0)
(> x maxx)
(< y 0)
(> y maxy))
rover
new-pos)))
(defn rove-
[plateau-size start-pos commands]
{:pre [(vector? plateau-size) (vector? start-pos) (string? commands)]}
(let [move-fns (movement-functions commands)
rover (rover-hash (take 2 start-pos) (start-pos 2))]
(reduce #(apply-movement %1 plateau-size %2) (cons rover move-fns))))
(defn str-to-vec [s]
(read-string (str "[" s "]")))
(defn char-if-sym [s]
(if (symbol? s)
(first (str s))
s))
(defn convert-position [pos]
{:pre [(string? pos)]}
(vec (map char-if-sym (str-to-vec pos))))
(defn rover-to-string [rover]
(str (first (:position rover)) " " (second (:position rover)) " " (:orientation rover)))
(defn positions-to-string [position-list]
(clojure.string/join "\n" (map rover-to-string position-list)))
(defn rove [in]
{:pre [(string? in)]}
(let [lines (clojure.string/split-lines in)
plateau-size (str-to-vec (first lines))
pos-and-command-pairs (partition 2 (rest lines))]
(positions-to-string
(map #(rove- plateau-size
(convert-position (first %))
(first (rest %))) pos-and-command-pairs))))
@mikebridge
Copy link
Author

(ns codelesson.test.assignment-4
  (:use codelesson.assignment-4)
  (:use clojure.test))

(deftest rotate-right-tests
  (are [old new] (= (rotate-right old) new)
       \W \N
       \N \E
       \E \S
       \S \W))

(deftest rotate-left-tests
  (are [old new] (= (rotate-left old) new)
       \N \W
       \E \N
       \S \E
       \W \S))

(deftest rover-rotate-left
  (let [rover (rover-hash [1 2] \N)]
    (is (= \W (:orientation ((command \L) rover))))))

(deftest rover-rotate-right
  (let [rover (rover-hash [1 2] \N)]
    (is (= \E (:orientation ((command \R) rover))))))

(deftest rover-move-freely
  (let [rover (rover-hash [3 3] \N)]
    (is (= [3 4] (:position ((command \M) rover)))))
  (let [rover (rover-hash [3 3] \W)]
    (is (= [2 3] (:position ((command \M) rover)))))
  (let [rover (rover-hash [3 3] \E)]
    (is (= [4 3] (:position ((command \M) rover)))))
  (let [rover (rover-hash [3 3] \S)]    
    (is (= [3 2] (:position ((command \M) rover))))))

(deftest new-point-calc
  (is (= (new-point [3 4] [1 2]) [4 6])))

(deftest sym-if-char-when-sym
  (is (= \N (char-if-sym 'N))))

(deftest sym-if-char-when-int
  (is (= 1 (sym-if-char 1))))

(deftest convert-position-test
  (is (= [1 2 \N] (convert-position "1 2 N"))))

(deftest collide-with-top  
  (is (= {:position [5 5] :orientation \N}
         (apply-movement (rover-hash [5 5] \N) [5 5] (command \M)))))

(deftest move-north
  (is (= {:position [5 5] :orientation \N}
         (apply-movement (rover-hash [5 4] \N) [5 5] (command \M)))))

(deftest collide-with-bottom  
  (is (= {:position [0 0] :orientation \S}
         (apply-movement (rover-hash [0 0] \S) [5 5] (command \M)))))

(deftest move-south
  (is (= {:position [5 3] :orientation \S}
         (apply-movement (rover-hash [5 4] \S) [5 5] (command \M)))))

(deftest move-west
  (is (= {:position [4 3] :orientation \W}
         (apply-movement (rover-hash [5 3] \W) [5 5] (command \M)))))

(deftest collide-with-left  
  (is (= {:position [0 3] :orientation \W}
         (apply-movement (rover-hash [0 3] \W) [5 5] (command \M)))))

(deftest move-east
  (is (= {:position [5 3] :orientation \E}
         (apply-movement (rover-hash [4 3] \E) [5 5] (command \M)))))

(deftest collide-with-right
  (is (= {:position [5 3] :orientation \E}
         (apply-movement (rover-hash [5 3] \E) [5 5] (command \M)))))

(deftest full-movement
  (let [testdata (str "5 5
1 2 N
LMLMLMLMM
3 3 E
MMRMMRMRRM")]
    (is (= (str "1 3 N
5 1 E")
           (rove testdata)))))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment