       (gdom/removeChildren card-list)
       (doseq [card cards] (gdom/appendChild card-list card)))))
 
+(defn group-score
+  [layout group]
+  "calculates maximum distance in rows between cards from one group"
+  (transduce
+   (comp
+    (mapcat
+     (fn [[column-id cards]]
+       (map vector (range 0 (count cards)) cards)))
+    (filter #(get group (second %)))
+    (map first))
+   (fn
+     ([[min-pos max-pos]] (- max-pos min-pos))
+     ([[min-pos max-pos] position]
+        [(min min-pos position) (max max-pos position)]))
+   [(reduce max (map #(count (second %)) layout)) 0]
+   layout))
+
 (defn get-layout-score
-  [layout]
-  0)
+  [layout card-deps]
+  (reduce
+   (fn [score group]
+     (+ score (group-score layout group)))
+   0
+   card-deps))
 
 (defn better-score
   [left right]

     (fn [[ungrouped grouped]]
       [column-id
        (reduce into []
                (into
                 (interleave ungrouped grouped)
                 (drop (count grouped) ungrouped)))])
     (cartesian-product [ungrouped-slices grouped-permutations]))))

(defn layout-permuations
  [layout]
  (let [groups (get-card-deps)
        columns-permutations (map (partial column-permutations groups) layout)]
    (map
     (partial into {})
     (cartesian-product columns-permutations))))

(defn optimize-layout
  [layout]
  (let [permutations (layout-permuations layout)]
    (transduce
     (map (fn [layout] [(get-layout-score layout) layout]))
     (fn
       ([final]
          (second final))
       ([best current]
          (if best
            (let [[best-score _] best
                  [current-score _] current]
              (if (better-score current-score best-score)
                current
                best))


(defn handle-layout-change
  [layout]
  (.log js/console "layout changed")
  (-> (optimize-layout layout (get-card-deps))
      apply-layout))

(defn listen-drag
