forked from dmitriy-kiriyenko/Mars-Rovers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mars-rovers.clj
84 lines (63 loc) · 2.91 KB
/
mars-rovers.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
(ns marsrovers
(:import (java.io BufferedReader FileReader)))
(def x-min 0)
(def y-min 0)
(def dirs [:N :E :S :W ])
(def dir-count (count dirs))
(def shifts [[0 1] [1 0] [0 -1] [-1 0]])
; -----------------------------------------------------------------------------
; Prepare input data.
(defn- str-to-xy [str]
(vec (map #(Integer/parseInt %) (re-seq #"\d+" str))))
(defn- str-to-dir [str]
(keyword (re-find (re-matcher #"[NEWS]" str))))
(defn- xy-max [file-reader]
(vec (map #(Integer/parseInt %)
(clojure.string/split (first (line-seq file-reader)) #" "))))
(defn- str-to-keywords [string]
(map #(keyword (str %)) (seq string)))
; -----------------------------------------------------------------------------
(defn- write-result [result file-writer]
(let [x (first (first result))
y (second (first result))
dir (name (last (first result)))]
(.write file-writer (str x " " y " " dir "\n"))))
; -----------------------------------------------------------------------------
(defn- remain-between [n min-boundary max-boundary]
(min max-boundary (max n min-boundary)))
(defn- create-rover [[x y dir] plateau]
[(remain-between x (:x-min plateau) (:x-max plateau))
(remain-between y (:y-min plateau) (:y-max plateau))
dir])
(defn- dir-index [dir] (.indexOf dirs dir))
(def moves {:R (fn [[x y dir] plateau]
[[x y (nth dirs (rem (+ (dir-index dir) 1) dir-count))] plateau])
:L (fn [[x y dir] plateau]
[[x y (nth dirs (rem (+ (- (dir-index dir) 1) dir-count) dir-count))] plateau])
:M (fn [[x y dir] plateau]
[(create-rover [(+ x ((shifts (dir-index dir)) 0))
(+ y ((shifts (dir-index dir)) 1))
dir] plateau) plateau])})
(defn- move [[rover plateau] step]
(let [make-move (moves step)]
(make-move rover plateau)))
(defn- end-point [rover plateau steps]
(reduce move [rover plateau] steps))
(defn- create-initial-rover [xy-string plateau]
(create-rover (conj (str-to-xy xy-string)
(str-to-dir xy-string))
plateau))
(defn- process-with-open [file-reader file-writer]
(let [max-coords (xy-max file-reader)
plateau {:x-min x-min :x-max (first max-coords) :y-min y-min :y-max (last max-coords)}]
(doseq [rover-data (partition 2 (line-seq file-reader))]
(let [rover (create-initial-rover (first rover-data) plateau)
path (str-to-keywords (last rover-data))]
(write-result (end-point rover plateau path)
file-writer)))))
(defn process [in-file-name out-file-name]
(with-open [file-reader (BufferedReader. (FileReader. in-file-name))]
(with-open [file-writer (clojure.java.io/writer out-file-name)]
(process-with-open file-reader file-writer))))
; -----------------------------------------------------------------------------
(process "input.txt" "output.txt")