(def burn-prob 0.1)
(def new-tree-prob 0.5)

(defn grow-new-tree? [] (> new-tree-prob (rand)))
(defn burn-tree? [] (> burn-prob (rand)))
(defn tree-maker [] (if (grow-new-tree?):tree:grass))

(defn make-forest
  ([] (make-forest 5))
  ([size]
  (take size (repeatedly #(take size (repeatedly tree-maker))))))

(defn tree-at [forest row col] (try (-> forest
                                   (nth row)
                                   (nth col))
                                    (catch Exception _ false)))

(defn neighbores-burning? [forest row col]
  (letfn [(burnt? [row col] (=:burnt (tree-at forest row col)))]
    (or
     (burnt? (inc row) col)
     (burnt? (dec row) col)
     (burnt? row (inc col))
     (burnt? row (dec col)))))

(defn lightning-strike [forest]
  (map (fn [forest-row]
         (map #(if (and (= %:tree) (burn-tree?))
                :fire!
                 %)
              forest-row)
         )
       forest))

(defn burn-out-trees [forest]
  (map (fn [forest-row]
         (map #(case %
             :burnt:grass
             :fire!:burnt
              %)
              forest-row))
       forest))

(defn burn-neighbores [forest]
  (let [forest-size (count forest)
        indicies (partition forest-size (for [row (range forest-size) col (range forest-size)] (cons row (list col))))]
    (map (fn [forest-row indicies-row]
           (map #(if (and
                       (=:tree %)
                       (neighbores-burning? forest (first %2) (second %2)))
                   :fire!
                    %)
                forest-row indicies-row))
         forest indicies)))

(defn grow-new-trees [forest] (map (fn [forest-row]
                                     (map #(if (= %:grass)
                                             (tree-maker)
                                             %)
                                          forest-row))
                                     forest))

(defn forest-fire
  ([] (forest-fire 5))
  ([forest-size]
  (loop
      [forest (make-forest forest-size)]
    (pprint forest)
    (Thread/sleep 300)
    (-> forest
        (burn-out-trees)
        (lightning-strike)
        (burn-neighbores)
        (grow-new-trees)
        (recur)))))

(forest-fire)