 
 (timbre/refer-timbre)
 
+(declare print-cells)
+
+(defn range*
+  [v1 v2]
+  (range (min v1 v2) (inc (max v1 v2))))
+
 (defn canvas
   "Create a blank grid using `nil` for cell values."
   [width height]
   (vec (repeat height (vec (repeat width nil)))))
 
-(defn make-room
-  "A room is a map with
-
-  * an id
-
-  * x and y values for the upper-left corner
-
-  * a width a height"
-  [min-x min-y max-x max-y room-idx]
-  {:id     (keyword (str room-idx))
-   :x      (+ min-x (rand-int max-x))
-   :y      (+ min-y (rand-int max-y))
-   :width  (+ 2 (rand-int 5))
-   :height (+ 2 (rand-int 5))})
+(defn find-point-relation [[start-x start-y] [end-x end-y]]
+  "  top
+    \\    /
+     \\  /
+      \\/
+  left/\\right
+     /  \\
+    /    \\
+    bottom"
+  (let [left-bottom  (> (- end-y start-y) (- end-x start-x))
+        bottom-right (> (- end-y start-y) (* -1 (- end-x start-x)))]
+    (cond
+      (and left-bottom bottom-right)
+        :bottom
+      left-bottom
+        :left
+      bottom-right
+        :right
+      :else
+        :top)))
+
+
+(defn find-door
+  "Takes a room and returns an [x y] of a door on the edge of the room."
+  [[x-min y-min x-max y-max] start end]
+  (let [side         (find-point-relation start end)]
+    (println "find-door" start end side)
+    (rand-nth (case side
+                :left
+                  (map (fn [i] [x-min i]) (range (inc y-min) y-max))
+                :right
+                  (map (fn [i] [x-max i]) (range (inc y-min) y-max))
+                :top
+                  (map (fn [i] [i y-min]) (range (inc x-min) x-max))
+                :bottom
+                  (map (fn [i] [i y-max]) (range (inc x-min) x-max))))))
 
 (defn rooms-to-edges
   "Generate a random set of edges between rooms such that each room

        ;; list: [[x y width height] ...]
        room-bounds  (mapcat (fn [row] 
                               (map (fn [column]
                                      (let [width (rand-int-range min-width max-width)
                                            height (rand-int-range min-height max-height)
                                            x (rand-int-range (* column max-width) (+ (* column max-width) max-width (- width))) 
                                            y (rand-int-range (* row max-height) (+ (* row max-height) max-height (- height)))]
                                      [x y (+ x width) (+ y height)]))
                                    (range columns)))
                             (range rows))
        rooms        (map #(apply room-to-cellsxy %) room-bounds)
        room-centers (map (fn [[x1 y1 x2 y2]] [(int (/ (+ x1 x2) 2))
                                               (int (/ (+ y1 y2) 2))])
                          room-bounds)
        fcg          (points-to-fully-connected-graph room-centers)
        g            (graph-to-minimum-spanning-tree fcg)
        egraph (graph/get-wtd-edge-graph fcg true) 
        eds    (map first (sort-by second egraph)) 
        V  (set (flatten eds))
        uf (algotools.data.union-find/make-union-find V)
         MST (reduce (fn [T [x y]]
                          (if-not (algotools.data.union-find/same-comp? uf x y)
                                  (do (algotools.data.union-find/union uf x y)
                                      (conj T [x y]))
                                  T))
                    [] eds)
        _ (println "egraph" egraph)
        _ (println "eds" eds)
        _ (println "V" V)
        _ (println "uf" uf)
        _ (println "MST" MST)
        corridors    (map (fn [[[x1 y1] [x2 y2]]]
                            (points-to-corridor
                              (edge-to-points x1 y1 x2 y2 (< (rand-int 2) 1))))
                          g)
        upstairs     (conj [(first room-centers)] {:type :up-stairs})
        downstairs   (conj [(last room-centers)] {:type :down-stairs})]
    (println fcg)
    (println g)
    ;(println (vec room-bounds))
    ;(println (vec rooms))
    {:place (apply merge-with-canvas (canvas width height)
                   (concat corridors rooms))
     :up-stairs upstairs
     :down-stairs downstairs}))


         [(read-string from) (read-string to)])
       (graph/MST-kruskal g true)))

(defn vertical-or-horizontally-aligned?
  [& xys]
  (some (partial apply =) (apply map vector xys)))

(defn horizontal-s-segment
  "x*****
        *
        ******x"
  [[x1 y1] [x2 y2]]
  (println "horizontal-s-segment")
  (let [mid-x (int (/ (+ x1 x2) 2))]
    (concat (map #(vector % y1)    (range* x1 mid-x))
            (map #(vector mid-x %) (range* y1 y2))
            (map #(vector % y2)    (range* mid-x x2)))))

(defn vertical-s-segment
  "    x
       *
       *
       ****
          *
          *
          x"
  [[x1 y1] [x2 y2]]
  (println "vertical-s-segment")
  (let [mid-y (int (/ (+ y1 y2) 2))]
    (concat (map #(vector x1 %)    (range* y1 mid-y))
            (map #(vector % mid-y) (range* x1 x2))
            (map #(vector x2 %)    (range* mid-y y2)))))

(defn vertical-corner-segment
  "  x
     *
     *
     *****x"
  [[x1 y1] [x2 y2]]
  (println "vertical-corner-segment")
  (concat (map #(vector x1 %) (range* y1 y2))
          (map #(vector % y2) (range* x1 x2))))

(defn horizontal-corner-segment
  "  x*****
          *
          *
          x"
  [[x1 y1] [x2 y2]]
  (println "horizontal-corner-segment")
  (concat (map #(vector x1 %) (range* y1 y2))
          (map #(vector % y2) (range* x1 x2))))

(defn wall-type
  [[min-x min-y max-x max-y] [x y]]
  (cond
    (= x min-x)
      :vertical
    (= x max-x)
      :vertical
    (= y min-y)
      :horizontal
    (= y max-y)
      :horizontal
    :else
      (assert false (format "Unknown wall type %d %d %d %d %d %d" min-x min-y max-x max-y x y))))

(defn multi-part-segment
  [from from-type to to-type]
  {:pre [(contains? #{:vertical :horizontal} from-type)
         (contains? #{:vertical :horizontal} to-type)]}
  (println "multi-part-segment" from-type to-type)
  (cond
    (= from-type to-type :horizontal)
      (vertical-s-segment from to)
    (= from-type to-type :vertical)
      (horizontal-s-segment from to)
    (= from-type :horizontal)
      (vertical-corner-segment from to)
    (= from-type :vertical)
      (horizontal-corner-segment from to)))

(defn make-corridor-points [cells room-centers-to-room-bounds start end]
  "Finds a list of `[x y]`s comprising a corridor from `start` to `end`.
   `room-centers-to-room-bounds` is a map with `[x y]` keys and `[min-x min-y max-x max-y]` values."
  (let [start-room-bounds (get room-centers-to-room-bounds start)
        end-room-bounds   (get room-centers-to-room-bounds end)
        door-xy-1         (find-door start-room-bounds start end)
        door-xy-2         (find-door end-room-bounds end start)]
    (println "start" start)
    (println "start-room-bounds" start-room-bounds)
    (println "end" end)
    (println "end-room-bounds"end-room-bounds)
    (println "door-1" door-xy-1)
    (println "door-2" door-xy-2)
    (cond
      (vertical-or-horizontally-aligned? door-xy-1 door-xy-2)
        (rlos/line-segment door-xy-1 door-xy-2)
      :else
        (multi-part-segment door-xy-1
                           (wall-type start-room-bounds door-xy-1)
                            door-xy-2
                           (wall-type end-room-bounds door-xy-2)))))

(defn cellsxy-to-cells
  "Convert a grid of `[x y cell]` to cell."
  [cells-xy]
  (let [lines-xy (map (fn [[_ v]] (first v)) (group-by second cells-xy))
